├── .gitignore ├── .gitmodules ├── CHANGELOG ├── LICENSE ├── README.md ├── SECURITY.md ├── configure ├── bininfo.json ├── multi_sec_name └── offset.json ├── examples ├── 01_play_symbol │ ├── Makefile │ ├── hello.c │ ├── hello.h │ └── main.c ├── 02_hook_got_plt │ ├── Makefile │ ├── arch │ │ └── x86_64 │ │ │ └── syscall.c │ ├── crackme.c │ ├── myfunc.c │ └── script.ld ├── 03_infect_like_virus │ ├── Makefile │ ├── arch │ │ └── x86_64 │ │ │ └── syscall.c │ ├── hello.c │ ├── script.ld │ └── shellcode.c ├── 04_trans_exe_into_lib │ ├── Makefile │ ├── crackme.c │ └── harness.c ├── 05_checksec │ ├── Makefile │ └── main.c ├── 06_confuse_symbol │ ├── Makefile │ ├── check.c │ ├── check.h │ └── main.c ├── 07_inject_so │ ├── Makefile │ ├── check.c │ ├── check.h │ ├── crackme.c │ └── my.c ├── 08_inject_interpreter │ ├── 43565.asm │ ├── Makefile │ └── hello.c └── 09_gen_elf_seeds │ ├── crash.py │ └── seeds.py ├── pictures ├── 1.png ├── 2.png ├── 3.png └── 4.png └── src ├── Makefile ├── addelfinfo.c ├── addelfinfo.h ├── addsec.c ├── addsec.h ├── common.c ├── common.h ├── delete.c ├── delete.h ├── edit.c ├── edit.h ├── forensic.c ├── gnuhash.c ├── gnuhash.h ├── infect.c ├── infect.h ├── injectso.c ├── injectso.h ├── joinelf.c ├── joinelf.h ├── main.c ├── parse.c ├── parse.h ├── rel.c ├── rel.h ├── section.c ├── section.h ├── segment.c └── segment.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | src/*.o 3 | src/cJSON/*.o 4 | src/elfspirit -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/cJSON"] 2 | path = src/cJSON 3 | url = https://github.com/DaveGamble/cJSON.git 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | [2025-02-11] 2 | elfspirit 1.10.0 3 | - Add the ELF forensic analysis 4 | - Update the help information of the tool 5 | - Fix some issues 6 | 7 | [2025-01-19] 8 | elfspirit 1.9.2 9 | - Add the ability to save shellcode hex to binary & Redesign to convert the bare-meta/shellcode into an elf file 10 | - Delete the first space character in output formatting 11 | - Optimize the introduction document of elfspirit 12 | - Add more cases 13 | 14 | [2025-01-12] 15 | elfspirit 1.9.1 16 | - Add the ability to refresh the gnu hash table and example of confusing symbols 17 | - Add security document for clarifying the difference between bugs and security vulnerabilities 18 | - Improve command-line help 19 | 20 | [2025-01-09] 21 | elfspirit 1.9.0 22 | - Add the ability to confuse symbols of the string table 23 | - Integrate the code of the elf deletion module and add the function of removing symbol table 24 | - Modify some command-line parameters 25 | - Fix some issues 26 | 27 | [2025-01-04] 28 | elfspirit 1.8.2 29 | - Add the ability to parse DT_GNU_HASH table 30 | - Add the ability to transform an ELF executable into a library 31 | - Fix spelling errors of certain words 32 | 33 | [2024-12-31] 34 | elfspirit 1.8.1 35 | - Add examples for elfspirit wiki 36 | - Add the ability to hook external function through .got.plt infection 37 | - Fix issue about parsing relocation section 38 | - Update README command-line parameters 39 | 40 | [2024-12-26] 41 | elfspirit 1.8.0 42 | - Add the ability to obtain or edit pointer in ELF including .init_array, .finit_array and so on 43 | - Re optimize the command-line parameters of the tool 44 | - Remove redundant code and fix some issues 45 | 46 | [2024-12-17] 47 | elfspirit 1.7 48 | - Add more infect algorithm 49 | - Add the ability to set rpath, run path and interpreter 50 | - Allow modifying the symbols to longer strings 51 | - Continue to optimize and adjust some code structures 52 | 53 | [2024-12-03] 54 | elfspirit 1.6 55 | - Add the ability to modify section name 56 | - Add the ability to add a segment 57 | - Add the ability to add a section (new scenario) 58 | - Add the ability to infect text segment using silvio 59 | - Simplify makefile file 60 | - Fix some errors 61 | 62 | [2024-11-19] 63 | elfspirit 1.5 64 | - Add the more ability to parse and modify ELF, such as .rel*. and .dynamic section 65 | - Allow users to set the length of the string to be displayed themselves 66 | - Fix some errors 67 | 68 | [2024-11-04] 69 | elfspirit 1.4 70 | - Add the ability to modify any byte of ELF 71 | - Print more ELF header information (.dynsym and .symtab) 72 | 73 | [2024-10-29] 74 | elfspirit 1.3 75 | - Add the ability to modify section information 76 | - Add the ability to extract binary fragments from the target file 77 | - Add more description for ELF header 78 | - Fix several bugs 79 | 80 | [2022-09-27] 81 | elfspirit 1.2.2 82 | - Add program segment for qemu 83 | - Connect each bin in firmware for IDA 84 | - Patch firmware for IDA 85 | 86 | [2022-09-17] 87 | elfspirit 1.2.1 88 | - Add ELF info to firmware(64bit) for IDA 89 | - Close issue #5 #6 90 | 91 | [2022-09-17] 92 | elfspirit 1.2.0 93 | - Add ELF info to firmware(arm32) for IDA 94 | - Update README.txt 95 | 96 | [2022-03-15] 97 | elfspirit 1.1.4 98 | - Fix https://github.com/secnotes/elfspirit/issues/4 99 | - Fix https://github.com/secnotes/elfspirit/issues/3 100 | - Prevent CWE - 101 | 102 | [2022-02-17] 103 | elfspirit 1.1.3 104 | - Fix bugs from ELF parser 105 | - Add many options for ELF parser 106 | 107 | [2022-02-15] 108 | elfspirit 1.1.2 109 | - Significantly adjust the architecture of ELF64 parser 110 | 111 | [2022-02-15] 112 | elfspirit 1.1.1 113 | - Significantly adjust the architecture of ELF32 parser 114 | 115 | [2022-02-11] 116 | elfspirit 1.1.0 117 | - Fix CVE-2022-21711 118 | - Merge pull request #2 from ware/main 119 | - Check the format of ELF file 120 | 121 | [2022-01-22] 122 | elfspirit 1.0 123 | - Add version information 124 | - Add Chinese help 125 | - Update README.txt 126 | 127 | [2021-11-07] 128 | elfspirit 0.1 129 | - Original version 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SecNotes 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # elfspirit 3 | 4 | [![arch](https://img.shields.io/badge/arch-i386%20%7C%20amd64-orange)](#) 5 | [![platform](https://img.shields.io/badge/platform-Ubuntu%20%7C%20Kali-orange)](https://github.com/secnotes/elfspirit#Limitations) 6 | [![GitHub Tag](https://img.shields.io/github/v/tag/secnotes/elfspirit)](https://github.com/secnotes/elfspirit/tags) 7 | [![license](https://img.shields.io/github/license/secnotes/elfspirit)](https://github.com/secnotes/elfspirit/blob/main/LICENSE) 8 | 9 | **elfspirit** is a useful program that parse, manipulate and camouflage ELF files. It provides a variety of functions, including parsing ELF like `readelf`, editing ELF like `010 editor`, adding section or segment, pathing ELF like `patchelf`, infecting ELF, deleting the section header table to increase the difficulty of reverse engineering. 10 | 11 | You might be familiar with popular open-source tools like [LIEF](https://github.com/lief-project/LIEF), [libelfmaster](https://github.com/elfmaster/libelfmaster), and [patchelf](https://github.com/NixOS/patchelf) (**Thanks for the inspiration and innovation that these tools have bestowed upon us!**). **elfspirit** distinguishes itself by offering not only enhanced flexibility in editing but also a What You See Is What You Get (WYSIWYG) editing perspective and unique features. Its primary objective is to empower hackers to effortlessly manipulate every byte of an ELF file. 12 | 13 | **For further information, refer to the [elfspirit wiki](https://github.com/secnotes/elfspirit/wiki) for a detailed exploration of its capabilities.** 14 | 15 | 16 | ## Building 17 | 18 | **elfspirit** can be installed easily: 19 | 20 | ```shell 21 | git clone --recursive https://github.com/secnotes/elfspirit.git 22 | make 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Analyze ELF format, like readelf 28 | 29 | ```shell 30 | $ elfspirit parse -H myelf 31 | [+] ELF32 Header 32 | 0 ~ 15bit ---------------------------------------------- 33 | Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 34 | ELF E L F | | | | | 35 | 32/64bit | | | | 36 | little/big endian | | | 37 | os type | | 38 | ABI version | 39 | byte index of padding bytes 40 | 16 ~ 63bit --------------------------------------------- 41 | [ 0] e_type: 0x2 (An executable file) 42 | [ 1] e_machine: 0x3 (Sun Microsystems SPARC) 43 | [ 2] e_version: 0x2 (Unkown) 44 | [ 3] e_entry: 0x1077 (Entry point address) 45 | [ 4] e_phoff: 0x34 (Start of program headers) 46 | [ 5] e_shoff: 0x35d4 (Start of section headers) 47 | [ 6] e_flags: (nil) 48 | [ 7] e_ehsize: 0x34 (Size of this header) 49 | [ 8] e_phentsize: 0x20 (Size of program headers) 50 | [ 9] e_phnum: 0xb (Number of program headers) 51 | [10] e_shentsize: 0x28 (Size of section headers) 52 | [11] e_shnum: 0x1d (Number of section headers) 53 | [12] e_shstrndx: 0x1c (Section header string table index) 54 | ``` 55 | 56 | ### Freely edit every byte of ELF, not just 010 editor 57 | 58 | We can easily edit any byte of ELF files using elfspirit, such as removing the stack non executable feature (`-z noexecstack`) of executable binary files. 59 | 60 | The original PT_GNU-STACK segment only had read and write permissions (6=rw), as shown below 61 | 62 | ![1](pictures/1.png) 63 | 64 | You can use elfspirit to grant executable permissions to the PT_GNU-STACK segment. Just set the parameters (i, j) to the coordinates of the target. 65 | 66 | ```shell 67 | $ elfspirit edit -P -i11 -j6 -m7 myelf 68 | 6->7 69 | ``` 70 | 71 | Wasn't this process a piece of cake? 72 | 73 | ![2](pictures/2.png) 74 | 75 | 76 | ### Patch IoT firmware for IDA 77 | 78 | As is well known, the firmware of many embedded devices is bare metal programs without ELF header. Therefore, elfspirit can be used to add ELF header information, making it convenient to use reverse engineering tools such as IDA to decompile it. 79 | 80 | ```shell 81 | # Add elf header for IoT firmware.bin 82 | $ ./elfspirit addelfinfo -a arm -m 32 -e big -b 0x18308000 ~/Documents/app.bin 83 | ``` 84 | 85 | In addition, elfspirit also has the function of splicing firmware. A common situation we encounter is that IoT firmware has many bins stored in different partitions. They share an address space, and if you only analyze a single bin, you will find that the function jumps to an unfamiliar address. At this point, we need to use `elfspirit join` 86 | 87 | ```shell 88 | # Connect multi-bin 89 | $ ./elfspirit joinelf -a arm -m 32 -e big -c ./configure/bininfo.json ~/Documents/app.bin 90 | ``` 91 | 92 | ### Patch ELF 93 | 94 | * Change the ELF interpreter ("the dynamic loader/linker") of executables: 95 | 96 | ```shell 97 | elfspirit --set-interpreter [-s] ELF 98 | ``` 99 | 100 | * Change the `RPATH` or `RUNPATH` of executables and libraries: 101 | 102 | ```shell 103 | elfspirit --set-rpath [-s] ELF 104 | elfspirit --set-runpath [-s] ELF 105 | ``` 106 | 107 | * Add section or segment of executables and libraries: 108 | 109 | ```shell 110 | elfspirit --add-section [-z] ELF 111 | elfspirit --add-segment [-z] ELF 112 | ``` 113 | 114 | ### Infect ELF (experimental) 115 | 116 | * Silvio text segment infectction technic: 117 | 118 | ```shell 119 | elfspirit --infect-silvio [-s] [-z] ELF 120 | ``` 121 | 122 | * Reverse text segment infectction technic (Skeksi): 123 | 124 | ```shell 125 | elfspirit --infect-skeksi [-s] [-z] ELF 126 | ``` 127 | 128 | * Data segment infectction technic (Skeksi): 129 | 130 | ```shell 131 | elfspirit --infect-data [-s] [-z] ELF 132 | ``` 133 | 134 | ## Limitations 135 | 136 | **elfspirit** is a work in process, and some things still aren't implemented. We run **elfspirit** common function using : 137 | 138 | - Ubuntu 22.04 / Kali Linux 2024.4 139 | 140 | While other environments might be compatible, regrettably, we lack the resources to delve into potential compatibility issues. Given the absence of robust support for object-oriented programming in the C language and our constrained individual capabilities, there might exist redundant and unreasonable code within this project. Your understanding in this matter is greatly appreciated. 141 | 142 | ## License 143 | 144 | **elfspirit** is open source software. See the `LICENSE` file for more details. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ELFSPIRIT functions as a tool, and like any tool, it may contain occasional bugs and security vulnerabilities. Given its primary utility for Security Researchers, we uphold a rigorous standard when identifying security vulnerabilities. 2 | 3 | Our classification of security issues is stringent, focusing solely on vulnerabilities that have the potential for real-world exploitation. It is advised not to employ the elfspirit tool with untrusted executables. 4 | 5 | We encourage the community to report issues and submit pull requests for continual improvement. Your contributions are highly valued and appreciated! -------------------------------------------------------------------------------- /configure/bininfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "0x14080000": "/home/kali/Documents/app.bin" 3 | } -------------------------------------------------------------------------------- /configure/multi_sec_name: -------------------------------------------------------------------------------- 1 | .note.gnu.property 2 | .note.gnu.build-id 3 | .eh_frame_hdr -------------------------------------------------------------------------------- /configure/offset.json: -------------------------------------------------------------------------------- 1 | { 2 | "x86": { 3 | "2.31":{ 4 | "_ld_fini": "0x0", 5 | "_ld_catch_exception_got": "0xc", 6 | "_ld_catch_exception": "0x0013F4E0", 7 | "__libc_dlopen_mode": "0x0013EAF0" 8 | } 9 | }, 10 | 11 | "x86_64": { 12 | "2.32":{ 13 | "_ld_fini": "0x102F0", 14 | "_ld_catch_exception_got": "0x2B018", 15 | "_ld_catch_exception": "0x137A90", 16 | "__libc_dlopen_mode": "0x1370C0" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/01_play_symbol/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: main.bin hello.so 5 | 6 | main.bin: main.c hello.so 7 | $(CC) $^ -o $@ 8 | 9 | hello.so: hello.c 10 | $(CC) -shared $^ -o $@ 11 | 12 | run: all 13 | unset LD_LIBRARY_PATH 14 | LD_LIBRARY_PATH=. ./main.bin 15 | 16 | .PHONY: clean 17 | clean: 18 | rm -rf *.so *.bin -------------------------------------------------------------------------------- /examples/01_play_symbol/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hello.h" 3 | void func1() { 4 | printf("Hello, this is func1.\n"); 5 | } 6 | void func2() { 7 | printf("Hello, this is func2.\n"); 8 | } -------------------------------------------------------------------------------- /examples/01_play_symbol/hello.h: -------------------------------------------------------------------------------- 1 | void func1(); 2 | void func2(); -------------------------------------------------------------------------------- /examples/01_play_symbol/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hello.h" 3 | 4 | void main() { 5 | func1(); 6 | getchar(); 7 | } -------------------------------------------------------------------------------- /examples/02_hook_got_plt/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: crackme.bin myfunc.bin 5 | 6 | crackme.bin: crackme.c 7 | $(CC) -z lazy $^ -o $@ 8 | 9 | myfunc.bin: myfunc.c 10 | $(CC) -Wl,-T script.ld -fno-stack-protector -nostdlib -nodefaultlibs -fPIC -Wl,-shared $^ -o $@ 11 | 12 | .PHONY: clean 13 | clean: 14 | rm -rf *.bin -------------------------------------------------------------------------------- /examples/02_hook_got_plt/arch/x86_64/syscall.c: -------------------------------------------------------------------------------- 1 | // write syscall 2 | static long _write(long fd, const char *buf, unsigned long len) { 3 | 4 | register long ret asm ("rax"); 5 | register int sys_write asm ("rax") = 1; 6 | register long _fd asm ("rdi") = fd; 7 | register const char* _buf asm ("rsi") = buf; 8 | register unsigned long _len asm ("rdx") = len; 9 | asm volatile ( 10 | "syscall;" 11 | : "=r" (ret) 12 | : "r" (sys_write), "r" (_fd), "r" (_buf), "r" (_len) 13 | : 14 | ); 15 | return ret; 16 | } 17 | 18 | // exit syscall 19 | static long _exit(int errcode) { 20 | 21 | register long ret asm ("rax"); 22 | register int sys_exit asm ("rax") = 60; 23 | register int _errcode asm ("rdi") = errcode; 24 | asm volatile ( 25 | "syscall;" 26 | : "=r" (ret) 27 | : "r" (sys_exit), "r" (_errcode) 28 | : 29 | ); 30 | return ret; 31 | } 32 | -------------------------------------------------------------------------------- /examples/02_hook_got_plt/crackme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // flag{YoU_goT_the_FlaG1216} 6 | char password[] = "\x66\x6c\x61\x67\x7b\x59\x6f\x55\x5f\x67\x6f\x54\x5f\x74\x68\x65\x5f\x46\x6c\x61\x47\x31\x32\x31\x36\x7d"; 7 | 8 | int check(char* input) { 9 | for (int i = 0; i < sizeof(password) - 1; ++i) { 10 | password[i] ^= 0x0; 11 | } 12 | return memcmp(password, input, sizeof(password) - 1); 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | if (argc != 2) { 17 | printf("Usage: %s \n", argv[0]); 18 | return EXIT_FAILURE; 19 | } 20 | 21 | if (strlen(argv[1]) == (sizeof(password) - 1) && check(argv[1]) == 0) { 22 | printf("You got it !!\n"); 23 | return EXIT_SUCCESS; 24 | } 25 | 26 | printf("Wrong\n"); 27 | return EXIT_FAILURE; 28 | } 29 | -------------------------------------------------------------------------------- /examples/02_hook_got_plt/myfunc.c: -------------------------------------------------------------------------------- 1 | #include "arch/x86_64/syscall.c" 2 | #define stdout 1 3 | 4 | int my_memcmp(const void* lhs, const void* rhs, int n) { 5 | const char msg[] = "Hook add\n"; 6 | _write(stdout, msg, sizeof(msg)); 7 | _write(stdout, (const char*)lhs, n); 8 | _write(stdout, "\n", 2); 9 | _write(stdout, (const char*)rhs, n); 10 | _write(stdout, "\n", 2); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /examples/02_hook_got_plt/script.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .text : { *(.text) } 4 | .data : { *(.data) } 5 | .bss : { *(.bss) } 6 | } -------------------------------------------------------------------------------- /examples/03_infect_like_virus/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: hello.bin shellcode.bin 5 | 6 | hello.bin: hello.c 7 | $(CC) $^ -o $@ 8 | 9 | shellcode.bin: shellcode.c 10 | $(CC) -Wl,-T script.ld -fno-stack-protector -nostdlib -nodefaultlibs -fPIC -Wl,-shared $^ -o $@ 11 | 12 | run: all 13 | unset LD_LIBRARY_PATH 14 | LD_LIBRARY_PATH=. ./hello.bin 15 | 16 | .PHONY: clean 17 | clean: 18 | rm -rf *.bin -------------------------------------------------------------------------------- /examples/03_infect_like_virus/arch/x86_64/syscall.c: -------------------------------------------------------------------------------- 1 | // write syscall 2 | static long _write(long fd, const char *buf, unsigned long len) { 3 | 4 | register long ret asm ("rax"); 5 | register int sys_write asm ("rax") = 1; 6 | register long _fd asm ("rdi") = fd; 7 | register const char* _buf asm ("rsi") = buf; 8 | register unsigned long _len asm ("rdx") = len; 9 | asm volatile ( 10 | "syscall;" 11 | : "=r" (ret) 12 | : "r" (sys_write), "r" (_fd), "r" (_buf), "r" (_len) 13 | : 14 | ); 15 | return ret; 16 | } 17 | 18 | // exit syscall 19 | static long _exit(int errcode) { 20 | 21 | register long ret asm ("rax"); 22 | register int sys_exit asm ("rax") = 60; 23 | register int _errcode asm ("rdi") = errcode; 24 | asm volatile ( 25 | "syscall;" 26 | : "=r" (ret) 27 | : "r" (sys_exit), "r" (_errcode) 28 | : 29 | ); 30 | return ret; 31 | } -------------------------------------------------------------------------------- /examples/03_infect_like_virus/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((constructor)) void msg(int argc, char **argv) { 4 | printf("Hello, this is constructor.\n"); 5 | } 6 | 7 | int main() { 8 | puts("Hello, this is main."); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /examples/03_infect_like_virus/script.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .text : { *(.text) } 4 | .data : { *(.data) } 5 | .bss : { *(.bss) } 6 | } -------------------------------------------------------------------------------- /examples/03_infect_like_virus/shellcode.c: -------------------------------------------------------------------------------- 1 | #include "arch/x86_64/syscall.c" 2 | #define stdout 1 3 | 4 | int my_print(const void* lhs, const void* rhs, int n) { 5 | const char msg[] = "This is shellcode!\n"; 6 | _write(stdout, msg, sizeof(msg)); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /examples/04_trans_exe_into_lib/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: crackme.bin harness.bin 5 | 6 | crackme.bin: crackme.c 7 | $(CC) -Wl,-strip-all $^ -o $@ 8 | 9 | harness.bin: harness.c 10 | $(CC) $^ -o $@ 11 | 12 | .PHONY: clean 13 | clean: 14 | rm -rf *.bin -------------------------------------------------------------------------------- /examples/04_trans_exe_into_lib/crackme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int check_username(char* input) { 6 | if (strcmp(input, "tom")) 7 | return 0; 8 | else 9 | return 1; 10 | } 11 | 12 | int check_password(char* input) { 13 | if (strcmp(input, "654321")) 14 | return 0; 15 | else 16 | return 1; 17 | } 18 | 19 | int main(int argc, char** argv) { 20 | if (argc != 3) { 21 | printf("Usage: %s username password\n", argv[0]); 22 | exit(-1); 23 | } 24 | 25 | if (!check_username(argv[1])) { 26 | printf("Wrong username!\n"); 27 | } else { 28 | if (!check_password(argv[2])) { 29 | printf("Wrong password!\n"); 30 | } else { 31 | printf("Well done!\n"); 32 | } 33 | } 34 | return 0; 35 | } -------------------------------------------------------------------------------- /examples/04_trans_exe_into_lib/harness.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef int(*check_t)(char*); 6 | 7 | int main (int argc, char** argv) { 8 | if (argc != 2) { 9 | printf("Usage: %s password\n", argv[0]); 10 | exit(-1); 11 | } 12 | 13 | void* handler = dlopen("./crackme.bin", RTLD_LAZY); 14 | if (!handler) { 15 | fprintf(stderr, "dlopen error: %s\n", dlerror()); 16 | return 1; 17 | } 18 | 19 | check_t check_password = (check_t)dlsym(handler, "check_password"); 20 | if (check_password == NULL) { 21 | fprintf(stderr, "dlsym error: %s\n", dlerror()); 22 | return 1; 23 | } 24 | 25 | int output = check_password(argv[1]); 26 | 27 | printf("Output of check_password('%s'): %d\n", argv[1], output); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/05_checksec/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: main 5 | 6 | main: main.c 7 | $(CC) $^ -fstack-protector-all -z now -o $@ 8 | 9 | run: all 10 | ./main 11 | 12 | .PHONY: clean 13 | clean: 14 | rm -rf main -------------------------------------------------------------------------------- /examples/05_checksec/main.c: -------------------------------------------------------------------------------- 1 | /* Inspired from exploit.db */ 2 | /* Linux/x64 - execve "cat /etc/shadow" Shellcode (66 bytes) */ 3 | #include 4 | 5 | int main() 6 | { 7 | unsigned char shellcode[] = \ 8 | "\x48\x31\xc0\x48\x31\xed\x50\x48\xbd\x63\x2f\x73\x68\x61\x64\x6f\x77\x55\x48\xbd\x2f\x2f\x2f\x2f\x2f\x2f\x65\x74\x55\x48\x89\xe5\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x63\x61\x74\x53\x48\x89\xe3\x48\x89\xe7\x50\x48\x89\xe2\x55\x53\x48\x89\xe6\x66\x6a\x3b\x66\x58\x0f\x05"; 9 | 10 | int (*ret)() = (int(*)())shellcode; 11 | ret(); 12 | } -------------------------------------------------------------------------------- /examples/06_confuse_symbol/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: main.bin check.so 5 | 6 | main.bin: main.c check.so 7 | $(CC) -Wl,-rpath,./ $^ -o $@ 8 | 9 | check.so: check.c 10 | $(CC) -shared $^ -o $@ 11 | 12 | run: all 13 | ./main.bin 14 | 15 | .PHONY: clean 16 | clean: 17 | rm -rf *.so *.bin -------------------------------------------------------------------------------- /examples/06_confuse_symbol/check.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check.h" 4 | 5 | int check_username(char* input) { 6 | if (strcmp(input, "tom")) 7 | return 0; 8 | else 9 | return 1; 10 | } 11 | 12 | int check_password(char* input) { 13 | if (strcmp(input, "654321")) 14 | return 0; 15 | else 16 | return 1; 17 | } -------------------------------------------------------------------------------- /examples/06_confuse_symbol/check.h: -------------------------------------------------------------------------------- 1 | int check_username(char* input); 2 | int check_password(char* input); -------------------------------------------------------------------------------- /examples/06_confuse_symbol/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "check.h" 5 | 6 | int main(int argc, char** argv) { 7 | if (argc != 3) { 8 | printf("Usage: %s username password\n", argv[0]); 9 | exit(-1); 10 | } 11 | 12 | if (!check_username(argv[1])) { 13 | printf("Wrong username!\n"); 14 | } else { 15 | if (!check_password(argv[2])) { 16 | printf("Wrong password!\n"); 17 | } else { 18 | printf("Well done!\n"); 19 | } 20 | } 21 | return 0; 22 | } -------------------------------------------------------------------------------- /examples/07_inject_so/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: crackme.bin check.so my.so 5 | 6 | crackme.bin: crackme.c check.so 7 | $(CC) -Wl,-rpath,./ $^ -o $@ 8 | 9 | check.so: check.c 10 | $(CC) -shared $^ -o $@ 11 | 12 | my.so: my.c 13 | $(CC) -shared $^ -o $@ 14 | 15 | run: all 16 | ./crackme.bin 17 | 18 | .PHONY: clean 19 | clean: 20 | rm -rf *.so *.bin -------------------------------------------------------------------------------- /examples/07_inject_so/check.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check.h" 4 | 5 | int check_username(char* input) { 6 | if (strcmp(input, "tom")) 7 | return 0; 8 | else 9 | return 1; 10 | } 11 | 12 | int check_password(char* input) { 13 | if (strcmp(input, "654321")) 14 | return 0; 15 | else 16 | return 1; 17 | } 18 | 19 | void decrypt(char *str) { 20 | char *ptr = str; 21 | 22 | while (*ptr != '\0') { 23 | if ((*ptr >= 'a' && *ptr <= 'w') || (*ptr >= 'A' && *ptr <= 'W')) { 24 | *ptr = *ptr + 3; 25 | } else if (*ptr == 'x') { 26 | *ptr = 'a'; 27 | } else if (*ptr == 'y') { 28 | *ptr = 'b'; 29 | } else if (*ptr == 'z') { 30 | *ptr = 'c'; 31 | } else if (*ptr == 'X') { 32 | *ptr = 'A'; 33 | } else if (*ptr == 'Y') { 34 | *ptr = 'B'; 35 | } else if (*ptr == 'Z') { 36 | *ptr = 'C'; 37 | } 38 | 39 | ptr++; 40 | } 41 | } -------------------------------------------------------------------------------- /examples/07_inject_so/check.h: -------------------------------------------------------------------------------- 1 | int check_username(char* input); 2 | int check_password(char* input); 3 | void decrypt(char *str); -------------------------------------------------------------------------------- /examples/07_inject_so/crackme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "check.h" 5 | 6 | int main(int argc, char** argv) { 7 | if (argc != 3) { 8 | printf("Usage: %s username password\n", argv[0]); 9 | exit(-1); 10 | } 11 | 12 | char flag[100] = "cixd{Vlr_Dlq_cfopq_irzhv_ZEXOJ_lc_2023}"; 13 | 14 | if (!check_username(argv[1])) { 15 | printf("Wrong username!\n"); 16 | } else { 17 | if (!check_password(argv[2])) { 18 | printf("Wrong password!\n"); 19 | } else { 20 | decrypt(flag); 21 | printf("%s\n", flag); 22 | } 23 | } 24 | 25 | getchar(); // pause to cat /proc/pid/maps | grep crackme.bin 26 | return 0; 27 | } -------------------------------------------------------------------------------- /examples/07_inject_so/my.c: -------------------------------------------------------------------------------- 1 | int my_check_username(char* input) { 2 | return 1; 3 | } 4 | 5 | int my_check_password(char* input) { 6 | return 1; 7 | } -------------------------------------------------------------------------------- /examples/08_inject_interpreter/43565.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | ; Author Mr.Un1k0d3r - RingZer0 Team 3 | ; Read /etc/passwd Linux x86_64 Shellcode 4 | ; Shellcode size 82 bytes 5 | global _start 6 | 7 | section .text 8 | 9 | _start: 10 | jmp _push_filename 11 | 12 | _readfile: 13 | ; syscall open file 14 | pop rdi ; pop path value 15 | ; NULL byte fix 16 | xor byte [rdi + 11], 0x41 17 | 18 | xor rax, rax 19 | add al, 2 20 | xor rsi, rsi ; set O_RDONLY flag 21 | syscall 22 | 23 | ; syscall read file 24 | sub sp, 0xfff 25 | lea rsi, [rsp] 26 | mov rdi, rax 27 | xor rdx, rdx 28 | mov dx, 0xfff; size to read 29 | xor rax, rax 30 | syscall 31 | 32 | ; syscall write to stdout 33 | xor rdi, rdi 34 | add dil, 1 ; set stdout fd = 1 35 | mov rdx, rax 36 | xor rax, rax 37 | add al, 1 38 | syscall 39 | 40 | ; syscall exit 41 | xor rax, rax 42 | add al, 60 43 | syscall 44 | 45 | _push_filename: 46 | call _readfile 47 | path: db "/etc/passwdA" 48 | 49 | Shellcode: 50 | 51 | \xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41 -------------------------------------------------------------------------------- /examples/08_inject_interpreter/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | 4 | all: hello.bin 5 | 6 | hello.bin: hello.c 7 | $(CC) $^ -o $@ 8 | 9 | run: all 10 | ./hello.bin 11 | 12 | .PHONY: clean 13 | clean: 14 | rm -rf *.bin -------------------------------------------------------------------------------- /examples/08_inject_interpreter/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void main() { 4 | printf("Hello, world\n"); 5 | } -------------------------------------------------------------------------------- /examples/09_gen_elf_seeds/crash.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import subprocess 3 | 4 | def traverse_files(directory): 5 | file_list = [] 6 | for root, dirs, files in os.walk(directory): 7 | for file in files: 8 | file_list.append(os.path.join(root, file)) 9 | return file_list 10 | 11 | def run(bin, dir): 12 | print("bin: %s, dir: %s" % (bin, dir)) 13 | files = traverse_files(dir) 14 | all = len(files) 15 | count = 0 16 | for file in files: 17 | cmd = bin + " " + file 18 | try: 19 | result = subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) 20 | print(result.stdout) 21 | except subprocess.CalledProcessError as e: 22 | # 127: return, 132: illegal hardware instruction, 135: bus error 23 | if e.returncode not in [127, 132, 135]: 24 | count += 1 25 | print(f"Error: {e}") 26 | print("[%d in %d]" % (count, all)) 27 | 28 | if __name__ == '__main__': 29 | if len(sys.argv) < 3: 30 | print("Usage: %s %s %s" % (sys.argv[0], "binary", "crash_dir")) 31 | exit(0) 32 | 33 | run(sys.argv[1], sys.argv[2]) -------------------------------------------------------------------------------- /examples/09_gen_elf_seeds/seeds.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import os 4 | 5 | class Edit: 6 | seed_num = 0 7 | def __init__(self, option, max_i, max_j, file): 8 | self.maxi = max_i # row 9 | self.maxj = max_j # clumn 10 | self.option = option # [-H|S|P|B|D|R|I] 11 | self.file = file 12 | 13 | def run(self): 14 | for i in range(self.maxi): 15 | for j in range(self.maxj): 16 | # create new elf file 17 | new_file = self.file + "_" + self.option.strip("-") + "_" + "%03d" % Edit.seed_num 18 | cmd = "cp %s %s" % (self.file, new_file) 19 | os.system(cmd) 20 | Edit.seed_num = Edit.seed_num + 1 21 | # mutation 22 | cmd = "elfspirit edit %s -i %d -j %d -m %d %s" % (self.option, i, j, random.randint(1, 65535), new_file) 23 | os.system(cmd) 24 | 25 | if __name__ == '__main__': 26 | if len(sys.argv) < 3: 27 | print("Usage: %s %s %s elf_file" % (sys.argv[0], "[-H|S|P|B|D|R|I]", "row(optional)")) 28 | exit(0) 29 | elif len(sys.argv) == 3: 30 | num = 100 31 | file_name = sys.argv[2] 32 | else: 33 | num = sys.argv[2] 34 | file_name = sys.argv[3] 35 | 36 | if sys.argv[1] == "-H": 37 | header = Edit("-H", 13, 1, file_name) 38 | header.run() 39 | 40 | if sys.argv[1] == "-S": 41 | section = Edit("-S", 40, 10, file_name) 42 | section.run() 43 | 44 | if sys.argv[1] == "-P": 45 | segment = Edit("-P", 20, 8, file_name) 46 | segment.run() 47 | 48 | if sys.argv[1] == "-B": 49 | symtab = Edit("-B", num, 7, file_name) 50 | symtab.run() 51 | 52 | if sys.argv[1] == "-D": 53 | symtab = Edit("-D", num, 7, file_name) 54 | symtab.run() 55 | 56 | if sys.argv[1] == "-R": 57 | rela = Edit("-R", num, 7, file_name) 58 | rela.run() 59 | -------------------------------------------------------------------------------- /pictures/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secnotes/elfspirit/c9eca4a4619529ec8a5b787f51bb61b6434212d7/pictures/1.png -------------------------------------------------------------------------------- /pictures/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secnotes/elfspirit/c9eca4a4619529ec8a5b787f51bb61b6434212d7/pictures/2.png -------------------------------------------------------------------------------- /pictures/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secnotes/elfspirit/c9eca4a4619529ec8a5b787f51bb61b6434212d7/pictures/3.png -------------------------------------------------------------------------------- /pictures/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secnotes/elfspirit/c9eca4a4619529ec8a5b787f51bb61b6434212d7/pictures/4.png -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=elfspirit 2 | OUT=/usr/local/bin/ 3 | SRCS = $(wildcard *.c cJSON/cJSON.c) 4 | OBJS = $(SRCS:.c=.o) 5 | CFLAGS = -w -c 6 | 7 | ifeq ($(debug), true) 8 | CXXFLAGS=-g -fsanitize=address 9 | CXXFLAGS+=-Ddebug 10 | else 11 | CXXFLAGS=-O3 12 | endif 13 | 14 | $(TARGET) : $(OBJS) 15 | $(CC) $(CXXFLAGS) $(OBJS) -o $(TARGET) 16 | %.o: %.c 17 | $(CC) $(CFLAGS) $(CXXFLAGS) $< -o $@ 18 | 19 | .PHONY: clean 20 | clean: 21 | rm -rvf *.o 22 | rm -rvf cJSON/*.o 23 | rm -vf $(TARGET) 24 | 25 | .PHONY: install 26 | install:$(TARGET) 27 | @echo "begin install "$(TARGET) 28 | cp $(TARGET) $(OUT) 29 | @echo $(TARGET) "install success!" -------------------------------------------------------------------------------- /src/addelfinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021-2022 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "common.h" 33 | 34 | static int conv_arch(uint8_t *arch, uint32_t class) { 35 | if (!(strcmp(arch, "arm") & strcmp(arch, "ARM"))) { 36 | return EM_ARM; 37 | } 38 | 39 | else if (!(strcmp(arch, "x86") & strcmp(arch, "X86"))) { 40 | if (class == 32) 41 | return EM_386; 42 | else if (class == 64) 43 | return EM_X86_64; 44 | } 45 | 46 | else if (!(strcmp(arch, "mips") & strcmp(arch, "MIPS"))) { 47 | return EM_MIPS; 48 | } 49 | 50 | else 51 | return NULL; 52 | } 53 | 54 | /** 55 | * @description: add ELF info to firmware for IDA 56 | * @param {uint8_t} *bin 57 | * @param {uint8_t} *arch 58 | * @param {uint32_t} class 59 | * @param {uint8_t} *endian 60 | * @param {uint64_t} *base_addr 61 | * @return {*} 62 | */ 63 | int add_elf_info(uint8_t *bin, uint8_t *arch, uint32_t class, uint8_t *endian, uint64_t base_addr){ 64 | int fd; 65 | struct stat st; 66 | uint8_t *bin_map; 67 | uint8_t *new_bin_map; 68 | uint32_t *new_size; 69 | 70 | fd = open(bin, O_RDONLY); 71 | if (fd < 0) { 72 | perror("open in add_elf_info"); 73 | return -1; 74 | } 75 | 76 | if (fstat(fd, &st) < 0) { 77 | perror("fstat"); 78 | return -1; 79 | } 80 | 81 | bin_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 82 | if (bin_map == MAP_FAILED) { 83 | perror("mmap"); 84 | return -1; 85 | } 86 | 87 | /* 32bit */ 88 | if (class == 32) { 89 | /*****| ELF Header | Phdr*2 | Shdr | padding | data | *****/ 90 | if (base_addr == 0) { 91 | base_addr = 0x08048000; 92 | } 93 | new_size = 0x1000 + st.st_size; 94 | new_bin_map = malloc(new_size); 95 | if (new_bin_map < 0) { 96 | return -1; 97 | } 98 | memset(new_bin_map, 0, new_size); 99 | 100 | Elf32_Ehdr ehdr = { 101 | .e_ident = 0x0, 102 | .e_type = ET_EXEC, 103 | .e_machine = conv_arch(arch, class), 104 | .e_version = EV_CURRENT, 105 | .e_entry = base_addr + 0x1000, 106 | .e_phoff = sizeof(Elf32_Ehdr), 107 | .e_shoff = sizeof(Elf32_Ehdr) * 2 + sizeof(Elf32_Phdr) * 2, 108 | .e_flags = 0, 109 | .e_ehsize = sizeof(Elf32_Ehdr), 110 | .e_phentsize = sizeof(Elf32_Phdr), 111 | .e_phnum = 2, 112 | .e_shentsize = sizeof(Elf32_Shdr), 113 | .e_shnum = 1, 114 | .e_shstrndx = 0, 115 | }; 116 | if (ehdr.e_machine == EM_ARM) { 117 | ehdr.e_flags = 0x05000200; /* arm32 */ 118 | } 119 | ehdr.e_ident[0] = '\x7f'; 120 | ehdr.e_ident[1] = 'E'; 121 | ehdr.e_ident[2] = 'L'; 122 | ehdr.e_ident[3] = 'F'; 123 | ehdr.e_ident[4] = ELFCLASS32; /* ELF class */ 124 | if (!strcmp(endian, "little")) 125 | ehdr.e_ident[5] = '\x01'; 126 | else if(!strcmp(endian, "big")) 127 | ehdr.e_ident[5] = '\x02'; 128 | ehdr.e_ident[6] = '\x01'; /* EI_VERSION */ 129 | 130 | Elf32_Phdr phdr1 = { 131 | .p_type = PT_LOAD, 132 | .p_offset = 0, 133 | .p_vaddr = base_addr, 134 | .p_paddr = base_addr, 135 | .p_filesz = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * 2 + sizeof(Elf32_Shdr) * 2, 136 | .p_memsz = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * 2 + sizeof(Elf32_Shdr) * 2, 137 | .p_flags = PF_R, 138 | .p_align = 0x1000 139 | }; 140 | 141 | Elf32_Phdr phdr2 = { 142 | .p_type = PT_LOAD, 143 | .p_offset = 0x1000, 144 | .p_vaddr = base_addr + 0x1000, 145 | .p_paddr = base_addr + 0x1000, 146 | .p_filesz = st.st_size, 147 | .p_memsz = st.st_size, 148 | .p_flags = PF_R | PF_W | PF_X, 149 | .p_align = 0x1000 150 | }; 151 | 152 | Elf32_Shdr shdr = { 153 | .sh_name = 0x0, 154 | .sh_type = SHT_PROGBITS, /* Program data */ 155 | .sh_flags = SHF_EXECINSTR, /* Executable */ 156 | .sh_addr = base_addr + 0x1000, 157 | .sh_offset = 0x1000, 158 | .sh_size = st.st_size, /* Section(bin) size */ 159 | .sh_link = 0x0, 160 | .sh_info = 0x0, 161 | .sh_addralign = 4, 162 | .sh_entsize = 0x0 163 | }; 164 | 165 | /*****| ELF Header | Phdr*2 | Shdr*2 | padding | data | *****/ 166 | memset(new_bin_map, 0, new_size); 167 | memcpy(new_bin_map, &ehdr, sizeof(Elf32_Ehdr)); 168 | memcpy(new_bin_map + sizeof(Elf32_Ehdr), &phdr1, sizeof(Elf32_Phdr)); 169 | memcpy(new_bin_map + sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr), &phdr2, sizeof(Elf32_Phdr)); 170 | memcpy(new_bin_map + sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * 2, &shdr, sizeof(Elf32_Shdr)); 171 | memcpy(new_bin_map + 0x1000, bin_map, st.st_size); 172 | } 173 | 174 | /* 64bit */ 175 | if (class == 64) { 176 | /*****| ELF Header | ELF Phdr | ELF Section header1 | ELF Section header2 |*****/ 177 | if (base_addr == 0) { 178 | base_addr = 0x400000; 179 | } 180 | new_size = 0x1000 + st.st_size; 181 | new_bin_map = malloc(new_size); 182 | if (new_bin_map < 0) { 183 | return -1; 184 | } 185 | memset(new_bin_map, 0, new_size); 186 | 187 | Elf64_Ehdr ehdr = { 188 | .e_ident = 0x0, 189 | .e_type = ET_EXEC, 190 | .e_machine = conv_arch(arch, class), 191 | .e_version = EV_CURRENT, 192 | .e_entry = base_addr + 0x1000, 193 | .e_phoff = sizeof(Elf64_Ehdr), 194 | .e_shoff = sizeof(Elf64_Ehdr) * 2 + sizeof(Elf64_Phdr) * 2, 195 | .e_flags = 0, 196 | .e_ehsize = sizeof(Elf64_Ehdr), 197 | .e_phentsize = sizeof(Elf64_Phdr), 198 | .e_phnum = 2, 199 | .e_shentsize = sizeof(Elf64_Shdr), 200 | .e_shnum = 1, 201 | .e_shstrndx = 0, 202 | }; 203 | if (ehdr.e_machine == EM_ARM) { 204 | ehdr.e_flags = 0x05000200; /* arm64?? */ 205 | } 206 | ehdr.e_ident[0] = '\x7f'; 207 | ehdr.e_ident[1] = 'E'; 208 | ehdr.e_ident[2] = 'L'; 209 | ehdr.e_ident[3] = 'F'; 210 | ehdr.e_ident[4] = ELFCLASS64; /* ELF class */ 211 | if (!strcmp(endian, "little")) 212 | ehdr.e_ident[5] = '\x01'; 213 | else if(!strcmp(endian, "big")) 214 | ehdr.e_ident[5] = '\x02'; 215 | ehdr.e_ident[6] = '\x01'; /* EI_VERSION */ 216 | 217 | Elf64_Phdr phdr1 = { 218 | .p_type = PT_LOAD, 219 | .p_offset = 0, 220 | .p_vaddr = base_addr, 221 | .p_paddr = base_addr, 222 | .p_filesz = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * 2 + sizeof(Elf64_Shdr) * 2, 223 | .p_memsz = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * 2 + sizeof(Elf64_Shdr) * 2, 224 | .p_flags = PF_R, 225 | .p_align = 0x1000 226 | }; 227 | 228 | Elf64_Phdr phdr2 = { 229 | .p_type = PT_LOAD, 230 | .p_offset = 0x1000, 231 | .p_vaddr = base_addr + 0x1000, 232 | .p_paddr = base_addr + 0x1000, 233 | .p_filesz = st.st_size, 234 | .p_memsz = st.st_size, 235 | .p_flags = PF_R | PF_W | PF_X, 236 | .p_align = 0x1000 237 | }; 238 | 239 | Elf64_Shdr shdr = { 240 | .sh_name = 0x0, 241 | .sh_type = SHT_PROGBITS, /* Program data */ 242 | .sh_flags = SHF_EXECINSTR, /* Executable */ 243 | .sh_addr = base_addr + 0x1000, 244 | .sh_offset = 0x1000, 245 | .sh_size = st.st_size, /* Section(bin) size */ 246 | .sh_link = 0x0, 247 | .sh_info = 0x0, 248 | .sh_addralign = 4, 249 | .sh_entsize = 0x0 250 | }; 251 | 252 | /*****| ELF Header | Phdr*2 | Shdr*2 | padding | data | *****/ 253 | memset(new_bin_map, 0, new_size); 254 | memcpy(new_bin_map, &ehdr, sizeof(Elf64_Ehdr)); 255 | memcpy(new_bin_map + sizeof(Elf64_Ehdr), &phdr1, sizeof(Elf64_Phdr)); 256 | memcpy(new_bin_map + sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr), &phdr2, sizeof(Elf64_Phdr)); 257 | memcpy(new_bin_map + sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * 2, &shdr, sizeof(Elf64_Shdr)); 258 | memcpy(new_bin_map + 0x1000, bin_map, st.st_size); 259 | } 260 | 261 | INFO("source file length is 0x%x\n", st.st_size); 262 | INFO("base address is 0x%x\n", base_addr); 263 | create_file(bin, new_bin_map, new_size, 1); 264 | free(new_bin_map); 265 | close(fd); 266 | } -------------------------------------------------------------------------------- /src/addelfinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021-2022 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | /** 28 | * @description: add ELF info to firmware for IDA (为原始固件添加ELF信息, 方便IDA识别) 29 | * @param {uint8_t} *bin 30 | * @param {uint8_t} *arch 31 | * @param {uint32_t} class 32 | * @param {uint8_t} *endian 33 | * @param {uint64_t} *base_addr 34 | * @return {*} 35 | */ 36 | int add_elf_info(uint8_t *bin, uint8_t *arch, uint32_t class, uint8_t *endian, uint64_t base_addr); 37 | -------------------------------------------------------------------------------- /src/addsec.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "common.h" 32 | 33 | /** 34 | * @description: append data to ELF 35 | * @param {uint8_t} *elf 36 | * @param {uint32_t} elf_size 37 | * @param {uint32_t} offset 38 | * @param {uint32_t} data_size 39 | * @param {uint8_t} *ret 40 | * @return {*} 41 | */ 42 | int add_data(uint8_t *elf, uint32_t elf_size, uint32_t offset, uint32_t data_size, uint8_t *ret) { 43 | char *tmp; 44 | tmp = malloc(elf_size + data_size); 45 | if (tmp < 0) { 46 | return NULL; 47 | } 48 | 49 | memset(tmp, 0, elf_size + data_size); 50 | memcpy(tmp, elf, offset); 51 | memset(&tmp[offset], 0, data_size); 52 | memcpy(&tmp[offset + data_size], &elf[offset], elf_size - offset); 53 | memcpy(ret, tmp, elf_size + data_size); 54 | free(tmp); 55 | return 0; 56 | } 57 | 58 | /** 59 | * @description: add a section 60 | * @param {uint8_t} *elf 61 | * @param {uint32_t} offset 62 | * @param {uint8_t} *new_sec 63 | * @param {uint32_t} sec_size 64 | * @return {*} 65 | */ 66 | int add_section_bak(uint8_t *elf, uint32_t offset, uint8_t *new_sec, uint32_t sec_size) { 67 | int fd; 68 | struct stat st; 69 | int range; /* indicate the range of offset */ 70 | uint8_t *elf_map; 71 | uint8_t *elf_map_new; 72 | uint8_t *tmp_sec_name; 73 | uint32_t tmp_map_size; 74 | uint32_t new_map_size; 75 | uint32_t start; 76 | 77 | fd = open(elf, O_RDONLY); 78 | if (fd < 0) { 79 | perror("open"); 80 | return -1; 81 | } 82 | 83 | if (fstat(fd, &st) < 0) { 84 | perror("fstat"); 85 | return -1; 86 | } 87 | 88 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 89 | if (elf_map == MAP_FAILED) { 90 | perror("mmap"); 91 | return -1; 92 | } 93 | 94 | /* offset is section address */ 95 | offset = offset?offset:st.st_size; /* set default offset value */ 96 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elf_map; 97 | INFO("offset to insert: %p\n", offset); 98 | if (!(offset == ehdr->e_shoff || offset == st.st_size || is_sec_addr(elf, offset) > -1)) { 99 | WARNING("The recommended insertion location is the starting address of a section/header/the end of the file\n"); 100 | return -1; 101 | } 102 | 103 | /* 32bit */ 104 | if (MODE == ELFCLASS32) { 105 | Elf32_Ehdr *ehdr; 106 | Elf32_Shdr *shdr; 107 | Elf32_Shdr *shstrtab; 108 | 109 | ehdr = (Elf32_Ehdr *)elf_map; 110 | shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff]; 111 | shstrtab = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx]; 112 | 113 | /* section contnet + section header + section header string */ 114 | new_map_size = st.st_size + sec_size + sizeof(Elf32_Shdr) + PTR_ALIGN(strlen(new_sec), 4); 115 | elf_map_new = malloc(new_map_size); 116 | if (elf_map_new == NULL) { 117 | ERROR("malloc elf new error!\n"); 118 | munmap(elf_map, st.st_size); 119 | close(fd); 120 | return -1; 121 | } 122 | 123 | /* 1.add section content */ 124 | tmp_map_size = st.st_size; 125 | start = offset; 126 | add_data(elf_map, tmp_map_size, start, sec_size, elf_map_new); 127 | 128 | ehdr = (Elf32_Ehdr *)elf_map_new; 129 | if (offset <= shstrtab->sh_offset) { 130 | range = 1; 131 | ehdr->e_shoff += sec_size; 132 | shdr = (Elf32_Shdr *)&elf_map_new[ehdr->e_shoff]; 133 | /* update */ 134 | shstrtab = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx]; 135 | /* if you use shstrtab without pointer, elf memory will not not be changed. 136 | * shstrtab = shdr[ehdr->e_shstrndx] 137 | */ 138 | 139 | shstrtab->sh_offset += sec_size; /* not write data to memory! */ 140 | 141 | } else if (offset == ehdr->e_shoff) { 142 | range = 2; 143 | ehdr->e_shoff += sec_size; 144 | } else { 145 | range = 3; 146 | } 147 | 148 | munmap(elf_map, st.st_size); 149 | tmp_map_size += sec_size; 150 | 151 | /* 2.add section header */ 152 | start = ehdr->e_shoff + sizeof(Elf32_Shdr) * ehdr->e_shnum; 153 | add_data(elf_map_new, tmp_map_size, start, sizeof(Elf32_Shdr), elf_map_new); 154 | 155 | ehdr = (Elf32_Ehdr *)elf_map_new; 156 | shdr = (Elf32_Shdr *)&elf_map_new[ehdr->e_shoff]; 157 | shstrtab = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx]; 158 | ehdr->e_shnum++; 159 | 160 | if (range == 3) { 161 | offset += sizeof(Elf32_Shdr); 162 | } 163 | 164 | tmp_map_size += sizeof(Elf32_Shdr); 165 | 166 | /* 3.add section header string */ 167 | start = shstrtab->sh_offset + shstrtab->sh_size; 168 | add_data(elf_map_new, tmp_map_size, start, PTR_ALIGN(strlen(new_sec), 4), elf_map_new); 169 | memcpy(elf_map_new + start, new_sec, strlen(new_sec)); 170 | 171 | /* section header off */ 172 | ehdr->e_shoff += PTR_ALIGN(strlen(new_sec), 4); 173 | ehdr = (Elf32_Ehdr *)elf_map_new; 174 | shdr = (Elf32_Shdr *)&elf_map_new[ehdr->e_shoff]; 175 | shstrtab = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx]; 176 | shstrtab->sh_size += PTR_ALIGN(strlen(new_sec), 4); 177 | 178 | if (range >= 2) { 179 | offset += PTR_ALIGN(strlen(new_sec), 4); 180 | } 181 | 182 | /* 4.set value for added section header */ 183 | Elf32_Shdr new_sec_head = { 184 | .sh_name = shstrtab->sh_size - PTR_ALIGN(strlen(new_sec), 4), 185 | .sh_type = 1, 186 | .sh_flags = 0x6, 187 | .sh_addr = offset, 188 | .sh_offset = offset, 189 | .sh_size = sec_size, 190 | .sh_link = 0x0, 191 | .sh_info = 0x0, 192 | .sh_addralign = 4, 193 | .sh_entsize = 0x0 194 | }; 195 | 196 | memcpy(&elf_map_new[ehdr->e_shoff + sizeof(Elf32_Shdr) * (ehdr->e_shnum - 1)], &new_sec_head, sizeof(Elf32_Shdr)); 197 | } 198 | 199 | /* 64bit */ 200 | if (MODE == ELFCLASS64) { 201 | Elf64_Ehdr *ehdr; 202 | Elf64_Shdr *shdr; 203 | Elf64_Shdr *shstrtab; 204 | 205 | ehdr = (Elf64_Ehdr *)elf_map; 206 | shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff]; 207 | shstrtab = (Elf64_Shdr *)&shdr[ehdr->e_shstrndx]; 208 | 209 | /* section contnet + section header + section header string */ 210 | new_map_size = st.st_size + sec_size + sizeof(Elf64_Shdr) + PTR_ALIGN(strlen(new_sec), 4); 211 | elf_map_new = malloc(new_map_size); 212 | if (elf_map_new == NULL) { 213 | ERROR("malloc elf new error!\n"); 214 | munmap(elf_map, st.st_size); 215 | close(fd); 216 | return -1; 217 | } 218 | 219 | /* 1.add section content */ 220 | tmp_map_size = st.st_size; 221 | start = offset; 222 | add_data(elf_map, tmp_map_size, start, sec_size, elf_map_new); 223 | 224 | ehdr = (Elf64_Ehdr *)elf_map_new; 225 | if (offset <= shstrtab->sh_offset) { 226 | range = 1; 227 | ehdr->e_shoff += sec_size; 228 | shdr = (Elf64_Shdr *)&elf_map_new[ehdr->e_shoff]; 229 | /* update */ 230 | shstrtab = (Elf64_Shdr *)&shdr[ehdr->e_shstrndx]; 231 | /* if you use shstrtab without pointer, elf memory will not not be changed. 232 | * shstrtab = shdr[ehdr->e_shstrndx] 233 | */ 234 | 235 | shstrtab->sh_offset += sec_size; /* not write data to memory! */ 236 | 237 | } else if (offset == ehdr->e_shoff) { 238 | range = 2; 239 | ehdr->e_shoff += sec_size; 240 | } else { 241 | range = 3; 242 | } 243 | 244 | munmap(elf_map, st.st_size); 245 | tmp_map_size += sec_size; 246 | 247 | /* 2.add section header */ 248 | start = ehdr->e_shoff + sizeof(Elf64_Shdr) * ehdr->e_shnum; 249 | add_data(elf_map_new, tmp_map_size, start, sizeof(Elf64_Shdr), elf_map_new); 250 | 251 | ehdr = (Elf64_Ehdr *)elf_map_new; 252 | shdr = (Elf64_Shdr *)&elf_map_new[ehdr->e_shoff]; 253 | shstrtab = (Elf64_Shdr *)&shdr[ehdr->e_shstrndx]; 254 | ehdr->e_shnum++; 255 | 256 | if (range == 3) { 257 | offset += sizeof(Elf64_Shdr); 258 | } 259 | 260 | tmp_map_size += sizeof(Elf64_Shdr); 261 | 262 | /* 3.add section header string */ 263 | start = shstrtab->sh_offset + shstrtab->sh_size; 264 | add_data(elf_map_new, tmp_map_size, start, PTR_ALIGN(strlen(new_sec), 4), elf_map_new); 265 | memcpy(elf_map_new + start, new_sec, strlen(new_sec)); 266 | 267 | /* section header off */ 268 | ehdr->e_shoff += PTR_ALIGN(strlen(new_sec), 4); 269 | ehdr = (Elf64_Ehdr *)elf_map_new; 270 | shdr = (Elf64_Shdr *)&elf_map_new[ehdr->e_shoff]; 271 | shstrtab = (Elf64_Shdr *)&shdr[ehdr->e_shstrndx]; 272 | shstrtab->sh_size += PTR_ALIGN(strlen(new_sec), 4); 273 | 274 | if (range >= 2) { 275 | offset += PTR_ALIGN(strlen(new_sec), 4); 276 | } 277 | 278 | /* 4.set value for added section header */ 279 | Elf64_Shdr new_sec_head = { 280 | .sh_name = shstrtab->sh_size - PTR_ALIGN(strlen(new_sec), 4), 281 | .sh_type = 1, 282 | .sh_flags = 0x6, 283 | .sh_addr = offset, 284 | .sh_offset = offset, 285 | .sh_size = sec_size, 286 | .sh_link = 0x0, 287 | .sh_info = 0x0, 288 | .sh_addralign = 4, 289 | .sh_entsize = 0x0 290 | }; 291 | 292 | memcpy(&elf_map_new[ehdr->e_shoff + sizeof(Elf64_Shdr) * (ehdr->e_shnum - 1)], &new_sec_head, sizeof(Elf64_Shdr)); 293 | } 294 | 295 | create_file(elf, elf_map_new, new_map_size, 1); 296 | 297 | free(elf_map_new); 298 | close(fd); 299 | 300 | return 0; 301 | } -------------------------------------------------------------------------------- /src/addsec.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | /** 27 | * @description: add a section 28 | * @param {uint8_t} *elf 29 | * @param {uint32_t} offset 30 | * @param {uint8_t} *new_sec 31 | * @param {uint32_t} sec_size 32 | * @return {*} 33 | */ 34 | int add_section_bak(uint8_t *elf, uint32_t offset, uint8_t *new_sec, uint32_t sec_size); 35 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "cJSON/cJSON.h" 26 | 27 | #define LENGTH 64 28 | #define PATH_LENGTH LENGTH 29 | /* generate new file name */ 30 | #define PATH_LENGTH_NEW LENGTH + 4 31 | 32 | #define __ALIGN_MASK(x, mask) (((x) + (mask))&~(mask)) 33 | #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) 34 | #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) 35 | 36 | #define NONE "\e[0m" // Clear color 清除颜色,即之后的打印为正常输出,之前的不受影响 37 | #define L_RED "\e[1;31m" // Light Red 鲜红 38 | #define L_GREEN "\e[1;32m" // Light Green 鲜绿 39 | #define YELLOW "\e[1;33m" // Light Yellow 鲜黄 40 | 41 | #define WARNING(format, ...) printf (""YELLOW"[!] "format""NONE"", ##__VA_ARGS__) 42 | #define ERROR(format, ...) printf (""L_RED"[-] "format""NONE"", ##__VA_ARGS__) 43 | #define INFO(format, ...) printf (""L_GREEN"[+] "format""NONE"", ##__VA_ARGS__) 44 | #define VERBOSE(format, ...) printf (""YELLOW"[*] "format""NONE"", ##__VA_ARGS__) 45 | 46 | #define CHECK_WARNING(format, ...) printf (""YELLOW""format""NONE"", ##__VA_ARGS__) 47 | #define CHECK_ERROR(format, ...) printf (""L_RED""format""NONE"", ##__VA_ARGS__) 48 | #define CHECK_INFO(format, ...) printf (""L_GREEN""format""NONE"", ##__VA_ARGS__) 49 | #define CHECK_COMMON(format, ...) printf (""format"", ##__VA_ARGS__) 50 | 51 | #ifdef debug 52 | #define DEBUG(format, ...) printf (""YELLOW"[d] "format""NONE"", ##__VA_ARGS__) 53 | #else 54 | #define DEBUG(format, ...) 55 | #endif 56 | 57 | #define UNKOWN "Unkown" 58 | #define PAGE_SIZE 4096 // 4K的大小 59 | 60 | /* ELF class */ 61 | extern int MODE; 62 | 63 | /* ELF architecture */ 64 | extern int ARCH; 65 | 66 | typedef struct handle32 { 67 | Elf32_Ehdr *ehdr; 68 | Elf32_Phdr *phdr; 69 | Elf32_Shdr *shdr; 70 | Elf32_Shdr *shstrtab; 71 | int sec_index; // section index 72 | size_t sec_size; // section size 73 | uint8_t *mem; 74 | int fd; 75 | size_t size; // file size 76 | } handle_t32; 77 | 78 | typedef struct handle64 { 79 | Elf64_Ehdr *ehdr; 80 | Elf64_Phdr *phdr; 81 | Elf64_Shdr *shdr; 82 | Elf64_Shdr *shstrtab; 83 | int sec_index; // section index 84 | size_t sec_size; // section size 85 | uint8_t *mem; 86 | int fd; 87 | size_t size; // file size 88 | } handle_t64; 89 | 90 | typedef struct GnuHash { 91 | uint32_t nbuckets; // 桶的数量 92 | uint32_t symndx; // 符号表的开始索引 93 | uint32_t maskbits; // 掩码位数 94 | uint32_t shift; // 用于计算哈希值的位移量 95 | uint32_t buckets[]; // 桶数组,大小为 nbuckets 96 | // 后面可能跟着链表和其他数据 97 | } gnuhash_t; 98 | 99 | void log_warning(char *str); 100 | void log_error(char *str); 101 | void log_info(char *str); 102 | 103 | void get_name(char *file, char *file_name); 104 | void get_path(char *file, char *file_path); 105 | 106 | /** 107 | * @description: hex string to int 108 | * @param {char} *hex 109 | * @return {*} 110 | */ 111 | unsigned int hex2int(char *hex); 112 | 113 | /** 114 | * @description: Convert hex to printable string (将十六进制转化为可打印的字符串) 115 | * @param {unsigned int} hex 116 | * @param {char} *ret 117 | * @param {unsigned int} len string length 118 | * @return {*} 119 | */ 120 | int hex2str(unsigned int hex, char *ret, unsigned int len); 121 | 122 | /** 123 | * @description: String reverse from start to end (指定位置的字符串逆序) 124 | * @param {char} *str 125 | * @param {int} offset 126 | * @param {int} length 127 | * @return {*} 128 | */ 129 | char *str_reverse(char *str, int offset, int length); 130 | 131 | /** 132 | * @brief Compare string 133 | * 134 | * @param str1 135 | * @param str2 136 | * @param n 137 | * @return int 138 | */ 139 | int compare_firstN_chars(const char *str1, const char *str2, int n); 140 | 141 | /** 142 | * @brief 计算一个地址的4K对齐地址 143 | * align 4k address 144 | * @param address input address 145 | * @return uint64_t output 4k address 146 | */ 147 | uint64_t align_to_4k(uint64_t address); 148 | 149 | /** 150 | * @brief 将命令行传入的shellcode,转化为内存实际值 151 | * convert the shellcode passed in from the command line to the actual value in memory 152 | * @param sc_str input shellcode string 153 | * @param sc_mem output shellcode memory 154 | */ 155 | int cmdline_shellcode(char *sc_str, char *sc_mem); 156 | 157 | /** 158 | * @description: Determine whether elf is in 32-bit mode or 64-bit mode (判断elf是32位还是64位) 159 | * @param {char} *elf_name 160 | * @return {*} 161 | */ 162 | int get_elf_class(char *elf_name); 163 | 164 | /** 165 | * @description: Get elf architecture, such as EM_386, EM_X86_64, EM_ARM and EM_MIPS. (ELF文件架构) 166 | * @param {char} *elf_name 167 | * @return {*} 168 | */ 169 | int get_elf_machine(char *elf_name); 170 | 171 | /** 172 | * @description: Judge whether the address is the starting address of the section (判断地址是否为section起始地址) 173 | * @param {char} *elf_name 174 | * @param {int} offset 175 | * @return {*} 176 | */ 177 | int is_sec_addr(char *elf_name, int offset); 178 | 179 | /** 180 | * @description: Create new file to store changes 181 | * @param {char} *elf_name original file name 182 | * @param {char} *elf_map 183 | * @param {uint32_t} map_size 184 | * @param {uint32_t} is_new 185 | * @return {*} 186 | */ 187 | int create_file(char *elf_name, char *elf_map, uint32_t map_size, uint32_t is_new); 188 | 189 | /** 190 | * @description: Create json object from json file 191 | * @param {char} *name original json file name 192 | * @return {*} 193 | */ 194 | cJSON *get_json_object(char *name); 195 | 196 | /** 197 | * @brief 获取节头表的偏移 198 | * get program header table offset 199 | * @return uint64_t section address 200 | */ 201 | uint64_t get_shdr_offset(char *elf_name); 202 | 203 | /** 204 | * @brief 获取程序头表的偏移 205 | * get program header table offset 206 | * @return uint64_t segment address 207 | */ 208 | uint64_t get_phdr_offset(char *elf_name); 209 | 210 | /** 211 | * @brief 获取程序入口 212 | * get program entry 213 | * @return uint64_t program entry 214 | */ 215 | uint64_t get_entry(char *elf_name); 216 | 217 | /** 218 | * @brief Extract binary fragments from the target file 219 | * 220 | * @param input_file original file name 221 | * @param offset start address 222 | * @param size end address(size) 223 | * @param output fragments content 224 | * @return error code {-1:error,0:sucess} 225 | */ 226 | int extract_fragment(const char *input_file, long offset, size_t size, char *output); 227 | 228 | 229 | /* EXTERN API */ 230 | /** 231 | * @description: Judge whether the memory address is legal 232 | * @param {uint64_t} addr 233 | * @param {uint64_t} start 234 | * @param {uint64_t} end 235 | * @return {*} 236 | */ 237 | int validated_offset(uint64_t addr, uint64_t start, uint64_t end); 238 | 239 | /** 240 | * @brief Set the interpreter object 241 | * 242 | * @param elf_name elf file name 243 | * @param new_interpreter string 244 | * @return int error code {-1:error,0:sucess} 245 | */ 246 | int set_interpreter(char *elf_name, char *new_interpreter); 247 | 248 | /** 249 | * @brief 判断二进制是否开启地址随机化 250 | * determine whether binary has enabled address randomization 251 | * @param elfname 252 | * @return int {1:true,0:false} 253 | */ 254 | int is_pie(char *elfname); 255 | 256 | /** 257 | * @brief 编辑指针 258 | * edit pointers in the ELF files 259 | * @param elf_name elf file name 260 | * @param offset start elf file offset 261 | * @return int error code {-1:error,0:sucess} 262 | */ 263 | int set_pointer(char *elf_name, uint64_t offset, uint64_t value); 264 | 265 | /** 266 | * @brief 向ELF文件特定偏移处,写入一段数据 267 | * Write a piece of data to a specific offset in the ELF file 268 | * @param elf_name elf file name 269 | * @param offset start elf file offset 270 | * @param content new value string value to be edited 271 | * @param size content size 272 | * @return int error code {-1:error,0:sucess} 273 | */ 274 | int set_content(char *elf_name, uint64_t offset, char *content, size_t size); 275 | 276 | /** 277 | * @brief 设置新的解释器(动态链接器) 278 | * set up a new interpreter (dynamic linker) 279 | * @param elf_name elf file name 280 | * @param new_interpreter string 281 | * @return int error code {-1:error,0:sucess} 282 | */ 283 | int set_interpreter(char *elf_name, char *new_interpreter); 284 | 285 | /** 286 | * @brief 设置rpath 287 | * set rpath 288 | * @param elf_name elf file name 289 | * @param rpath string 290 | * @return int error code {-1:error,0:sucess} 291 | */ 292 | int set_rpath(char *elf_name, char *rpath); 293 | 294 | /** 295 | * @brief 设置runpath 296 | * set runpath 297 | * @param elf_name elf file name 298 | * @param rpath string 299 | * @return int error code {-1:error,0:sucess} 300 | */ 301 | int set_runpath(char *elf_name, char *rpath); 302 | 303 | /** 304 | * @brief hook外部函数 305 | * hook function by .got.plt 306 | * @param elf_name elf file name 307 | * @param symbol symbol name 308 | * @param hookfile hook function file 309 | * @param hook_offset hook function offset in hook file 310 | * @return int error code {-1:error,0:sucess} 311 | */ 312 | int hook_extern(char *elf_name, char *symbol, char *hookfile, uint64_t hook_offset); 313 | 314 | /** 315 | * @brief 增加一个.dynsym table条目 316 | * add a dynamic symbol stable item 317 | * @param elf_name elf file name 318 | * @param name dynamic symbol name 319 | * @param value dynamic symbol address 320 | * @param code_size func size 321 | * @return int error code {-1:error,0:sucess} 322 | */ 323 | int add_dynsym_entry(char *elf_name, char *name, uint64_t value, size_t code_size); 324 | 325 | /** 326 | * @brief 调整字符串表中的字符串顺序 327 | * adjust the string order in the string table 328 | * @param elf_name elf file name 329 | * @param strtab string table name 330 | * @return int error code {-1:error,0:sucess} 331 | */ 332 | int confuse_symbol(char *elf_name, char *strtab); -------------------------------------------------------------------------------- /src/delete.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "common.h" 33 | #include "section.h" 34 | 35 | /** 36 | * @description: delete data from ELF memory 37 | * @param {char} *elf_map 38 | * @param {uint32_t} file_size 39 | * @param {uint32_t} offset data offset in elf 40 | * @param {uint32_t} data_size data size 41 | * @return {*} 42 | */ 43 | char *delete_data_from_mem(char *elf_map, uint32_t file_size, uint32_t offset, uint32_t data_size) { 44 | char *tmp; 45 | tmp = malloc(file_size - data_size); 46 | if (tmp < 0) { 47 | return NULL; 48 | } 49 | 50 | memcpy(tmp, elf_map, offset); 51 | memcpy(&tmp[offset], &elf_map[offset + data_size], file_size - data_size - offset); 52 | return tmp; 53 | } 54 | 55 | /** 56 | * @brief 从文件中删除特定片段,请注意这个操作会改变文件大小 57 | * Delete specific fragments from the file, 58 | * please note that this operation will change the file size 59 | * @param file_name file name 60 | * @param offset fragment offset 61 | * @param size fragment size 62 | * @return int error code {-1:error,0:sucess} 63 | */ 64 | char *delete_data_from_file(char *file_name, uint64_t offset, size_t size) { 65 | FILE *file = fopen(file_name, "r+b"); 66 | 67 | if (!file) { 68 | fprintf(stderr, "Error opening file\n"); 69 | return; 70 | } 71 | 72 | // 移动文件指针到删除位置 73 | if (fseek(file, offset + size, SEEK_SET) != 0) { 74 | fprintf(stderr, "Error seeking in file\n"); 75 | fclose(file); 76 | return; 77 | } 78 | 79 | // 读取后续数据位置 80 | long int file_size; 81 | fseek(file, 0, SEEK_END); 82 | file_size = ftell(file); 83 | 84 | // 申请缓冲区,用于存储后续数据 85 | char *buffer = (char *)malloc(file_size - (offset + size)); 86 | if (!buffer) { 87 | fprintf(stderr, "Error allocating memory\n"); 88 | fclose(file); 89 | return; 90 | } 91 | 92 | // 移动文件指针到后续数据位置 93 | if (fseek(file, offset + size, SEEK_SET) != 0) { 94 | fprintf(stderr, "Error seeking in file\n"); 95 | free(buffer); 96 | fclose(file); 97 | return; 98 | } 99 | 100 | // 读取后续数据 101 | fread(buffer, 1, file_size - (offset + size), file); 102 | 103 | // 移动文件指针回到删除位置 104 | fseek(file, offset, SEEK_SET); 105 | 106 | // 写入后续数据 107 | fwrite(buffer, 1, file_size - (offset + size), file); 108 | 109 | // 截断文件,删除多余数据 110 | ftruncate(fileno(file), file_size - size); 111 | 112 | free(buffer); 113 | fclose(file); 114 | } 115 | 116 | int clear_section_imp(char *elf_name, char *section_name, int is_rename) { 117 | int fd; 118 | struct stat st; 119 | uint8_t *elf_map; 120 | uint8_t *elf_map_new; 121 | uint8_t *tmp_sec_name; 122 | 123 | fd = open(elf_name, O_RDONLY); 124 | if (fd < 0) { 125 | perror("open"); 126 | return -1; 127 | } 128 | 129 | if (fstat(fd, &st) < 0) { 130 | perror("fstat"); 131 | return -1; 132 | } 133 | 134 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 135 | if (elf_map == MAP_FAILED) { 136 | perror("mmap"); 137 | return -1; 138 | } 139 | 140 | /* 32bit */ 141 | if (MODE == ELFCLASS32) { 142 | Elf32_Ehdr *ehdr; 143 | Elf32_Shdr *shdr; 144 | Elf32_Phdr *phdr; 145 | Elf32_Shdr shstrtab; 146 | 147 | ehdr = (Elf32_Ehdr *)elf_map; 148 | shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff]; 149 | shstrtab = shdr[ehdr->e_shstrndx]; 150 | 151 | for (int i = 0; i < ehdr->e_shnum; i++) { 152 | tmp_sec_name = elf_map + shstrtab.sh_offset + shdr[i].sh_name; 153 | if (!strcmp(section_name, tmp_sec_name)) { 154 | /* clean section */ 155 | memset(elf_map + shdr[i].sh_offset, 0, shdr[i].sh_size); 156 | 157 | /* clean shstrtab */ 158 | memset(tmp_sec_name, 0, strlen(tmp_sec_name)); 159 | 160 | /* modify section header table number */ 161 | ehdr->e_shnum--; 162 | 163 | /* modify section header string table index */ 164 | if (i < ehdr->e_shstrndx) { 165 | ehdr->e_shstrndx--; 166 | } else { 167 | WARNING("Delete section header string table will result in a section header resolution error\n"); 168 | ehdr->e_shstrndx = 0; 169 | } 170 | 171 | /* delete section header table */ 172 | elf_map_new = delete_data_from_mem(elf_map, st.st_size, ehdr->e_shoff + i * sizeof(Elf32_Shdr), sizeof(Elf32_Shdr)); 173 | if (elf_map_new == NULL) { 174 | WARNING("delete section header table error\n"); 175 | munmap(elf_map, st.st_size); 176 | close(fd); 177 | return -1; 178 | } 179 | 180 | break; 181 | } 182 | } 183 | 184 | close(fd); 185 | create_file(elf_name, elf_map_new, st.st_size - sizeof(Elf32_Shdr), is_rename); 186 | } 187 | 188 | /* 64bit */ 189 | if (MODE == ELFCLASS64) { 190 | Elf64_Ehdr *ehdr; 191 | Elf64_Shdr *shdr; 192 | Elf64_Phdr *phdr; 193 | Elf64_Shdr shstrtab; 194 | 195 | ehdr = (Elf64_Ehdr *)elf_map; 196 | shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff]; 197 | shstrtab = shdr[ehdr->e_shstrndx]; 198 | 199 | for (int i = 0; i < ehdr->e_shnum; i++) { 200 | tmp_sec_name = elf_map + shstrtab.sh_offset + shdr[i].sh_name; 201 | if (!strcmp(section_name, tmp_sec_name)) { 202 | /* clean section */ 203 | memset(elf_map + shdr[i].sh_offset, 0, shdr[i].sh_size); 204 | 205 | /* clean shstrtab */ 206 | memset(tmp_sec_name, 0, strlen(tmp_sec_name)); 207 | 208 | /* modify section header table number */ 209 | ehdr->e_shnum--; 210 | 211 | /* modify section header string table index */ 212 | if (i < ehdr->e_shstrndx) { 213 | ehdr->e_shstrndx--; 214 | } else { 215 | WARNING("Delete section header string table will result in a section header resolution error\n"); 216 | ehdr->e_shstrndx = 0; 217 | } 218 | 219 | /* delete section header table */ 220 | elf_map_new = delete_data_from_mem(elf_map, st.st_size, ehdr->e_shoff + i * sizeof(Elf64_Shdr), sizeof(Elf64_Shdr)); 221 | if (elf_map_new == NULL) { 222 | WARNING("delete section header table error\n"); 223 | munmap(elf_map, st.st_size); 224 | close(fd); 225 | return -1; 226 | } 227 | 228 | break; 229 | } 230 | } 231 | 232 | close(fd); 233 | create_file(elf_name, elf_map_new, st.st_size - sizeof(Elf64_Shdr), is_rename); 234 | } 235 | 236 | free(elf_map_new); 237 | munmap(elf_map, st.st_size); 238 | 239 | return 0; 240 | } 241 | 242 | /** 243 | * @brief 清理节的内容,但是并没有改变节的大小 244 | * clean up the content of the section, but do not change the size of the section 245 | * @param elf_name elf file name 246 | * @param section_name section name 247 | * @param config_name multi section name 248 | * @return int error code {-1:error,0:sucess} 249 | */ 250 | int clear_section(char *elf_name, char *section_name, char *config_name) { 251 | FILE *fp; 252 | int count = 0; 253 | char tmp_sec_name[LENGTH]; 254 | char new_file[LENGTH]; 255 | snprintf(new_file, LENGTH, "%s.new", elf_name); 256 | 257 | if (strlen(config_name) == 0) { 258 | printf("delete %s\n", tmp_sec_name); 259 | clear_section_imp(elf_name, section_name, 1); 260 | return 0; 261 | } 262 | 263 | fp = fopen(config_name, "r"); 264 | if (fp <= 0) { 265 | perror("fopen"); 266 | return -1; 267 | } 268 | 269 | while (!feof(fp)) { 270 | fgets(tmp_sec_name, LENGTH, fp); 271 | if ( tmp_sec_name[strlen(tmp_sec_name) - 1] == '\n') 272 | tmp_sec_name[strlen(tmp_sec_name) - 1] = '\0'; /* delete \n */ 273 | printf("delete %s\n", tmp_sec_name); 274 | 275 | if (!count) 276 | clear_section_imp(elf_name, tmp_sec_name, 1); 277 | else { 278 | clear_section_imp(new_file, tmp_sec_name, 0); 279 | } 280 | count++; 281 | } 282 | fclose(fp); 283 | } 284 | 285 | /** 286 | * @brief 删除节头表 287 | * delelet section header table 288 | * @param elf_name elf file name 289 | * @return int error code {-1:error,0:sucess} 290 | */ 291 | int delete_shtab(char *elf_name) { 292 | int fd; 293 | struct stat st; 294 | uint8_t *elf_map; 295 | uint8_t *elf_map_new; 296 | uint32_t shtab_size; 297 | 298 | fd = open(elf_name, O_RDONLY); 299 | if (fd < 0) { 300 | perror("open"); 301 | return -1; 302 | } 303 | 304 | if (fstat(fd, &st) < 0) { 305 | perror("fstat"); 306 | return -1; 307 | } 308 | 309 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 310 | if (elf_map == MAP_FAILED) { 311 | perror("mmap"); 312 | return -1; 313 | } 314 | 315 | /* 32bit */ 316 | if (MODE == ELFCLASS32) { 317 | Elf32_Ehdr *ehdr; 318 | ehdr = (Elf32_Ehdr *)elf_map; 319 | shtab_size = ehdr->e_shnum * sizeof(Elf32_Shdr); 320 | elf_map_new = delete_data_from_mem(elf_map, st.st_size, ehdr->e_shoff, shtab_size); 321 | ehdr = (Elf32_Ehdr *)elf_map_new; 322 | ehdr->e_shnum = 0; 323 | ehdr->e_shoff = 0; 324 | ehdr->e_shentsize = 0; 325 | create_file(elf_name, elf_map_new, st.st_size - shtab_size, 1); 326 | } 327 | 328 | /* 64bit */ 329 | if (MODE == ELFCLASS64) { 330 | Elf64_Ehdr *ehdr; 331 | ehdr = (Elf64_Ehdr *)elf_map; 332 | shtab_size = ehdr->e_shnum * sizeof(Elf64_Shdr); 333 | elf_map_new = delete_data_from_mem(elf_map, st.st_size, ehdr->e_shoff, shtab_size); 334 | ehdr = (Elf64_Ehdr *)elf_map_new; 335 | ehdr->e_shnum = 0; 336 | ehdr->e_shoff = 0; 337 | ehdr->e_shentsize = 0; 338 | create_file(elf_name, elf_map_new, st.st_size - shtab_size, 1); 339 | } 340 | 341 | free(elf_map_new); 342 | munmap(elf_map, st.st_size); 343 | close(fd); 344 | return 0; 345 | } 346 | 347 | /** 348 | * @brief 删除以下三个不必要的节 349 | * delelet .comment .symtab .strtab section 350 | * @param elf_name elf file name 351 | * @return int error code {-1:error,0:sucess} 352 | */ 353 | int strip(char *elf_name) { 354 | uint64_t data_offset = get_section_offset(elf_name, ".comment"); 355 | uint64_t shstrtab_offset = get_section_offset(elf_name, ".shstrtab"); 356 | size_t shstrtab_size = get_section_size(elf_name, ".shstrtab"); 357 | DEBUG("start offset: 0x%x, end offset: 0x%x, shstrtab size: 0x%x\n", data_offset, shstrtab_offset, shstrtab_size); 358 | if (!data_offset || !shstrtab_offset) { 359 | WARNING("no .comment or .symtab\n"); 360 | return -1; 361 | } 362 | 363 | // 1. set .shstrtab offset 364 | int idx = get_section_index(elf_name, ".shstrtab"); 365 | DEBUG("shstrtab index: %d(0x%x)\n", idx, idx); 366 | set_section_off(elf_name, idx, data_offset); 367 | // 2. set shdr offset 368 | set_header_shoff(elf_name, data_offset + shstrtab_size); 369 | // 3. delete .comment .symtab .strtab 370 | int ret = delete_data_from_file(elf_name, data_offset, shstrtab_offset - data_offset); 371 | if (ret < 0) { 372 | ERROR("delete data error\n"); 373 | return -1; 374 | } 375 | 376 | // 4. delete shdr entry .comment .symtab .strtab 377 | if (MODE == ELFCLASS32) 378 | ret = delete_data_from_file(elf_name, data_offset + shstrtab_size + (idx - 3) * sizeof(Elf32_Shdr), 3 * sizeof(Elf32_Shdr)); 379 | if (MODE == ELFCLASS64) 380 | ret = delete_data_from_file(elf_name, data_offset + shstrtab_size + (idx - 3) * sizeof(Elf64_Shdr), 3 * sizeof(Elf64_Shdr)); 381 | if (ret < 0) { 382 | ERROR("delete data error\n"); 383 | return -1; 384 | } 385 | set_header_shstrndx(elf_name, idx - 3); 386 | set_header_shnum(elf_name, idx - 2); // should num - 3 387 | return 0; 388 | } -------------------------------------------------------------------------------- /src/delete.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @description: delete data from ELF memory 27 | * @param {char} *elf_map 28 | * @param {uint32_t} file_size 29 | * @param {uint32_t} offset data offset in elf 30 | * @param {uint32_t} data_size data size 31 | * @return {*} 32 | */ 33 | char *delete_data_from_mem(char *elf_map, uint32_t file_size, uint32_t offset, uint32_t data_size); 34 | 35 | /** 36 | * @brief 从文件中删除特定片段,请注意这个操作会改变文件大小 37 | * Delete specific fragments from the file, 38 | * please note that this operation will change the file size 39 | * @param file_name file name 40 | * @param offset fragment offset 41 | * @param size fragment size 42 | * @return int error code {-1:error,0:sucess} 43 | */ 44 | char *delete_data_from_file(char *file_name, uint64_t offset, size_t size); 45 | 46 | /** 47 | * @brief 清理节的内容,但是并没有改变节的大小 48 | * clean up the content of the section, but do not change the size of the section 49 | * @param elf_name elf file name 50 | * @param section_name section name 51 | * @param config_name multi section name 52 | * @return int error code {-1:error,0:sucess} 53 | */ 54 | int clear_section(char *elf_name, char *section_name, char *config_name); 55 | 56 | /** 57 | * @brief 删除节头表 58 | * delelet section header table 59 | * @param elf_name elf file name 60 | * @return int error code {-1:error,0:sucess} 61 | */ 62 | int delete_shtab(char *elf); -------------------------------------------------------------------------------- /src/edit.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @brief Set the section name 27 | * 28 | * @param elf_name elf file name 29 | * @param value 30 | * @return error code {-1:error,0:sucess} 31 | */ 32 | int set_header_type(char *elf_name, int value); 33 | int set_header_machine(char *elf_name, int value); 34 | int set_header_version(char *elf_name, int value); 35 | int set_header_entry(char *elf_name, int value); 36 | int set_header_phoff(char *elf_name, int value); 37 | int set_header_shoff(char *elf_name, int value); 38 | int set_header_flags(char *elf_name, int value); 39 | int set_header_ehsize(char *elf_name, int value); 40 | int set_header_phentsize(char *elf_name, int value); 41 | int set_header_phnum(char *elf_name, int value); 42 | int set_header_shentsize(char *elf_name, int value); 43 | int set_header_shnum(char *elf_name, int value); 44 | int set_header_shstrndx(char *elf_name, int value); 45 | 46 | /** 47 | * @brief Set the section name 48 | * 49 | * @param elf_name elf file name 50 | * @param index readelf section row 51 | * @param value 52 | * @return error code {-1:error,0:sucess} 53 | */ 54 | int set_section_name(char *elf_name, int index, int value); 55 | int set_section_type(char *elf_name, int index, int value); 56 | int set_section_flags(char *elf_name, int index, int value); 57 | int set_section_addr(char *elf_name, int index, int value); 58 | int set_section_off(char *elf_name, int index, int value); 59 | int set_section_size(char *elf_name, int index, int value); 60 | int set_section_link(char *elf_name, int index, int value); 61 | int set_section_info(char *elf_name, int index, int value); 62 | int set_section_align(char *elf_name, int index, int value); 63 | int set_section_entsize(char *elf_name, int index, int value); 64 | 65 | int set_section_name_by_str(char *elf_name, int index, char *value); 66 | 67 | /** 68 | * @brief Set the segment type 69 | * 70 | * @param elf_name elf file name 71 | * @param index readelf segment row 72 | * @param value 73 | * @return error code {-1:error,0:sucess} 74 | */ 75 | int set_segment_type(char *elf_name, int index, int value); 76 | int set_segment_flags(char *elf_name, int index, int value); 77 | int set_segment_offset(char *elf_name, int index, int value); 78 | int set_segment_vaddr(char *elf_name, int index, int value); 79 | int set_segment_paddr(char *elf_name, int index, int value); 80 | int set_segment_filesz(char *elf_name, int index, int value); 81 | int set_segment_memsz(char *elf_name, int index, int value); 82 | int set_segment_align(char *elf_name, int index, int value); 83 | 84 | /** 85 | * @brief Set the dynsym or symtab object 86 | * 87 | * @param elf_name elf file name 88 | * @param index readelf .dynsym row 89 | * @param value value to be edited 90 | * @param section_name .dynsym or .symtab 91 | * @return error code {-1:error,0:sucess} 92 | */ 93 | int set_sym_name(char *elf_name, int index, int value, char *section_name); 94 | int set_sym_value(char *elf_name, int index, int value, char *section_name); 95 | int set_sym_size(char *elf_name, int index, int value, char *section_name); 96 | int set_sym_type(char *elf_name, int index, int value, char *section_name); 97 | int set_sym_bind(char *elf_name, int index, int value, char *section_name); 98 | int set_sym_other(char *elf_name, int index, int value, char *section_name); 99 | int set_sym_shndx(char *elf_name, int index, int value, char *section_name); 100 | 101 | /** 102 | * @brief Set the .rela section offset 103 | * 104 | * @param elf_name elf file name 105 | * @param index readelf section row 106 | * @param value 107 | * @return error code {-1:error,0:sucess} 108 | */ 109 | int set_rela_offset(char *elf_name, int index, int value, char *section_name); 110 | int set_rela_info(char *elf_name, int index, int value, char *section_name); 111 | int set_rela_type(char *elf_name, int index, int value, char *section_name); 112 | int set_rela_index(char *elf_name, int index, int value, char *section_name); 113 | int set_rela_addend(char *elf_name, int index, int value, char *section_name); 114 | /* .rel.* */ 115 | int set_rel_offset(char *elf_name, int index, int value, char *section_name); 116 | int set_rel_info(char *elf_name, int index, int value, char *section_name); 117 | int set_rel_type(char *elf_name, int index, int value, char *section_name); 118 | int set_rel_index(char *elf_name, int index, int value, char *section_name); 119 | 120 | /** 121 | * @brief Set the .dynamic section offset 122 | * 123 | * @param elf_name elf file name 124 | * @param index readelf section row 125 | * @param value 126 | * @return error code {-1:error,0:sucess} 127 | */ 128 | int set_dyn_tag(char *elf_name, int index, int value); 129 | int set_dyn_value(char *elf_name, int index, int value); 130 | 131 | /** 132 | * @brief Set the dynsym name by str object 133 | * 134 | * @param elf_name elf file name 135 | * @param index elf file name 136 | * @param name string value to be edited 137 | * @param section_name .dynsym or .symtab 138 | * @param str_section_name .dynstr or .strtab 139 | * @return int 140 | */ 141 | int edit_sym_name_string(char *elf_name, int index, char *name, char *section_name, char *str_section_name); 142 | int edit_dyn_name_value(char *elf_name, int index, char *name); 143 | 144 | /** 145 | * @brief 编辑某些节存储的指针 146 | * edit pointers stored in certain sections 147 | * @param elf_name elf file name 148 | * @param index item index 149 | * @param value new pointer 150 | * @param section_name section name, such as .init_array. 151 | * @return int error code {-1:error,0:sucess} 152 | */ 153 | int edit_pointer_value(char *elf_name, int index, uint64_t value, char *section_name); 154 | 155 | int edit(char *elf, parser_opt_t *po, int row, int column, int value, char *section_name, char *file_name); -------------------------------------------------------------------------------- /src/forensic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "common.h" 10 | #include "section.h" 11 | 12 | enum ELF_TYPE { 13 | ELF_STATIC, 14 | ELF_EXE_NOW, 15 | ELF_EXE_LAZY, 16 | ELF_SHARED 17 | }; 18 | 19 | /** 20 | * @brief elf类型 21 | * get elf type 22 | * @param h32 elf file handle struct 23 | * @param h64 elf file handle struct 24 | * @return int error code {-1:error,elf type} 25 | */ 26 | int get_elf_type(handle_t32 *h32, handle_t64 *h64) { 27 | int has_dynamic = 0; 28 | if (MODE == ELFCLASS32) { 29 | Elf32_Dyn *dyn = NULL; 30 | uint32_t dyn_c; 31 | for (int i = 0; i < h32->ehdr->e_phnum; i++) { 32 | if (h32->phdr[i].p_type == PT_DYNAMIC) { 33 | has_dynamic = 1; 34 | dyn = h32->mem + h32->phdr[i].p_offset; 35 | dyn_c = h32->phdr[i].p_filesz / sizeof(Elf32_Dyn); 36 | break; 37 | } 38 | } 39 | if (!has_dynamic && h32->ehdr->e_type == ET_EXEC) { 40 | return ELF_STATIC; 41 | } 42 | else if (has_dynamic && h32->ehdr->e_type == ET_DYN) { 43 | for (int i = 0; i < dyn_c; i++) { 44 | if (dyn[i].d_tag == DT_FLAGS_1) { 45 | if (has_flag(dyn[i].d_un.d_val, DF_1_NOW)) 46 | return ELF_EXE_NOW; 47 | else 48 | return ELF_EXE_LAZY; 49 | break; 50 | } 51 | } 52 | return ELF_SHARED; 53 | } 54 | } 55 | if (MODE == ELFCLASS64) { 56 | Elf64_Dyn *dyn = NULL; 57 | uint64_t dyn_c; 58 | for (int i = 0; i < h64->ehdr->e_phnum; i++) { 59 | if (h64->phdr[i].p_type == PT_DYNAMIC) { 60 | has_dynamic = 1; 61 | dyn = h64->mem + h64->phdr[i].p_offset; 62 | dyn_c = h64->phdr[i].p_filesz / sizeof(Elf64_Dyn); 63 | break; 64 | } 65 | } 66 | if (!has_dynamic && h64->ehdr->e_type == ET_EXEC) { 67 | return ELF_STATIC; 68 | } 69 | else if (has_dynamic && h64->ehdr->e_type == ET_DYN) { 70 | for (int i = 0; i < dyn_c; i++) { 71 | if (dyn[i].d_tag == DT_FLAGS_1) { 72 | if (has_flag(dyn[i].d_un.d_val, DF_1_NOW)) 73 | return ELF_EXE_NOW; 74 | else 75 | return ELF_EXE_LAZY; 76 | break; 77 | } 78 | } 79 | return ELF_SHARED; 80 | } 81 | } 82 | return -1; 83 | } 84 | 85 | /** 86 | * @brief 检查hook外部函数 87 | * chekc hook function by .got.plt 88 | * @param h32 elf file handle struct 89 | * @param h64 elf file handle struct 90 | * @param start start address 91 | * @param size area size 92 | * @return int error code {-1:error,0:sucess,1:failed} 93 | */ 94 | int check_hook(handle_t32 *h32, handle_t64 *h64, uint64_t start, size_t size) { 95 | uint64_t offset = 0; 96 | 97 | /* attention: The 32-bit program has not been tested! */ 98 | if (MODE == ELFCLASS32) { 99 | h32->sec_size = sizeof(Elf32_Rel); // init 100 | for (int i = 0; i < h32->sec_size / sizeof(Elf32_Rel); i++) { 101 | offset = get_rel32_offset(h32, ".rel.plt", i); 102 | if (offset == -1) { 103 | return -1; 104 | } 105 | uint32_t *p = (uint32_t *)(h32->mem + offset); 106 | DEBUG("0x%x, 0x%x\n", offset, *p); 107 | if (*p < start || *p >= start + size) { 108 | return 1; 109 | } 110 | } 111 | } 112 | 113 | if (MODE == ELFCLASS64) { 114 | h64->sec_size = sizeof(Elf64_Rela); // init 115 | for (int i = 0; i < h64->sec_size / sizeof(Elf64_Rela); i++) { 116 | offset = get_rela64_offset(h64, ".rela.plt", i); 117 | if (offset == -1) { 118 | return -1; 119 | } 120 | uint64_t *p = (uint64_t *)(h64->mem + offset); 121 | DEBUG("0x%x, 0x%x\n", offset, *p); 122 | if (*p < start || *p >= start + size) { 123 | return 1; 124 | } 125 | } 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | /** 132 | * @brief 检查load 133 | * chekc load segment flags 134 | * @param h32 elf file handle struct 135 | * @param h64 elf file handle struct 136 | * @return int error code {-1:error,0:sucess,1:failed} 137 | */ 138 | int check_load_flags(handle_t32 *h32, handle_t64 *h64) { 139 | int count = 0; 140 | 141 | if (MODE == ELFCLASS32) { 142 | for (int i = 0; i < h32->ehdr->e_phnum; i++) { 143 | if (h32->phdr[i].p_type == PT_LOAD) { 144 | // flags:E 145 | if (h32->phdr[i].p_flags & 0x1) { 146 | count++; 147 | } 148 | } 149 | } 150 | } 151 | 152 | if (MODE == ELFCLASS64) { 153 | for (int i = 0; i < h64->ehdr->e_phnum; i++) { 154 | if (h64->phdr[i].p_type == PT_LOAD) { 155 | // flags:E 156 | if (h64->phdr[i].p_flags & 0x1) { 157 | count++; 158 | } 159 | } 160 | } 161 | } 162 | 163 | DEBUG("executable segment count: %d\n", count); 164 | if (count > 1) { 165 | return 1; 166 | } else if (count == 1) { 167 | return 0; 168 | } else if (count == 0) { 169 | return -1; 170 | } 171 | } 172 | 173 | /** 174 | * @brief 检查段是否连续 175 | * check if the load segments are continuous 176 | * @param h32 elf file handle struct 177 | * @param h64 elf file handle struct 178 | * @return int error code {-1:error,0:sucess,1:failed} 179 | */ 180 | int check_load_continuity(handle_t32 *h32, handle_t64 *h64) { 181 | int last = 0; 182 | int current = 0; 183 | int has_first = 0; 184 | 185 | if (MODE == ELFCLASS32) { 186 | for (int i = 0; i < h32->ehdr->e_phnum; i++) { 187 | if (h32->phdr[i].p_type == PT_LOAD) { 188 | if (!has_first) { 189 | has_first = 1; 190 | last = i; 191 | continue; 192 | } 193 | 194 | current = i; 195 | if (current - last != 1) { 196 | return 1; 197 | } 198 | last = i; 199 | } 200 | } 201 | } 202 | 203 | if (MODE == ELFCLASS64) { 204 | for (int i = 0; i < h64->ehdr->e_phnum; i++) { 205 | if (h64->phdr[i].p_type == PT_LOAD) { 206 | if (!has_first) { 207 | has_first = 1; 208 | last = i; 209 | continue; 210 | } 211 | 212 | current = i; 213 | if (current - last != 1) { 214 | return 1; 215 | } 216 | last = i; 217 | } 218 | } 219 | } 220 | 221 | return 0; 222 | } 223 | 224 | /** 225 | * @brief 检查DT_NEEDED是否连续 226 | * check if the DT_NEEDED so are continuous 227 | * @param h32 elf file handle struct 228 | * @param h64 elf file handle struct 229 | * @return int error code {-1:error,0:sucess,1:failed} 230 | */ 231 | int check_needed_continuity(handle_t32 *h32, handle_t64 *h64) { 232 | int last = 0; 233 | int current = 0; 234 | int has_first = 0; 235 | int ret = 0; 236 | 237 | if (MODE == ELFCLASS32) { 238 | Elf32_Dyn *dyn = NULL; 239 | uint32_t dyn_c; 240 | for (int i = 0; i < h32->ehdr->e_phnum; i++) { 241 | if (h32->phdr[i].p_type == PT_DYNAMIC) { 242 | dyn = h32->mem + h32->phdr[i].p_offset; 243 | dyn_c = h32->phdr[i].p_filesz / sizeof(Elf32_Dyn); 244 | break; 245 | } 246 | } 247 | if (!dyn) ret = -1; 248 | else { 249 | for (int i = 0; i < dyn_c; i++) { 250 | if (dyn[i].d_tag == DT_NEEDED) { 251 | if (!has_first) { 252 | has_first = 1; 253 | last = i; 254 | continue; 255 | } 256 | 257 | current = i; 258 | if (current - last != 1) { 259 | ret = 1; 260 | break; 261 | } 262 | last = i; 263 | } 264 | } 265 | } 266 | } 267 | 268 | if (MODE == ELFCLASS64) { 269 | Elf64_Dyn *dyn = NULL; 270 | uint64_t dyn_c; 271 | for (int i = 0; i < h64->ehdr->e_phnum; i++) { 272 | if (h64->phdr[i].p_type == PT_DYNAMIC) { 273 | dyn = h64->mem + h64->phdr[i].p_offset; 274 | dyn_c = h64->phdr[i].p_filesz / sizeof(Elf64_Dyn); 275 | break; 276 | } 277 | } 278 | if (!dyn) ret = -1; 279 | else { 280 | for (int i = 0; i < dyn_c; i++) { 281 | if (dyn[i].d_tag == DT_NEEDED) { 282 | if (!has_first) { 283 | has_first = 1; 284 | last = i; 285 | continue; 286 | } 287 | 288 | current = i; 289 | if (current - last != 1) { 290 | ret = 1; 291 | break; 292 | } 293 | last = i; 294 | } 295 | } 296 | } 297 | } 298 | 299 | return ret; 300 | } 301 | 302 | /** 303 | * @brief 检查节头表是否存在 304 | * check if the section header table exists 305 | * @param h32 elf file handle struct 306 | * @param h64 elf file handle struct 307 | * @return int error code {-1:error,0:sucess,1:failed,2:warn} 308 | */ 309 | int check_shdr(handle_t32 *h32, handle_t64 *h64) { 310 | int ret = 0; 311 | 312 | if (MODE == ELFCLASS32) { 313 | if (h32->ehdr->e_shoff == 0 || h32->ehdr->e_shnum == 0) { 314 | ret = 1; 315 | } else if (h32->ehdr->e_shoff != h32->size - sizeof(Elf32_Shdr) * h32->ehdr->e_shnum) { 316 | ret = 2; 317 | } 318 | } 319 | 320 | if (MODE == ELFCLASS64) { 321 | if (h64->ehdr->e_shoff == 0 || h64->ehdr->e_shnum == 0) { 322 | ret = 1; 323 | } else if (h64->ehdr->e_shoff != h64->size - sizeof(Elf64_Shdr) * h64->ehdr->e_shnum) { 324 | ret = 2; 325 | } 326 | } 327 | 328 | return ret; 329 | } 330 | 331 | /** 332 | * @brief 检查dynstr是否连续以及字符串是否存在空格 333 | * check if the dynstr segments are continuous and whether there are extra spaces in the string 334 | * @param h32 elf file handle struct 335 | * @param h64 elf file handle struct 336 | * @return int error code {-1:error,0:sucess,1:failed} 337 | */ 338 | int check_dynstr(handle_t32 *h32, handle_t64 *h64) { 339 | char *name; 340 | int ret = 0; 341 | int dynsym_i = 0, dynstr_i = 0; 342 | char *tmp; 343 | size_t tmp_size = 1; 344 | if (MODE == ELFCLASS32) { 345 | for (int i = 0; i < h32->ehdr->e_shnum; i++) { 346 | name = h32->mem + h32->shstrtab->sh_offset + h32->shdr[i].sh_name; 347 | if (validated_offset(name, h32->mem, h32->mem + h32->size)) { 348 | ERROR("Corrupt file format\n"); 349 | ret = -1; 350 | } 351 | if (!strcmp(name, ".dynsym")) dynsym_i = i; 352 | if (!strcmp(name, ".dynstr")) dynstr_i = i; 353 | } 354 | /* check if the dynstr segments are continuous */ 355 | if (h32->shdr[dynsym_i].sh_offset + h32->shdr[dynsym_i].sh_size != h32->shdr[dynstr_i].sh_offset) 356 | ret = 1; 357 | /* check if the string length is less than original one */ 358 | tmp = h32->mem + h32->shdr[dynstr_i].sh_offset + 1; 359 | while (tmp_size < h32->shdr[dynstr_i].sh_size) { 360 | tmp_size += strlen(tmp) + 1; 361 | DEBUG("%s 0x%x\n", tmp, tmp_size); 362 | tmp += strlen(tmp) + 1; 363 | if (tmp_size != h32->shdr[dynstr_i].sh_size && strlen(tmp) == 0) { 364 | ret = 1; 365 | break; 366 | } 367 | } 368 | } 369 | else if (MODE == ELFCLASS64) { 370 | for (int i = 0; i < h64->ehdr->e_shnum; i++) { 371 | name = h64->mem + h64->shstrtab->sh_offset + h64->shdr[i].sh_name; 372 | if (validated_offset(name, h64->mem, h64->mem + h64->size)) { 373 | ERROR("Corrupt file format\n"); 374 | ret = -1; 375 | } 376 | if (!strcmp(name, ".dynsym")) dynsym_i = i; 377 | if (!strcmp(name, ".dynstr")) dynstr_i = i; 378 | } 379 | /* check if the dynstr segments are continuous */ 380 | if (h64->shdr[dynsym_i].sh_offset + h64->shdr[dynsym_i].sh_size != h64->shdr[dynstr_i].sh_offset) 381 | ret = 1; 382 | /* check if the string length is less than original one */ 383 | tmp = h64->mem + h64->shdr[dynstr_i].sh_offset + 1; 384 | while (tmp_size < h64->shdr[dynstr_i].sh_size) { 385 | tmp_size += strlen(tmp) + 1; 386 | DEBUG("%s 0x%x\n", tmp, tmp_size); 387 | tmp += strlen(tmp) + 1; 388 | if (tmp_size != h64->shdr[dynstr_i].sh_size && strlen(tmp) == 0) { 389 | ret = 1; 390 | break; 391 | } 392 | } 393 | } 394 | 395 | return ret; 396 | } 397 | 398 | /** 399 | * @brief 检查interpreter 400 | * check if the interpreter is legal 401 | * @param h32 elf file handle struct 402 | * @param h64 elf file handle struct 403 | * @return int error code {-1:error,0:sucess,1:failed} 404 | */ 405 | int check_interpreter(handle_t32 *h32, handle_t64 *h64) { 406 | char *name; 407 | int ret = 0; 408 | int interp_i = -1; 409 | char *tmp; 410 | size_t tmp_size = 1; 411 | if (MODE == ELFCLASS32) { 412 | for (int i = 0; i < h32->ehdr->e_shnum; i++) { 413 | name = h32->mem + h32->shstrtab->sh_offset + h32->shdr[i].sh_name; 414 | if (validated_offset(name, h32->mem, h32->mem + h32->size)) { 415 | ERROR("Corrupt file format\n"); 416 | ret = -1; 417 | } 418 | if (!strcmp(name, ".interp")) interp_i = i; 419 | } 420 | name = h32->mem + h32->shdr[interp_i].sh_offset; 421 | /* check index */ 422 | if (interp_i == -1) { 423 | ret = -1; 424 | } 425 | else if (interp_i > 2) { 426 | ret = 1; 427 | } 428 | /* check if the string length is less than original one */ 429 | else if (strlen(name) != h32->shdr[interp_i].sh_size - 1) { 430 | ret = 1; 431 | } 432 | } 433 | else if (MODE == ELFCLASS64) { 434 | for (int i = 0; i < h64->ehdr->e_shnum; i++) { 435 | name = h64->mem + h64->shstrtab->sh_offset + h64->shdr[i].sh_name; 436 | if (validated_offset(name, h64->mem, h64->mem + h64->size)) { 437 | ERROR("Corrupt file format\n"); 438 | ret = -1; 439 | } 440 | if (!strcmp(name, ".interp")) interp_i = i; 441 | } 442 | name = h64->mem + h64->shdr[interp_i].sh_offset; 443 | /* check index */ 444 | if (interp_i == -1) { 445 | ret = -1; 446 | } 447 | else if (interp_i > 2) { 448 | ret = 1; 449 | } 450 | /* check if the string length is less than original one */ 451 | else if (strlen(name) != h64->shdr[interp_i].sh_size - 1) { 452 | ret = 1; 453 | } 454 | } 455 | 456 | return ret; 457 | } 458 | 459 | /** 460 | * @brief 检查elf文件是否合法 461 | * check if the elf file is legal 462 | * @param elf_name elf file name 463 | * @return int error code {-1:error,0:sucess} 464 | */ 465 | int checksec(char *elf_name) { 466 | handle_t32 h32; 467 | handle_t64 h64; 468 | int ret = init_elf(elf_name, &h32, &h64); 469 | if (ret) { 470 | ERROR("init elf error\n"); 471 | return -1; 472 | } 473 | 474 | char *mode, *tmp, *bind; 475 | char elf_info[1000]; 476 | enum ELF_TYPE type; 477 | type = get_elf_type(&h32, &h64); 478 | if (MODE == ELFCLASS32) { 479 | mode = "32-bit"; 480 | } else if (MODE == ELFCLASS64) { 481 | mode = "64-bit"; 482 | } 483 | if (type == ELF_EXE_LAZY) { 484 | bind = "bind lazy"; 485 | tmp = "pie executable"; 486 | } else if (type == ELF_EXE_NOW) { 487 | bind = "bind now"; 488 | tmp = "pie executable"; 489 | } else if (type == ELF_SHARED) { 490 | bind = "dynamically linked"; 491 | tmp = "shared object"; 492 | } else if (type == ELF_STATIC) { 493 | bind = "statically linked"; 494 | tmp = "executable"; 495 | } 496 | snprintf(elf_info, 1000, "ELF %s %s, %s", mode, tmp, bind); 497 | printf("%s\n", elf_info); 498 | 499 | char TAG[50]; 500 | printf("|--------------------------------------------------------------------------|\n"); 501 | printf("|%-20s|%1s| %-50s|\n", "checkpoint", "s", "description"); 502 | printf("|--------------------------------------------------------------------------|\n"); 503 | /* check entry */ 504 | strcpy(TAG, "entry point"); 505 | uint64_t entry = get_entry(elf_name); 506 | uint64_t addr = get_section_addr(elf_name, ".text"); 507 | size_t size = get_section_size(elf_name, ".text"); 508 | if (type == ELF_SHARED && entry == 0) { 509 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(shared library)"); 510 | } 511 | else if (entry == addr) { 512 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 513 | } else if (entry > addr && entry < addr + size) { 514 | CHECK_WARNING("|%-20s|%1s| %-50s|\n", TAG, "!", "is NOT at the start of the .TEXT section"); 515 | } else { 516 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "is NOT inside the .TEXT section"); 517 | } 518 | 519 | /* check plt/got hook (lazy bind) */ 520 | strcpy(TAG, "hook in .got.plt"); 521 | if (type == ELF_SHARED) { 522 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(shared library)"); 523 | } else if (type == ELF_STATIC) { 524 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(statically linked)"); 525 | } else { 526 | addr = get_section_addr(elf_name, ".plt"); 527 | size = get_section_size(elf_name, ".plt"); 528 | ret = check_hook(&h32, &h64, addr, size); 529 | switch (ret) 530 | { 531 | case 0: 532 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 533 | break; 534 | 535 | case 1: 536 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", ".got.plt hook is detected"); 537 | break; 538 | 539 | default: 540 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(bind now)"); 541 | break; 542 | } 543 | } 544 | 545 | 546 | /* check load segment permission */ 547 | strcpy(TAG, "segment flags"); 548 | ret = check_load_flags(&h32, &h64); 549 | switch (ret) 550 | { 551 | case 0: 552 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 553 | break; 554 | 555 | case 1: 556 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "more than one executable segment"); 557 | break; 558 | 559 | default: 560 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(no executable elf file)"); 561 | break; 562 | } 563 | 564 | /* check segment continuity */ 565 | strcpy(TAG, "segment continuity"); 566 | ret = check_load_continuity(&h32, &h64); 567 | switch (ret) 568 | { 569 | case 0: 570 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 571 | break; 572 | 573 | case 1: 574 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "load segments are NOT continuous"); 575 | break; 576 | 577 | default: 578 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na"); 579 | break; 580 | } 581 | 582 | /* check DLL injection */ 583 | strcpy(TAG, "DLL injection"); 584 | ret = check_needed_continuity(&h32, &h64); 585 | switch (ret) 586 | { 587 | case 0: 588 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 589 | break; 590 | 591 | case 1: 592 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "DT_NEEDED libraries are NOT continuous"); 593 | break; 594 | 595 | default: 596 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(statically linked)"); 597 | break; 598 | } 599 | 600 | /* check section header table */ 601 | strcpy(TAG, "section header table"); 602 | ret = check_shdr(&h32, &h64); 603 | switch (ret) 604 | { 605 | case 0: 606 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 607 | break; 608 | 609 | case 1: 610 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "NO section header table"); 611 | break; 612 | 613 | case 2: 614 | CHECK_WARNING("|%-20s|%1s| %-50s|\n", TAG, "!", "is NOT at the end of the file"); 615 | break; 616 | 617 | default: 618 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na"); 619 | break; 620 | } 621 | 622 | /* check .dynstr */ 623 | strcpy(TAG, "symbol injection"); 624 | ret = check_dynstr(&h32, &h64); 625 | switch (ret) 626 | { 627 | case 0: 628 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 629 | break; 630 | 631 | case 1: 632 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "modified symbol is detected"); 633 | break; 634 | 635 | default: 636 | CHECK_WARNING("|%-20s|%1s| %-50s|\n", TAG, "-", "na(no .dynstr section)"); 637 | break; 638 | } 639 | 640 | /* check .interp */ 641 | strcpy(TAG, "interp injection"); 642 | ret = check_interpreter(&h32, &h64); 643 | switch (ret) 644 | { 645 | case 0: 646 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "✓", "normal"); 647 | break; 648 | 649 | case 1: 650 | CHECK_ERROR("|%-20s|%1s| %-50s|\n", TAG, "✗", "modified interpreter is detected"); 651 | break; 652 | 653 | default: 654 | CHECK_COMMON("|%-20s|%1s| %-50s|\n", TAG, "-", "na(no .interp section)"); 655 | break; 656 | } 657 | 658 | printf("|--------------------------------------------------------------------------|\n"); 659 | finit_elf(&h32, &h64); 660 | return 0; 661 | } -------------------------------------------------------------------------------- /src/gnuhash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | #include "parse.h" 4 | 5 | extern struct ElfData g_dynsym; 6 | extern parser_opt_t po; 7 | 8 | // compute symbol hash 9 | uint32_t dl_new_hash(const char* name) { 10 | uint32_t h = 5381; 11 | 12 | for (unsigned char c = *name; c != '\0'; c = *++name) { 13 | h = h * 33 + c; 14 | } 15 | 16 | return h & 0xffffffff; 17 | } 18 | 19 | /* 重新计算hash表 */ 20 | /* Mainly inspired from LIEF */ 21 | int set_hash_table32(char *elf_name) { 22 | size_t src_size = 0; // source .gnu.hash size 23 | size_t size = 0; // new .gnu.hash size 24 | uint64_t src_offset; // source .gnu.hash offset 25 | int seg_i; 26 | int ret; 27 | src_offset = get_section_offset(elf_name, ".gnu.hash"); 28 | src_size = get_section_size(elf_name, ".gnu.hash"); 29 | gnuhash_t *src_gnuhash = malloc(src_size); 30 | if (!src_gnuhash) { 31 | return -1; 32 | } 33 | 34 | memset(src_gnuhash, 0, src_size); 35 | ret = read_file_offset(elf_name, src_offset, src_size, &src_gnuhash); 36 | if (ret == -1) { 37 | free(src_gnuhash); 38 | return -1; 39 | } 40 | 41 | /* init symbol string table*/ 42 | parse(elf_name, &po, 0); 43 | 44 | size = 4 * sizeof(uint32_t) + // header 45 | src_gnuhash->maskbits * 4 + // bloom filters 46 | src_gnuhash->nbuckets * sizeof(uint32_t) + // buckets 47 | (g_dynsym.count - src_gnuhash->symndx) * sizeof(uint32_t); // hash values 48 | 49 | gnuhash_t *raw_gnuhash = malloc(size); 50 | if (!raw_gnuhash) { 51 | free(src_gnuhash); 52 | return -1; 53 | } 54 | memset(raw_gnuhash, 0, size); 55 | 56 | /* set header */ 57 | raw_gnuhash->nbuckets = src_gnuhash->nbuckets; 58 | raw_gnuhash->symndx = src_gnuhash->symndx; 59 | raw_gnuhash->maskbits = src_gnuhash->maskbits; 60 | raw_gnuhash->shift = src_gnuhash->shift; 61 | 62 | /* compute bloom filter */ 63 | size_t bloom_size = sizeof(uint32_t) * raw_gnuhash->maskbits; 64 | uint32_t *bloom_filters = malloc(bloom_size); 65 | if (!bloom_filters) { 66 | free(src_gnuhash); 67 | free(raw_gnuhash); 68 | return -1; 69 | } 70 | memset(bloom_filters, 0, bloom_size); 71 | size_t C = 32; // 32 for ELF, 64 for ELF64 72 | 73 | for (size_t i = raw_gnuhash->symndx; i < g_dynsym.count; ++i) { 74 | const uint32_t hash = dl_new_hash(g_dynsym.name[i]); 75 | const size_t pos = (hash / C) & (raw_gnuhash->maskbits - 1); 76 | uint32_t tmp = 1; // 32 for ELF, 64 for ELF64 77 | uint32_t V = (tmp << (hash % C)) | 78 | (tmp << ((hash >> raw_gnuhash->shift) % C)); 79 | bloom_filters[pos] |= V; 80 | } 81 | for (size_t idx = 0; idx < raw_gnuhash->maskbits; ++idx) { 82 | DEBUG("Bloom filter [%d]: 0x%x\n", idx, bloom_filters[idx]); 83 | } 84 | 85 | uint32_t *bloom_filters_raw = raw_gnuhash->buckets; 86 | memcpy(bloom_filters_raw, bloom_filters, bloom_size); 87 | 88 | /* set buckets */ 89 | int previous_bucket = -1; 90 | size_t hash_value_idx = 0; 91 | size_t buckets_size = sizeof(uint32_t) * raw_gnuhash->nbuckets; 92 | size_t hash_chain_size = sizeof(uint32_t) * (g_dynsym.count - raw_gnuhash->symndx); 93 | uint32_t *buckets = malloc(buckets_size); 94 | uint32_t *hash_chain = malloc(hash_chain_size); 95 | memset(buckets, 0, buckets_size); 96 | memset(hash_chain, 0, hash_chain_size); 97 | 98 | for (size_t i = raw_gnuhash->symndx; i < g_dynsym.count; ++i) { 99 | DEBUG("Dealing with symbol %s\n", g_dynsym.name[i]); 100 | const uint32_t hash = dl_new_hash(g_dynsym.name[i]); 101 | int bucket = hash % raw_gnuhash->nbuckets; 102 | 103 | if (bucket < previous_bucket) { 104 | ERROR("Previous bucket is greater than the current one (%s < %s)", 105 | bucket, previous_bucket); 106 | return 0; 107 | } 108 | 109 | if (bucket != previous_bucket) { 110 | buckets[bucket] = i; 111 | previous_bucket = bucket; 112 | if (hash_value_idx > 0) { 113 | hash_chain[hash_value_idx - 1] |= 1; 114 | } 115 | } 116 | 117 | hash_chain[hash_value_idx] = hash & ~1; 118 | ++hash_value_idx; 119 | } 120 | 121 | if (hash_value_idx > 0) { 122 | hash_chain[hash_value_idx - 1] |= 1; 123 | } 124 | 125 | uint32_t *buckets_raw = &bloom_filters_raw[raw_gnuhash->maskbits]; 126 | memcpy(buckets_raw, buckets, buckets_size); 127 | uint32_t *hash_chain_raw = &buckets_raw[raw_gnuhash->nbuckets]; 128 | memcpy(hash_chain_raw, hash_chain, hash_chain_size); 129 | 130 | if (size > src_size) { 131 | /* add hash table*/ 132 | seg_i = add_hash_segment(elf_name, raw_gnuhash, size); 133 | } else { 134 | /* update hash table*/ 135 | set_content(elf_name, src_offset, raw_gnuhash, size); 136 | ; 137 | } 138 | 139 | free(hash_chain); 140 | free(buckets); 141 | free(bloom_filters); 142 | free(raw_gnuhash); 143 | free(src_gnuhash); 144 | return 0; 145 | } 146 | 147 | int set_hash_table64(char *elf_name) { 148 | size_t src_size = 0; // source .gnu.hash size 149 | size_t size = 0; // new .gnu.hash size 150 | uint64_t src_offset; // source .gnu.hash offset 151 | int seg_i; 152 | int ret; 153 | src_offset = get_section_offset(elf_name, ".gnu.hash"); 154 | src_size = get_section_size(elf_name, ".gnu.hash"); 155 | gnuhash_t *src_gnuhash = malloc(src_size); 156 | if (!src_gnuhash) { 157 | return -1; 158 | } 159 | 160 | memset(src_gnuhash, 0, src_size); 161 | ret = read_file_offset(elf_name, src_offset, src_size, &src_gnuhash); 162 | if (ret == -1) { 163 | free(src_gnuhash); 164 | return -1; 165 | } 166 | 167 | /* init symbol string table*/ 168 | parse(elf_name, &po, 0); 169 | 170 | size = 4 * sizeof(uint32_t) + // header 171 | src_gnuhash->maskbits * 8 + // bloom filters 172 | src_gnuhash->nbuckets * sizeof(uint32_t) + // buckets 173 | (g_dynsym.count - src_gnuhash->symndx) * sizeof(uint32_t); // hash values 174 | 175 | gnuhash_t *raw_gnuhash = malloc(size); 176 | if (!raw_gnuhash) { 177 | free(src_gnuhash); 178 | return -1; 179 | } 180 | memset(raw_gnuhash, 0, size); 181 | 182 | /* set header */ 183 | raw_gnuhash->nbuckets = src_gnuhash->nbuckets; 184 | raw_gnuhash->symndx = src_gnuhash->symndx; 185 | raw_gnuhash->maskbits = src_gnuhash->maskbits; 186 | raw_gnuhash->shift = src_gnuhash->shift; 187 | 188 | /* compute bloom filter */ 189 | size_t bloom_size = sizeof(uint64_t) * raw_gnuhash->maskbits; 190 | uint64_t *bloom_filters = malloc(bloom_size); 191 | if (!bloom_filters) { 192 | free(src_gnuhash); 193 | free(raw_gnuhash); 194 | return -1; 195 | } 196 | memset(bloom_filters, 0, bloom_size); 197 | size_t C = 64; // 32 for ELF, 64 for ELF64 198 | 199 | for (size_t i = raw_gnuhash->symndx; i < g_dynsym.count; ++i) { 200 | const uint32_t hash = dl_new_hash(g_dynsym.name[i]); 201 | const size_t pos = (hash / C) & (raw_gnuhash->maskbits - 1); 202 | uint64_t tmp = 1; // 32 for ELF, 64 for ELF64 203 | uint64_t V = (tmp << (hash % C)) | 204 | (tmp << ((hash >> raw_gnuhash->shift) % C)); 205 | bloom_filters[pos] |= V; 206 | } 207 | for (size_t idx = 0; idx < raw_gnuhash->maskbits; ++idx) { 208 | DEBUG("Bloom filter [%d]: 0x%x\n", idx, bloom_filters[idx]); 209 | } 210 | 211 | uint64_t *bloom_filters_raw = raw_gnuhash->buckets; 212 | memcpy(bloom_filters_raw, bloom_filters, bloom_size); 213 | 214 | /* set buckets */ 215 | int previous_bucket = -1; 216 | size_t hash_value_idx = 0; 217 | size_t buckets_size = sizeof(uint32_t) * raw_gnuhash->nbuckets; 218 | size_t hash_chain_size = sizeof(uint32_t) * (g_dynsym.count - raw_gnuhash->symndx); 219 | uint32_t *buckets = malloc(buckets_size); 220 | uint32_t *hash_chain = malloc(hash_chain_size); 221 | memset(buckets, 0, buckets_size); 222 | memset(hash_chain, 0, hash_chain_size); 223 | 224 | for (size_t i = raw_gnuhash->symndx; i < g_dynsym.count; ++i) { 225 | DEBUG("Dealing with symbol %s\n", g_dynsym.name[i]); 226 | const uint32_t hash = dl_new_hash(g_dynsym.name[i]); 227 | int bucket = hash % raw_gnuhash->nbuckets; 228 | 229 | if (bucket < previous_bucket) { 230 | ERROR("Previous bucket is greater than the current one (%s < %s)", 231 | bucket, previous_bucket); 232 | return 0; 233 | } 234 | 235 | if (bucket != previous_bucket) { 236 | buckets[bucket] = i; 237 | previous_bucket = bucket; 238 | if (hash_value_idx > 0) { 239 | hash_chain[hash_value_idx - 1] |= 1; 240 | } 241 | } 242 | 243 | hash_chain[hash_value_idx] = hash & ~1; 244 | ++hash_value_idx; 245 | } 246 | 247 | if (hash_value_idx > 0) { 248 | hash_chain[hash_value_idx - 1] |= 1; 249 | } 250 | 251 | uint32_t *buckets_raw = &bloom_filters_raw[raw_gnuhash->maskbits]; 252 | memcpy(buckets_raw, buckets, buckets_size); 253 | uint32_t *hash_chain_raw = &buckets_raw[raw_gnuhash->nbuckets]; 254 | memcpy(hash_chain_raw, hash_chain, hash_chain_size); 255 | 256 | if (size > src_size) { 257 | /* add hash table*/ 258 | seg_i = add_hash_segment(elf_name, raw_gnuhash, size); 259 | } else { 260 | /* update hash table*/ 261 | set_content(elf_name, src_offset, raw_gnuhash, size); 262 | ; 263 | } 264 | 265 | free(hash_chain); 266 | free(buckets); 267 | free(bloom_filters); 268 | free(raw_gnuhash); 269 | free(src_gnuhash); 270 | return 0; 271 | } 272 | 273 | /* refresh gnu hash table */ 274 | int refresh_hash_table(char *elf_name) { 275 | if (MODE == ELFCLASS32) 276 | return set_hash_table32(elf_name); 277 | if (MODE == ELFCLASS64) 278 | return set_hash_table64(elf_name); 279 | } -------------------------------------------------------------------------------- /src/gnuhash.h: -------------------------------------------------------------------------------- 1 | /* 重新计算hash表 */ 2 | /* Mainly inspired from LIEF */ 3 | int set_hash_table32(char *elf_name); 4 | int set_hash_table64(char *elf_name); 5 | /* refresh gnu hash table */ 6 | int refresh_hash_table(char *elf_name); -------------------------------------------------------------------------------- /src/infect.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "common.h" 34 | 35 | /** 36 | * @brief 在文件offset偏移处插入一段数据 37 | * insert a piece of data at the offset of the file 38 | * @param elfname elf file name 39 | * @param offset elf file offset 40 | * @param data data 41 | * @param data_size data size 42 | * @return int result code {-1:error,0:false,1:true} 43 | */ 44 | int insert_data(const char *filename, off_t offset, const void *data, size_t data_size) { 45 | FILE *file = fopen(filename, "r+b"); 46 | if (file == NULL) { 47 | perror("fopen"); 48 | return -1; 49 | } 50 | 51 | // 获取文件末尾位置 52 | fseek(file, 0, SEEK_END); 53 | long file_size = ftell(file); 54 | 55 | // 将文件指针移动到插入位置 56 | fseek(file, offset, SEEK_SET); 57 | 58 | // 读取插入位置后的数据 59 | char *temp_buffer = (char *)malloc(file_size - offset); 60 | fread(temp_buffer, file_size - offset, 1, file); 61 | 62 | // 将数据写入插入位置 63 | fseek(file, offset, SEEK_SET); 64 | fwrite(data, data_size, 1, file); 65 | 66 | // 写入剩余数据 67 | fwrite(temp_buffer, file_size - offset, 1, file); 68 | 69 | // 释放内存并关闭文件 70 | free(temp_buffer); 71 | fclose(file); 72 | return 0; 73 | } 74 | 75 | /* 76 | 77 | 78 | memory layout file layout 79 | 80 | ─── ┌──────────────┐ 0x0000 ┌──────────────┐ 0x0000 81 | ▲ │ ehdr/phdr │ const│ ehdr/phdr │ 82 | │ ├──────────────┤ 0x1000 ├──────────────┤ 0x1000 83 | │ │ TEXT │ │ TEXT │ 84 | │ ├──────────────┤ ├──────────────┤ 85 | const│xxxxxxxxxxxxxx│ │xxxxxxxxxxxxxx│ 86 | ├──────────────┤ ├───────┬──────┤ 87 | │ │ │ │ │ │ 88 | │ │ │ │ │ │ 89 | ▼ │ │ │ ▼ │ 90 | ─── │ │ │ PAGE_SIZE │ 91 | │ │ │ │ 92 | └──────────────┘ ├──────────────┤ 93 | │ shdr │ 94 | └──────────────┘ 95 | 96 | */ 97 | 98 | /** 99 | * @brief 使用silvio感染算法,填充text段 100 | * use the Silvio infection algorithm to fill in text segments 101 | * @param elfname elf file name 102 | * @param parasite shellcode 103 | * @param size shellcode size (< 1KB) 104 | * @return uint64_t parasite address {-1:error,0:false,address} 105 | */ 106 | uint64_t infect_silvio(char *elfname, char *parasite, size_t size) { 107 | int fd; 108 | struct stat st; 109 | uint8_t *mapped; 110 | int text_index; 111 | uint64_t parasite_addr; 112 | uint64_t parasite_offset; 113 | 114 | fd = open(elfname, O_RDWR); 115 | if (fd < 0) { 116 | perror("open"); 117 | return -1; 118 | } 119 | 120 | if (fstat(fd, &st) < 0) { 121 | perror("fstat"); 122 | return -1; 123 | } 124 | 125 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 126 | if (mapped == MAP_FAILED) { 127 | perror("mmap"); 128 | return -1; 129 | } 130 | 131 | if (MODE == ELFCLASS32) { 132 | Elf32_Ehdr *ehdr; 133 | Elf32_Phdr *phdr; 134 | Elf32_Shdr *shdr; 135 | ehdr = (Elf32_Ehdr *)mapped; 136 | phdr = (Elf32_Phdr *)&mapped[ehdr->e_phoff]; 137 | shdr = (Elf32_Shdr *)&mapped[ehdr->e_shoff]; 138 | for (int i = 0; i < ehdr->e_phnum; i++) { 139 | if (phdr[i].p_type == PT_LOAD) { 140 | // 1. text段扩容size 141 | if (phdr[i].p_flags == (PF_R | PF_X)) { 142 | text_index = i; 143 | parasite_addr = phdr[i].p_vaddr + phdr[i].p_memsz; 144 | parasite_offset = phdr[i].p_offset + phdr[i].p_filesz; 145 | phdr[i].p_memsz += size; 146 | phdr[i].p_filesz += size; 147 | VERBOSE("expand [%d] TEXT Segment at [0x%x]\n", i, parasite_addr); 148 | break; 149 | } 150 | } 151 | } 152 | 153 | for (int i = 0; i < ehdr->e_phnum; i++) { 154 | if (phdr[i].p_type == PT_LOAD) { 155 | // 2. 其他load段向后偏移 156 | if (phdr[i].p_offset > phdr[text_index].p_offset) { 157 | //phdr[i].p_vaddr += PAGE_SIZE; 158 | //phdr[i].p_paddr += PAGE_SIZE; 159 | phdr[i].p_offset += PAGE_SIZE; 160 | } 161 | } 162 | } 163 | 164 | for (int i = 0; i < ehdr->e_shnum; i++) { 165 | // 3. 寄生代码之后的节,偏移PAGE_SIZE 166 | if (shdr[i].sh_offset > parasite_offset) { 167 | //shdr[i].sh_addr += PAGE_SIZE; 168 | shdr[i].sh_offset += PAGE_SIZE; 169 | } 170 | // 4. text节,偏移size 171 | else if (shdr[i].sh_addr + shdr[i].sh_size == parasite_addr) { 172 | shdr[i].sh_size += size; 173 | } 174 | } 175 | // 5. elf节头偏移PAGE_SIZE 176 | ehdr->e_shoff += PAGE_SIZE; 177 | } 178 | 179 | else if (MODE == ELFCLASS64) { 180 | Elf64_Ehdr *ehdr; 181 | Elf64_Phdr *phdr; 182 | Elf64_Shdr *shdr; 183 | ehdr = (Elf64_Ehdr *)mapped; 184 | phdr = (Elf64_Phdr *)&mapped[ehdr->e_phoff]; 185 | shdr = (Elf64_Shdr *)&mapped[ehdr->e_shoff]; 186 | for (int i = 0; i < ehdr->e_phnum; i++) { 187 | if (phdr[i].p_type == PT_LOAD) { 188 | // 1. text段扩容size 189 | if (phdr[i].p_flags == (PF_R | PF_X)) { 190 | text_index = i; 191 | parasite_addr = phdr[i].p_vaddr + phdr[i].p_memsz; 192 | parasite_offset = phdr[i].p_offset + phdr[i].p_filesz; 193 | phdr[i].p_memsz += size; 194 | phdr[i].p_filesz += size; 195 | VERBOSE("expand [%d] TEXT Segment at [0x%x]\n", i, parasite_addr); 196 | break; 197 | } 198 | } 199 | } 200 | 201 | for (int i = 0; i < ehdr->e_phnum; i++) { 202 | if (phdr[i].p_type == PT_LOAD) { 203 | // 2. 其他load段向后偏移 204 | if (phdr[i].p_offset > phdr[text_index].p_offset) { 205 | phdr[i].p_offset += PAGE_SIZE; 206 | } 207 | } 208 | } 209 | 210 | for (int i = 0; i < ehdr->e_shnum; i++) { 211 | // 3. 寄生代码之后的节,偏移PAGE_SIZE 212 | if (shdr[i].sh_offset > parasite_offset) { 213 | shdr[i].sh_offset += PAGE_SIZE; 214 | } 215 | // 4. text节,偏移size 216 | else if (shdr[i].sh_addr + shdr[i].sh_size == parasite_addr) { 217 | shdr[i].sh_size += size; 218 | } 219 | } 220 | // 5. elf节头偏移PAGE_SIZE 221 | ehdr->e_shoff += PAGE_SIZE; 222 | } 223 | 224 | close(fd); 225 | munmap(mapped, st.st_size); 226 | 227 | // 6. 插入寄生代码 228 | char *parasite_expand = malloc(PAGE_SIZE); 229 | memset(parasite_expand, 0, PAGE_SIZE); 230 | memcpy(parasite_expand, parasite, PAGE_SIZE - size > 0? size: PAGE_SIZE); 231 | int ret = insert_data(elfname, parasite_offset, parasite_expand, PAGE_SIZE); 232 | if (ret == 0) { 233 | VERBOSE("insert successfully\n"); 234 | } else { 235 | VERBOSE("insert failed\n"); 236 | } 237 | free(parasite_expand); 238 | 239 | return parasite_addr; 240 | } 241 | 242 | /* 243 | The address of the load segment in memory cannot be easily changed 244 | .rela.dyn->offset->.dynamic 245 | 246 | memory layout file layout 247 | 248 | ┌──────────────┐ 0x0000 ┌──────────────┐ 0x0000 249 | │xxxxxxxxxxxxxx│ const│ ehdr/phdr │ 250 | ─── ├──────────────┤ 0x1000 ├──────────────┤ 0x1000 251 | ▲ │ TEXT │ │xxxxxxxxxxxxxx│ 252 | │ ├──────────────┤ ├──────────────┤ 253 | │ │ │ │ TEXT │ 254 | const│ │ ├──────────────┤ 255 | │ │ │ │ │ 256 | │ │ │ │ │ 257 | ▼ │ │ │ │ 258 | ─── ├──────────────┤ │ │ 259 | │ ehrdr/phdr │ │ │ 260 | └──────────────┘ ├──────────────┤ 261 | │ shdr │ 262 | └──────────────┘ 263 | 264 | */ 265 | 266 | /** 267 | * @brief 使用skeksi增强版感染算法,填充text段. 此算法适用于开启pie的二进制 268 | * use the Skeksi plus infection algorithm to fill in text segments 269 | * this algorithm is suitable for opening binary pie 270 | * @param elfname elf file name 271 | * @param parasite shellcode 272 | * @param size shellcode size (< 1KB) 273 | * @return uint64_t parasite address {-1:error,0:false,address} 274 | */ 275 | uint64_t infect_skeksi_pie(char *elfname, char *parasite, size_t size) { 276 | int fd; 277 | struct stat st; 278 | uint8_t *mapped; 279 | int text_index; 280 | uint64_t parasite_addr; 281 | size_t distance; 282 | uint64_t min_paddr = 0x0; 283 | uint64_t origin_text_vaddr = 0x0; 284 | uint64_t origin_text_offset = 0x0; 285 | size_t origin_text_size = 0x0; 286 | 287 | uint64_t vstart, vend; 288 | get_segment_range(elfname, PT_LOAD, &vstart, &vend); 289 | 290 | fd = open(elfname, O_RDWR); 291 | if (fd < 0) { 292 | perror("open"); 293 | return -1; 294 | } 295 | 296 | if (fstat(fd, &st) < 0) { 297 | perror("fstat"); 298 | return -1; 299 | } 300 | 301 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 302 | if (mapped == MAP_FAILED) { 303 | perror("mmap"); 304 | return -1; 305 | } 306 | 307 | if (MODE == ELFCLASS32) { 308 | Elf32_Ehdr *ehdr; 309 | Elf32_Phdr *phdr; 310 | Elf32_Shdr *shdr; 311 | Elf32_Dyn *dyn; 312 | ehdr = (Elf32_Ehdr *)mapped; 313 | phdr = (Elf32_Phdr *)&mapped[ehdr->e_phoff]; 314 | shdr = (Elf32_Shdr *)&mapped[ehdr->e_shoff]; 315 | 316 | // memory layout 317 | for (int i = 0; i < ehdr->e_phnum; i++) { 318 | if (phdr[i].p_type == PT_LOAD) { 319 | if (phdr[i].p_flags == (PF_R | PF_X)) { 320 | text_index = i; 321 | for (int j = 0; j < i; j++) { 322 | if (phdr[j].p_vaddr < min_paddr) 323 | min_paddr = phdr[j].p_vaddr; 324 | } 325 | origin_text_vaddr = phdr[i].p_vaddr; 326 | origin_text_size = phdr[i].p_memsz; 327 | origin_text_offset = phdr[i].p_offset; 328 | phdr[i].p_memsz += PAGE_SIZE; 329 | phdr[i].p_vaddr -= PAGE_SIZE; 330 | phdr[i].p_paddr -= PAGE_SIZE; 331 | parasite_addr = phdr[i].p_vaddr; 332 | VERBOSE("expand [%d] TEXT Segment at [0x%x]\n", i, parasite_addr); 333 | break; 334 | } 335 | } 336 | } 337 | 338 | for (int i = 0; i < ehdr->e_phnum; i++) { 339 | if (i == text_index) 340 | continue; 341 | if (phdr[i].p_vaddr < origin_text_vaddr) { 342 | phdr[i].p_vaddr += align_to_4k(vend); 343 | phdr[i].p_paddr += align_to_4k(vend); 344 | continue; 345 | } 346 | 347 | // if (phdr[i].p_vaddr > origin_text_vaddr) { 348 | // phdr[i].p_vaddr += PAGE_SIZE; 349 | // } 350 | } 351 | 352 | for (int i = 0; i < ehdr->e_shnum; i++) { 353 | if (shdr[i].sh_addr == origin_text_vaddr) { 354 | shdr[i].sh_addr -= PAGE_SIZE; 355 | shdr[i].sh_size += PAGE_SIZE; 356 | } 357 | else if (shdr[i].sh_addr < origin_text_vaddr) { 358 | shdr[i].sh_addr += align_to_4k(vend); 359 | } 360 | // else if (shdr[i].sh_addr >= origin_text_vaddr + origin_text_size) { 361 | // shdr[i].sh_addr += PAGE_SIZE; 362 | // } 363 | } 364 | 365 | // start----------------------- edit .dynamic 366 | // 32: REL 367 | for (int i = 0; i < ehdr->e_phnum; i++) { 368 | if (phdr[i].p_type == PT_DYNAMIC) { 369 | dyn = (Elf32_Dyn *)(mapped + phdr[i].p_offset); 370 | for (int j = 0; j < phdr[i].p_filesz / sizeof(Elf32_Dyn); j++) { 371 | if (dyn[j].d_tag == DT_STRTAB | 372 | dyn[j].d_tag == DT_SYMTAB | 373 | dyn[j].d_tag == DT_REL | 374 | dyn[j].d_tag == DT_JMPREL | 375 | dyn[j].d_tag == DT_VERNEED | 376 | dyn[j].d_tag == DT_VERSYM) { 377 | dyn[j].d_un.d_val += align_to_4k(vend); 378 | } 379 | } 380 | } 381 | } 382 | // end------------------------- edit .dynamic 383 | 384 | // file layout 385 | for (int i = 0; i < ehdr->e_phnum; i++) { 386 | if (i == text_index) { 387 | phdr[i].p_filesz += PAGE_SIZE; 388 | continue; 389 | } 390 | if (phdr[i].p_offset > origin_text_offset) { 391 | phdr[i].p_offset += PAGE_SIZE; 392 | } 393 | } 394 | 395 | for (int i = 0; i < ehdr->e_shnum; i++) { 396 | if (shdr[i].sh_offset >= origin_text_offset + origin_text_size) { 397 | shdr[i].sh_offset += PAGE_SIZE; 398 | } 399 | } 400 | 401 | // elf节头表偏移PAGE_SIZE 402 | ehdr->e_shoff += PAGE_SIZE; 403 | } 404 | 405 | else if (MODE == ELFCLASS64) { 406 | Elf64_Ehdr *ehdr; 407 | Elf64_Phdr *phdr; 408 | Elf64_Shdr *shdr; 409 | Elf64_Dyn *dyn; 410 | ehdr = (Elf64_Ehdr *)mapped; 411 | phdr = (Elf64_Phdr *)&mapped[ehdr->e_phoff]; 412 | shdr = (Elf64_Shdr *)&mapped[ehdr->e_shoff]; 413 | 414 | // memory layout 415 | for (int i = 0; i < ehdr->e_phnum; i++) { 416 | if (phdr[i].p_type == PT_LOAD) { 417 | if (phdr[i].p_flags == (PF_R | PF_X)) { 418 | text_index = i; 419 | for (int j = 0; j < i; j++) { 420 | if (phdr[j].p_vaddr < min_paddr) 421 | min_paddr = phdr[j].p_vaddr; 422 | } 423 | origin_text_vaddr = phdr[i].p_vaddr; 424 | origin_text_size = phdr[i].p_memsz; 425 | origin_text_offset = phdr[i].p_offset; 426 | phdr[i].p_memsz += PAGE_SIZE; 427 | phdr[i].p_vaddr -= PAGE_SIZE; 428 | phdr[i].p_paddr -= PAGE_SIZE; 429 | parasite_addr = phdr[i].p_vaddr; 430 | VERBOSE("expand [%d] TEXT Segment at [0x%x]\n", i, parasite_addr); 431 | break; 432 | } 433 | } 434 | } 435 | 436 | for (int i = 0; i < ehdr->e_phnum; i++) { 437 | if (i == text_index) 438 | continue; 439 | if (phdr[i].p_vaddr < origin_text_vaddr) { 440 | phdr[i].p_vaddr += align_to_4k(vend); 441 | phdr[i].p_paddr += align_to_4k(vend); 442 | continue; 443 | } 444 | } 445 | 446 | for (int i = 0; i < ehdr->e_shnum; i++) { 447 | if (shdr[i].sh_addr == origin_text_vaddr) { 448 | shdr[i].sh_addr -= PAGE_SIZE; 449 | shdr[i].sh_size += PAGE_SIZE; 450 | } 451 | else if (shdr[i].sh_addr < origin_text_vaddr) { 452 | shdr[i].sh_addr += align_to_4k(vend); 453 | } 454 | } 455 | 456 | // start----------------------- edit .dynamic 457 | // 64: RELA 458 | for (int i = 0; i < ehdr->e_phnum; i++) { 459 | if (phdr[i].p_type == PT_DYNAMIC) { 460 | dyn = (Elf64_Dyn *)(mapped + phdr[i].p_offset); 461 | for (int j = 0; j < phdr[i].p_filesz / sizeof(Elf64_Dyn); j++) { 462 | if (dyn[j].d_tag == DT_STRTAB | 463 | dyn[j].d_tag == DT_SYMTAB | 464 | dyn[j].d_tag == DT_RELA | 465 | dyn[j].d_tag == DT_JMPREL | 466 | dyn[j].d_tag == DT_VERNEED | 467 | dyn[j].d_tag == DT_VERSYM) { 468 | dyn[j].d_un.d_val += align_to_4k(vend); 469 | } 470 | } 471 | } 472 | } 473 | // end------------------------- edit .dynamic 474 | 475 | // file layout 476 | for (int i = 0; i < ehdr->e_phnum; i++) { 477 | if (i == text_index) { 478 | phdr[i].p_filesz += PAGE_SIZE; 479 | continue; 480 | } 481 | if (phdr[i].p_offset > origin_text_offset) { 482 | phdr[i].p_offset += PAGE_SIZE; 483 | } 484 | } 485 | 486 | for (int i = 0; i < ehdr->e_shnum; i++) { 487 | if (shdr[i].sh_offset >= origin_text_offset + origin_text_size) { 488 | shdr[i].sh_offset += PAGE_SIZE; 489 | } 490 | } 491 | 492 | // elf节头表偏移PAGE_SIZE 493 | ehdr->e_shoff += PAGE_SIZE; 494 | } 495 | 496 | close(fd); 497 | munmap(mapped, st.st_size); 498 | 499 | // insert parasite code 500 | char *parasite_expand = malloc(PAGE_SIZE); 501 | memset(parasite_expand, 0, PAGE_SIZE); 502 | memcpy(parasite_expand, parasite, PAGE_SIZE - size > 0? size: PAGE_SIZE); 503 | int ret = insert_data(elfname, origin_text_offset, parasite_expand, PAGE_SIZE); 504 | if (ret == 0) { 505 | VERBOSE("insert successfully\n"); 506 | } else { 507 | VERBOSE("insert failed\n"); 508 | } 509 | free(parasite_expand); 510 | 511 | return parasite_addr; 512 | } 513 | 514 | /* 515 | 516 | memory layout file layout 517 | 518 | ─── ┌──────────────┐ 0x0000 ─── ┌──────────────┐ 0x0000 519 | ▲ │ ehdr/phdr │ ▲ │ ehdr/phdrr │ 520 | │ ├──────────────┤ 0x1000 │ ├──────────────┤ 0x1000 521 | │ │ TEXT │ │ │ TEXT │ 522 | │ ├──────────────┤ │ ├──────────────┤ 523 | │ │ │ │ │ │ 524 | const│ │ const│ │ 525 | │ │ │ │ │ │ 526 | │ │ │ │ │ │ 527 | │ │ │ │ │ │ 528 | │ ├──────────────┤ │ ├──────────────┤ 529 | ▼ │ data │ ▼ │ data │ 530 | ─── ├──────────────┤ ─── ├──────────────┤ 531 | │xxxxxxxxxxxxxx│ │xxxxxxxxxxxxxx│ 532 | └──────────────┘ ├──────────────┤ 533 | │ shdr │ 534 | └──────────────┘ 535 | */ 536 | 537 | /** 538 | * @brief 填充text段感染 539 | * fill in data segments infection algorithm 540 | * @param elfname elf file name 541 | * @param parasite shellcode 542 | * @param size shellcode size (< 1KB) 543 | * @return uint64_t parasite address {-1:error,0:false,address} 544 | */ 545 | uint64_t infect_data(char *elfname, char *parasite, size_t size) { 546 | int fd; 547 | struct stat st; 548 | uint8_t *mapped; 549 | int data_index; 550 | uint64_t origin_data_offset; 551 | 552 | uint64_t vstart, vend; 553 | get_segment_range(elfname, PT_LOAD, &vstart, &vend); 554 | 555 | fd = open(elfname, O_RDWR); 556 | if (fd < 0) { 557 | perror("open"); 558 | return -1; 559 | } 560 | 561 | if (fstat(fd, &st) < 0) { 562 | perror("fstat"); 563 | return -1; 564 | } 565 | 566 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 567 | if (mapped == MAP_FAILED) { 568 | perror("mmap"); 569 | return -1; 570 | } 571 | 572 | if (MODE == ELFCLASS32) { 573 | Elf32_Ehdr *ehdr; 574 | Elf32_Phdr *phdr; 575 | Elf32_Shdr *shdr; 576 | ehdr = (Elf32_Ehdr *)mapped; 577 | phdr = (Elf32_Phdr *)&mapped[ehdr->e_phoff]; 578 | shdr = (Elf32_Shdr *)&mapped[ehdr->e_shoff]; 579 | 580 | for (int i = 0; i < ehdr->e_phnum; i++) { 581 | if (phdr[i].p_vaddr + phdr[i].p_memsz == vend && phdr[i].p_type == PT_LOAD) { 582 | data_index = i; 583 | origin_data_offset = phdr[i].p_offset + phdr[i].p_filesz; 584 | phdr[i].p_memsz += size; 585 | phdr[i].p_filesz += size; 586 | phdr[i].p_flags |= PF_X; 587 | VERBOSE("expand [%d] DATA Segment, address: [0x%x], offset: [0x%x]\n", i, vend, origin_data_offset); 588 | break; 589 | } 590 | } 591 | 592 | for (int i = 0; i < ehdr->e_shnum; i++) { 593 | if (shdr[i].sh_addr + shdr[i].sh_size == vend) { 594 | shdr[i].sh_size += size; 595 | } else if (shdr[i].sh_offset >= origin_data_offset) { 596 | shdr[i].sh_offset += size; 597 | } 598 | } 599 | 600 | ehdr->e_shoff += size; 601 | } 602 | 603 | else if (MODE == ELFCLASS64) { 604 | Elf64_Ehdr *ehdr; 605 | Elf64_Phdr *phdr; 606 | Elf64_Shdr *shdr; 607 | ehdr = (Elf64_Ehdr *)mapped; 608 | phdr = (Elf64_Phdr *)&mapped[ehdr->e_phoff]; 609 | shdr = (Elf64_Shdr *)&mapped[ehdr->e_shoff]; 610 | 611 | for (int i = 0; i < ehdr->e_phnum; i++) { 612 | if (phdr[i].p_vaddr + phdr[i].p_memsz == vend && phdr[i].p_type == PT_LOAD) { 613 | data_index = i; 614 | origin_data_offset = phdr[i].p_offset + phdr[i].p_filesz; 615 | phdr[i].p_memsz += size; 616 | phdr[i].p_filesz += size; 617 | phdr[i].p_flags |= PF_X; 618 | VERBOSE("expand [%d] DATA Segment, address: [0x%x], offset: [0x%x]\n", i, vend, origin_data_offset); 619 | break; 620 | } 621 | } 622 | 623 | for (int i = 0; i < ehdr->e_shnum; i++) { 624 | if (shdr[i].sh_addr + shdr[i].sh_size == vend) { 625 | shdr[i].sh_size += size; 626 | } else if (shdr[i].sh_offset >= origin_data_offset) { 627 | shdr[i].sh_offset += size; 628 | } 629 | } 630 | 631 | ehdr->e_shoff += size; 632 | } 633 | 634 | close(fd); 635 | munmap(mapped, st.st_size); 636 | 637 | // insert parasite code 638 | int ret = insert_data(elfname, origin_data_offset, parasite, size); 639 | if (ret == 0) { 640 | VERBOSE("insert successfully\n"); 641 | } else { 642 | VERBOSE("insert failed\n"); 643 | } 644 | 645 | return vend; 646 | } -------------------------------------------------------------------------------- /src/infect.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "common.h" 26 | 27 | /** 28 | * @brief 使用silvio感染算法,填充text段 29 | * use the Silvio infection algorithm to fill in text segments 30 | * @param elfname elf file name 31 | * @param parasite shellcode 32 | * @param size shellcode size (< 1KB) 33 | * @return uint64_t parasite address {-1:error,0:false,address} 34 | */ 35 | uint64_t infect_silvio(char *elfname, char *parasite, size_t size); 36 | 37 | /** 38 | * @brief 使用skeksi增强版感染算法,填充text段. 此算法适用于开启pie的二进制 39 | * use the Skeksi plus infection algorithm to fill in text segments 40 | * this algorithm is suitable for opening binary pie 41 | * @param elfname elf file name 42 | * @param parasite shellcode 43 | * @param size shellcode size (< 1KB) 44 | * @return uint64_t parasite address {-1:error,0:false,address} 45 | */ 46 | uint64_t infect_skeksi_pie(char *elfname, char *parasite, size_t size); 47 | 48 | /** 49 | * @brief 填充text段感染 50 | * fill in data segments infection algorithm 51 | * @param elfname elf file name 52 | * @param parasite shellcode 53 | * @param size shellcode size (< 1KB) 54 | * @return uint64_t parasite address {-1:error,0:false,address} 55 | */ 56 | uint64_t infect_data(char *elfname, char *parasite, size_t size); -------------------------------------------------------------------------------- /src/injectso.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "common.h" 34 | #include "cJSON/cJSON.h" 35 | 36 | #define X86 37 | #define SO_LENGTH 16 38 | 39 | uint8_t sc_x86[] = \ 40 | /* start */ 41 | "\x55" // push ebp 0 42 | "\x89\xe5" // mov ebp, esp 1 43 | "\x83\xec\x28" // sub esp, 28h 3 44 | "\xc7\x45\xe4\x6c\x69\x62\x70" // mov DWORD PTR [ebp-0x1c],0x7062696c 6 45 | "\xc7\x45\xe8\x61\x74\x63\x68" // mov DWORD PTR [ebp-0x18],0x68637461 13 46 | "\xc7\x45\xec\x64\x65\x6d\x6f" // mov DWORD PTR [ebp-0x14],0x6f6d6564 20 47 | "\xc7\x45\xf0\x2e\x73\x6f\x00" // mov DWORD PTR [ebp-0x10],0x6f732e<= 16B 27 48 | "\x6a\x01" // push 0x1 34 49 | "\x8d\x6d\xe4" // lea ebp, [ebp-0x1c] 36 50 | "\x55" // push ebp 39 51 | "\x8b\x4b\x0c" // mov ecx, DWORD PTR [ebx + 0xc] 40 52 | "\x81\xe9\xe0\xf4\x13\x00" // sub ecx, 0x0013F4E0 43 53 | "\x81\xc1\xf0\xea\x13\x00" // add ecx, 0x0013EAF0 49 54 | "\xff\xd1" // call ecx --> <__libc_dlopen_mode@plt> 55 55 | "\x83\xc4\x08" // add esp, 0x8 56 | "\xc9" // leave 57 | /* end */ 58 | "\xe8" // call <_start> (e8 ** = _start - eip) 0x10b0 - (0x2061 + 5) 59 | "\x00\x00\x00\x00"; 60 | 61 | uint8_t sc_x86_64[] = \ 62 | /* start */ 63 | "\x55" // push rbp 0 64 | "\x48\x89\xe5" // mov rbp, rsp 1 65 | "\x48\x83\xec\x30" // sub rsp, 30h 4 66 | "\x48\xb8\x6c\x69\x62\x70\x61\x74\x63\x68" // movabs rax,0x686374617062696c 8 67 | "\x48\xbb\x64\x65\x6d\x6f\x2e\x73\x6f\x00" // movabs rbx,0x6f732e6f6d6564 18 68 | "\x48\x89\x45\xe0" // mov QWORD PTR [rbp-0x20],rax 28 69 | "\x48\x89\x5d\xe8" // mov QWORD PTR [rbp-0x18],rbx 32 70 | "\x48\x8d\x45\xe0" // lea rax,[rbp-0x20] 36 71 | "\xbe\x01\x00\x00\x00" // mov esi,0x1 40 72 | "\x48\x89\xc7" // mov rdi,rax 45 73 | "\x4c\x8b\x8a\x68\xae\x01\x00" // mov r9, [rdx + 0x1ae68] 48 74 | "\x49\x81\xe9\xe0\x81\x13\x00" // sub r9, 0x0000000001381E0 55 75 | "\x49\x81\xc1\x00\x78\x13\x00" // add r9, 0x000000000137800 62 76 | "\x41\xff\xd1" // call r9 77 | "\xc9" // leave 78 | /* end */ 79 | "\xe8\x0b\x00\x00\x00"; // call <_start> 80 | 81 | uint8_t sc_mipsel[] = \ 82 | /* start */ 83 | /* end */ 84 | "\x00\x00\x00\x00" // jal <_ftext> 85 | "\x00\x00\x00\x00"; // nop 86 | 87 | typedef struct Offset{ 88 | uint32_t _ld_fini; // ld.so 89 | uint32_t _ld_catch_exception_got; 90 | uint32_t _ld_catch_exception; // libc.so 91 | uint32_t __libc_dlopen_mode; 92 | }AddrOffset; 93 | 94 | int read_offset(char *json_name, AddrOffset *addr_offset, char *arch, char *version) { 95 | cJSON *root = NULL; 96 | cJSON *item = NULL; 97 | root = get_json_object(json_name); 98 | 99 | if (!root) { 100 | ERROR("Error before: [%s]\n", cJSON_GetErrorPtr()); 101 | return -1; 102 | } else { 103 | /* architecture */ 104 | item = cJSON_GetObjectItem(root, arch); 105 | if (item) { 106 | /* version */ 107 | item = cJSON_GetObjectItem(item, version); 108 | if (item) { 109 | cJSON *tmp; 110 | tmp = cJSON_GetObjectItem(item, "_ld_fini"); 111 | if (tmp) { 112 | addr_offset->_ld_fini = hex2int(tmp->valuestring); 113 | } else { 114 | ERROR("No _ld_fini in json file\n"); 115 | goto FreeJson; 116 | } 117 | 118 | tmp = cJSON_GetObjectItem(item, "_ld_catch_exception_got"); 119 | if (tmp) { 120 | addr_offset->_ld_catch_exception_got = hex2int(tmp->valuestring); 121 | } else { 122 | ERROR("No _ld_catch_exception_got in json file\n"); 123 | goto FreeJson; 124 | } 125 | 126 | tmp = cJSON_GetObjectItem(item, "_ld_catch_exception"); 127 | if (tmp) { 128 | addr_offset->_ld_catch_exception = hex2int(tmp->valuestring); 129 | } else { 130 | ERROR("No _ld_catch_exception in json file\n"); 131 | goto FreeJson; 132 | } 133 | 134 | tmp = cJSON_GetObjectItem(item, "__libc_dlopen_mode"); 135 | if (tmp) { 136 | addr_offset->__libc_dlopen_mode = hex2int(tmp->valuestring); 137 | } else { 138 | ERROR("No __libc_dlopen_mode in json file\n"); 139 | goto FreeJson; 140 | } 141 | } else { 142 | ERROR("Please check libc version in json file\n"); 143 | goto FreeJson; 144 | } 145 | } else { 146 | ERROR("Please check architecture in json file\n"); 147 | goto FreeJson; 148 | } 149 | } 150 | cJSON_Delete(root); 151 | return 0; 152 | FreeJson: 153 | cJSON_Delete(root); 154 | return -1; 155 | } 156 | 157 | /** 158 | * @description: Write offset according to different libc (根据不同的libc,修改汇编代码中的偏移) 159 | * @param {char} *json_name 160 | * @param {char} *arch 161 | * @param {char} *version 162 | * @return {*} 163 | */ 164 | int init_dlopen(char *json_name, char *arch, char *version) { 165 | uint32_t tmp_off; 166 | uint8_t tmp_off_str[4]; 167 | AddrOffset addr_offset; 168 | 169 | if (read_offset(json_name, &addr_offset, arch, version)){ 170 | exit(-1); 171 | } 172 | 173 | /* 32bit */ 174 | if (MODE == ELFCLASS32) { 175 | /* mov ecx, DWORD PTR [ebx + _ld_catch_exception_got(offest->.got.plt)] */ 176 | tmp_off = addr_offset._ld_catch_exception_got; 177 | hex2str(tmp_off, tmp_off_str, 1); 178 | memcpy(sc_x86 + 42, tmp_off_str, 1); 179 | 180 | /* sub ecx, _ld_catch_exception */ 181 | tmp_off = addr_offset._ld_catch_exception; 182 | hex2str(tmp_off, tmp_off_str, 4); 183 | memcpy(sc_x86 + 45, tmp_off_str, 4); 184 | 185 | /* add ecx, __libc_dlopen_mode */ 186 | tmp_off = addr_offset.__libc_dlopen_mode; 187 | hex2str(tmp_off, tmp_off_str, 4); 188 | memcpy(sc_x86 + 51, tmp_off_str, 4); 189 | } 190 | 191 | /* 64bit */ 192 | if (MODE == ELFCLASS64) { 193 | /* mov r9, [rdx + _ld_catch_exception_got - _ld_fini] */ 194 | tmp_off = addr_offset._ld_catch_exception_got - addr_offset._ld_fini; 195 | hex2str(tmp_off, tmp_off_str, 4); 196 | memcpy(sc_x86_64 + 51, tmp_off_str, 4); 197 | 198 | /* sub r9, _ld_catch_exception */ 199 | tmp_off = addr_offset._ld_catch_exception; 200 | hex2str(tmp_off, tmp_off_str, 4); 201 | memcpy(sc_x86_64 + 58, tmp_off_str, 4); 202 | 203 | /* add r9, __libc_dlopen_mode */ 204 | tmp_off = addr_offset.__libc_dlopen_mode; 205 | hex2str(tmp_off, tmp_off_str, 4); 206 | memcpy(sc_x86_64 + 65, tmp_off_str, 4); 207 | } 208 | 209 | return 0; 210 | } 211 | 212 | /** 213 | * @description: Write file name to stack (将文件名写入栈) 214 | * @param {char} *path 215 | * @param {int} size <= 16B 216 | * @return {*} 217 | */ 218 | int name2mem(char *path, int size) { 219 | char revstr[PATH_LENGTH]; 220 | /* 32bit */ 221 | if (MODE == ELFCLASS32) { 222 | if (size <= SO_LENGTH) { 223 | for (int i = 0; i <= size / 4; i++) { 224 | // 9:offset 7: instruction length 225 | char *asm_start = sc_x86 + 9 + i * 7; 226 | memcpy(asm_start, path + i * 4, 4); 227 | } 228 | } else { 229 | ERROR("The string length is greater than %d bytes!\n", SO_LENGTH); 230 | exit(-1); 231 | } 232 | } 233 | 234 | /* 64bit */ 235 | if (MODE == ELFCLASS64) { 236 | if (size <= SO_LENGTH) { 237 | for (int i = 0; i <= size / 8; i++) { 238 | char *asm_start = sc_x86_64 + 10 + i * 10; 239 | memcpy(asm_start, path + i * 8, 8); 240 | } 241 | } else { 242 | ERROR("The string length is greater than %d bytes!\n", SO_LENGTH); 243 | exit(-1); 244 | } 245 | } 246 | } 247 | 248 | /** 249 | * @description: Generate the JAL instruction according to the address to jump (根据要跳转的地址,生成jal指令) 250 | * @param {unsigned int} addr 251 | * @return {*} 252 | */ 253 | int mips_jal_insn(unsigned int addr) { 254 | return ((addr & 0b1111111111111111111111111111) >> 2) + (0b11 << 26); 255 | } 256 | 257 | /** 258 | * @description: Modify the content of a section of elf to load so (修改elf某个节的内容用于加载so) 259 | * @param {char} *elf_name 260 | * @param {char} *modify_sec_name 261 | * @param {char} *so_name 262 | * @param {char} *json_name file contains libc/ld offset 263 | * @param {char} *version libc or ld version 264 | * @return {*} 265 | */ 266 | int inject_so(char *elf_name, char *modify_sec_name, char *so_name, char *json_name, char *version) { 267 | ARCH = get_elf_machine(elf_name); 268 | name2mem(so_name, strlen(so_name) - 1); 269 | char arch[10]; 270 | memset(arch, 0, 10); 271 | 272 | switch (ARCH) { 273 | case EM_386: 274 | strcpy(arch, "x86"); 275 | init_dlopen(json_name, arch, version); 276 | break; 277 | 278 | case EM_X86_64: 279 | strcpy(arch, "x86_64"); 280 | init_dlopen(json_name, arch, version); 281 | break; 282 | 283 | default: 284 | ERROR("Sorry, current architecture is not supported\n"); 285 | return -1; 286 | break; 287 | } 288 | 289 | INFO("architecture: %s\n", arch); 290 | 291 | int fd; 292 | struct stat st; 293 | uint8_t *elf_map; 294 | uint8_t *sec_name; 295 | 296 | fd = open(elf_name, O_RDONLY); 297 | if (fd < 0) { 298 | perror("open"); 299 | return -1; 300 | } 301 | 302 | if (fstat(fd, &st) < 0) { 303 | perror("fstat"); 304 | return -1; 305 | } 306 | 307 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 308 | if (elf_map == MAP_FAILED) { 309 | perror("mmap"); 310 | return -1; 311 | } 312 | 313 | /* 32bit */ 314 | if (MODE == ELFCLASS32) { 315 | Elf32_Ehdr *ehdr; 316 | Elf32_Shdr *shdr; 317 | Elf32_Phdr *phdr; 318 | Elf32_Shdr shstrtab; 319 | Elf32_Shdr sec_text; 320 | uint32_t sec_addr; 321 | uint32_t insn_call_addr; 322 | uint32_t tmp; 323 | 324 | ehdr = (Elf32_Ehdr *)elf_map; 325 | shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff]; 326 | shstrtab = shdr[ehdr->e_shstrndx]; 327 | 328 | for (int i = 0; i < ehdr->e_shnum; i++) { 329 | sec_name = &elf_map[shstrtab.sh_offset + shdr[i].sh_name]; 330 | if (strcmp(".text", sec_name) == 0) { 331 | sec_text = shdr[i]; 332 | break; 333 | } 334 | } 335 | 336 | for (int i = 0; i < ehdr->e_shnum; i++) { 337 | sec_name = &elf_map[shstrtab.sh_offset + shdr[i].sh_name]; 338 | sec_addr = shdr[i].sh_addr; 339 | 340 | // if (strcmp(".eh_frame", sec_name) == 0) { 341 | if (!strcmp(modify_sec_name, sec_name)) { 342 | INFO("%s\toffset: %p\tviraddr: %p\n", sec_name, shdr[i].sh_offset, shdr[i].sh_addr); 343 | tmp = ehdr->e_entry; 344 | // 1. modify entry 345 | ehdr->e_entry = shdr[i].sh_addr; 346 | 347 | // 2. modify section 348 | 349 | // asm: call _start 350 | if (tmp == sec_text.sh_addr) 351 | insn_call_addr = tmp - (ehdr->e_entry + sizeof(sc_x86) - 1); 352 | else 353 | insn_call_addr = sec_text.sh_addr - (ehdr->e_entry + sizeof(sc_x86) - 1); 354 | uint8_t jmp_start[4]; 355 | hex2str(insn_call_addr, jmp_start, 4); 356 | memcpy(&sc_x86[sizeof(sc_x86) - 5], jmp_start, 4); 357 | memcpy(&elf_map[shdr[i].sh_offset], sc_x86, sizeof(sc_x86)); 358 | INFO("%s: %s\n", sec_name, sc_x86); 359 | // asm: call <__libc_dlopen_mode@plt> 360 | INFO("entry point address: %p -> %p\n", tmp, ehdr->e_entry); 361 | break; 362 | } 363 | } 364 | 365 | /* .eh_frame->LOAD R-E */ 366 | phdr = (Elf32_Phdr *)&elf_map[ehdr->e_phoff]; 367 | for (int i = 0; i < ehdr->e_phnum; i++) { 368 | if (phdr[i].p_vaddr <= sec_addr && sec_addr < phdr[i].p_vaddr + phdr[i].p_memsz) { 369 | if (phdr[i].p_type == PT_LOAD) { 370 | uint32_t tmp = phdr[i].p_flags; 371 | phdr[i].p_flags = PF_R | PF_X; 372 | INFO("LOAD offset: %p\tvaddr: %p\n", phdr[i].p_offset, phdr[i].p_vaddr); 373 | INFO("LOAD flag: %p -> %p\n", tmp, phdr[i].p_flags); 374 | break; 375 | } 376 | } 377 | } 378 | } 379 | 380 | /* 64bit */ 381 | if (MODE == ELFCLASS64) { 382 | Elf64_Ehdr *ehdr; 383 | Elf64_Shdr *shdr; 384 | Elf64_Phdr *phdr; 385 | Elf64_Shdr shstrtab; 386 | Elf64_Shdr sec_text; 387 | uint64_t sec_addr; 388 | uint64_t insn_call_addr; 389 | uint64_t tmp; 390 | 391 | ehdr = (Elf64_Ehdr *)elf_map; 392 | shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff]; 393 | shstrtab = shdr[ehdr->e_shstrndx]; 394 | 395 | for (int i = 0; i < ehdr->e_shnum; i++) { 396 | sec_name = &elf_map[shstrtab.sh_offset + shdr[i].sh_name]; 397 | if (strcmp(".text", sec_name) == 0) { 398 | sec_text = shdr[i]; 399 | break; 400 | } 401 | } 402 | 403 | for (int i = 0; i < ehdr->e_shnum; i++) { 404 | sec_name = &elf_map[shstrtab.sh_offset + shdr[i].sh_name]; 405 | sec_addr = shdr[i].sh_addr; 406 | 407 | // if (strcmp(".eh_frame", sec_name) == 0) { 408 | if (!strcmp(modify_sec_name, sec_name)) { 409 | INFO("%s\toffset: %p\tviraddr: %p\n", sec_name, shdr[i].sh_offset, shdr[i].sh_addr); 410 | tmp = ehdr->e_entry; 411 | // 1. modify entry 412 | ehdr->e_entry = shdr[i].sh_addr; 413 | 414 | // 2. modify section 415 | if (tmp == sec_text.sh_addr) 416 | insn_call_addr = tmp - (ehdr->e_entry + sizeof(sc_x86_64) - 1); 417 | else 418 | insn_call_addr = sec_text.sh_addr - (ehdr->e_entry + sizeof(sc_x86_64) - 1); 419 | uint8_t jmp_start[4]; 420 | hex2str(insn_call_addr, jmp_start, 4); 421 | memcpy(&sc_x86_64[sizeof(sc_x86_64) - 5], jmp_start, 4); 422 | memcpy(&elf_map[shdr[i].sh_offset], sc_x86_64, sizeof(sc_x86_64)); 423 | INFO("%s: %s\n", sec_name, sc_x86_64); 424 | INFO("entry point address: %p -> %p\n", tmp, ehdr->e_entry); 425 | break; 426 | } 427 | } 428 | 429 | /* .eh_frame->LOAD R-E */ 430 | phdr = (Elf64_Phdr *)&elf_map[ehdr->e_phoff]; 431 | for (int i = 0; i < ehdr->e_phnum; i++) { 432 | if (phdr[i].p_vaddr <= sec_addr && sec_addr < phdr[i].p_vaddr + phdr[i].p_memsz) { 433 | if (phdr[i].p_type == PT_LOAD) { 434 | uint32_t tmp = phdr[i].p_flags; 435 | phdr[i].p_flags = PF_R | PF_X; 436 | INFO("LOAD offset: %p\tvaddr: %p\n", phdr[i].p_offset, phdr[i].p_vaddr); 437 | INFO("LOAD flag: %p -> %p\n", tmp, phdr[i].p_flags); 438 | break; 439 | } 440 | } 441 | } 442 | } 443 | 444 | #ifdef MIPSEL 445 | uint8_t jmp_start[4]; 446 | hex2str(mips_jal_insn(sec_text.sh_addr), jmp_start); 447 | memcpy(&sc_mipsel[sizeof(sc_mipsel) - 8], jmp_start, 4); 448 | memcpy(&elf_map[shdr[i].sh_offset - 1], sc_mipsel, sizeof(sc_mipsel)); 449 | printf("-------%p----%p\n\n", shdr[i].sh_offset, shdr[i].sh_addr); 450 | #endif 451 | 452 | /* new file */ 453 | create_file(elf_name, elf_map, st.st_size, 1); 454 | 455 | munmap(elf_map, st.st_size); 456 | close(fd); 457 | 458 | return 0; 459 | } -------------------------------------------------------------------------------- /src/injectso.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @description: Modify the content of a section of elf to load so (修改elf某个节的内容用于加载so) 27 | * @param {char} *elf_name 28 | * @param {char} *modify_sec_name 29 | * @param {char} *so_name 30 | * @param {char} *json_name file contains libc/ld offset 31 | * @param {char} *version libc or ld version 32 | * @return {*} 33 | */ 34 | int inject_so(char *elf_name, char *modify_sec_name, char *so_name, char *json_name, char *version); -------------------------------------------------------------------------------- /src/joinelf.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021-2022 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "cJSON/cJSON.h" 33 | 34 | #include "common.h" 35 | 36 | typedef struct Bininfo { 37 | uint8_t *name; // bin file path and name 38 | uint64_t base_addr; // bin load address 39 | uint64_t size; // bin size 40 | uint64_t bin_mem; // bin map 41 | }Bin; 42 | 43 | static int conv_arch(uint8_t *arch) { 44 | if (!(strcmp(arch, "arm") & strcmp(arch, "ARM"))) { 45 | return EM_ARM; 46 | } 47 | 48 | else if (!(strcmp(arch, "x86") & strcmp(arch, "X86"))) { 49 | return EM_386; 50 | } 51 | 52 | else if (!(strcmp(arch, "mips") & strcmp(arch, "MIPS"))) { 53 | return EM_MIPS; 54 | } 55 | 56 | else 57 | return NULL; 58 | } 59 | 60 | /** 61 | * @description: connect each bin in firmware for IDA 62 | * @param {uint8_t} *configure 63 | * @param {uint8_t} *arch 64 | * @param {uint32_t} class 65 | * @param {uint8_t} *endian 66 | * @param {uint8_t} *out 67 | * @return {*} 68 | */ 69 | int join_elf(uint8_t *configure, uint8_t *arch, uint32_t class, uint8_t *endian, uint8_t *out) { 70 | uint32_t count = 0; 71 | uint32_t size = 0; 72 | uint32_t new_size = 0; 73 | uint8_t *new_bin_map; 74 | Bin *bin; 75 | uint8_t *point_t; // map address 76 | uint32_t offset_t; // section address 77 | 78 | cJSON *root = NULL; 79 | root = get_json_object(configure); 80 | if (!root) { 81 | ERROR("Error before: [%s]\n", cJSON_GetErrorPtr()); 82 | return -1; 83 | } else { 84 | count = cJSON_GetArraySize(root); 85 | bin = (Bin *)malloc(sizeof(Bin) * count); 86 | if (bin == NULL) { 87 | perror("malloc"); 88 | return -1; 89 | } 90 | 91 | for (int i = 0; i < count; i++) { 92 | cJSON *item = cJSON_GetArrayItem(root, i); 93 | if (!cJSON_IsNull(item) & item->type == cJSON_String) { 94 | bin[i].base_addr = hex2int(item->string); 95 | bin[i].name = item->valuestring; 96 | int fd = open(bin[i].name, O_RDONLY); 97 | struct stat st; 98 | if (fd < 0) { 99 | ERROR("%s\n", bin[i].name); 100 | perror("open in join_elf"); 101 | free(bin); 102 | cJSON_Delete(root); 103 | return -1; 104 | } 105 | 106 | if (fstat(fd, &st) < 0) { 107 | perror("fstat"); 108 | free(bin); 109 | cJSON_Delete(root); 110 | return -1; 111 | } 112 | 113 | bin[i].size = st.st_size; 114 | bin[i].bin_mem = mmap(0, bin[i].size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 115 | if (bin[i].bin_mem == NULL) { 116 | perror("mmap"); 117 | free(bin); 118 | cJSON_Delete(root); 119 | return -1; 120 | } 121 | 122 | size += bin[i].size; 123 | close(fd); 124 | } 125 | } 126 | } 127 | 128 | if (class == 32) { 129 | /*****| ELF Header | ELF Section header1 | ELF Section header2 |*****/ 130 | new_size = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * (count + 1) + size; 131 | new_bin_map = malloc(new_size); 132 | memset(new_bin_map, 0, new_size); 133 | Elf32_Ehdr ehdr = { 134 | .e_ident = 0x0, 135 | .e_type = ET_EXEC, 136 | .e_machine = conv_arch(arch), 137 | .e_version = EV_CURRENT, 138 | .e_entry = bin[0].base_addr, 139 | .e_phoff = 0, 140 | .e_shoff = sizeof(Elf32_Ehdr), 141 | .e_flags = 0, 142 | .e_ehsize = sizeof(Elf32_Ehdr), 143 | .e_phentsize = sizeof(Elf32_Phdr), 144 | .e_phnum = 0, 145 | .e_shentsize = sizeof(Elf32_Shdr), 146 | .e_shnum = 2, 147 | .e_shstrndx = 0, 148 | }; 149 | if (ehdr.e_machine == EM_ARM) { 150 | ehdr.e_flags = 0x05000200; /* arm32 */ 151 | } 152 | ehdr.e_ident[0] = '\x7f'; 153 | ehdr.e_ident[1] = 'E'; 154 | ehdr.e_ident[2] = 'L'; 155 | ehdr.e_ident[3] = 'F'; 156 | ehdr.e_ident[4] = ELFCLASS32; /* ELF class */ 157 | if (!strcmp(endian, "little")) 158 | ehdr.e_ident[5] = '\x01'; 159 | else if(!strcmp(endian, "big")) 160 | ehdr.e_ident[5] = '\x02'; 161 | ehdr.e_ident[6] = '\x01'; /* EI_VERSION */ 162 | 163 | /*****| ELF Header | ELF Section header1 | ELF Section header2 |*****/ 164 | point_t = new_bin_map; 165 | memcpy(point_t, &ehdr, sizeof(Elf32_Ehdr)); 166 | point_t += sizeof(Elf32_Ehdr); 167 | /***** null section header *****/ 168 | point_t += sizeof(Elf32_Shdr); 169 | offset_t = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * (count + 1); 170 | 171 | for (int i = 0; i < count; i++) { 172 | Elf32_Shdr shdr = { 173 | .sh_name = 0x0, 174 | .sh_type = SHT_PROGBITS, /* Program data */ 175 | .sh_flags = SHF_EXECINSTR, /* Executable */ 176 | .sh_addr = bin[i].base_addr, /* Bin offset */ 177 | .sh_offset = offset_t, 178 | .sh_size = bin[i].size, /* Section(bin) size */ 179 | .sh_link = 0x0, 180 | .sh_info = 0x0, 181 | .sh_addralign = 4, 182 | .sh_entsize = 0x0 183 | }; 184 | memcpy(point_t, &shdr, sizeof(Elf32_Shdr)); 185 | memcpy(offset_t + new_bin_map, bin[i].bin_mem, bin[i].size); 186 | point_t += sizeof(Elf32_Shdr); 187 | offset_t += bin[i].size; 188 | } 189 | } 190 | 191 | create_file(out, new_bin_map, new_size, 0); 192 | free(new_bin_map); 193 | free(bin); 194 | cJSON_Delete(root); 195 | return 0; 196 | } -------------------------------------------------------------------------------- /src/joinelf.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021-2022 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | /** 28 | * @description: connect each bin in firmware for IDA 29 | * @param {uint8_t} *configure 30 | * @param {uint8_t} *arch 31 | * @param {uint32_t} class 32 | * @param {uint8_t} *endian 33 | * @param {uint8_t} *out 34 | * @return {*} 35 | */ 36 | int join_elf(uint8_t *configure, uint8_t *arch, uint32_t class, uint8_t *endian, uint8_t *out); -------------------------------------------------------------------------------- /src/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /* ELF parser options */ 26 | #ifndef __PARSE_H 27 | #define __PARSE_H 28 | typedef enum PARSE_OPT { 29 | ALL = 1, 30 | HEADERS, 31 | SECTIONS, 32 | SEGMENTS, 33 | SYMTAB, 34 | DYNSYM, 35 | LINK, 36 | RELA, 37 | POINTER, 38 | GNUHASH, 39 | END 40 | } PARSE_OPT_T; 41 | 42 | typedef struct parser_opt { 43 | char options[END]; 44 | int index; 45 | } parser_opt_t; 46 | #endif 47 | 48 | #define STR_NUM 0x4096 49 | #define STR_LENGTH 0x1024 50 | struct ElfData { 51 | size_t count; 52 | uint64_t value[STR_NUM]; 53 | char name[STR_NUM][STR_LENGTH]; 54 | }; 55 | 56 | int parse(char *elf, parser_opt_t *po, uint32_t length); 57 | 58 | /** 59 | * @description: Judge whether the option is true 60 | * @param {parser_opt_t} po 61 | * @param {PARSE_OPT_T} option 62 | * @return {*} 63 | */ 64 | int get_option(parser_opt_t *po, PARSE_OPT_T option); 65 | -------------------------------------------------------------------------------- /src/rel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "common.h" 10 | #include "parse.h" 11 | #include "rel.h" 12 | 13 | extern struct ElfData g_dynsym; 14 | extern parser_opt_t po; 15 | 16 | /** 17 | * @brief 初始化elf文件,将elf文件转化为elf结构体 18 | * initialize the elf file and convert it into an elf structure 19 | * @param elf elf file name 20 | * @return error code {-1:error, 0:success} 21 | */ 22 | int init_elf(char *elf, handle_t32 *h32, handle_t64 *h64) { 23 | int fd = -1; 24 | struct stat st; 25 | uint8_t *elf_map = NULL; 26 | 27 | memset(h32, 0, sizeof(handle_t32)); 28 | memset(h64, 0, sizeof(handle_t64)); 29 | 30 | if (MODE == -1) { 31 | return -1; 32 | } 33 | 34 | fd = open(elf, O_RDWR); 35 | if (fd < 0) { 36 | perror("open"); 37 | return -1; 38 | } 39 | 40 | if (fstat(fd, &st) < 0) { 41 | perror("fstat"); 42 | close(fd); 43 | return -1; 44 | } 45 | 46 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 47 | if (elf_map == MAP_FAILED) { 48 | perror("mmap"); 49 | close(fd); 50 | return -1; 51 | } 52 | 53 | /* 32bit */ 54 | if (MODE == ELFCLASS32) { 55 | h32->mem = elf_map; 56 | h32->ehdr = (Elf32_Ehdr *)h32->mem; 57 | h32->shdr = (Elf32_Shdr *)&h32->mem[h32->ehdr->e_shoff]; 58 | h32->phdr = (Elf32_Phdr *)&h32->mem[h32->ehdr->e_phoff]; 59 | h32->shstrtab = (Elf32_Shdr *)&h32->shdr[h32->ehdr->e_shstrndx]; 60 | h32->size = st.st_size; 61 | } 62 | 63 | /* 64bit */ 64 | if (MODE == ELFCLASS64) { 65 | h64->mem = elf_map; 66 | h64->ehdr = (Elf64_Ehdr *)h64->mem; 67 | h64->shdr = (Elf64_Shdr *)&h64->mem[h64->ehdr->e_shoff]; 68 | h64->phdr = (Elf64_Phdr *)&h64->mem[h64->ehdr->e_phoff]; 69 | h64->shstrtab = (Elf64_Shdr *)&h64->shdr[h64->ehdr->e_shstrndx]; 70 | h64->size = st.st_size; 71 | } 72 | 73 | /* init symbol string table*/ 74 | parse(elf, &po, 0); 75 | return 0; 76 | } 77 | 78 | int finit_elf(handle_t32 *h32, handle_t64 *h64) { 79 | close(h32->fd); 80 | munmap(h32->mem, h32->size); 81 | close(h64->fd); 82 | munmap(h64->mem, h64->size); 83 | } 84 | 85 | /** 86 | * @brief 根据节名,获取节的下标 87 | * obtain the index of the section based on its name 88 | * @param h elf struct 89 | * @param sec_name section name, such as .rela.plt 90 | * @return section index {-1:error} 91 | */ 92 | int get_sec_index32(handle_t32 *h, char *sec_name) { 93 | void *tmp_name = NULL; 94 | h->sec_index = -1; 95 | for (int i = 0; i < h->ehdr->e_shnum; i++) { 96 | tmp_name = h->mem + h->shstrtab->sh_offset + h->shdr[i].sh_name; 97 | if (validated_offset(tmp_name, h->mem, h->mem + h->size)) { 98 | ERROR("Corrupt file format\n"); 99 | return -1; 100 | } 101 | if (!strcmp(tmp_name, sec_name)) { 102 | h->sec_index = i; 103 | h->sec_size = h->shdr[i].sh_size; 104 | break; 105 | } 106 | } 107 | return h->sec_index; 108 | } 109 | 110 | int get_sec_index64(handle_t64 *h, char *sec_name) { 111 | void *tmp_name = NULL; 112 | h->sec_index = -1; 113 | for (int i = 0; i < h->ehdr->e_shnum; i++) { 114 | tmp_name = h->mem + h->shstrtab->sh_offset + h->shdr[i].sh_name; 115 | if (validated_offset(tmp_name, h->mem, h->mem + h->size)) { 116 | ERROR("Corrupt file format\n"); 117 | return -1; 118 | } 119 | if (!strcmp(tmp_name, sec_name)) { 120 | h->sec_index = i; 121 | h->sec_size = h->shdr[i].sh_size; 122 | break; 123 | } 124 | } 125 | return h->sec_index; 126 | } 127 | 128 | /** 129 | * @brief 根据节名,获取relocation 130 | * obtain .rel section based on its name 131 | * @param h elf struct 132 | * @param sec_name section name, such as .rel.plt 133 | * @param rel output .rel content 134 | * @return section index {-1:error} 135 | */ 136 | int get_rel32(handle_t32 *h, char *sec_name, Elf32_Rel **rel) { 137 | if (get_sec_index32(h, sec_name) < 0) { 138 | return -1; 139 | } 140 | *rel = h->mem + h->shdr[h->sec_index].sh_offset; 141 | return 0; 142 | } 143 | 144 | int get_rel64(handle_t64 *h, char *sec_name, Elf64_Rel **rel) { 145 | if (get_sec_index64(h, sec_name) < 0) { 146 | return -1; 147 | } 148 | *rel = h->mem + h->shdr[h->sec_index].sh_offset; 149 | return 0; 150 | } 151 | 152 | /** 153 | * @brief 根据节名,获取relocation 154 | * obtain .rela section based on its name 155 | * @param h elf struct 156 | * @param sec_name section name, such as .rela.plt 157 | * @param rela output .rel content 158 | * @return section index {-1:error} 159 | */ 160 | int get_rela32(handle_t32 *h, char *sec_name, Elf32_Rela **rela) { 161 | if (get_sec_index32(h, sec_name) < 0) { 162 | return -1; 163 | } 164 | *rela = h->mem + h->shdr[h->sec_index].sh_offset; 165 | return 0; 166 | } 167 | 168 | int get_rela64(handle_t64 *h, char *sec_name, Elf64_Rela **rela) { 169 | if (get_sec_index64(h, sec_name) < 0) { 170 | return -1; 171 | } 172 | *rela = h->mem + h->shdr[h->sec_index].sh_offset; 173 | return 0; 174 | } 175 | 176 | // rel.plt, .rela.plt, .rel.dyn, .rela.dyn, .rel.android, .rela.android 177 | /** 178 | * @brief 得到重定位符号的偏移(其实是指地址,而非文件偏移) 179 | * obtain the offset of the relocation symbol (actually referring to the address, not the file offset) 180 | * @param h elf file struct 181 | * @param sec_name section name 182 | * @return item address {-1:error, 0:success} 183 | */ 184 | uint32_t get_rel32_addr(handle_t32 *h, char *sec_name, int index) { 185 | Elf32_Rel *rel; 186 | if (get_rel32(h, sec_name, &rel)) { 187 | return -1; 188 | } 189 | if (index > h->sec_size / sizeof(Elf32_Rel)) { 190 | return -1; 191 | } 192 | return rel[index].r_offset; 193 | } 194 | 195 | uint64_t get_rel64_addr(handle_t64 *h, char *sec_name, int index) { 196 | Elf64_Rel *rel; 197 | if (get_rel64(h, sec_name, &rel)) { 198 | return -1; 199 | } 200 | if (index > h->sec_size / sizeof(Elf64_Rel)) { 201 | return -1; 202 | } 203 | return rel[index].r_offset; 204 | } 205 | 206 | /** 207 | * @brief 得到重定位符号的偏移(其实是指地址,而非文件偏移) 208 | * obtain the offset of the relocation symbol (actually referring to the address, not the file offset) 209 | * @param h elf file struct 210 | * @param sec_name section name 211 | * @return item address {-1:error, 0:success} 212 | */ 213 | uint32_t get_rela32_addr(handle_t32 *h, char *sec_name, int index) { 214 | Elf32_Rela *rela; 215 | if (get_rela32(h, sec_name, &rela)) { 216 | return -1; 217 | } 218 | if (index > h->sec_size / sizeof(Elf32_Rela)) { 219 | return -1; 220 | } 221 | return rela[index].r_offset; 222 | } 223 | 224 | uint64_t get_rela64_addr(handle_t64 *h, char *sec_name, int index) { 225 | Elf64_Rela *rela; 226 | if (get_rela64(h, sec_name, &rela)) { 227 | return -1; 228 | } 229 | if (index > h->sec_size / sizeof(Elf64_Rela)) { 230 | return -1; 231 | } 232 | return rela[index].r_offset; 233 | } 234 | 235 | /** 236 | * @brief 得到重定位符号的符号名 237 | * obtain the name of the relocation symbol 238 | * @param h elf file struct 239 | * @param sec_name section name 240 | * @param index .rel section item index 241 | * @param name symbol name 242 | * @return error code {-1:error, 0:success} 243 | */ 244 | int get_rel32_name(handle_t32 *h, char *sec_name, int index, char **name) { 245 | Elf32_Rel *rel; 246 | if (get_rel32(h, sec_name, &rel)) { 247 | return -1; 248 | } 249 | if (index > h->sec_size / sizeof(Elf32_Rel)) { 250 | return -1; 251 | } 252 | int str_index = ELF32_R_SYM(rel[index].r_info); 253 | *name = &g_dynsym.name[str_index]; 254 | return 0; 255 | } 256 | 257 | int get_rel64_name(handle_t64 *h, char *sec_name, int index, char **name) { 258 | Elf64_Rel *rel; 259 | if (get_rel64(h, sec_name, &rel)) { 260 | return -1; 261 | } 262 | if (index > h->sec_size / sizeof(Elf64_Rel)) { 263 | return -1; 264 | } 265 | int str_index = ELF64_R_SYM(rel[index].r_info); 266 | *name = &g_dynsym.name[str_index]; 267 | return 0; 268 | } 269 | 270 | int get_rela32_name(handle_t32 *h, char *sec_name, int index, char **name) { 271 | Elf32_Rela *rela; 272 | if (get_rela32(h, sec_name, &rela)) { 273 | return -1; 274 | } 275 | if (index > h->sec_size / sizeof(Elf64_Rel)) { 276 | return -1; 277 | } 278 | int str_index = ELF32_R_SYM(rela[index].r_info); 279 | *name = &g_dynsym.name[str_index]; 280 | return 0; 281 | } 282 | 283 | int get_rela64_name(handle_t64 *h, char *sec_name, int index, char **name) { 284 | Elf64_Rela *rela; 285 | if (get_rela64(h, sec_name, &rela)) { 286 | return -1; 287 | } 288 | if (index > h->sec_size / sizeof(Elf64_Rel)) { 289 | return -1; 290 | } 291 | int str_index = ELF64_R_SYM(rela[index].r_info); 292 | *name = &g_dynsym.name[str_index]; 293 | return 0; 294 | } 295 | 296 | /** 297 | * @brief 得到重定位符号的文件偏移 298 | * obtain the file offset of the relocation symbol 299 | * @param h elf file struct 300 | * @param sec_name section name 301 | * @return item file offset {-1:error, 0:success} 302 | */ 303 | uint32_t get_rel32_offset(handle_t32 *h, char *sec_name, int index) { 304 | uint32_t addr = get_rel32_addr(h, sec_name, index); 305 | int ret = get_sec_index32(h, ".got.plt"); 306 | if (ret < 0) { 307 | return -1; 308 | } 309 | int diff = h->shdr[h->sec_index].sh_addr - h->shdr[h->sec_index].sh_offset; 310 | // refresh .rela.plt size 311 | get_rel32_addr(h, sec_name, index); 312 | return addr - diff; 313 | } 314 | 315 | uint64_t get_rel64_offset(handle_t64 *h, char *sec_name, int index) { 316 | uint64_t addr = get_rel64_addr(h, sec_name, index); 317 | int ret = get_sec_index64(h, ".got.plt"); 318 | if (ret < 0) { 319 | return -1; 320 | } 321 | int diff = h->shdr[h->sec_index].sh_addr - h->shdr[h->sec_index].sh_offset; 322 | // refresh .rela.plt size 323 | get_rel64_addr(h, sec_name, index); 324 | return addr - diff; 325 | } 326 | 327 | uint32_t get_rela32_offset(handle_t32 *h, char *sec_name, int index) { 328 | uint32_t addr = get_rela32_addr(h, sec_name, index); 329 | int ret = get_sec_index32(h, ".got.plt"); 330 | if (ret < 0) { 331 | return -1; 332 | } 333 | int diff = h->shdr[h->sec_index].sh_addr - h->shdr[h->sec_index].sh_offset; 334 | // refresh .rela.plt size 335 | get_rela32_addr(h, sec_name, index); 336 | return addr - diff; 337 | } 338 | 339 | uint64_t get_rela64_offset(handle_t64 *h, char *sec_name, int index) { 340 | uint64_t addr = get_rela64_addr(h, sec_name, index); 341 | int ret = get_sec_index64(h, ".got.plt"); 342 | if (ret < 0) { 343 | return -1; 344 | } 345 | int diff = h->shdr[h->sec_index].sh_addr - h->shdr[h->sec_index].sh_offset; 346 | // refresh .rela.plt size 347 | get_rela64_addr(h, sec_name, index); 348 | return addr - diff; 349 | } 350 | 351 | // /** 352 | // * @brief 根据下标获取某一项重定位 353 | // * retrieve a relocation based on the index 354 | // * @param elf_name elf name 355 | // * @param section_name section name, such as .rela.plt 356 | // * @param idnex relocation item index 357 | // * @return all relocation size 358 | // */ 359 | // int get_rel(char *elf_name, char *section_name, int index, char *out_relocation) { 360 | // int fd; 361 | // struct stat st; 362 | // uint8_t *elf_map; 363 | // uint8_t *tmp_sec_name; 364 | // size_t size = 0; 365 | 366 | // fd = open(elf_name, O_RDWR); 367 | // if (fd < 0) { 368 | // perror("open"); 369 | // return -1; 370 | // } 371 | 372 | // if (fstat(fd, &st) < 0) { 373 | // perror("fstat"); 374 | // return -1; 375 | // } 376 | 377 | // elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 378 | // if (elf_map == MAP_FAILED) { 379 | // perror("mmap"); 380 | // return -1; 381 | // } 382 | 383 | // /* 32bit */ 384 | // if (MODE == ELFCLASS32) { 385 | // Elf32_Ehdr *ehdr; 386 | // Elf32_Shdr *shdr; 387 | // Elf32_Shdr shstrtab; 388 | // Elf32_Rel *rel; 389 | // Elf32_Rela *rela; 390 | 391 | // ehdr = (Elf32_Ehdr *)elf_map; 392 | // shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff]; 393 | // shstrtab = shdr[ehdr->e_shstrndx]; 394 | 395 | // for (int i = 0; i < ehdr->e_shnum; i++) { 396 | // tmp_sec_name = elf_map + shstrtab.sh_offset + shdr[i].sh_name; 397 | // if (!strcmp(section_name, tmp_sec_name)) { 398 | // rel = (Elf32_Rel *)(elf_map + shdr[i].sh_offset); 399 | // rela = (Elf32_Rela *)(elf_map + shdr[i].sh_offset); 400 | // size = shdr[i].sh_size; 401 | // break; 402 | // } 403 | // } 404 | 405 | // if (!compare_firstN_chars(section_name, ".rela", 5)) { 406 | // memcpy(out_relocation, &rela[index], sizeof(Elf32_Rela)); 407 | // } else if (!compare_firstN_chars(section_name, ".rel.", 5)) { 408 | // memcpy(out_relocation, &rel[index], sizeof(Elf32_Rel)); 409 | // } 410 | // } 411 | 412 | // /* 64bit */ 413 | // if (MODE == ELFCLASS64) { 414 | // } 415 | 416 | // close(fd); 417 | // munmap(elf_map, st.st_size); 418 | // return size; 419 | // } 420 | 421 | // /** 422 | // * @brief 重定位节的项目的地址 423 | // * get relocation item address 424 | // * @param elf_name elf name 425 | // * @param section_name section name, such as .rela.plt 426 | // * @return item address/offset 427 | // */ 428 | // int get_rel_addr(char *elf_name, char *section_name, int index) { 429 | // size_t size = 0; 430 | // if (MODE == ELFCLASS32) { 431 | // if (!compare_firstN_chars(section_name, ".rela", 5)) { 432 | // Elf32_Rela rela; 433 | // size = get_rel(elf_name, section_name, index, &rela); 434 | // if (!size) { 435 | // return -1; 436 | // } 437 | // return rela.r_offset; 438 | // } else if (!compare_firstN_chars(section_name, ".rel.", 5)) { 439 | // Elf32_Rel rel; 440 | // size = get_rel(elf_name, section_name, index, &rel); 441 | // if (!size) { 442 | // return -1; 443 | // } 444 | // return rel.r_offset; 445 | // } 446 | // } else if (MODE == ELFCLASS64) { 447 | // if (!compare_firstN_chars(section_name, ".rela", 5)) { 448 | // Elf64_Rela rela; 449 | // size = get_rel(elf_name, section_name, index, &rela); 450 | // if (!size) { 451 | // return -1; 452 | // } 453 | // return rela.r_offset; 454 | // } else if (!compare_firstN_chars(section_name, ".rel.", 5)) { 455 | // Elf64_Rel rel; 456 | // size = get_rel(elf_name, section_name, index, &rel); 457 | // if (!size) { 458 | // return -1; 459 | // } 460 | // return rel.r_offset; 461 | // } 462 | // } 463 | // } -------------------------------------------------------------------------------- /src/rel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief 得到重定位符号的偏移(其实是指地址,而非文件偏移) 3 | * obtain the offset of the relocation symbol (actually referring to the address, not the file offset) 4 | * @param h elf file struct 5 | * @param sec_name section name 6 | * @return item address {-1:error, 0:success} 7 | */ 8 | uint32_t get_rel32_addr(handle_t32 *h, char *sec_name, int index); 9 | uint64_t get_rel64_addr(handle_t64 *h, char *sec_name, int index); 10 | uint32_t get_rela32_addr(handle_t32 *h, char *sec_name, int index); 11 | uint64_t get_rela64_addr(handle_t64 *h, char *sec_name, int index); 12 | 13 | /** 14 | * @brief 得到重定位符号的符号名 15 | * obtain the name of the relocation symbol 16 | * @param h elf file struct 17 | * @param sec_name section name 18 | * @param index .rel section item index 19 | * @param name symbol name 20 | * @return error code {-1:error, 0:success} 21 | */ 22 | int get_rel32_name(handle_t32 *h, char *sec_name, int index, char **name); 23 | int get_rel64_name(handle_t64 *h, char *sec_name, int index, char **name); 24 | int get_rela32_name(handle_t32 *h, char *sec_name, int index, char **name); 25 | int get_rela64_name(handle_t64 *h, char *sec_name, int index, char **name); 26 | 27 | /** 28 | * @brief 得到重定位符号的文件偏移 29 | * obtain the file offset of the relocation symbol 30 | * @param h elf file struct 31 | * @param sec_name section name 32 | * @return item file offset {-1:error, 0:success} 33 | */ 34 | uint32_t get_rel32_offset(handle_t32 *h, char *sec_name, int index); 35 | uint64_t get_rel64_offset(handle_t64 *h, char *sec_name, int index); 36 | uint32_t get_rela32_offset(handle_t32 *h, char *sec_name, int index); 37 | uint64_t get_rela64_offset(handle_t64 *h, char *sec_name, int index); -------------------------------------------------------------------------------- /src/section.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #define _GNU_SOURCE 1 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "common.h" 35 | #include "cJSON/cJSON.h" 36 | 37 | /** 38 | * @brief 判断节头表是否在文件结尾 39 | * determine if section header table is at the end of the file 40 | * @param elfname elf file name 41 | * @return int result code {-1:error,0:false,1:true} 42 | */ 43 | static int is_shdr_end(char *elfname) { 44 | int fd; 45 | struct stat st; 46 | uint8_t *mapped; 47 | 48 | fd = open(elfname, O_RDWR); 49 | if (fd < 0) { 50 | perror("open"); 51 | return -1; 52 | } 53 | 54 | if (fstat(fd, &st) < 0) { 55 | perror("fstat"); 56 | return -1; 57 | } 58 | 59 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 60 | if (mapped == MAP_FAILED) { 61 | perror("mmap"); 62 | return -1; 63 | } 64 | 65 | /* 32bit */ 66 | if (MODE == ELFCLASS32) { 67 | Elf32_Ehdr *ehdr; 68 | ehdr = (Elf32_Ehdr *)mapped; 69 | if (ehdr->e_shoff + ehdr->e_shnum * sizeof(Elf32_Shdr) == st.st_size) { 70 | goto TRUE; 71 | } 72 | } 73 | 74 | /* 64bit */ 75 | if (MODE == ELFCLASS64) { 76 | Elf64_Ehdr *ehdr; 77 | ehdr = (Elf64_Ehdr *)mapped; 78 | if (ehdr->e_shoff + ehdr->e_shnum * sizeof(Elf64_Shdr) == st.st_size) { 79 | goto TRUE; 80 | } 81 | } 82 | 83 | close(fd); 84 | munmap(mapped, st.st_size); 85 | return 0; 86 | TRUE: 87 | close(fd); 88 | munmap(mapped, st.st_size); 89 | return 1; 90 | } 91 | 92 | /** 93 | * @brief 将节头表移动到文件的另外一个位置 94 | * move the section header table to another location in the file 95 | * @param elfname elf file name 96 | * @param offset start address 97 | * @return int error code {-1:error,0:sucess} 98 | */ 99 | static int mov_shdr(char *elf_name, uint64_t offset) { 100 | int fd; 101 | struct stat st; 102 | void *mapped; 103 | size_t shdr_size; 104 | size_t file_size; 105 | 106 | fd = open(elf_name, O_RDWR); 107 | if (fd < 0) { 108 | perror("open"); 109 | return -1; 110 | } 111 | 112 | if (fstat(fd, &st) < 0) { 113 | perror("fstat"); 114 | return -1; 115 | } 116 | 117 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 118 | if (mapped == MAP_FAILED) { 119 | perror("mmap"); 120 | return -1; 121 | } 122 | 123 | file_size = st.st_size; 124 | 125 | /* 32bit */ 126 | if (MODE == ELFCLASS32) { 127 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *)mapped; 128 | shdr_size = ehdr->e_shnum * sizeof(Elf32_Shdr); 129 | 130 | // 扩展文件大小 131 | file_size = file_size + shdr_size - (st.st_size - offset); 132 | ftruncate(fd, file_size); 133 | // 更新内存映射 134 | mapped = mremap(mapped, st.st_size, file_size, MREMAP_MAYMOVE); 135 | if (mapped == MAP_FAILED) { 136 | perror("mremap"); 137 | goto ERR_EXIT; 138 | } 139 | ehdr = (Elf32_Ehdr *)mapped; 140 | // 拷贝节头表 141 | char *shdr_tmp = malloc(shdr_size); 142 | memcpy(shdr_tmp, mapped + ehdr->e_shoff, shdr_size); 143 | memcpy(mapped + offset, shdr_tmp, shdr_size); 144 | free(shdr_tmp); 145 | // 更新节头表的偏移 146 | ehdr->e_shoff = offset; 147 | } 148 | 149 | /* 64bit */ 150 | if (MODE == ELFCLASS64) { 151 | Elf64_Ehdr *ehdr = (Elf64_Ehdr *)mapped; 152 | shdr_size = ehdr->e_shnum * sizeof(Elf64_Shdr); 153 | 154 | // 扩展文件大小 155 | file_size = file_size + shdr_size - (st.st_size - offset); 156 | ftruncate(fd, file_size); 157 | // 更新内存映射 158 | mapped = mremap(mapped, st.st_size, file_size, MREMAP_MAYMOVE); 159 | if (mapped == MAP_FAILED) { 160 | perror("mremap"); 161 | goto ERR_EXIT; 162 | } 163 | ehdr = (Elf64_Ehdr *)mapped; 164 | // 拷贝节头表 165 | char *shdr_tmp = malloc(shdr_size); 166 | memcpy(shdr_tmp, mapped + ehdr->e_shoff, shdr_size); 167 | memcpy(mapped + offset, shdr_tmp, shdr_size); 168 | free(shdr_tmp); 169 | // 更新节头表的偏移 170 | ehdr->e_shoff = offset; 171 | } 172 | 173 | close(fd); 174 | munmap(mapped, file_size); 175 | return 0; 176 | 177 | ERR_EXIT: 178 | close(fd); 179 | munmap(mapped, file_size); 180 | return -1; 181 | } 182 | 183 | /** 184 | * @brief 增加一个节头表 185 | * add a section header table 186 | * @param elfname elf file name 187 | * @return int section index {-1:error,0:sucess} 188 | */ 189 | int add_shdr(char *elfname) { 190 | int fd; 191 | struct stat st; 192 | uint8_t *mapped; 193 | uint64_t tmpsize; 194 | int index; 195 | 196 | fd = open(elfname, O_RDWR); 197 | if (fd < 0) { 198 | perror("open"); 199 | return -1; 200 | } 201 | 202 | if (fstat(fd, &st) < 0) { 203 | perror("fstat"); 204 | return -1; 205 | } 206 | 207 | if (MODE == ELFCLASS32) { 208 | tmpsize = st.st_size + sizeof(Elf32_Shdr); 209 | } 210 | if (MODE == ELFCLASS64) { 211 | tmpsize = st.st_size + sizeof(Elf64_Shdr); 212 | } 213 | 214 | ftruncate(fd, tmpsize); 215 | mapped = mmap(0, tmpsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 216 | if (mapped == MAP_FAILED) { 217 | perror("mmap"); 218 | return -1; 219 | } 220 | 221 | if (MODE == ELFCLASS32) { 222 | Elf32_Ehdr *ehdr; 223 | Elf32_Shdr *shdr; 224 | ehdr = (Elf32_Ehdr *)mapped; 225 | shdr = (Elf32_Shdr *)&mapped[ehdr->e_shoff]; 226 | ehdr->e_shnum += 1; 227 | index = ehdr->e_shnum - 1; 228 | } 229 | 230 | else if (MODE == ELFCLASS64) { 231 | Elf64_Ehdr *ehdr; 232 | Elf64_Shdr *shdr; 233 | ehdr = (Elf64_Ehdr *)mapped; 234 | shdr = (Elf64_Shdr *)&mapped[ehdr->e_shoff]; 235 | ehdr->e_shnum += 1; 236 | index = ehdr->e_shnum - 1; 237 | } 238 | 239 | close(fd); 240 | munmap(mapped, st.st_size); 241 | return index; 242 | } 243 | 244 | /** 245 | * @brief 增加一个节 246 | * add a section 247 | * @param elfname 248 | * @param size section size 249 | * @return int section index 250 | */ 251 | int add_section(char *elfname, size_t size) { 252 | int fd; 253 | struct stat st; 254 | uint8_t *mapped; 255 | uint64_t secoffset; // segment offset 256 | int index; // shdr index 257 | 258 | // 判断shdr是否在文件结尾 259 | // determine if SHDR is at the end of the file 260 | if(is_shdr_end(elfname) != 1) { 261 | VERBOSE("section header table is not at the end of the file\n"); 262 | VERBOSE("move section header table\n"); 263 | mov_shdr(elfname, get_file_size(elfname)); 264 | } else { 265 | VERBOSE("section header table is at the end of the file\n"); 266 | } 267 | 268 | // 节头表往后移size 269 | // move the section header table back size 270 | secoffset = get_shdr_offset(elfname); 271 | if (size) { 272 | mov_shdr(elfname, secoffset + size); 273 | } 274 | VERBOSE("move the shdr: %d\n", size); 275 | 276 | // 如果节头表在ELF文件末尾处,直接增加一个节头 277 | // if section header is at the end of elf 278 | index = add_shdr(elfname); 279 | VERBOSE("add a shdr: [%d]\n", index); 280 | 281 | // 设置新增的节的参数 282 | // set new segment args 283 | fd = open(elfname, O_RDWR); 284 | if (fd < 0) { 285 | perror("open"); 286 | return -1; 287 | } 288 | 289 | if (fstat(fd, &st) < 0) { 290 | perror("fstat"); 291 | return -1; 292 | } 293 | 294 | mapped = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 295 | if (mapped == MAP_FAILED) { 296 | perror("mmap"); 297 | return -1; 298 | } 299 | 300 | if (MODE == ELFCLASS32) { 301 | Elf32_Ehdr *ehdr; 302 | Elf32_Shdr *shdr; 303 | ehdr = (Elf32_Ehdr *)mapped; 304 | shdr = (Elf32_Shdr *)&mapped[ehdr->e_shoff]; 305 | // 增加节头的同时,又增加了节的大小,这时需要设置新增的节头参数 306 | // at the same time as adding a section header, the size of the section is also increased. 307 | // in this case, it is necessary to set the parameters for the newly added section header. 308 | if (size) { 309 | shdr[index].sh_offset = secoffset; 310 | shdr[index].sh_size = size; 311 | } 312 | } 313 | 314 | if (MODE == ELFCLASS64) { 315 | Elf64_Ehdr *ehdr; 316 | Elf64_Shdr *shdr; 317 | ehdr = (Elf64_Ehdr *)mapped; 318 | shdr = (Elf64_Shdr *)&mapped[ehdr->e_shoff]; 319 | // 增加节头的同时,又增加了节的大小,这时需要设置新增的节头参数 320 | // at the same time as adding a section header, the size of the section is also increased. 321 | // in this case, it is necessary to set the parameters for the newly added section header. 322 | if (size) { 323 | shdr[index].sh_offset = secoffset; 324 | shdr[index].sh_size = size; 325 | } 326 | } 327 | 328 | VERBOSE("add section successfully: [%d]\n", index); 329 | close(fd); 330 | munmap(mapped, st.st_size); 331 | return index; 332 | } 333 | 334 | /** 335 | * @brief Get the section content 336 | * 337 | * @param elf_name original file name 338 | * @param section_name input argument: section name 339 | * @param section_info output argument: section content 340 | * @return error code {-1:error,0:sucess} 341 | */ 342 | int get_section(char *elf_name, char *section_name, char *section_info) { 343 | int fd; // file descriptor 344 | int result; // return result 345 | struct stat st; 346 | uint8_t *elf_map; 347 | uint8_t *name; 348 | int flag = 0; 349 | 350 | fd = open(elf_name, O_RDONLY); 351 | if (fd < 0) { 352 | perror("open"); 353 | return -1; 354 | } 355 | 356 | if (fstat(fd, &st) < 0) { 357 | perror("fstat"); 358 | return -1; 359 | } 360 | 361 | elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 362 | if (elf_map == MAP_FAILED) { 363 | perror("mmap"); 364 | return -1; 365 | } 366 | 367 | /* 32bit */ 368 | if (MODE == ELFCLASS32) { 369 | Elf32_Ehdr *ehdr; 370 | Elf32_Shdr *shdr; 371 | Elf32_Shdr shstrtab; 372 | 373 | ehdr = (Elf32_Ehdr *)elf_map; 374 | shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff]; 375 | shstrtab = shdr[ehdr->e_shstrndx]; 376 | 377 | for (int i = 0; i < ehdr->e_shnum; i++) { 378 | name = elf_map + shstrtab.sh_offset + shdr[i].sh_name; 379 | if (validated_offset(name, elf_map, elf_map + st.st_size)) { 380 | ERROR("Corrupt file format\n"); 381 | goto ERR_EXIT; 382 | } 383 | if (!strcmp(name, section_name)) { 384 | flag = 1; 385 | result = i; 386 | memcpy(section_info, &shdr[i], sizeof(Elf32_Shdr)); 387 | break; 388 | } 389 | } 390 | } 391 | 392 | /* 64bit */ 393 | else if (MODE == ELFCLASS64) { 394 | Elf64_Ehdr *ehdr; 395 | Elf64_Shdr *shdr; 396 | Elf64_Shdr shstrtab; 397 | 398 | ehdr = (Elf64_Ehdr *)elf_map; 399 | shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff]; 400 | shstrtab = shdr[ehdr->e_shstrndx]; 401 | 402 | for (int i = 0; i < ehdr->e_shnum; i++) { 403 | name = elf_map + shstrtab.sh_offset + shdr[i].sh_name; 404 | if (validated_offset(name, elf_map, elf_map + st.st_size)) { 405 | ERROR("Corrupt file format\n"); 406 | goto ERR_EXIT; 407 | } 408 | if (!strcmp(name, section_name)) { 409 | flag = 1; 410 | result = i; 411 | memcpy(section_info, &shdr[i], sizeof(Elf32_Shdr)); 412 | break; 413 | } 414 | } 415 | } 416 | 417 | else { 418 | ERROR("Invalid ELF class"); 419 | goto ERR_EXIT; 420 | } 421 | 422 | if (!flag) { 423 | DEBUG("This file does not have %s\n", section_name); 424 | goto ERR_EXIT; 425 | } 426 | 427 | close(fd); 428 | munmap(elf_map, st.st_size); 429 | return result; 430 | 431 | ERR_EXIT: 432 | close(fd); 433 | munmap(elf_map, st.st_size); 434 | return -1; 435 | }; 436 | 437 | /** 438 | * @brief Get the section address 439 | * 440 | * @param elf_name original file name 441 | * @param section_name section name 442 | * @return section address 443 | */ 444 | int get_section_addr(char *elf_name, char *section_name) { 445 | if (MODE == ELFCLASS32) { 446 | Elf32_Shdr section_info; 447 | get_section(elf_name, section_name, §ion_info); 448 | return section_info.sh_addr; 449 | } else if (MODE == ELFCLASS64) { 450 | Elf64_Shdr section_info; 451 | get_section(elf_name, section_name, §ion_info); 452 | return section_info.sh_addr; 453 | } 454 | } 455 | 456 | /** 457 | * @brief Get the section file offset address 458 | * 459 | * @param elf_name original file name 460 | * @param section_name section name 461 | * @return section file offset address 462 | */ 463 | int get_section_offset(char *elf_name, char *section_name) { 464 | if (MODE == ELFCLASS32) { 465 | Elf32_Shdr section_info; 466 | get_section(elf_name, section_name, §ion_info); 467 | return section_info.sh_offset; 468 | } else if (MODE == ELFCLASS64) { 469 | Elf64_Shdr section_info; 470 | get_section(elf_name, section_name, §ion_info); 471 | return section_info.sh_offset; 472 | } 473 | } 474 | 475 | /** 476 | * @brief Get the section size 477 | * 478 | * @param elf_name original file name 479 | * @param section_name section name 480 | * @return section size 481 | */ 482 | size_t get_section_size(char *elf_name, char *section_name) { 483 | if (MODE == ELFCLASS32) { 484 | Elf32_Shdr section_info; 485 | get_section(elf_name, section_name, §ion_info); 486 | return section_info.sh_size; 487 | } else if (MODE == ELFCLASS64) { 488 | Elf64_Shdr section_info; 489 | get_section(elf_name, section_name, §ion_info); 490 | return section_info.sh_size; 491 | } 492 | } 493 | 494 | /** 495 | * @brief Get the section index 496 | * 497 | * @param elf_name original file name 498 | * @param section_name section name 499 | * @return section index 500 | */ 501 | int get_section_index(char *elf_name, char *section_name) { 502 | Elf64_Shdr section_info; 503 | return get_section(elf_name, section_name, §ion_info); 504 | } 505 | -------------------------------------------------------------------------------- /src/section.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @brief 增加一个节 27 | * add a section 28 | * @param elfname 29 | * @param size section size 30 | * @return int section index 31 | */ 32 | int add_section(char *elfname, size_t size); 33 | 34 | /** 35 | * @brief Get the section address 36 | * 37 | * @param elf_name original file name 38 | * @param section_name section name 39 | * @return section address 40 | */ 41 | int get_section_addr(char *elf_name, char *section_name); 42 | 43 | /** 44 | * @brief Get the section file offset address 45 | * 46 | * @param elf_name original file name 47 | * @param section_name section name 48 | * @return section file offset address 49 | */ 50 | int get_section_offset(char *elf_name, char *section_name); 51 | 52 | /** 53 | * @brief Get the section size 54 | * 55 | * @param elf_name original file name 56 | * @param section_name section name 57 | * @return section size 58 | */ 59 | size_t get_section_size(char *elf_name, char *section_name); 60 | 61 | /** 62 | * @brief Get the section index 63 | * 64 | * @param elf_name original file name 65 | * @param section_name section name 66 | * @return section index 67 | */ 68 | int get_section_index(char *elf_name, char *section_name); -------------------------------------------------------------------------------- /src/segment.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 SecNotes 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | /* get or set function */ 26 | enum OPT_FUNCTION { 27 | GET_SEG, 28 | SET_SEG, 29 | INDEX_SEG, 30 | }; 31 | 32 | /** 33 | * @brief 增加一个段 34 | * add a segment 35 | * @param elf_name 36 | * @param type segment type 37 | * @param size segment size 38 | * @return int segment index 39 | */ 40 | int add_segment(char *elf_name, int type, size_t size); 41 | 42 | /** 43 | * @brief 增加一个段,并填充内容 44 | * add a paragraph and fill in the content 45 | * @param elf_name 46 | * @param type segment type 47 | * @param content segment content 48 | * @param size segment size 49 | * @return int segment index {-1:error} 50 | */ 51 | int add_segment_content(char *elf_name, int type, char *content, size_t size); 52 | 53 | /** 54 | * @brief 扩充一个节或者一个段,通过将节或者段移动到文件末尾实现。 55 | * expand a section or segment by moving it to the end of the file. 56 | * @param elfname 57 | * @param offset sec/seg offset 58 | * @param org_size sec/seg origin size 59 | * @param add_content new added content 60 | * @param content_size new added content size 61 | * @return segment index {-1:error} 62 | */ 63 | int expand_segment(char *elfname, uint64_t offset, size_t org_size, char *add_content, size_t content_size); 64 | 65 | /** 66 | * @brief 扩充dynstr段,通过将节或者段移动到文件末尾实现。 67 | * expand dynstr segment by moving it to the end of the file. 68 | * @param elfname 69 | * @param str new dynstr item 70 | * @return segment index {-1:error} 71 | */ 72 | int expand_dynstr_segment(char *elfname, char *str); 73 | 74 | /** 75 | * @brief 扩充strtab,通过将节移动到文件末尾实现。 76 | * expand strtab section by moving it to the end of the file. 77 | * @param elfname 78 | * @param str new strtab item 79 | * @return section index {-1:error} 80 | */ 81 | int expand_strtab_section(char *elfname, char *str); 82 | 83 | /** 84 | * @brief 添加新的hash节,通过将节移动到文件末尾实现。 85 | * add a new hash section by moving it to the end of the file. 86 | * @param elfname 87 | * @param content new section content 88 | * @param content_size new section content size 89 | * @return segment index {-1:error} 90 | */ 91 | int add_hash_segment(char *elfname, char *content, size_t content_size); 92 | 93 | /** 94 | * @brief 得到段的映射地址范围 95 | * Obtain the mapping address range of the segment 96 | * @param elf_name 97 | * @param type segment type 98 | * @param start output args 99 | * @param end output args 100 | * @return int error code {-1:error,0:sucess} 101 | */ 102 | int get_segment_range(char *elf_name, int type, uint64_t *start, uint64_t *end); 103 | 104 | /** 105 | * @brief 根据段的下标,获取段的偏移 106 | * obtain the offset of the segment based on its index 107 | * @param elfname 108 | * @param i segment index 109 | * @return uint64_t segment offset 110 | */ 111 | uint64_t get_segment_offset(char *elfname, int i); 112 | uint64_t get_segment_vaddr(char *elfname, int i); 113 | uint64_t get_segment_paddr(char *elfname, int i); 114 | uint64_t get_segment_filesz(char *elfname, int i); 115 | uint64_t get_segment_memsz(char *elfname, int i); 116 | uint64_t get_segment_type(char *elfname, int i); 117 | uint64_t get_segment_flags(char *elfname, int i); 118 | uint64_t get_segment_align(char *elfname, int i); 119 | 120 | /** 121 | * @brief 根据dynamic段的tag,得到值 122 | * get dynamic segment value by tag 123 | * @param elfname 124 | * @param tag dynamic segment tag 125 | * @param value dynamic segment value 126 | * @return int error code {-1:error,0:sucess} 127 | */ 128 | uint64_t get_dynamic_value_by_tag(char *elfname, int tag, uint64_t *value); 129 | 130 | /** 131 | * @brief 根据dynamic段的tag,得到下标 132 | * get dynamic segment index by tag 133 | * @param elfname 134 | * @param tag dynamic item tag 135 | * @param index dynamic item index 136 | * @return dynamic item index {-1:error,0:sucess} 137 | */ 138 | uint64_t get_dynamic_index_by_tag(char *elfname, int tag, uint64_t *index); 139 | 140 | /** 141 | * @brief 根据dynamic段的tag,设置值 142 | * set dynamic segment value by tag 143 | * @param elfname 144 | * @param tag dynamic segment tag 145 | * @param value dynamic segment value 146 | * @return int error code {-1:error,0:sucess} 147 | */ 148 | uint64_t set_dynamic_value_by_tag(char *elfname, int tag, uint64_t *value); 149 | 150 | /** 151 | * @brief 根据tag判断某个动态item是否存在 152 | * determine whether a dynamic item exists based on the tag 153 | * @param elfname 154 | * @param tag dynamic item tag 155 | * @return dynamic item index {-1:false, other:true} 156 | */ 157 | int has_dynamic_by_tag(char *elfname, int tag); --------------------------------------------------------------------------------