relocmain/README.md

95 lines
3.0 KiB
Markdown
Raw Normal View History

2021-01-23 04:20:24 +00:00
# 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_<arch>_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_<arch>_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 <pcrel32>]` instruction near `_start`, this is often the
instruction that loads `main` to pass it to `__libc_start_main` (at least on
2021-01-23 04:52:09 +00:00
glibc and musl it is). This then gets overwritten *at runtime by* `ld.so` due
2021-01-23 04:20:24 +00:00
to a relocation of type `R_X86_64_PC32` targetting the `pcrel32` operand of
that instruction --- all without touching any code of the executable.
2021-01-23 04:52:09 +00:00
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
2021-01-23 04:54:02 +00:00
$ ./manip-exe ./hello.glibc{,.manip} main2
2021-01-23 04:52:09 +00:00
```
```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 <main>
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
```
2021-01-23 04:20:24 +00:00
## Usage
```sh
# build only the tool
make manip-exe
# usage: ./manip-exe <input> <output> <symbol>
# also show some example stuff
make all
```
## License
2021-01-23 04:28:40 +00:00
```
be gay, do crimes, death to america
```
2021-01-23 04:20:24 +00:00