Pokology - a community-driven site around GNU poke

_____ ---' __\_______ ______)

Fun with ELF files

__) __) ---._______) Table of Contents _________________ 1. Substitute a string with another same-size string 2. Replace main function .. 1. With objdump assistance 1 Substitute a string with another same-size string =================================================== Let's assume that we only have the compiled version of the following C code (produced by gcc -o hello hello.c on a 64-bit machine): ,---- | #include | int | main() | { | puts("Hello, Jose!"); | return 0; | } `---- To replace Jose with Luca in binary file hello, you can do this using GNU poke: ,---- | (poke) .set obase 16 | (poke) .set endian little | (poke) .set pretty-print no | (poke) load elf | (poke) .file hello | (poke) var efile = Elf64_File @ 0#B | (poke) var rodata_arr = efile.get_sections_by_name(".rodata") | (poke) rodata_arr'length | 0x1UL | (poke) var rodata = rodata_arr[0] | (poke) efile.get_section_name(rodata.sh_name) | ".rodata" | (poke) rodata | Elf64_Shdr { | sh_name=0xb3U#B, | sh_type=0x1U, | sh_flags=Elf64_SectionFlags { | flags=0x2UL | }, | sh_addr=0x2000UL#B, | sh_offset=0x2000UL#B, | sh_size=0x11UL#B, | sh_link=0x0U, | sh_info=0x0U, | sh_addralign=0x4UL, | sh_entsize=0x0UL#b | } | (poke) /* Dump the content of the section */ | (poke) dump :from rodata.sh_offset :size rodata.sh_size | 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF | 00002000: 0100 0200 4865 6c6c 6f2c 204a 6f73 6521 ....Hello, Jose! | 00002010: 00 . | (poke) byte[4] @ (rodata.sh_offset + 4#B + 7#B) = ['L', 'u', 'c', 'a'] | (poke) dump :from rodata.sh_offset :size rodata.sh_size | 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF | 00002000: 0100 0200 4865 6c6c 6f2c 204c 7563 6121 ....Hello, Luca! | 00002010: 00 . | (poke) .exit `---- If you run ./hello program, it'll show ,---- | Hello, Luca! `---- instead of original ,---- | Hello, Jose! `---- And obviously other names with at most 4 characters, are also acceptable :) 2 Replace main function ======================= Consider the following program: ,---- | #include | int | main() | { | puts("main()"); | return 0; | } | int | main2() | { | puts("main2()"); | return 0; | } `---- We want to change the executable file (produced by gcc -o main2 main2.c), to call main2 function instead of main after the startup. 2.1 With objdump assistance ~~~~~~~~~~~~~~~~~~~~~~~~~~~ By looking at the disassembly of .text section (using objdump -D -j .text main2), we can see these instructions at the end of _start label: ,---- | [...] | 105a: 48 8d 0d 0f 01 00 00 lea 0x10f(%rip),%rcx # 1170 <__libc_csu_init> | 1061: 48 8d 3d d1 00 00 00 lea 0xd1(%rip),%rdi # 1139 <main> | 1068: ff 15 72 2f 00 00 call *0x2f72(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5> | 106e: f4 hlt | 106f: 90 nop `---- The instruction lea 0xd1(%rip),%rdi is loading the address of main into the %rdi. So we have to change the d1 00 00 00 part of the instruction which is a uint32 immediate value. Again, by looking at the objdump disassembly of main and main2, we can see that main2 - main = 0x1153 - 0x1139 = 0x1a = 26. ,---- | 0000000000001139 <main>: | 1139: 55 push %rbp | 113a: 48 89 e5 mov %rsp,%rbp | 113d: 48 8d 05 c0 0e 00 00 lea 0xec0(%rip),%rax # 2004 <_IO_stdin_used+0x4> | 1144: 48 89 c7 mov %rax,%rdi | 1147: e8 e4 fe ff ff call 1030 <puts@plt> | 114c: b8 00 00 00 00 mov $0x0,%eax | 1151: 5d pop %rbp | 1152: c3 ret | | 0000000000001153 <main2>: | 1153: 55 push %rbp | 1154: 48 89 e5 mov %rsp,%rbp | 1157: 48 8d 05 ab 0e 00 00 lea 0xeab(%rip),%rax # 2009 <_IO_stdin_used+0x9> | 115e: 48 89 c7 mov %rax,%rdi | 1161: e8 ca fe ff ff call 1030 <puts@plt> | 1166: b8 00 00 00 00 mov $0x0,%eax | 116b: 5d pop %rbp | 116c: c3 ret | 116d: 0f 1f 00 nopl (%rax) `---- In poke we have to update that immediate value to points to main2: ,---- | (poke) .file main2 | (poke) .set endian little | (poke) uint32 @ 0x1064#B = (uint32 @ 0x1064#B) + 0x1a | (poke) .close `---- After closing the poke editor, you can run the main2 and see the following output: ,---- | main2() `----