Image : link.
strip - Remove symbol table and sections.
Remove a section :
$ gcc main.c -o binary $ objdump -s --section .comment ./binary ./binary: file format elf64-x86-64 Contents of section .comment: 0000 4743433a 2028474e 55292031 312e312e GCC: (GNU) 11.1. 0010 3000 0. $ strip -R .comment binary $ objdump -s --section .comment ./binary ./binary: file format elf64-x86-64 objdump: section '.comment' mentioned in a -j option, but not found in any input file
Removing the Section Headers Table
The section headers table is useful for a reverse engineer because it breaks down the binary’s address space into very specific chunks.
The section headers table isn’t actually needed for execution. You can remove it entirely.
There are four variables from the ELF header that are used to find, parse, and display the section headers table:
- Start of sections headers
- Size of section headers
- Number of section headers
- Section header string table index
Little Endian or Big Endian?
The sixth byte is called
EI_DATA and it indicates the endianness of the binary.
This field isn't necessary to execute a binary. A system is either little-endian or big-endian (unless its ARM which can be bi-endian). As such, a loader probably doesn't need to check this byte because it can only execute one or the other.
Little endian :
$ gcc test.c -o test $ readelf -a ./test | head ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 $ ./test I'm still working !!!
Let's manually overwrite the
EI_DATA field, to fake a big endian binary :
$ printf '\x02' | dd conv=notrunc of=./test bs=1 seek=5 1+0 records in 1+0 records out 1 byte copied, 3.3036e-05 s, 30.3 kB/s
$ readelf -a ./test | head readelf: Warning: The e_shentsize field in the ELF header is larger than the size of an ELF section header readelf: Error: Reading 125829120 bytes extends past end of file for section headers readelf: Error: Section headers are not available! readelf: Error: Too many program headers - 0xd00 - the file is not that big readelf: Error: ELF Header: Too many program headers - 0xd00 - the file is not that big Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, big endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: <unknown>: 300 Machine: <unknown>: 0x3e00 Version: 0x1000000
$ gdb ./test GNU gdb (GDB) 11.1 [...] For help, type "help". Type "apropos word" to search for commands related to "word"... "/tmp/./test": not in executable format: file format not recognized (gdb) Quit
$ r2 ./test -- There is no F5 key in radare2 yet [0x4010000000000000]> aaa [af: Cannot find function at 0x4010000000000000try0 (aa) [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Finding and parsing C++ vtables (avrr) [x] Type matching analysis for all functions (aaft) [x] Propagate noreturn information (aanr) [x] Use -AA or aaaa to perform additional experimental analysis. [0x4010000000000000]> pdf @main Invalid address (main) |ERROR| Invalid command 'pdf @main' (0x70)
Executing the binary :
$ ./test I'm still working !!!
radare2 seems to be broken, but the binary is still working.
Flipping the Executable bit
An important part of the program headers is the
flags field. The flag field describes if a segment is executable, writeable, and/or readable.
You can create a fake section headers table that reverses the program headers
There are two special sections that you’ll often come across in ELF binaries :
These sections contain code that execute before and after the main() function.
If you include .init and .fini sections in the fake section headers table can you potentially force the disassembler to disassemble at bad locations. It can be harder for a disassembler to find the entrypoint.
Mixing the Symbols
This section will discuss an anti reverse engineering technique that requires the dynamic symbol table to be present (no static compilation).
In this technique, you’ll append a fake dynamic symbol table to the end of the binary. Then you’ll repoint the offset in the
.dynmsym section header to point to the fake symbol table. Finally, you’ll mix all of the symbol name pointers for the FUNC symbols. This will cause the disassemblers that rely on the sections table, instead of the program headers, to display incorrect function names in the disassembly