├── test ├── run_tests.bat ├── requirements.txt ├── run_tests.sh ├── binaries │ ├── rsa │ ├── rsa.gzf │ ├── passcode │ ├── passcode.gzf │ ├── test_ghidra │ ├── test_ghidra.gzf │ ├── test_ghidra.c │ └── passcode64.c ├── test_rsa.py ├── test_passcode.py ├── test_ghidra.py ├── generate_dbg.py └── util.py ├── src ├── .gitignore ├── ghidra2dwarf.sh ├── ghidra2dwarf.py └── elf.py ├── img ├── gdb.png ├── run-script.png ├── ghidra2dwarf.png └── script-directories.png ├── lib ├── .gitignore ├── fetch_libs_and_build.sh ├── pom.xml └── src │ └── main │ └── java │ └── libdwarf │ └── LibdwarfLibrary.java ├── .gitignore ├── .github └── workflows │ ├── release.yml │ └── tests.yml ├── LICENSE └── README.md /test/run_tests.bat: -------------------------------------------------------------------------------- 1 | python3 generate_dbg.py %1 -------------------------------------------------------------------------------- /test/requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==6.1.2 2 | pygdbmi==0.10.0.0 3 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.gpr 2 | *.rep 3 | ghidra/ 4 | ghidra_builtins.pyi 5 | -------------------------------------------------------------------------------- /test/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./generate_dbg.py $1 && pytest . 4 | -------------------------------------------------------------------------------- /img/gdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/img/gdb.png -------------------------------------------------------------------------------- /img/run-script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/img/run-script.png -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | src/main/resources/ 3 | .classpath 4 | .project 5 | .settings/ 6 | -------------------------------------------------------------------------------- /test/binaries/rsa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/rsa -------------------------------------------------------------------------------- /img/ghidra2dwarf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/img/ghidra2dwarf.png -------------------------------------------------------------------------------- /test/binaries/rsa.gzf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/rsa.gzf -------------------------------------------------------------------------------- /test/binaries/passcode: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/passcode -------------------------------------------------------------------------------- /img/script-directories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/img/script-directories.png -------------------------------------------------------------------------------- /test/binaries/passcode.gzf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/passcode.gzf -------------------------------------------------------------------------------- /test/binaries/test_ghidra: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/test_ghidra -------------------------------------------------------------------------------- /test/binaries/test_ghidra.gzf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philzook58/ghidra2dwarf/master/test/binaries/test_ghidra.gzf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | 5 | .gdb_history 6 | .pytest_cache/ 7 | *.gpr 8 | *.rep/ 9 | idata/ 10 | 11 | /test/binaries/*_dbg* -------------------------------------------------------------------------------- /test/test_rsa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from util import Gdb 4 | 5 | 6 | def test_function(): 7 | gdb = Gdb("binaries", "rsa_dbg", debug=False) 8 | gdb.breakpoint(434) 9 | gdb.run() 10 | 11 | assert 0xC5 == gdb.get_int("local_ac0") 12 | assert "local_abf = 0xd6;" == gdb.get_line(434) 13 | 14 | gdb.execute_raw("n") 15 | assert 0xD6 == gdb.get_int("local_abf") 16 | -------------------------------------------------------------------------------- /src/ghidra2dwarf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #script to automatically decompile and output source code of a binary with ghidra 4 | 5 | GHIDRA_PATH=/opt/ghidra 6 | if [ "$#" -ne 4 ] 7 | then 8 | echo "$0 " 9 | exit 10 | fi 11 | 12 | DIR=$1 13 | NAME=$2 14 | BINARY_PATH=$3 15 | BINARY=$4 16 | 17 | #remove gpr and rep files first (CAREFUL!) 18 | rm -rf *.gpr *.rep 19 | 20 | time $GHIDRA_PATH/support/analyzeHeadless $DIR/ $NAME -process $BINARY -postscript ./ghidra2dwarf.py 21 | 22 | -------------------------------------------------------------------------------- /test/test_passcode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from util import Gdb 4 | 5 | 6 | def test_function(): 7 | gdb = Gdb("binaries", "passcode_dbg", debug=True) 8 | gdb.breakpoint(193) 9 | gdb.breakpoint(166) 10 | 11 | NAME = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa' 12 | INPUT = f'{NAME} 1 2' 13 | gdb.run(stdin=INPUT) 14 | 15 | assert NAME == gdb.get_string("(char *)name") 16 | gdb.execute_raw("c") 17 | 18 | assert 0x61616179 == gdb.get_int("passcode1") 19 | assert 'scanf' in gdb.get_line(166) 20 | -------------------------------------------------------------------------------- /test/test_ghidra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from util import Gdb 4 | 5 | 6 | def test_function(): 7 | gdb = Gdb("binaries", "test_ghidra_dbg", debug=True) 8 | gdb.breakpoint(136) 9 | gdb.breakpoint(142) 10 | gdb.run() 11 | 12 | gdb.execute_raw("c 2") 13 | assert 2 == gdb.get_int("i") 14 | assert "i = i + 1;" == gdb.get_line(136) 15 | 16 | gdb.execute_raw("c 3") 17 | d = gdb.get_struct("*ex_2") 18 | assert 15 == d["x"] 19 | assert 20 == d["y"] 20 | assert "Example 1" in d["name"] 21 | 22 | assert 15 == gdb.get_int("ex_2->x") 23 | 24 | assert "print_example(ex_2);" == gdb.get_line(144) 25 | -------------------------------------------------------------------------------- /lib/fetch_libs_and_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [ ! -f src/main/resources/linux-x86-64/libdwarf.so ] && \ 4 | curl -o src/main/resources/linux-x86-64/libdwarf.so -L --create-dirs https://github.com/cesena/libdwarf-ghidra2dwarf/releases/download/latest/libdwarf.so 5 | 6 | [ ! -f src/main/resources/win32-x86-64/libdwarf.dll ] && \ 7 | curl -o src/main/resources/win32-x86-64/libdwarf.dll -L --create-dirs https://github.com/cesena/libdwarf-ghidra2dwarf/releases/download/latest/libdwarf.dll 8 | 9 | [ ! -f src/main/resources/darwin/libdwarf.dylib ] && \ 10 | curl -o src/main/resources/darwin/libdwarf.dylib -L --create-dirs https://github.com/cesena/libdwarf-ghidra2dwarf/releases/download/latest/libdwarf.dylib 11 | 12 | mvn package 13 | -------------------------------------------------------------------------------- /test/generate_dbg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import tempfile 6 | import subprocess 7 | 8 | BINS_DIR = 'binaries' 9 | 10 | ghidra_dir = sys.argv[1] 11 | headless_path = os.path.join(ghidra_dir, 'support', 'analyzeHeadless') 12 | if os.name == 'nt': 13 | headless_path += '.bat' 14 | 15 | with tempfile.TemporaryDirectory(prefix='temp_ghidra2dwarf_') as temp_dir: 16 | for f in os.listdir(BINS_DIR): 17 | if not f.endswith('.gzf'): 18 | continue 19 | name, _ = os.path.splitext(f) 20 | print(name) 21 | cmd = [ 22 | headless_path, temp_dir, name, '-readonly', '-noanalysis', 23 | '-import', os.path.join(BINS_DIR, f), '-scriptPath', os.path.join('..', 'src'), 24 | '-postScript', 'ghidra2dwarf.py', os.path.join(BINS_DIR, name) 25 | ] 26 | print(' '.join(cmd)) 27 | p = subprocess.run(cmd, check=True, stderr=subprocess.PIPE) 28 | print(p.stderr.decode()) 29 | exception = b'Traceback' in p.stderr 30 | assert not exception 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - name: Run latest-tag 14 | uses: EndBug/latest-tag@latest 15 | 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11.0.4 20 | architecture: x64 21 | 22 | - name: Build jar 23 | run: | 24 | cd lib 25 | ./fetch_libs_and_build.sh 26 | mv target/libdwarf.jar ../src 27 | 28 | - name: Zip release 29 | run: | 30 | mv src ghidra2dwarf 31 | zip ghidra2dwarf.zip ghidra2dwarf/libdwarf.jar ghidra2dwarf/ghidra2dwarf.py ghidra2dwarf/elf.py 32 | 33 | - name: Release file 34 | uses: djnicholson/release-action@v2.11 35 | with: 36 | token: ${{ secrets.GITHUB_TOKEN }} 37 | asset-name: 'ghidra2dwarf.zip' 38 | file: 'ghidra2dwarf.zip' 39 | tag-name: 'latest' 40 | release-name: 'Latest build' 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 CeSeNA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/binaries/test_ghidra.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct example { 8 | int x; 9 | int y; 10 | char *name; 11 | } EXAMPLE; 12 | 13 | typedef struct dummy { 14 | int a; 15 | int b; 16 | int c; 17 | } DUMMY; 18 | 19 | EXAMPLE *ex_1; 20 | 21 | EXAMPLE *dup_example(EXAMPLE *ex) { 22 | /* Use this structure not in a return type */ 23 | DUMMY *dum = malloc(sizeof(DUMMY)); 24 | dum->a = 10; 25 | EXAMPLE *new = malloc(sizeof(EXAMPLE)); 26 | new->x = ex->x; 27 | new->y = ex->y; 28 | new->name = ex->name; 29 | return new; 30 | } 31 | 32 | void print_example(EXAMPLE *ex) { 33 | printf("x: %d\ty: %d\tname: %s\n", ex->x, ex->y, ex->name); 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | int i = 0; 38 | ex_1 = malloc(sizeof(EXAMPLE)); 39 | ex_1->x = 10; 40 | for (i = 0; i < 5; i++) { 41 | ex_1->x++; 42 | } 43 | ex_1->y = 20; 44 | ex_1->name = "Example 1"; 45 | print_example(ex_1); 46 | EXAMPLE *ex_2 = dup_example(ex_1); 47 | ex_2->name = "Example 2"; 48 | ex_2->y += ex_2->x; 49 | print_example(ex_2); 50 | return 0; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ghidra2Dwarf 2 | 3 | ![](./img/ghidra2dwarf.png) 4 | 5 | Inspired by: [dwarfexport](https://github.com/ALSchwalm/dwarfexport) 6 | 7 | Contributions are welcome, feel free to open an issue if something is broken. 8 | 9 | Ghidra2Dwarf is a ghidra plugin that allows to exports informations (such as functions, 10 | decompiled code, types) from ghidra to dwarf sections inside ELF binaries. 11 | 12 | More specifically it exports inside a source file named `${program}_dbg.c` all the decompiled 13 | functions, and create an ELF binary named `${program}_dbg` that can be used to 14 | do source code level debugging. 15 | 16 | Example: 17 | 18 | ![](./img/gdb.png) 19 | 20 | Inside gdb now you can use: 21 | 22 | 1. `list ` to display the function's source code. 23 | 2. `n` to step one source code line instruction. 24 | 3. `ni` to step one assembly instruction. 25 | 4. `p variable` to print the variable's value. 26 | 27 | ## Install 28 | 29 | - Unzip the [latest release](https://github.com/cesena/ghidra2dwarf/releases/latest). 30 | - In the script manager -> script directories add the extracted directory: 31 | 32 | ![](./img/script-directories.png) 33 | 34 | Phil: 35 | - You should actually pick the `src` directory for your script path 36 | - Go into `/lib` and run `./fetch_libs_and_build.sh`. Copy libdwarf.jar into src 37 | 38 | ## Run 39 | 40 | Run `ghidra2dwarf.py` inside the script manager: 41 | 42 | ![](./img/run-script.png) 43 | 44 | ### Headless mode 45 | 46 | This mode only works in ghidra 9.1.2 at the moment https://github.com/NationalSecurityAgency/ghidra/issues/2561 47 | 48 | #### Linux 49 | 50 | If you saved the project and ghidra is closed, you can launch [ghidra2dwarf.sh](./src/ghidra2dwarf.sh) 51 | to run ghidra in headless mode and export the dwarf informations: 52 | 53 | ```sh 54 | $ ./src/ghidra2dwarf.sh 55 | $ # Example: ./src/ghidra2dwarf.sh ~/.local/share/ghidra/ TEST ~/CTF/ chall 56 | ``` 57 | 58 | #### Windows 59 | 60 | TODO 61 | 62 | -------------------------------------------------------------------------------- /lib/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | it.cesena 7 | libdwarf 8 | libdwarf 9 | 1.0 10 | jar 11 | 12 | UTF-8 13 | 1.7 14 | 1.7 15 | 16 | 17 | 18 | net.java.dev.jna 19 | jna 20 | 5.6.0 21 | 22 | 23 | 24 | original-${project.name} 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-shade-plugin 29 | 3.2.4 30 | 31 | 32 | package 33 | 34 | shade 35 | 36 | 37 | ${project.name} 38 | true 39 | 40 | 41 | org.scala-lang:scala-library 42 | 43 | 44 | 45 | 46 | *:* 47 | 48 | META-INF/*.SF 49 | META-INF/*.DSA 50 | META-INF/*.RSA 51 | META-INF/maven/** 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /test/binaries/passcode64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | padding 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | */ 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | void login(void) 160 | 161 | { 162 | int passcode1; 163 | int passcode2; 164 | 165 | printf("enter passcode1 : "); 166 | scanf("%d",&passcode1); 167 | fflush(stdin); 168 | printf("enter passcode2 : "); 169 | scanf("%d",&passcode2); 170 | puts("checking..."); 171 | if ((passcode1 == 0x528e6) && (passcode2 == 0xcc07c9)) { 172 | puts("Login OK!"); 173 | system("/bin/cat flag"); 174 | return; 175 | } 176 | puts("Login Failed!"); 177 | /* WARNING: Subroutine does not return */ 178 | exit(0); 179 | } 180 | 181 | 182 | 183 | void welcome(void) 184 | 185 | { 186 | char asd[100]; 187 | char * name = asd; 188 | int local_10; 189 | 190 | //local_10 = *(int *)(in_GS_OFFSET + 0x14); 191 | printf("enter you name : "); 192 | scanf("%100s",name); 193 | printf("Welcome %s!\n",name); 194 | //if (local_10 != *(int *)(in_GS_OFFSET + 0x14)) { 195 | /* WARNING: Subroutine does not return */ 196 | // __stack_chk_fail(); 197 | //} 198 | return; 199 | } 200 | 201 | 202 | 203 | int main(void) 204 | 205 | { 206 | puts("Toddler\'s Secure Login System 1.0 beta."); 207 | welcome(); 208 | login(); 209 | puts("Now I can safely trust you that you have credential :)"); 210 | return 0; 211 | } 212 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | test-ubuntu: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Set up JDK 11 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 11.0.4 21 | architecture: x64 22 | 23 | - uses: er28-0652/setup-ghidra@master 24 | with: 25 | version: "9.1.2" 26 | 27 | - name: install 32bit libs 28 | run: | 29 | sudo dpkg --add-architecture i386 30 | sudo apt update 31 | sudo apt install libc6:i386 32 | 33 | - name: install gdb 34 | run: sudo apt install gdb 35 | 36 | - name: Build jar 37 | run: | 38 | cd lib 39 | ./fetch_libs_and_build.sh 40 | mv target/libdwarf.jar ../src 41 | 42 | - name: install python requirements 43 | run: | 44 | cd test 45 | sudo python3 -m pip install -r requirements.txt 46 | 47 | - name: test 48 | run: | 49 | cd test 50 | #./generate_dbg.py $GHIDRA_INSTALL_DIR 51 | #cd binaries 52 | #chmod +x ./passcode_dbg 53 | #gdb --batch -ex 'start < passcode_input.txt' -ex list -ex continue ./passcode_dbg 54 | ./run_tests.sh $GHIDRA_INSTALL_DIR 55 | 56 | test-windows: 57 | runs-on: windows-latest 58 | steps: 59 | - uses: actions/checkout@v2 60 | 61 | - name: Set up JDK 11 62 | uses: actions/setup-java@v1 63 | with: 64 | java-version: 11.0.4 65 | architecture: x64 66 | 67 | - uses: er28-0652/setup-ghidra@master 68 | with: 69 | version: "9.1.2" 70 | 71 | - uses: actions/setup-python@v2 72 | with: 73 | python-version: '3.x' 74 | 75 | - name: Build jar 76 | shell: cmd 77 | run: | 78 | cd lib 79 | bash fetch_libs_and_build.sh 80 | move target\libdwarf.jar ..\src 81 | 82 | - name: test 83 | shell: cmd 84 | run: | 85 | cd test 86 | copy %pythonLocation%\python.exe python3.exe 87 | call run_tests %GHIDRA_INSTALL_DIR% 88 | 89 | test-macos: 90 | runs-on: macos-latest 91 | steps: 92 | - uses: actions/checkout@v2 93 | 94 | - name: Set up JDK 11 95 | uses: actions/setup-java@v1 96 | with: 97 | java-version: 11.0.4 98 | architecture: x64 99 | 100 | - uses: NextLight/setup-ghidra@octokit-auth 101 | with: 102 | repo-token: ${{ secrets.GITHUB_TOKEN }} 103 | version: "9.1.2" 104 | 105 | - uses: actions/setup-python@v2 106 | with: 107 | python-version: '3.x' 108 | 109 | - name: Build jar 110 | run: | 111 | cd lib 112 | ./fetch_libs_and_build.sh 113 | mv target/libdwarf.jar ../src 114 | 115 | - name: test 116 | run: | 117 | cd test 118 | ./generate_dbg.py $GHIDRA_INSTALL_DIR 119 | -------------------------------------------------------------------------------- /test/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pygdbmi.gdbcontroller import GdbController 4 | from pprint import pprint 5 | from itertools import dropwhile 6 | import tempfile 7 | import os 8 | 9 | 10 | class Gdb: 11 | def __init__(self, directory: str, filename: str, *, debug: bool = False) -> None: 12 | os.chmod(os.path.join(directory, filename), 0o755) 13 | self.gdbmi = GdbController() 14 | self.debug = debug 15 | self.execute_raw(f"cd {directory}") 16 | self.execute_raw(f"-file-exec-and-symbols {filename}") 17 | self.execute_raw("set listsize 1") 18 | 19 | def execute_raw(self, cmd: str) -> list: 20 | response = self.gdbmi.write(cmd) 21 | if self.debug: 22 | print("CMD:", cmd) 23 | pprint(response) 24 | return response 25 | 26 | def execute_mi(self, cmd: str) -> dict: 27 | try: 28 | resp = next(x for x in self.execute_raw(cmd) if x["message"] == "done") 29 | return resp["payload"] 30 | except: 31 | raise Exception(f"The command {repr(cmd)} did not return a value.") 32 | 33 | def execute_gdb(self, cmd: str) -> str: 34 | lines = dropwhile(lambda x: x["type"] != "log", self.execute_raw(cmd)) 35 | r = "".join(x["payload"] for x in lines if x["type"] == "console" and x["stream"] == "stdout" and x["payload"]) 36 | r = r.encode("utf-8").decode("unicode_escape") 37 | if self.debug: 38 | print("RESP:", r) 39 | return r 40 | 41 | def _run_or_start(self, what: str, args: str, stdin: str): 42 | cmd = what 43 | if args: 44 | cmd += f' {args}' 45 | if stdin: 46 | self.f_stdin = tempfile.NamedTemporaryFile(prefix='g2d_stdin_') 47 | self.f_stdin.write(stdin.encode()) 48 | self.f_stdin.flush() 49 | cmd += f' < {self.f_stdin.name}' 50 | return self.execute_raw(cmd) 51 | 52 | def __del__(self): 53 | if hasattr(self, 'f_stdin'): 54 | self.f_stdin.close() 55 | 56 | def run(self, *, args: str='', stdin: str=''): 57 | return self._run_or_start('run', args=args, stdin=stdin) 58 | 59 | def start(self, *, args: str='', stdin: str=''): 60 | return self._run_or_start('start', args=args, stdin=stdin) 61 | 62 | def breakpoint(self, addr: int): 63 | return self.execute_mi(f"-break-insert {addr}") 64 | 65 | def create_var(self, name: str) -> dict: 66 | if isinstance(name, dict): 67 | return name 68 | out = self.execute_mi(f'-var-create - * "{name}"') 69 | return out 70 | 71 | def var_to_python(self, var: dict): 72 | t = var["type"] 73 | if t == "char *": 74 | return self.get_string(var) 75 | elif t[-1] == "]": 76 | return self.get_array(var) 77 | else: 78 | return self.get_int(var) 79 | 80 | def get_list_children(self, var: dict) -> list: 81 | # TODO: has_more? 82 | return self.execute_mi(f'-var-list-children {var["name"]}')["children"] 83 | 84 | def get_struct(self, expr: str) -> dict: 85 | var = self.create_var(expr) 86 | children = self.get_list_children(var) 87 | return {c["exp"]: self.var_to_python(c) for c in children} 88 | 89 | def get_array(self, expr: str) -> list: 90 | var = self.create_var(expr) 91 | return [self.var_to_python(c) for c in self.get_list_children(var)] 92 | 93 | def get_int(self, expr: str) -> int: 94 | var = self.create_var(expr) 95 | value = self.var_evaluate(var, format="hexadecimal") 96 | return int(value, 16) 97 | 98 | def get_string(self, expr: str) -> str: 99 | var = self.create_var(expr) 100 | value = self.var_evaluate(var) 101 | return value.split(" ", 1)[1].strip('"').encode("utf-8").decode("unicode_escape") 102 | 103 | def var_evaluate(self, var, *, format="natural") -> str: 104 | name = var["name"] if isinstance(var, dict) else var 105 | return self.execute_mi(f"-var-evaluate-expression -f {format} {name}")["value"] 106 | 107 | def get_line(self, line: int) -> str: 108 | res = self.execute_gdb(f"list {line}") 109 | _, payload = res.split(f"{line}\t") 110 | return payload.replace("\n", "").strip() 111 | -------------------------------------------------------------------------------- /lib/src/main/java/libdwarf/LibdwarfLibrary.java: -------------------------------------------------------------------------------- 1 | package libdwarf; 2 | import com.sun.jna.Callback; 3 | import com.sun.jna.Library; 4 | import com.sun.jna.Native; 5 | import com.sun.jna.Platform; 6 | import com.sun.jna.Pointer; 7 | import com.sun.jna.PointerType; 8 | import com.sun.jna.ptr.IntByReference; 9 | import com.sun.jna.ptr.LongByReference; 10 | import com.sun.jna.ptr.PointerByReference; 11 | 12 | public interface LibdwarfLibrary extends Library { 13 | public static final LibdwarfLibrary INSTANCE = (LibdwarfLibrary)Native.loadLibrary(Platform.isWindows() ? "libdwarf" : "dwarf", LibdwarfLibrary.class); 14 | 15 | // functions 16 | String dwarf_errmsg(LibdwarfLibrary.Dwarf_Error Dwarf_Error1); 17 | String dwarf_errmsg_by_number(long Dwarf_Unsigned1); 18 | int dwarf_producer_init(long Dwarf_Unsigned1, LibdwarfLibrary.Dwarf_Callback_Func Dwarf_Callback_Func1, LibdwarfLibrary.Dwarf_Handler Dwarf_Handler1, Pointer Dwarf_Ptr1, Pointer voidPtr1, String isa_name, String dwarf_version, String extra, PointerByReference Dwarf_P_DebugPtr1, PointerByReference Dwarf_ErrorPtr1); 19 | int dwarf_pro_set_default_string_form(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, int int1, PointerByReference Dwarf_ErrorPtr1); 20 | long dwarf_transform_to_disk_form(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, PointerByReference Dwarf_ErrorPtr1); 21 | Pointer dwarf_get_section_bytes(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, long Dwarf_Signed1, LongByReference Dwarf_SignedPtr1, LongByReference Dwarf_UnsignedPtr1, PointerByReference Dwarf_ErrorPtr1); 22 | int dwarf_producer_finish_a(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, PointerByReference Dwarf_ErrorPtr1); 23 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_targ_address(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, short Dwarf_Half1, long Dwarf_Unsigned1, long Dwarf_Signed1, PointerByReference Dwarf_ErrorPtr1); 24 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_unsigned_const(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, short Dwarf_Half1, long Dwarf_Unsigned1, PointerByReference Dwarf_ErrorPtr1); 25 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_reference(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, short Dwarf_Half1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die2, PointerByReference Dwarf_ErrorPtr1); 26 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_location_expr(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, short Dwarf_Half1, LibdwarfLibrary.Dwarf_P_Expr Dwarf_P_Expr1, PointerByReference Dwarf_ErrorPtr1); 27 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_string(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, short Dwarf_Half1, String charPtr1, PointerByReference Dwarf_ErrorPtr1); 28 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_comp_dir(LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, String charPtr1, PointerByReference Dwarf_ErrorPtr1); 29 | LibdwarfLibrary.Dwarf_P_Attribute dwarf_add_AT_name(LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, String charPtr1, PointerByReference Dwarf_ErrorPtr1); 30 | long dwarf_add_directory_decl(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, String charPtr1, PointerByReference Dwarf_ErrorPtr1); 31 | long dwarf_add_file_decl(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, String charPtr1, long Dwarf_Unsigned1, long Dwarf_Unsigned2, long Dwarf_Unsigned3, PointerByReference Dwarf_ErrorPtr1); 32 | long dwarf_add_line_entry(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, long Dwarf_Unsigned1, long Dwarf_Addr1, long Dwarf_Unsigned2, long Dwarf_Signed1, int Dwarf_Bool1, int Dwarf_Bool2, PointerByReference Dwarf_ErrorPtr1); 33 | long dwarf_lne_set_address(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, long Dwarf_Unsigned1, long Dwarf_Unsigned2, PointerByReference Dwarf_ErrorPtr1); 34 | LibdwarfLibrary.Dwarf_P_Die dwarf_new_die(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, long Dwarf_Tag1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die2, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die3, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die4, PointerByReference Dwarf_ErrorPtr1); 35 | int dwarf_add_die_to_debug_a(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, LibdwarfLibrary.Dwarf_P_Die Dwarf_P_Die1, PointerByReference Dwarf_ErrorPtr1); 36 | LibdwarfLibrary.Dwarf_P_Expr dwarf_new_expr(LibdwarfLibrary.Dwarf_P_Debug Dwarf_P_Debug1, PointerByReference Dwarf_ErrorPtr1); 37 | long dwarf_add_expr_gen(LibdwarfLibrary.Dwarf_P_Expr Dwarf_P_Expr1, byte Dwarf_Small1, long Dwarf_Unsigned1, long Dwarf_Unsigned2, PointerByReference Dwarf_ErrorPtr1); 38 | long dwarf_add_expr_addr_b(LibdwarfLibrary.Dwarf_P_Expr Dwarf_P_Expr1, long Dwarf_Unsigned1, long Dwarf_Unsigned2, PointerByReference Dwarf_ErrorPtr1); 39 | 40 | // callbacks 41 | public interface Dwarf_Handler extends Callback { 42 | void apply(Pointer Dwarf_Error1, Pointer Dwarf_Ptr1); 43 | }; 44 | public interface Dwarf_Callback_Func extends Callback { 45 | int apply(Pointer charPtr1, int int1, long Dwarf_Unsigned1, long Dwarf_Unsigned2, long Dwarf_Unsigned3, long Dwarf_Unsigned4, LongByReference Dwarf_UnsignedPtr1, Pointer voidPtr1, IntByReference intPtr1); 46 | }; 47 | 48 | // classes 49 | public static class Dwarf_P_Debug extends PointerType { 50 | public Dwarf_P_Debug(Pointer address) { 51 | super(address); 52 | } 53 | public Dwarf_P_Debug() { 54 | super(); 55 | } 56 | }; 57 | public static class Dwarf_P_Expr extends PointerType { 58 | public Dwarf_P_Expr(Pointer address) { 59 | super(address); 60 | } 61 | public Dwarf_P_Expr() { 62 | super(); 63 | } 64 | }; 65 | public static class Dwarf_Error extends PointerType { 66 | public Dwarf_Error(Pointer address) { 67 | super(address); 68 | } 69 | public Dwarf_Error() { 70 | super(); 71 | } 72 | }; 73 | public static class Dwarf_P_Die extends PointerType { 74 | public Dwarf_P_Die(Pointer address) { 75 | super(address); 76 | } 77 | public Dwarf_P_Die() { 78 | super(); 79 | } 80 | }; 81 | public static class Dwarf_P_Attribute extends PointerType { 82 | public Dwarf_P_Attribute(Pointer address) { 83 | super(address); 84 | } 85 | public Dwarf_P_Attribute() { 86 | super(); 87 | } 88 | }; 89 | 90 | // constants 91 | public static final int DW_ATE_address = (int)0x01; 92 | public static final int DW_ATE_boolean = (int)0x02; 93 | public static final int DW_ATE_complex_float = (int)0x03; 94 | public static final int DW_ATE_float = (int)0x04; 95 | public static final int DW_ATE_signed = (int)0x05; 96 | public static final int DW_ATE_signed_char = (int)0x06; 97 | public static final int DW_ATE_unsigned = (int)0x07; 98 | public static final int DW_ATE_unsigned_char = (int)0x08; 99 | public static final int DW_AT_byte_size = (int)0x0b; 100 | public static final int DW_AT_const_value = (int)0x1c; 101 | public static final int DW_AT_count = (int)0x37; 102 | public static final int DW_AT_data_member_location = (int)0x38; 103 | public static final int DW_AT_decl_file = (int)0x3a; 104 | public static final int DW_AT_decl_line = (int)0x3b; 105 | public static final int DW_AT_encoding = (int)0x3e; 106 | public static final int DW_AT_frame_base = (int)0x40; 107 | public static final int DW_AT_high_pc = (int)0x12; 108 | public static final int DW_AT_linkage_name = (int)0x6e; 109 | public static final int DW_AT_location = (int)0x02; 110 | public static final int DW_AT_low_pc = (int)0x11; 111 | public static final int DW_AT_type = (int)0x49; 112 | public static final int DW_DLC_OFFSET32 = (int)0x00010000; 113 | public static final int DW_DLC_POINTER64 = (int)0x40000000; 114 | public static final int DW_DLC_SYMBOLIC_RELOCATIONS = (int)0x04000000; 115 | public static final int DW_DLC_TARGET_LITTLEENDIAN = (int)0x00100000; 116 | public static final int DW_DLC_WRITE = (int)1; 117 | public static final Pointer DW_DLV_BADADDR = new Pointer((long)(~0)); 118 | public static final long DW_DLV_NOCOUNT = (long)-1; 119 | public static final int DW_DLV_OK = (int)0; 120 | public static final int DW_FORM_string = (int)0x08; 121 | public static final int DW_FRAME_HIGHEST_NORMAL_REGISTER = (int)188; 122 | public static final int DW_FRAME_LAST_REG_NUM = (int)(DW_FRAME_HIGHEST_NORMAL_REGISTER + 3); 123 | public static final int DW_OP_breg0 = (int)0x70; 124 | public static final int DW_OP_breg1 = (int)0x71; 125 | public static final int DW_OP_breg2 = (int)0x72; 126 | public static final int DW_OP_breg3 = (int)0x73; 127 | public static final int DW_OP_breg4 = (int)0x74; 128 | public static final int DW_OP_breg5 = (int)0x75; 129 | public static final int DW_OP_breg6 = (int)0x76; 130 | public static final int DW_OP_breg7 = (int)0x77; 131 | public static final int DW_OP_breg8 = (int)0x78; 132 | public static final int DW_OP_breg9 = (int)0x79; 133 | public static final int DW_OP_breg10 = (int)0x7a; 134 | public static final int DW_OP_breg11 = (int)0x7b; 135 | public static final int DW_OP_breg12 = (int)0x7c; 136 | public static final int DW_OP_breg13 = (int)0x7d; 137 | public static final int DW_OP_breg14 = (int)0x7e; 138 | public static final int DW_OP_breg15 = (int)0x7f; 139 | public static final int DW_OP_breg16 = (int)0x80; 140 | public static final int DW_OP_breg17 = (int)0x81; 141 | public static final int DW_OP_breg18 = (int)0x82; 142 | public static final int DW_OP_breg19 = (int)0x83; 143 | public static final int DW_OP_breg20 = (int)0x84; 144 | public static final int DW_OP_breg21 = (int)0x85; 145 | public static final int DW_OP_breg22 = (int)0x86; 146 | public static final int DW_OP_breg23 = (int)0x87; 147 | public static final int DW_OP_breg24 = (int)0x88; 148 | public static final int DW_OP_breg25 = (int)0x89; 149 | public static final int DW_OP_breg26 = (int)0x8a; 150 | public static final int DW_OP_breg27 = (int)0x8b; 151 | public static final int DW_OP_breg28 = (int)0x8c; 152 | public static final int DW_OP_breg29 = (int)0x8d; 153 | public static final int DW_OP_breg30 = (int)0x8e; 154 | public static final int DW_OP_breg31 = (int)0x8f; 155 | public static final int DW_OP_call_frame_cfa = (int)0x9c; 156 | public static final int DW_OP_fbreg = (int)0x91; 157 | public static final int DW_OP_plus_uconst = (int)0x23; 158 | public static final int DW_OP_regx = (int)0x90; 159 | public static final int DW_TAG_array_type = (int)0x01; 160 | public static final int DW_TAG_base_type = (int)0x24; 161 | public static final int DW_TAG_compile_unit = (int)0x11; 162 | public static final int DW_TAG_enumeration_type = (int)0x04; 163 | public static final int DW_TAG_enumerator = (int)0x28; 164 | public static final int DW_TAG_formal_parameter = (int)0x05; 165 | public static final int DW_TAG_member = (int)0x0d; 166 | public static final int DW_TAG_pointer_type = (int)0x0f; 167 | public static final int DW_TAG_structure_type = (int)0x13; 168 | public static final int DW_TAG_subprogram = (int)0x2e; 169 | public static final int DW_TAG_subrange_type = (int)0x21; 170 | public static final int DW_TAG_variable = (int)0x34; 171 | } 172 | -------------------------------------------------------------------------------- /src/ghidra2dwarf.py: -------------------------------------------------------------------------------- 1 | # Ghidra2Dwarf 2 | # @author sen, meowmeowxw 3 | # @category PWN 4 | # @keybinding 5 | # @menupath 6 | # @toolbar 7 | 8 | try: 9 | from ghidra_builtins import * 10 | except: 11 | pass 12 | 13 | import os 14 | import sys 15 | 16 | from ghidra.app.decompiler import DecompInterface, DecompileOptions 17 | from ghidra.app.util.bin.format.elf import ElfSymbolTable 18 | from ghidra.app.decompiler.component import DecompilerUtils 19 | from ghidra.program.database.data import PointerDB 20 | from ghidra.program.model.symbol import SymbolTable, SymbolType 21 | from ghidra.program.model.data import Pointer, Structure, DefaultDataType, BuiltInDataType, BooleanDataType, CharDataType, AbstractIntegerDataType, AbstractFloatDataType, AbstractComplexDataType, ArrayDataType, Array, Enum 22 | from ghidra.app.util.bin.format.dwarf4.next import DWARFRegisterMappingsManager 23 | from ghidra.util.task import ConsoleTaskMonitor 24 | from ghidra.app.util.opinion import ElfLoader 25 | from ghidra.framework import OperatingSystem 26 | 27 | from elf import add_sections_to_elf 28 | 29 | # we have to load libdwarf.jar dynamically by adding it to the path for some reason 30 | script_path = sourceFile.absolutePath 31 | libdwarf_jar_path = os.path.join(os.path.dirname(script_path), "libdwarf.jar") 32 | sys.path.append(libdwarf_jar_path) 33 | 34 | from libdwarf import LibdwarfLibrary 35 | from com.sun.jna.ptr import PointerByReference, LongByReference 36 | from com.sun.jna import Memory 37 | from java.nio import ByteBuffer 38 | 39 | 40 | curr = getCurrentProgram() 41 | if curr.executableFormat != ElfLoader.ELF_NAME: 42 | print "Only ELF binaries are supported" 43 | exit(1) 44 | image_base = curr.imageBase.offset 45 | is_pie = curr.relocationTable.relocatable 46 | orig_base = ElfLoader.getElfOriginalImageBase(curr) 47 | # this breaks stuff, we changed approach and started using get_real_address 48 | # curr.setImageBase(toAddr(orig_base), False) 49 | 50 | 51 | def get_real_address(addr): 52 | return addr.offset - image_base + orig_base 53 | 54 | 55 | def get_libdwarf_err(): 56 | derr = Dwarf_Error(err.value) 57 | print derr 58 | return dwarf_errmsg(derr) 59 | 60 | 61 | record = {} 62 | exe_path = curr.executablePath 63 | # workaround ghidra being dumb and putting a slash in front of Windows paths 64 | # this should be fixed in the next release as discussed here: 65 | # https://github.com/NationalSecurityAgency/ghidra/pull/2220 66 | if OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS and exe_path[0] == "/": 67 | exe_path = exe_path[1:] 68 | 69 | while not os.path.isfile(exe_path): 70 | print "I couldn't find the original file at path %s. Please specify its path:" % exe_path 71 | exe_path = askFile("Original binary path", "Open").path 72 | curr.executablePath = exe_path 73 | print "Changed binary path to %s." % exe_path 74 | 75 | out_path = exe_path + "_dbg" 76 | decompiled_c_path = exe_path + "_dbg.c" 77 | decomp_lines = [] 78 | 79 | ERR_IS_NOT_OK = lambda e: e != DW_DLV_OK 80 | ERR_IS_NOCOUNT = lambda e: e == DW_DLV_NOCOUNT 81 | ERR_IS_BADADDR = lambda e: e is None or e == DW_DLV_BADADDR or (hasattr(e, "pointer") and e.pointer == DW_DLV_BADADDR) 82 | DWARF_FUNCTIONS = { 83 | 'dwarf_producer_init': ERR_IS_NOT_OK, 84 | 'dwarf_pro_set_default_string_form': ERR_IS_NOT_OK, 85 | 'dwarf_transform_to_disk_form': ERR_IS_NOCOUNT, 86 | 'dwarf_get_section_bytes': ERR_IS_BADADDR, 87 | 'dwarf_producer_finish_a': ERR_IS_NOT_OK, 88 | 'dwarf_add_AT_targ_address': ERR_IS_BADADDR, 89 | 'dwarf_add_AT_unsigned_const': ERR_IS_BADADDR, 90 | 'dwarf_add_AT_reference': ERR_IS_BADADDR, 91 | 'dwarf_add_AT_location_expr': ERR_IS_BADADDR, 92 | 'dwarf_add_AT_string': ERR_IS_BADADDR, 93 | 'dwarf_add_AT_comp_dir': ERR_IS_BADADDR, 94 | 'dwarf_add_AT_name': ERR_IS_BADADDR, 95 | 'dwarf_add_directory_decl': ERR_IS_NOCOUNT, 96 | 'dwarf_add_file_decl': ERR_IS_NOCOUNT, 97 | 'dwarf_add_line_entry': ERR_IS_NOCOUNT, 98 | 'dwarf_lne_set_address': ERR_IS_NOCOUNT, 99 | 'dwarf_new_die': ERR_IS_BADADDR, 100 | 'dwarf_add_die_to_debug_a': ERR_IS_NOT_OK, 101 | 'dwarf_new_expr': ERR_IS_BADADDR, 102 | 'dwarf_add_expr_gen': ERR_IS_NOCOUNT, 103 | 'dwarf_add_expr_addr_b': ERR_IS_NOCOUNT 104 | } 105 | 106 | 107 | def generate_fun_wrapper(name, fun): 108 | def wrapper(*args): 109 | r = fun(*(args + (err,))) 110 | error_check = DWARF_FUNCTIONS[name] 111 | if error_check(r): 112 | # TODO: dwarf_errmsg (hence get_libdwarf_err) is broken for some reason 113 | # assert False, "%s failed: %s" % (name, get_libdwarf_err()) 114 | assert False, "%s failed. Returned %r" % (name, r) 115 | return r 116 | 117 | return wrapper 118 | 119 | 120 | l = LibdwarfLibrary.INSTANCE 121 | g = globals() 122 | for name in LibdwarfLibrary.__dict__.keys(): 123 | if name in DWARF_FUNCTIONS: 124 | fun = getattr(l, name) 125 | g[name] = generate_fun_wrapper(name, fun) 126 | else: 127 | g[name] = getattr(l, name) 128 | 129 | 130 | def add_debug_info(): 131 | dwarf_pro_set_default_string_form(dbg, DW_FORM_string) 132 | cu = dwarf_new_die(dbg, DW_TAG_compile_unit, None, None, None, None) 133 | 134 | c_file_name = os.path.split(decompiled_c_path)[1] 135 | dwarf_add_AT_name(cu, c_file_name) 136 | dir_index = dwarf_add_directory_decl(dbg, ".") 137 | file_index = dwarf_add_file_decl(dbg, c_file_name, dir_index, 0, 0) 138 | dwarf_add_AT_comp_dir(cu, ".") 139 | 140 | funcs = get_functions() 141 | for i, f in enumerate(funcs): 142 | print "Decompiling function %d: %s" % (i, f) 143 | add_function(cu, f, file_index) 144 | 145 | dwarf_add_die_to_debug_a(dbg, cu) 146 | add_global_variables(cu) 147 | add_structures(cu) 148 | 149 | 150 | def generate_register_mappings(): 151 | d2g_mapping = DWARFRegisterMappingsManager.getMappingForLang(curr.language) 152 | g2d_mapping = {} 153 | for i in range(DW_FRAME_LAST_REG_NUM): 154 | reg = d2g_mapping.getGhidraReg(i) 155 | if reg: 156 | g2d_mapping[reg.offset] = i 157 | stack_reg_num = d2g_mapping.DWARFStackPointerRegNum 158 | stack_reg_dwarf = globals()["DW_OP_breg%d" % stack_reg_num] 159 | return g2d_mapping, stack_reg_dwarf 160 | 161 | 162 | def generate_decomp_interface(): 163 | decompiler = DecompInterface() 164 | opts = DecompileOptions() 165 | opts.grabFromProgram(curr) 166 | decompiler.setOptions(opts) 167 | decompiler.toggleCCode(True) 168 | decompiler.toggleSyntaxTree(True) 169 | 170 | # - decompile -- The main decompiler action 171 | # - normalize -- Decompilation tuned for normalization 172 | # - jumptable -- Simplify just enough to recover a jump-table 173 | # - paramid -- Simplify enough to recover function parameters 174 | # - register -- Perform one analysis pass on registers, without stack variables 175 | # - firstpass -- Construct the initial raw syntax tree, with no simplification 176 | decompiler.setSimplificationStyle("decompile") 177 | decompiler.openProgram(curr) 178 | return decompiler 179 | 180 | 181 | def get_decompiled_function(func): 182 | return decompiler.decompileFunction(func, 0, monitor) 183 | 184 | 185 | def get_decompiled_variables(decomp): 186 | hf = decomp.highFunction 187 | symbolMap = hf.localSymbolMap 188 | params = [symbolMap.getParam(i).symbol for i in range(symbolMap.numParams) if symbolMap.getParam(i)] 189 | for s in symbolMap.symbols: 190 | yield s.name, s.dataType, s.PCAddress, s.storage, s in params 191 | 192 | 193 | def add_decompiler_func_info(cu, func_die, func, decomp, file_index, func_line): 194 | # https://ghidra.re/ghidra_docs/api/ghidra/app/decompiler/DecompileResults.html 195 | # print func.allVariables 196 | for name, datatype, addr, storage, is_param in get_decompiled_variables(decomp): 197 | add_variable(cu, func_die, name, datatype, addr, storage, is_parameter=is_param) 198 | 199 | cmarkup = decomp.CCodeMarkup 200 | # TODO: implement our own pretty printer? 201 | # https://github.com/NationalSecurityAgency/ghidra/blob/master/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/PrettyPrinter.java 202 | lines = DecompilerUtils.toLines(cmarkup) 203 | for l in lines: 204 | # TODO: multiple lines might have the same lowest address 205 | addresses = [get_real_address(t.minAddress) for t in l.allTokens if t.minAddress] 206 | # TODO: We need to use max or min? In some cases with min we have incorrect offset 207 | best_addr = addresses[0] if addresses else None 208 | 209 | if best_addr: 210 | # TODO: is this call to dwarf_lne_set_address needed? 211 | # dwarf_lne_set_address(dbg, lowest_line_addr, 0) 212 | # https://nxmnpg.lemoda.net/3/dwarf_add_line_entry 213 | dwarf_add_line_entry(dbg, file_index, best_addr, l.lineNumber + func_line - 1, 0, True, False) 214 | 215 | 216 | def get_functions(): 217 | fm = curr.functionManager 218 | funcs = fm.getFunctions(True) 219 | return funcs 220 | 221 | 222 | def get_function_range(func): 223 | return get_real_address(func.entryPoint), get_real_address(func.body.maxAddress) 224 | 225 | 226 | def is_function_executable(func): 227 | f_start, f_end = get_function_range(func) 228 | # Check for functions inside executable segments 229 | for s in curr.memory.executeSet.addressRanges: 230 | if f_start >= get_real_address(s.minAddress) and f_end <= get_real_address(s.maxAddress): 231 | return True 232 | return False 233 | 234 | 235 | def add_global_variables(cu): 236 | for s in curr.symbolTable.getAllSymbols(True): 237 | # TODO: What is the difference between GLOBAL and GLOBAL_VAR ? 238 | if s.symbolType in [SymbolType.LABEL, SymbolType.GLOBAL, SymbolType.GLOBAL_VAR]: 239 | t = curr.listing.getDataAt(s.address) 240 | if t: 241 | die = dwarf_new_die(dbg, DW_TAG_variable, cu, None, None, None) 242 | var_type_die = add_type(cu, t.dataType) 243 | 244 | dwarf_add_AT_name(die, s.name) 245 | dwarf_add_AT_reference(dbg, die, DW_AT_type, var_type_die) 246 | 247 | loc_expr = dwarf_new_expr(dbg) 248 | dwarf_add_expr_addr_b(loc_expr, get_real_address(t.address), 0) 249 | dwarf_add_AT_location_expr(dbg, die, DW_AT_location, loc_expr) 250 | 251 | 252 | def add_structures(cu): 253 | for s in curr.dataTypeManager.allStructures: 254 | add_type(cu, s) 255 | 256 | 257 | def add_variable(cu, func_die, name, datatype, addr, storage, is_parameter=False): 258 | # TODO: there could be more than one varnode, what does it even mean? 259 | varnode = storage.firstVarnode 260 | # It looks like sometimes ghidra creates a fake/temp variable without any varnodes, it should be ok to ignore it 261 | if varnode is None: 262 | return None 263 | varnode_addr = varnode.getAddress() 264 | 265 | # TODO: add varaible starting from addr 266 | tag = DW_TAG_variable 267 | if is_parameter: 268 | tag = DW_TAG_formal_parameter 269 | var_die = dwarf_new_die(dbg, tag, func_die, None, None, None) 270 | type_die = add_type(cu, datatype) 271 | 272 | dwarf_add_AT_reference(dbg, var_die, DW_AT_type, type_die) 273 | dwarf_add_AT_name(var_die, name) 274 | 275 | expr = dwarf_new_expr(dbg) 276 | 277 | try: 278 | if varnode_addr.isRegisterAddress(): 279 | reg = curr.getRegister(varnode_addr, varnode.size) 280 | reg_dwarf = register_mappings[reg.offset] 281 | dwarf_add_expr_gen(expr, DW_OP_regx, reg_dwarf, 0) 282 | elif varnode_addr.isStackAddress(): 283 | # TODO: properly get register size and figure out if this is always correct 284 | dwarf_add_expr_gen(expr, DW_OP_fbreg, varnode_addr.offset - varnode_addr.pointerSize, 0) 285 | elif varnode_addr.isMemoryAddress(): 286 | print name, varnode 287 | # TODO: globals? 288 | assert False, "Memory address" 289 | elif varnode_addr.isHashAddress(): 290 | # TODO: ghidra synthetic vars. 291 | # It however often can be linked to a register(/stack off?) if looking at the disass, 292 | # find, if possible, how to get it programmatically. 293 | # This info is likely lost when generating the decompiled code. :( 294 | # print 'hash', varnode, curr.getRegister(varnode_addr, varnode.size) 295 | pass 296 | else: 297 | assert False, ("ERR var:", varnode) 298 | 299 | dwarf_add_AT_location_expr(dbg, var_die, DW_AT_location, expr) 300 | except: 301 | return var_die 302 | return var_die 303 | 304 | 305 | def add_function(cu, func, file_index): 306 | die = dwarf_new_die(dbg, DW_TAG_subprogram, cu, None, None, None) 307 | loc_expr = dwarf_new_expr(dbg) 308 | dwarf_add_expr_gen(loc_expr, DW_OP_call_frame_cfa, 0, 0) 309 | dwarf_add_AT_location_expr(dbg, die, DW_AT_frame_base, loc_expr) 310 | f_name = func.name 311 | dwarf_add_AT_name(die, f_name) 312 | dwarf_add_AT_string(dbg, die, DW_AT_linkage_name, f_name) 313 | 314 | # TODO: Check for multiple ranges 315 | f_start, f_end = get_function_range(func) 316 | 317 | ret_type_die = add_type(cu, func.returnType) 318 | dwarf_add_AT_reference(dbg, die, DW_AT_type, ret_type_die) 319 | 320 | dwarf_add_AT_targ_address(dbg, die, DW_AT_low_pc, f_start, 0) 321 | dwarf_add_AT_targ_address(dbg, die, DW_AT_high_pc, f_end - 1, 0) 322 | 323 | func_line = len(decomp_lines) + 1 324 | 325 | res = get_decompiled_function(func) 326 | if res.decompiledFunction is None: 327 | d = "/* Error decompiling %s: %s */" % (func.getName(True), res.errorMessage) 328 | else: 329 | d = res.decompiledFunction.c 330 | decomp_lines.extend(d.split("\n")) 331 | 332 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_decl_file, file_index) 333 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_decl_line, func_line) 334 | dwarf_add_line_entry(dbg, file_index, f_start, func_line, 0, True, False) 335 | if res.decompiledFunction is not None: 336 | add_decompiler_func_info(cu, die, func, res, file_index, func_line) 337 | 338 | return die 339 | 340 | 341 | def write_source(): 342 | with open(decompiled_c_path, "wb") as src: 343 | src.write("\n".join(decomp_lines).encode("utf8")) 344 | 345 | 346 | def add_type(cu, t): 347 | if t.name in record: 348 | return record[t.name] 349 | 350 | if isinstance(t, Pointer): 351 | return add_ptr_type(cu, t) 352 | elif isinstance(t, Enum): 353 | return add_enum_type(cu, t) 354 | elif isinstance(t, Array): 355 | return add_array_type(cu, t) 356 | elif isinstance(t, Structure): 357 | return add_struct_type(cu, t) 358 | elif isinstance(t, (BuiltInDataType, DefaultDataType)): 359 | return add_default_type(cu, t) 360 | else: 361 | try: 362 | return add_default_type(cu, t) 363 | except: 364 | assert False, ("ERR type:", type(t), t) 365 | return None 366 | 367 | 368 | def add_default_type(cu, t): 369 | die = dwarf_new_die(dbg, DW_TAG_base_type, cu, None, None, None) 370 | record[t.name] = die 371 | dwarf_add_AT_name(die, t.name) 372 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_byte_size, t.length) 373 | 374 | # type encoding dwarfstd.org/doc/DWARF4.pdf#page=91 375 | if isinstance(t, BooleanDataType): 376 | encoding = DW_ATE_boolean 377 | elif isinstance(t, CharDataType): 378 | is_char_signed = t.dataTypeManager.dataOrganization.signedChar 379 | encoding = DW_ATE_signed_char if is_char_signed else DW_ATE_unsigned_char 380 | elif isinstance(t, AbstractIntegerDataType): 381 | encoding = DW_ATE_signed if t.signed else DW_ATE_unsigned 382 | elif isinstance(t, AbstractFloatDataType): 383 | encoding = DW_ATE_float 384 | elif isinstance(t, AbstractComplexDataType): 385 | encoding = DW_ATE_complex_float 386 | else: 387 | # if I forgot a type it's probably ok for it to be encoded as an unsigned integer 388 | encoding = DW_ATE_unsigned 389 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_encoding, encoding) 390 | return die 391 | 392 | 393 | def add_ptr_type(cu, t): 394 | die = dwarf_new_die(dbg, DW_TAG_pointer_type, cu, None, None, None) 395 | record[t.name] = die 396 | 397 | # Some pointer don't have childs 398 | if t.dataType: 399 | child_die = add_type(cu, t.dataType) 400 | dwarf_add_AT_reference(dbg, die, DW_AT_type, child_die) 401 | 402 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_byte_size, t.length) 403 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_encoding, DW_ATE_address) 404 | return die 405 | 406 | 407 | def add_enum_type(cu, t): 408 | die = dwarf_new_die(dbg, DW_TAG_enumeration_type, cu, None, None, None) 409 | record[t.name] = die 410 | 411 | dwarf_add_AT_name(die, t.name) 412 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_byte_size, t.length) 413 | 414 | int_type = AbstractIntegerDataType.getUnsignedDataType(t.length, curr.dataTypeManager) 415 | child_type_die = add_type(cu, int_type) 416 | dwarf_add_AT_reference(dbg, die, DW_AT_type, child_type_die) 417 | 418 | # In this way we iterate the values in order 419 | for value in t.values: 420 | name = t.getName(value) 421 | child_die = dwarf_new_die(dbg, DW_TAG_enumerator, die, None, None, None) 422 | dwarf_add_AT_name(child_die, name) 423 | dwarf_add_AT_unsigned_const(dbg, child_die, DW_AT_const_value, value) 424 | 425 | return die 426 | 427 | 428 | def add_struct_type(cu, struct): 429 | die = dwarf_new_die(dbg, DW_TAG_structure_type, cu, None, None, None) 430 | record[struct.name] = die 431 | dwarf_add_AT_name(die, struct.name.replace("struct", "")) 432 | dwarf_add_AT_unsigned_const(dbg, die, DW_AT_byte_size, struct.length) 433 | for c in struct.components: 434 | member_die = dwarf_new_die(dbg, DW_TAG_member, die, None, None, None) 435 | member_type_die = add_type(cu, c.dataType) 436 | dwarf_add_AT_reference(dbg, member_die, DW_AT_type, member_type_die) 437 | dwarf_add_AT_name(member_die, c.fieldName or c.defaultFieldName) 438 | 439 | loc_expr = dwarf_new_expr(dbg) 440 | dwarf_add_expr_gen(loc_expr, DW_OP_plus_uconst, c.offset, 0) 441 | 442 | dwarf_add_AT_location_expr(dbg, member_die, DW_AT_data_member_location, loc_expr) 443 | return die 444 | 445 | 446 | def add_array_type(cu, array): 447 | die = dwarf_new_die(dbg, DW_TAG_array_type, cu, None, None, None) 448 | record[array.name] = die 449 | 450 | element_die = add_type(cu, array.dataType) 451 | dwarf_add_AT_reference(dbg, die, DW_AT_type, element_die) 452 | 453 | subrange = dwarf_new_die(dbg, DW_TAG_subrange_type, die, None, None, None) 454 | # array.length is the total size of the array, so we need to divide it with 455 | # the dataType's length to find the number of elements 456 | dwarf_add_AT_unsigned_const(dbg, subrange, DW_AT_count, array.length / array.dataType.length) 457 | 458 | return die 459 | 460 | 461 | class SectionsCallback(Dwarf_Callback_Func): 462 | def __init__(self): 463 | self.sections = [] 464 | 465 | def apply(self, name, *args): 466 | name = str(name.getString(0)) 467 | print "info_callback", name 468 | self.sections.append(name) 469 | return len(self.sections) - 1 470 | 471 | 472 | def generate_dwarf_sections(): 473 | section_count = dwarf_transform_to_disk_form(dbg) 474 | print "section_count", section_count 475 | 476 | sections = {} 477 | for i in xrange(section_count): 478 | section_index = LongByReference() 479 | length = LongByReference() 480 | content = dwarf_get_section_bytes(dbg, i, section_index, length) 481 | 482 | section_index = section_index.value 483 | length = length.value 484 | content = bytearray(content.getByteArray(0, length)) 485 | section_name = sections_callback.sections[section_index] 486 | if section_name not in sections: 487 | sections[section_name] = "" 488 | sections[section_name] += content 489 | print section_index, section_name, length 490 | return sections.items() 491 | 492 | 493 | if __name__ == "__main__": 494 | decompiler = generate_decomp_interface() 495 | register_mappings, stack_register_dwarf = generate_register_mappings() 496 | dbg = PointerByReference() 497 | err = PointerByReference() 498 | sections_callback = SectionsCallback() 499 | dwarf_producer_init( 500 | DW_DLC_WRITE | DW_DLC_SYMBOLIC_RELOCATIONS | DW_DLC_POINTER64 | DW_DLC_OFFSET32 | DW_DLC_TARGET_LITTLEENDIAN, 501 | sections_callback, 502 | None, 503 | None, 504 | None, 505 | "x86_64", 506 | "V2", 507 | None, 508 | dbg, 509 | ) 510 | dbg = Dwarf_P_Debug(dbg.value) 511 | add_debug_info() 512 | write_source() 513 | sections = generate_dwarf_sections() 514 | dwarf_producer_finish_a(dbg) 515 | add_sections_to_elf(exe_path, out_path, sections) 516 | print "Done." 517 | print "ELF saved to", out_path 518 | print "C source saved to", decompiled_c_path 519 | -------------------------------------------------------------------------------- /src/elf.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | class ElfBase(object): 4 | def __init__(self, file_offset, map, values, **kwargs): 5 | self.__dict__['map'] = map 6 | self.file_offset = file_offset 7 | for n, v in zip(map, values): 8 | if isinstance(n, tuple): 9 | n, f = n 10 | v = f(v) 11 | setattr(self, n, v) 12 | 13 | @property 14 | def values(self): 15 | vv = (getattr(self, n[0] if isinstance(n, tuple) else n) for n in self.map) 16 | return [v.code if isinstance(v, DumbEnumValue) else v for v in vv] 17 | 18 | def __setattr__(self, name, value): 19 | if not hasattr(self, 'repr_pos'): 20 | object.__setattr__(self, 'repr_pos', {}) 21 | if name not in self.repr_pos: 22 | self.repr_pos[name] = len(self.repr_pos) 23 | return object.__setattr__(self, name, value) 24 | 25 | def __repr__(self): 26 | args = ', '.join('%s=%r' % (n, getattr(self, n)) for n, _ in sorted(self.repr_pos.items(), key=lambda x: x[1])) 27 | return '%s(%s)' % (self.__class__.__name__, args) 28 | 29 | class ElfIdent(ElfBase): 30 | def __init__(self, values, file_offset): 31 | return ElfBase.__init__(self, file_offset, [ 32 | 'magic', 33 | ('elf_class', ElfClass.__getitem__), 34 | ('elf_data', ElfData.__getitem__), 35 | 'file_version', 36 | 'osabi', 37 | 'abi_version', 38 | ], values) 39 | 40 | class ElfHeader(ElfBase): 41 | def __init__(self, values, file_offset): 42 | return ElfBase.__init__(self, file_offset, [ 43 | ('type', ET.__getitem__), 44 | ('machine', EM.__getitem__), 45 | 'version', 46 | 'entry', 47 | 'phoff', 48 | 'shoff', 49 | 'flags', 50 | 'ehsize', 51 | 'phentsize', 52 | 'phnum', 53 | 'shentsize', 54 | 'shnum', 55 | 'shstrndx', 56 | ], values) 57 | 58 | class ElfSectionHeader(ElfBase): 59 | def __init__(self, values, file_offset): 60 | self.name = '' 61 | return ElfBase.__init__(self, file_offset, [ 62 | 'name_offset', 63 | ('type', SHT.__getitem__), 64 | 'flags', 65 | 'addr', 66 | 'offset', 67 | 'section_size', 68 | 'link', 69 | 'info', 70 | 'addralign', 71 | 'entsize', 72 | ], values) 73 | 74 | 75 | struct_coders = { 76 | 'ElfIdent': struct.Struct('=4sBBBBBxxxxxxx'), 77 | 'ElfHeader': { 78 | '32le': struct.Struct('HHIIIIIHHHHHH'), 80 | '64le': struct.Struct('HHIQQQIHHHHHH'), 82 | }, 83 | 'ElfSectionHeader': { 84 | '32le': struct.Struct('IIIIIIIIII'), 86 | '64le': struct.Struct('IIQQQQIIQQ'), 88 | } 89 | } 90 | 91 | class Elf: 92 | def __init__(self, bytes): 93 | self.bytes = bytearray(bytes) 94 | self.extract_ident() 95 | bits = '64' if self.ident.elf_class == ElfClass.ELFCLASS64 else '32' 96 | #bits = '64' if ElfClass[self.ident.elf_class] == ElfClass.ELFCLASS64 else '32' 97 | endianness = 'le' if self.ident.elf_data == ElfData.ELFDATA2LSB else 'be' 98 | #endianness = 'le' if ElfData[self.ident.elf_data] == ElfData.ELFDATA2LSB else 'be' 99 | self.type = bits + endianness 100 | self.new_sections = [] 101 | 102 | def _get_struct(self, cls): 103 | s = struct_coders[cls.__name__] 104 | return s[self.type] if isinstance(s, dict) else s 105 | 106 | def _dump_struct(self, cls, off): 107 | s = self._get_struct(cls) 108 | # unpack_from doesn't work with jython 109 | # return cls(s.unpack_from(self.bytes, off), file_offset=off) 110 | bb = self.bytes[off:off+s.size] 111 | return cls(s.unpack(str(bb)), file_offset=off) 112 | 113 | def _export_struct(self, val, off): 114 | s = self._get_struct(val.__class__) 115 | # unpack_into doesn't work with jython 116 | # s.pack_into(self.bytes, off, *val.values) 117 | self.bytes[off:off+s.size] = s.pack(*val.values) 118 | 119 | def extract_ident(self): 120 | if hasattr(self, 'ident'): 121 | return self.ident 122 | self.ident = self._dump_struct(ElfIdent, 0) 123 | self.header_off = self._get_struct(ElfIdent).size 124 | return self.ident 125 | 126 | def extract_header(self): 127 | if hasattr(self, 'header'): 128 | return self.header 129 | self.header = self._dump_struct(ElfHeader, self.header_off) 130 | return self.header 131 | 132 | def extract_section_headers(self): 133 | if hasattr(self, 'section_headers'): 134 | return self.section_headers 135 | 136 | self.section_headers = [] 137 | h = self.extract_header() 138 | for i in range(h.shnum): 139 | self.section_headers.append(self._dump_struct(ElfSectionHeader, h.shoff + i * h.shentsize)) 140 | self.section_names = self.extract_section(self.section_headers[h.shstrndx]) 141 | for s in self.section_headers: 142 | s.name = self.section_names[s.name_offset:self.section_names.find('\x00', s.name_offset)] 143 | return self.section_headers 144 | 145 | def extract_section(self, section_header): 146 | return self.bytes[section_header.offset:section_header.offset+section_header.section_size] 147 | 148 | def encode_section_header(self, section_header): 149 | return self._get_struct(ElfSectionHeader).pack(*section_header.values) 150 | 151 | def add_section(self, name, body): 152 | self.new_sections.append((name, body)) 153 | 154 | def generate_updated_elf(self): 155 | section_headers = self.extract_section_headers() 156 | added_sections = False 157 | for name, body in self.new_sections: 158 | try: 159 | s = next(s for s in section_headers if s.name == name) 160 | except: 161 | added_sections = True 162 | name_off = len(self.section_names) 163 | self.section_names += name + '\x00' 164 | s = ElfSectionHeader([name_off, 1, 0, 0, -1, -1, 0, 0, 1, 0], file_offset=-1) 165 | s.name = name 166 | section_headers.append(s) 167 | s.offset = len(self.bytes) 168 | s.section_size = len(body) 169 | self.bytes += body 170 | 171 | h = self.header 172 | if added_sections: 173 | shstr = section_headers[h.shstrndx] 174 | shstr.section_size = len(self.section_names) 175 | shstr.offset = len(self.bytes) 176 | self.bytes += self.section_names 177 | h.shoff = len(self.bytes) 178 | h.shnum = len(section_headers) 179 | self.bytes += '\x00' * h.shentsize * h.shnum 180 | 181 | self._export_struct(h, self.header_off) 182 | for i, s in enumerate(section_headers): 183 | s.file_offset = h.shoff + i * h.shentsize 184 | self._export_struct(s, s.file_offset) 185 | 186 | return self.bytes 187 | 188 | def add_sections_to_elf(from_file, to_file, sections): 189 | with open(from_file, 'rb') as f: 190 | bb = f.read() 191 | e = Elf(bb) 192 | 193 | for name, s in sections: 194 | e.add_section(name, s) 195 | out = e.generate_updated_elf() 196 | with open(to_file, 'wb') as f: 197 | f.write(out) 198 | 199 | 200 | class DumbEnumValue: 201 | def __init__(self, name, code, desc): self.name, self.code, self.desc = name, code, desc 202 | def __repr__(self): return '%s(%r, %r)' % (self.name, self.code, self.desc) 203 | 204 | class DumbEnum(object): 205 | class __metaclass__(type): 206 | def __init__(cls, *args): 207 | cls._bycode = {} 208 | for n in dir(cls): 209 | if n[0] != '_': 210 | v = DumbEnumValue(n, *getattr(cls, n)) 211 | setattr(cls, n, v) 212 | cls._bycode[v.code] = v 213 | def __getitem__(cls, idx): 214 | try: 215 | return cls._bycode[idx] 216 | except KeyError: 217 | raise Exception('enum %s has no entry with code %d.' % (cls.__name__, idx)) 218 | 219 | 220 | # All the constants are parsed from https://github.com/slorquet/elffile2/blob/master/elffile.py 221 | class ElfClass(DumbEnum): 222 | """ 223 | Encodes the word size of the elf file as from the `ident portion 224 | of the ELF file header 225 | `_. 226 | This encodes :py:attr:`ElfFileIdent.elfClass`. 227 | """ 228 | ELFCLASSNONE = 0, 'Invalid class' 229 | ELFCLASS32 = 1, '32-bit objects' 230 | ELFCLASS64 = 2, '64-bit objects' 231 | ELFCLASSNUM = 3, '' # from libelf 232 | 233 | class ElfData(DumbEnum): 234 | """ 235 | Encodes the byte-wise endianness of the elf file as from the 236 | `ident portion of the elf file header 237 | `_. 238 | This encodes :py:attr:`ElfFileIdent.elfData`. 239 | """ 240 | ELFDATANONE = 0, 'Invalid data encoding' 241 | ELFDATA2LSB = 1, 'least significant byte first' 242 | ELFDATA2MSB = 2, 'most significant byte first' 243 | ELFDATANUM = 3, '' 244 | 245 | class EV(DumbEnum): 246 | """ 247 | Encodes the elf file format version of this elf file as from the `ident portion of the elf file 248 | header 249 | `_. 250 | """ 251 | EV_NONE = 0, 'Invalid version' 252 | EV_CURRENT = 1, 'Current version' 253 | EV_NUM = 2, '' 254 | 255 | class ElfOsabi(DumbEnum): 256 | """ 257 | Encodes OSABI values which represent operating system ELF format 258 | extensions as from the `'ident' portion of the elf file header 259 | `_. 260 | 261 | This encodes :py:attr:`ElfFileIdent.osabi`. 262 | """ 263 | ELFOSABI_NONE = 0, 'No extensions or unspecified' 264 | ELFOSABI_SYSV = 0, 'No extensions or unspecified' 265 | ELFOSABI_HPUX = 1, 'Hewlett-Packard HP-UX' 266 | ELFOSABI_NETBSD = 2, 'NetBSD' 267 | ELFOSABI_LINUX = 3, 'Linux' 268 | ELFOSABI_SOLARIS = 6, 'Sun Solaris' 269 | ELFOSABI_AIX = 7, 'AIX' 270 | ELFOSABI_IRIX = 8, 'IRIX' 271 | ELFOSABI_FREEBSD = 9, 'FreeBSD' 272 | ELFOSABI_TRU64 = 10, 'Compaq TRU64 UNIX' 273 | ELFOSABI_MODESTO = 11, 'Novell Modesto' 274 | ELFOSABI_OPENBSD = 12, 'Open BSD' 275 | ELFOSABI_OPENVMS = 13, 'Open VMS' 276 | ELFOSABI_NSK = 14, 'Hewlett-Packard Non-Stop Kernel' 277 | ELFOSABI_AROS = 15, 'Amiga Research OS' 278 | ELFOSABI_FENIXOS = 16, 'The FenixOS highly scalable multi-core OS' 279 | ELFOSABI_ARM_EABI = 64, 'ARM EABI' 280 | ELFOSABI_ARM = 97, 'ARM' 281 | ELFOSABI_STANDALONE = 255, 'Standalone (embedded) application' 282 | 283 | class ET(DumbEnum): 284 | """ 285 | Encodes the type of this elf file, (relocatable, executable, 286 | shared library, etc.), as represented in the `ELF file header 287 | `_. 288 | This encodes :py:attr:`ElfFileHeader.type`. 289 | """ 290 | ET_NONE = 0, 'No file type' 291 | ET_REL = 1, 'Relocatable file' 292 | ET_EXEC = 2, 'Executable file' 293 | ET_DYN = 3, 'Shared object file' 294 | ET_CORE = 4, 'Core file' 295 | ET_NUM = 5, '' 296 | ET_LOOS = 0xfe00, 'Operating system-specific' 297 | ET_HIOS = 0xfeff, 'Operating system-specific' 298 | ET_LOPROC = 0xff00, 'Processor-specific' 299 | ET_HIPROC = 0xffff, 'Processor-specific' 300 | 301 | class EM(DumbEnum): 302 | """ 303 | Encodes the processor type represented in this elf file as 304 | recorded in the `ELF file header `_. 305 | 306 | This encodes :py:attr:`ElfFileHeader.machine`. 307 | """ 308 | EM_NONE = 0, 'No machine' 309 | EM_M32 = 1, 'AT&T WE 32100' 310 | EM_SPARC = 2, 'SPARC' 311 | EM_386 = 3, 'Intel 80386' 312 | EM_68K = 4, 'Motorola 68000' 313 | EM_88K = 5, 'Motorola 88000' 314 | EM_486 = 6, 'Reserved for future use (was EM_486)' 315 | EM_860 = 7, 'Intel 80860' 316 | EM_MIPS = 8, 'MIPS I Architecture' 317 | EM_S370 = 9, 'IBM System/370 Processor' 318 | EM_MIPS_RS3_LE = 10, 'MIPS RS3000 Little-endian' 319 | # 11 - 14 reserved 320 | EM_PARISC = 15, 'Hewlett-Packard PA-RISC' 321 | # 16 reserved 322 | EM_VPP500 = 17, 'Fujitsu VPP500' 323 | EM_SPARC32PLUS = 18, 'Enhanced instruction set SPARC' 324 | EM_960 = 19, 'Intel 80960' 325 | EM_PPC = 20, 'PowerPC' 326 | EM_PPC64 = 21, '64-bit PowerPC' 327 | EM_S390 = 22, 'IBM System/390 Processor' 328 | EM_SPU = 23, 'IBM SPU/SPC' 329 | # 24 - 35 reserved 330 | EM_V800 = 36, 'NEC V800' 331 | EM_FR20 = 37, 'Fujitsu FR20' 332 | EM_RH32 = 38, 'TRW RH-32' 333 | EM_RCE = 39, 'Motorola RCE' 334 | EM_ARM = 40, 'Advanced RISC Machines ARM' 335 | EM_ALPHA = 41, 'Digital Alpha' 336 | EM_SH = 42, 'Hitachi SH' 337 | EM_SPARCV9 = 43, 'SPARC Version 9' 338 | EM_TRICORE = 44, 'Siemens TriCore embedded processor' 339 | EM_ARC = 45, 'Argonaut RISC Core, Argonaut Technologies Inc.' 340 | EM_H8_300 = 46, 'Hitachi H8/300' 341 | EM_H8_300H = 47, 'Hitachi H8/300H' 342 | EM_H8S = 48, 'Hitachi H8S' 343 | EM_H8_500 = 49, 'Hitachi H8/500' 344 | EM_IA_64 = 50, 'Intel IA-64 processor architecture' 345 | EM_MIPS_X = 51, 'Stanford MIPS-X' 346 | EM_COLDFIRE = 52, 'Motorola ColdFire' 347 | EM_68HC12 = 53, 'Motorola M68HC12' 348 | EM_MMA = 54, 'Fujitsu MMA Multimedia Accelerator' 349 | EM_PCP = 55, 'Siemens PCP' 350 | EM_NCPU = 56, 'Sony nCPU embedded RISC processor' 351 | EM_NDR1 = 57, 'Denso NDR1 microprocessor' 352 | EM_STARCORE = 58, 'Motorola Star*Core processor' 353 | EM_ME16 = 59, 'Toyota ME16 processor' 354 | EM_ST100 = 60, 'STMicroelectronics ST100 processor' 355 | EM_TINYJ = 61, 'Advanced Logic Corp. TinyJ embedded processor family' 356 | EM_X86_64 = 62, 'AMD x86-64 architecture' 357 | EM_PDSP = 63, 'Sony DSP Processor' 358 | EM_PDP10 = 64, 'Digital Equipment Corp. PDP-10' 359 | EM_PDP11 = 65, 'Digital Equipment Corp. PDP-11' 360 | EM_FX66 = 66, 'Siemens FX66 microcontroller' 361 | EM_ST9PLUS = 67, 'STMicroelectronics ST9+ 8/16 bit microcontroller' 362 | EM_ST7 = 68, 'STMicroelectronics ST7 8-bit microcontroller' 363 | EM_68HC16 = 69, 'Motorola MC68HC16 Microcontroller' 364 | EM_68HC11 = 70, 'Motorola MC68HC11 Microcontroller' 365 | EM_68HC08 = 71, 'Motorola MC68HC08 Microcontroller' 366 | EM_68HC05 = 72, 'Motorola MC68HC05 Microcontroller' 367 | EM_SVX = 73, 'Silicon Graphics SVx' 368 | EM_ST19 = 74, 'STMicroelectronics ST19 8-bit microcontroller' 369 | EM_VAX = 75, 'Digital VAX' 370 | EM_CRIS = 76, 'Axis Communications 32-bit embedded processor' 371 | EM_JAVELIN = 77, 'Infineon Technologies 32-bit embedded processor' 372 | EM_FIREPATH = 78, 'Element 14 64-bit DSP Processor' 373 | EM_ZSP = 79, 'LSI Logic 16-bit DSP Processor' 374 | EM_MMIX = 80, 'Donald Knuth\'s educational 64-bit processor' 375 | EM_HUANY = 81, 'Harvard University machine-independent object files' 376 | EM_PRISM = 82, 'SiTera Prism' 377 | EM_AVR = 83, 'Atmel AVR 8-bit microcontroller' 378 | EM_FR30 = 84, 'Fujitsu FR30' 379 | EM_D10V = 85, 'Mitsubishi D10V' 380 | EM_D30V = 86, 'Mitsubishi D30V' 381 | EM_V850 = 87, 'NEC v850' 382 | EM_M32R = 88, 'Mitsubishi M32R' 383 | EM_MN10300 = 89, 'Matsushita MN10300' 384 | EM_MN10200 = 90, 'Matsushita MN10200' 385 | EM_PJ = 91, 'picoJava' 386 | EM_OPENRISC = 92, 'OpenRISC 32-bit embedded processor' 387 | EM_ARC_COMPACT = 93, 'ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5)' 388 | EM_XTENSA = 94, 'Tensilica Xtensa Architecture' 389 | EM_VIDEOCORE = 95, 'Alphamosaic VideoCore processor' 390 | EM_TMM_GPP = 96, 'Thompson Multimedia General Purpose Processor' 391 | EM_NS32K = 97, 'National Semiconductor 32000 series' 392 | EM_TPC = 98, 'Tenor Network TPC processor' 393 | EM_SNP1K = 99, 'Trebia SNP 1000 processor' 394 | EM_ST200 = 100, 'STMicroelectronics (www.st.com) ST200 microcontroller' 395 | EM_IP2K = 101, 'Ubicom IP2xxx microcontroller family' 396 | EM_MAX = 102, 'MAX Processor' 397 | EM_CR = 103, 'National Semiconductor CompactRISC microprocessor' 398 | EM_F2MC16 = 104, 'Fujitsu F2MC16' 399 | EM_MSP430 = 105, 'Texas Instruments embedded microcontroller msp430' 400 | EM_BLACKFIN = 106, 'Analog Devices Blackfin (DSP) processor' 401 | EM_SE_C33 = 107, 'S1C33 Family of Seiko Epson processors' 402 | EM_SEP = 108, 'Sharp embedded microprocessor' 403 | EM_ARCA = 109, 'Arca RISC Microprocessor' 404 | EM_UNICORE = 110, 'Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University' 405 | EM_EXCESS = 111, 'eXcess: 16/32/64-bit configurable embedded CPU' 406 | EM_DXP = 112, 'Icera Semiconductor Inc. Deep Execution Processor' 407 | EM_ALTERA_NIOS2 = 113, 'Altera Nios II soft-core processor' 408 | EM_CRX = 114, 'National Semiconductor CompactRISC CRX microprocessor' 409 | EM_XGATE = 115, 'Motorola XGATE embedded processor' 410 | EM_C166 = 116, 'Infineon C16x/XC16x processor' 411 | EM_M16C = 117, 'Renesas M16C series microprocessors' 412 | EM_DSPIC30F = 118, 'Microchip Technology dsPIC30F Digital Signal Controller' 413 | EM_CE = 119, 'Freescale Communication Engine RISC core' 414 | EM_M32C = 120, 'Renesas M32C series microprocessors' 415 | # 121 - 130 reserved 416 | EM_TSK3000 = 131, 'Altium TSK3000 core' 417 | EM_RS08 = 132, 'Freescale RS08 embedded processor' 418 | # 133 reserved 419 | EM_ECOG2 = 134, 'Cyan Technology eCOG2 microprocessor' 420 | EM_SCORE7 = 135, 'Sunplus S+core7 RISC processor' 421 | EM_DSP24 = 136, 'New Japan Radio (NJR) 24-bit DSP Processor' 422 | EM_VIDEOCORE3 = 137, 'Broadcom VideoCore III processor' 423 | EM_LATTICEMICO32 = 138, 'RISC processor for Lattice FPGA architecture' 424 | EM_SE_C17 = 139, 'Seiko Epson C17 family' 425 | EM_TI_C6000 = 140, 'The Texas Instruments TMS320C6000 DSP family' 426 | EM_TI_C2000 = 141, 'The Texas Instruments TMS320C2000 DSP family' 427 | EM_TI_C5500 = 142, 'The Texas Instruments TMS320C55x DSP family' 428 | # 143 - 159 reserved 429 | EM_MMDSP_PLUS = 160, 'STMicroelectronics 64bit VLIW Data Signal Processor' 430 | EM_CYPRESS_M8C = 161, 'Cypress M8C microprocessor' 431 | EM_R32C = 162, 'Renesas R32C series microprocessors' 432 | EM_TRIMEDIA = 163, 'NXP Semiconductors TriMedia architecture family' 433 | EM_QDSP6 = 164, 'QUALCOMM DSP6 Processor' 434 | EM_8051 = 165, 'Intel 8051 and variants' 435 | EM_STXP7X = 166, 'STMicroelectronics STxP7x family of configurable and extensible RISC processors' 436 | EM_NDS32 = 167, 'Andes Technology compact code size embedded RISC processor family' 437 | EM_ECOG1 = 168, 'Cyan Technology eCOG1X family' 438 | EM_ECOG1X = 168, 'Cyan Technology eCOG1X family' 439 | EM_MAXQ30 = 169, 'Dallas Semiconductor MAXQ30 Core Micro-controllers' 440 | EM_XIMO16 = 170, 'New Japan Radio (NJR) 16-bit DSP Processor' 441 | EM_MANIK = 171, 'M2000 Reconfigurable RISC Microprocessor' 442 | EM_CRAYNV2 = 172, 'Cray Inc. NV2 vector architecture' 443 | EM_RX = 173, 'Renesas RX family' 444 | EM_METAG = 174, 'Imagination Technologies META processor architecture' 445 | EM_MCST_ELBRUS = 175, 'MCST Elbrus general purpose hardware architecture' 446 | EM_ECOG16 = 176, 'Cyan Technology eCOG16 family' 447 | EM_CR16 = 177, 'National Semiconductor CompactRISC CR16 16-bit microprocessor' 448 | EM_ETPU = 178, 'Freescale Extended Time Processing Unit' 449 | EM_SLE9X = 179, 'Infineon Technologies SLE9X core' 450 | # 180-182 Reserved for future Intel use 451 | # 183-184 Reserved for future ARM use 452 | EM_AVR32 = 185, 'Atmel Corporation 32-bit microprocessor family' 453 | EM_STM8 = 186, 'STMicroeletronics STM8 8-bit microcontroller' 454 | EM_TILE64 = 187, 'Tilera TILE64 multicore architecture family' 455 | EM_TILEPRO = 188, 'Tilera TILEPro multicore architecture family' 456 | EM_MICROBLAZE = 189, 'Xilinx MicroBlaze 32-bit RISC soft processor core' 457 | EM_CUDA = 190, 'NVIDIA CUDA architecture' 458 | EM_TILEGX = 191, 'Tilera TILE-Gx multicore architecture family' 459 | EM_CLOUDSHIELD = 192, 'CloudShield architecture family' 460 | EM_COREA_1ST = 193, 'KIPO-KAIST Core-A 1st generation processor family' 461 | EM_COREA_2ND = 194, 'KIPO-KAIST Core-A 2nd generation processor family' 462 | 463 | class SHN(DumbEnum): 464 | """ 465 | Encodes special section indices into the section header table. 466 | 467 | This is a subclass of :py:class:`coding.Coding`. 468 | """ 469 | SHN_UNDEF = 0, 'marks an undefined, missing, irrelevant, or otherwise meaningless section reference' 470 | SHN_LORESERVE = 0xff00, 'specifies the lower bound of the range of reserved indexes' 471 | SHN_BEFORE = 0xff00, 'Order section before all others (Solaris).' 472 | SHN_LOPROC = 0xff00, '' 473 | SHN_AFTER = 0xff01, 'Order section after all others (Solaris).' 474 | SHN_HIPROC = 0xff1f, '' 475 | SHN_LOOS = 0xff20, '' 476 | SHN_HIOS = 0xff3f, '' 477 | SHN_ABS = 0xfff1, 'specifies absolute values for the corresponding reference' 478 | SHN_COMMON = 0xfff2, 'symbols defined relative to this section are common symbols, such as FORTRAN COMMON or unallocated C external variables.' 479 | SHN_XINDEX = 0xffff, 'This value is an escape value. It indicates that the actual section header index is too large to fit in the containing field and is to be found in another location (specific to the structure where it appears). ' 480 | SHN_HIRESERVE = 0xffff, 'specifies the upper bound of the range of reserved indexes' 481 | 482 | class SHT(DumbEnum): 483 | """ 484 | Encodes the type of a section as represented in the section header 485 | entry of `the section header table 486 | `_. 487 | 488 | This encodes :py:attr:`ElfSectionHeader.type`. 489 | """ 490 | SHT_NULL = 0, 'marks the section header as inactive; it does not have an associated section. Other members of the section header have undefined values.' 491 | SHT_PROGBITS = 1, 'The section holds information defined by the program, whose format and meaning are determined solely by the program.' 492 | SHT_SYMTAB = 2, 'provides symbols for link editing, though it may also be used for dynamic linking.' 493 | SHT_STRTAB = 3, 'section holds a string table. An object file may have multiple string table sections.' 494 | SHT_RELA = 4, 'section holds relocation entries with explicit addends, such as type Elf32_Rela for the 32-bit class of object files or type Elf64_Rela for the 64-bit class of object files.' 495 | SHT_HASH = 5, 'section holds a symbol hash table' 496 | SHT_DYNAMIC = 6, 'section holds information for dynamic linking' 497 | SHT_NOTE = 7, 'section holds information that marks the file in some way' 498 | SHT_NOBITS = 8, 'A section of this type occupies no space in the file but otherwise resembles SHT_PROGBITS' 499 | SHT_REL = 9, 'section holds relocation entries without explicit addends' 500 | SHT_SHLIB = 10, 'section type is reserved but has unspecified semantics' 501 | SHT_DYNSYM = 11, 'holds a minimal set of dynamic linking symbols,' 502 | SHT_INIT_ARRAY = 14, 'section contains an array of pointers to initialization functions' 503 | SHT_FINI_ARRAY = 15, 'section contains an array of pointers to termination functions' 504 | SHT_PREINIT_ARRAY = 16, 'section contains an array of pointers to functions that are invoked before all other initialization functions' 505 | SHT_GROUP = 17, 'section defines a section group' 506 | SHT_SYMTAB_SHNDX = 18, 'section is associated with a section of type SHT_SYMTAB and is required if any of the section header indexes referenced by that symbol table contain the escape value SHN_XINDEX' 507 | SHT_LOOS = 0x60000000, '' 508 | SHT_GNU_ATTRIBUTES = 0x6ffffff5, 'Object attributes.' 509 | SHT_GNU_HASH = 0x6ffffff6, 'GNU-style hash table.' 510 | SHT_GNU_LIBLIST = 0x6ffffff7, 'Prelink library lis' 511 | SHT_CHECKSUM = 0x6ffffff8, 'Checksum for DSO content.' 512 | SHT_LOSUNW = 0x6ffffffa, 'Sun-specific low bound.' 513 | SHT_SUNW_move = 0x6ffffffa, 'efine SHT_SUNW_COMDAT' 514 | SHT_SUNW_COMDAT = 0x6ffffffb, '' 515 | SHT_SUNW_syminfo = 0x6ffffffc, '' 516 | SHT_GNU_verdef = 0x6ffffffd, 'Version definition section.' 517 | SHT_GNU_verneed = 0x6ffffffe, 'Version needs section.' 518 | SHT_GNU_versym = 0x6fffffff, 'Version symbol table.' 519 | SHT_HISUNW = 0x6fffffff, 'Sun-specific high bound.' 520 | SHT_HIOS = 0x6fffffff, '' 521 | SHT_LOPROC = 0x70000000, '' 522 | SHT_PROC_SPECIFIC = 0x70000001, '' 523 | SHT_PROC_SPECIFIC1 = 0x70000002, '' 524 | SHT_PROC_SPECIFIC2 = 0x70000003, '' 525 | SHT_PROC_SPECIFIC3 = 0x70000004, '' 526 | SHT_PROC_SPECIFIC4 = 0x70000005, '' 527 | SHT_HIPROC = 0x7fffffff, '' 528 | SHT_LOUSER = 0x80000000, '' 529 | SHT_HIUSER = 0xffffffff, '' 530 | 531 | class SHF(DumbEnum): 532 | """ 533 | Encodes the section flags as represented in the section header 534 | entry of `the section header table 535 | `_. 536 | 537 | This encodes :py:attr:`ElfSectionHeader.flags`. These are bit flags which are 538 | or'd together. 539 | """ 540 | SHF_WRITE = 0x1, 'section contains data that should be writable during process execution' 541 | SHF_ALLOC = 0x2, 'section occupies memory during process execution' 542 | SHF_EXECINSTR = 0x4, 'section contains executable machine instructions' 543 | SHF_MERGE = 0x10, 'data in the section may be merged to eliminate duplication' 544 | SHF_STRINGS = 0x20, 'data elements in the section consist of null-terminated character strings' 545 | SHF_INFO_LINK = 0x40, 'The sh_info field of this section header holds a section header table index' 546 | SHF_LINK_ORDER = 0x80, 'adds special ordering requirements for link editors' 547 | SHF_OS_NONCONFORMING = 0x100, 'section requires special OS-specific processing' 548 | SHF_GROUP = 0x200, 'section is a member of a section group' 549 | SHF_TLS = 0x400, 'section holds Thread-Local Storage' 550 | SHF_MASKOS = 0x0ff00000, 'All bits included in this mask are reserved for operating system-specific semantics' 551 | SHF_MASKPROC = 0xf0000000, 'All bits included in this mask are reserved for processor-specific semantics' 552 | SHF_ORDERED = (1 << 30), 'Special ordering requirement (Solaris).' 553 | SHF_EXCLUDE = (1 << 31), 'Section is excluded unless referenced or allocated (Solaris).' 554 | 555 | class PT(DumbEnum): 556 | """ 557 | Encodes the segment type as recorded in the `program header 558 | `_. 559 | 560 | This encodes :py:attr:`ElfProgramHeader.type`. 561 | """ 562 | PT_NULL = 0, 'array element is unused' 563 | PT_LOAD = 1, 'array element specifies a loadable segment' 564 | PT_DYNAMIC = 2, 'array element specifies dynamic linking information' 565 | PT_INTERP = 3, 'array element specifies the location and size of a null-terminated path name to invoke as an interpreter' 566 | PT_NOTE = 4, 'array element specifies the location and size of auxiliary information' 567 | PT_SHLIB = 5, 'segment type is reserved' 568 | PT_PHDR = 6, 'specifies the location and size of the program header table itself' 569 | PT_TLS = 7, 'array element specifies the Thread-Local Storage template' 570 | PT_LOOS = 0x60000000, '' 571 | PT_GNU_EH_FRAME = 0x6474e550, 'GCC .eh_frame_hdr segment' 572 | PT_GNU_STACK = 0x6474e551, 'Indicates stack executability' 573 | PT_GNU_RELRO = 0x6474e552, 'Read only after relocation' 574 | PT_LOSUNW = 0x6ffffffa, '' 575 | PT_SUNWBSS = 0x6ffffffa, 'Sun Specific segment' 576 | PT_SUNWSTACK = 0x6ffffffb, 'Stack segment' 577 | PT_HISUNW = 0x6fffffff, '' 578 | PT_HIOS = 0x6fffffff, '' 579 | PT_LOPROC = 0x70000000, '' 580 | PT_HIPROC = 0x7fffffff, '' 581 | 582 | class PF(DumbEnum): 583 | """ 584 | Encodes the segment flags as recorded in the `program header 585 | `_. 586 | 587 | This encodes :py:attr:`ElfProgramHeader.flags`. 588 | """ 589 | PF_X = 0x1, 'Execute' 590 | PF_W = 0x2, 'Write' 591 | PF_R = 0x4, 'Read' 592 | PF_MASKOS = 0x0ff00000, 'Unspecified' 593 | PF_MASKPROC = 0xf0000000, 'Unspecified' 594 | 595 | class GRP(DumbEnum): 596 | GRP_COMDAT = 0x1, 'This is a COMDAT group' 597 | GRP_MASKOS = 0x0ff00000, 'All bits included in this mask are reserved for operating system-specific semantics' 598 | GRP_MASKPROC = 0xf0000000, 'All bits included in this mask are reserved for processor-specific semantics' 599 | 600 | if __name__ == '__main__': 601 | from sys import argv 602 | from glob import glob 603 | 604 | from_file = argv[1] 605 | to_file = argv[2] 606 | section_names = argv[3:] 607 | sections = [(n, open(n, 'rb').read()) for nu in section_names for n in glob(nu)] 608 | add_sections_to_elf(from_file, to_file, sections) 609 | --------------------------------------------------------------------------------