torsdag 7 juli 2016

Patch a elf binary in linux with radare2

I have binary patching and done a lot off crackme's on windows for some time now. Ida pro and Immunity debugger is my favourite tools on that platform. However have never tried patching binaries on Linux. Have done some reversing with gdb and used xxd as hexeditor to patch binaries before and that works well, but was curious what people tend to use and wanted to extend my knowledge. If you don't want to spend a lot off money on Ida pro it looks like radare2 is a wonderful tool and this would probably be my favourite reversing tool on linux for the next decade. To learn how to do binary patches I created this example c program. The goal is to binary patch program to execute function1 instead of function2.

#include < stdio.h >

void function1()

void function2()

int main(int argc, char **argv)


Compile the program
gcc ./vuln.c -m32 -ggdb -o vuln
Test the program and watch the output. It know outputs failed but the goal is to binary patch it so function1 is executed and Victory is printed to the screen.
$ ./vuln
I used nm to find what memory address function1 is located in the binary as the output shows it's at address 0x0804841d

$ nm ./vuln
0804a020 B __bss_start
0804a020 b completed.6591
0804a018 D __data_start
0804a018 W data_start
08048360 t deregister_tm_clones
080483d0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804a024 B _end
080484d4 T _fini
080484e8 R _fp_hw
080483f0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
08048628 r __FRAME_END__
0804841d T function1
08048431 T function2
         w __gmon_start__
080482b0 T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
080484ec R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses
080484d0 T __libc_csu_fini
08048460 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
08048445 T main
         U puts@@GLIBC_2.0
08048390 t register_tm_clones
08048320 T _start
0804a020 D __TMC_END__
08048350 T __x86.get_pc_thunk.bx

Fire up radare in write mode and disassemble main

$ r2 -w ./vuln
 -- This should be documented, since it's not that obvious
