# relocmain Swap out an ELF executable's `main` function with another function from its symbol table, without touching its code at all. ## How it works The typical ELF entrypoint isn't `main` directly, but rather `_start`, an assembly stub that first does some runtime initialization before calling `main`. But instead of directly calling the latter function, it is often passed as a parameter to `__libc_start_main` (which in turn calls `main` after doing *more* initialization stuff). 'Relocations' are instructions for an ELF linker or loader on how to patch a binary when moving it around in memory or when resolving functions. Some examples are "this value here is an absolute address, so when you move me around, please keep it updated" (`R__RELATIVE`), or "I'm using this external function, and I'm accessing it through a PLT, so when you resolve the symbol, please put it in the PLT" (`R__JUMP_SLOT`). This programs adds another relocation entry that replaces the code that loads the address `main` (to pass it to `__libc_start_main`) with the address of a different symbol. Due to how relocations work, it is restricted to replacing it with another symbol that is either imported from another library, or exported by the executable itself. Currently, only x86_64 is supported (but it's not too hard to add support for other instruction sets, 32-bit ELF support is a bit harder). The code looks for a `lea rdi, [rel ]` instruction near `_start`, this is often the instruction that loads `main` to pass it to `__libc_start_main` (at least on glibc and musl it is). This then gets overwritten *at runtime by* `ld.so` due to a relocation of type `R_X86_64_PC32` targetting the `pcrel32` operand of that instruction --- all without touching any code of the executable. The result: ```c int main(int argc, char** argv[]){ printf("hello, world\n"); return 42; } extern int main2(int argc, char** argv[]); int main2(int argc, char** argv[]) { printf("be gay do crimes\n"); return 69; } ``` ``` $ ./hello.glibc hello, world $ ./manip-exe ./hello.glibc{,.manip} main2 ``` ```asm $ objdump -d hello.glibc.manip 0000000000001050 <_start>: 1050: 31 ed xor %ebp,%ebp 1052: 49 89 d1 mov %rdx,%r9 1055: 5e pop %rsi 1056: 48 89 e2 mov %rsp,%rdx 1059: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 105d: 50 push %rax 105e: 54 push %rsp 105f: 4c 8d 05 6a 01 00 00 lea 0x16a(%rip),%r8 # 11d0 <__libc_csu_fini> 1066: 48 8d 0d 03 01 00 00 lea 0x103(%rip),%rcx # 1170 <__libc_csu_init> 106d: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 1135
1074: ff 15 66 2f 00 00 callq *0x2f66(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5> ``` ``` $ ./hello.glibc.manip be gay do crimes ``` ```asm $ objdump -drR hello.glibc.manip 106d: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 1135
1070: R_X86_64_PC32 main2@@Base-0x4 # !!! ``` ## Usage ```sh # build only the tool make manip-exe # usage: ./manip-exe # also show some example stuff make all ``` ## License ``` be gay, do crimes, death to america ```