Reverse Engineering – Simple Patching 1

Today we will take a look at how to patch a simple binary using radare2.

You can download, compile and install radare2 from https://github.com/radare/radare2

For my system setup, please check out My current hardware

The test program we will use will be a basic C program that prints a string, here is the code:

#include "stdio.h"

int main(int argc, char **argv) {
	char *string1 = "you lose";
	char *string2 = "you win";

	printf(string1);

	return 0;
}

After you compile, I recommend making a copy to work on to make it easier to recover if you mess something up.

cp re_me_1 re_me_1_patch

If we run the program it should output “you lose”

~/Workspace/C/examples » ./re_me_1                                                         aaron@azurite
you lose% 

Lets open the program in radare2:
Aw tells radare2 to open the file in a writeable mode and analyze all referenced code.

r2 -Aw re_me_1_patch

If you aren’t familiar with radare2, I’d highly recommend reviewing their introductory guide here https://radare.gitbooks.io/radare2book/content/.

The first thing I like to do is look for interesting strings in the binary:

iz will show us strings parsed from the data section.

[0x00401040]> iz
[Strings]
Num Paddr      Vaddr      Len Size Section  Type  String
000 0x00002010 0x00402010   8   9 (.rodata) ascii you lose
001 0x00002019 0x00402019   7   8 (.rodata) ascii you win

So when we ran the program it displayed “you lose”. We want the program to display “you win” instead so lets see where the text is referenced and figure out how it’s being used. We can search for the string a few ways:

axt will find data references to a specific address, so we can use it like this:

[0x0000201d]> axt 0x00402010
sym.main 0x401135 [DATA] mov qword [local_8h], str.first_string

You can also make radare2 use the output of one command within a new command. So instead of writing 0x00402010 we can do:
axt `iz~:2[2]`
The `iz~:2[2]` part takes the 3rd row and 3rd column from the iz command.

[0x00402010]> iz
[Strings]
Num Paddr      Vaddr      Len Size Section  Type  String
000 0x00002010 0x00402010   8   9 (.rodata) ascii you lose
001 0x00002019 0x00402019   7   8 (.rodata) ascii you win

[0x00402010]> axt `iz~:2[2]`
sym.main 0x401135 [DATA] mov qword [format], str.you_lose
[0x00402010]>

From here, we see that the string was referenced by sym.main at address 0x401135. Lets seek there and see what’s going on:

s 0x401135
print ddisassemble function will print the function at our current address

[0x00401135]> pdf
            ;-- main:
/ (fcn) sym.main 55
|   sym.main (int argc, char **argv, char **envp);
|           ; var char **local_20h @ rbp-0x20
|           ; var int local_14h @ rbp-0x14
|           ; var int local_10h @ rbp-0x10
|           ; var char *format @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x401061)
|           0x00401126      55             push rbp
|           0x00401127      4889e5         mov rbp, rsp
|           0x0040112a      4883ec20       sub rsp, 0x2
|0
|           0x0040112e      897dec         mov dword [local_14h], edi  ; argc
|           0x00401131      488975e0       mov qword [local_20h], rsi  ; argv
|           ;-- hit0_0:
|           0x00401135  ~   48c745f81020.  mov qword [format], str.you_lose ; 0x402010 ; "you lose"
|           ;-- hit0_1:
..
|           0x0040113d      48c745f01920.  mov qword [local_10h], str.you_win ; 0x402019 ; "you win"
|           0x00401145      488b45f8       mov rax, qword [format]
|           0x00401149      4889c7         mov rdi, rax                ; const char *format
|           0x0040114c      b800000000     mov eax, 0
|           0x00401151      e8dafeffff     call sym.imp.printf         ; int printf(const char *format)
|           0x00401156      b800000000     mov eax, 0
|           0x0040115b      c9             leave
\           0x0040115c      c3             ret

So the interesting bits are:

|           0x00401135  ~   48c745f81020.  mov qword [format], str.you_lose ;
|           0x0040113d      48c745f01920.  mov qword [local_10h], str.you_win ; 0x402019 ; "you win"

This part shows us that the strings “you lose” and “you win” are stored in local variables.

afvd local_10h will show the actual location of the variable relative to the base pointer

[0x00401135]> afvd local_10h
pxr $w @rbp-0x10

Now lets take a look at the following

|           0x00401145      488b45f8       mov rax, qword [format]

It looks like this is where the local variable is moved into the register RAX right before the call to printf. So all we should have to do is change this line to mov the local_10h variable (rbp-0x10) into rax instead. Let’s try!

V will take us into visual mode, then use p to cycle through until you get to the disassembly view.

Once you’re in disassembly view, type o and then 0x00401145 to seek to the offset of the above line.

Now we press A to bring up the assemble command. If we type the following,

mov rax, [rbp-0x10]

you will notice radare2 start to change the line automatically to

mov rax, qword [local_10h]

Once satisfied, press enter and if you type everything correctly it should ask to save your changes. Save and exit radare2.

Run the program and you should see the text “you win”

~/Workspace/C/examples » ./re_me_1_patch                                                   aaron@azurite
you win%