[0x08048320]> pdf @ main
Cannot find function at 0x08048445
[0x08048320]> pd @ main
            ;-- sym.main:
            0x08048445    55           push ebp
            0x08048446    89e5         ebp = esp
            0x08048448    83e4f0       esp &= 0xfffffff0
            0x0804844b    e8e1ffffff   call sym.function2
               0x08048431(unk) ; sym.function2
            0x08048450    c9           
            0x08048451    c3           
            0x08048452    6690         
            0x08048454    6690         
            0x08048456    6690         
            0x08048458    6690         
            0x0804845a    6690         
            0x0804845c    6690         
            0x0804845e    6690         
            ;-- sym.__libc_csu_init:
            0x08048460    55           push ebp
            0x08048461    57           push edi
            0x08048462    31ff         edi = 0
            0x08048464    56           push esi
            0x08048465    53           push ebx
            0x08048466    e8e5feffff   call sym.__x86.get_pc_thunk.bx
               0x08048350(unk, unk, unk, unk) ; sym.__x86.get_pc_thunk.bx
            0x0804846b    81c3951b0000 ebx += 0x1b95
            0x08048471    83ec1c       esp -= 0x1c
            0x08048474    8b6c2430     ebp = [esp+0x30]
            0x08048478    8db30cffffff esi = [ebx-0xf4]
            0x0804847e    e82dfeffff   call sym._init
               0x080482b0() ; sym._init
            0x08048483    8d8308ffffff eax = [ebx-0xf8]
            0x08048489    29c6         esi -= eax
            0x0804848b    c1fe02       sar esi,0x2 
            0x0804848e    85f6         cmp esi, esi
        ┌─< 0x08048490    7427         je 0x80484b9
        │   0x08048492    8db600000000 esi = [esi]
       ┌──> 0x08048498    8b442438     eax = [esp+0x38]
       ││   0x0804849c    892c24       [esp] = ebp
       ││   0x0804849f    89442408     [esp+0x8] = eax
       ││   0x080484a3    8b442434     eax = [esp+0x34]
       ││   0x080484a7    89442404     [esp+0x4] = eax
       ││   0x080484ab    ff94bb08fff. call dword [ebx+edi*4-0xf8]
       ││      0x080483ba() ; sym.register_tm_clones
       ││   0x080484b2    83c701       edi += 0x1
       ││   0x080484b5    39f7         cmp edi, esi
       └──< 0x080484b7    75df         jne 0x8048498 
        └─> 0x080484b9    83c41c       esp += 0x1c
            0x080484bc    5b           pop ebx
            0x080484bd    5e           pop esi
            0x080484be    5f           pop edi
            0x080484bf    5d           pop ebp
            0x080484c0    c3           
      ┌───< 0x080484c1    eb0d         goto sym.__libc_csu_fini
      │     0x080484c3    90           
      │     0x080484c4    90           
      │     0x080484c5    90           
      │     0x080484c6    90           
      │     0x080484c7    90           
      │     0x080484c8    90           
      │     0x080484c9    90           
      │     0x080484ca    90           
      │     0x080484cb    90           
      │     0x080484cc    90           
      │     0x080484cd    90           
      │     0x080484ce    90           
      │     0x080484cf    90           
                    ;-- sym.__libc_csu_fini:
      └───> 0x080484d0    f3c3         repe ret 
            ;-- section_end..text:
            0x080484d2    0000         [eax] += al
            ;-- section..fini:
            0x080484d4    53           push ebx                  ; [13] va=0x080484d4 pa=0x000004d4 sz=20 vsz=20 rwx=-r-x .fini

            0x080484d5    83ec08       esp -= 0x8
            0x080484d8    e873feffff   call sym.__x86.get_pc_thunk.bx
               0x08048350(unk) ; sym.__x86.get_pc_thunk.bx
            0x080484dd    81c3231b0000 ebx += 0x1b23
            0x080484e3    83c408       esp += 0x8
            0x080484e6    5b           pop ebx
            0x080484e7    c3           
            ;-- section..rodata:
            0x080484e8 hex length=4 delta=0
 0300 0000                                ....            
            ;-- sym._IO_stdin_used:
            0x080484ec hex length=4 delta=0
 0100 0200                                ....            
            ;-- str.Victory:
            0x080484f0     .string "Victory" ; len=8
            ;-- str.Failed:
            0x080484f8     .string "Failed" ; len=7
            ;-- section_end..rodata:
            0x080484ff    0001         eax += [eax]    
            0x08048501    1b03         sbb eax,[ebx] 
            0x08048503    3b38         cmp edi, [eax]
            0x08048505    0000         [eax] += al
            0x08048507    0006         [esi] += al
            0x08048509    0000         [eax] += al
            0x0804850b    00e0         al += ah
            0x0804850d    fd           
            0x080485d7    0038         [eax] += bh
            0x080485d9    0000         [eax] += al
            0x080485db    00a000000080 [eax-0x80000000] += ah
            0x080485eb    088502410e0c [ebp+0xc0e4102] |= al
            0x080485f1    8703         xchg [ebx],eax 
            0x080485f3    43           inc ebx 
            0x080485f4    0e           push cs
            0x080485f5    108604410e14 adc [esi+0x140e4104],al 
            0x080485fb    83054e0e300. dword [0x2300e4e] += 0x48
            0x08048602    0e           push cs
            0x08048603    1441         adc al,0x41 
            0x08048605    c3           
            0x08048606    0e           push cs
            0x08048607    1041c6       adc [ecx-0x3a],al 
            0x0804860a    0e           push cs
            0x0804860b    0c41         al |= 0x41

Note this row in the output "0x0804844b e8e1ffffff call sym.function2" it's the row we want to patch to call function1 instead. Use s command to move to 0x0804844b offset in the binary.
[0x08048320]> s 0x0804844b
Now use wa to write assembler instruction to call our function2 memory address.
[0x0804844b]> wa call 0x0804841d
Written 5 bytes (call 0x0804841d) = wx e8f8000000
$ ./vuln
Wow that was easy radare2 is awesome :-)