Reverse Engineering Using Radare2
16 December 2017
By Jacob Pimental
This article assumes the reader has some basic knowledge in coding and assembly language. If not, a good resource for this would be the assembly tutorial from tutorialspoint.
Reverse Engineering is the ability to disassemble a program to see how it functions. It allows use to take apart a program or software and recreate it without knowing the source code. It’s used in things like Malware Analysis to understand what a piece of malware is doing and to create an identifier to stop it from infecting your computer again. It can also be used to patch bugs in old games you used to enjoy, or to find an exploit in some program.
Radare2 is a tool that is used in reverse engineering. It’s different from other tools in the fact that it’s free and open-source, and utilizes a sweet command-line interface as opposed to a graphical one. In this article I’m going to walk you through the very basics of reverse engineering using radare2 by disassembling a program I have already created. You can download this program used for this tutorial here, or create your own and just follow along.
To install Radare2 you need to clone it from gitHub and run the sys/install.sh file. I’m running Linux so the commands for that would be:
$ git clone https://github.com/radare/radare2
$ cd radare2
$ sudo sys/install.sh
$
Now let’s take a look at the intro binary that you downloaded earlier (or created yourself). It’s your standard, run of the mill “Hello World” program. If you were to run it the output would look like this:
$ ./intro
$ Hello World
$
The code for this program is simply:
#include <stdio.h>
void main(){
printf("Hello World\n");
}
Radare2 comes with a very handy tool called rabin2. It can be used to pull information out of a binary like strings, compile time, and other useful information. I normally use this before starting any serious analysis so I can get the gist of what a program may be doing. I start off by appending the -I flag. This will give us important information about the binary.
$ rabin2 -I intro
arch x86
binsz 6485
bintype elf
bits 64
canary false
class ELF64
crypto false
endian little
havecode true
intrp /lib64/ld-linux-x86-64.so.2
lang c
linenum true
lsyms true
machine AMD x86-64 architecture
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic true
relocs true
relro partial
rpath NONE
static false
stripped false
subsys linux
va true
$
This tells us that this program will run on linux and it was coded using the C programming language. We can also see the bintype being “elf”. This is called the “magic number” and can help us find out what type of file this is (Linux binary). That’s all we really need to know for now. The next command I like to use is rabin2 -z. This will list all of the strings from the data section of the binary. By running the command we can see our “Hello World” string.
$ rabin2 -z intro
vaddr=0x000006e4 paddr=0x000006e4 ordinal=000 sz=12 len=11 section=.rodata type=ascii string=Hello World
$
After this I sometimes follow up with rabin2 -zz, which shows all of the strings in the binary (not just in the data section). The output for this is normally really long. Sometimes there are important strings hidden in there, sometimes not. In this case there is not, so we’re done with rabin2. You can find other flags to append to rabin2 by running the command:
$ rabin2 -h
There are a lot of other interesting things rabin2 can show, like imports, exports, and code sections, but we’re not too concerned with that information for this binary. When getting into malware analysis these commands come in handy, but not for a simple program like this.
So now we can move on to actually running our program in radare2 to view the assembly code. Run the command:
$ r2 intro
This will load our binary into radare2. The next step is to have radare2 analyze the binary. This will find things like strings, functions, and other important information that radare2 can show us while analyzing so we’re not just staring at a bunch of blank assembly code. To do this, run the command “aa”. This is the basic analysis command for radare2. You also have “aaa” and “aaaa” each analyzing more information than the last. For now we can just go with “aa”.
$ r2 intro
-- Enhance your graphs by increasing the size of the block and graph.depth eval variable.
[0x00000540]> aa
[x] Analyze all flags starting with sym. and entry0 (aa)
[0x00000540]>
Now that our binary is analyzed, we can jump to a section in the binary where there is actually code. The “s” command in radare2 is used to “seek” to a spot in memory. This can either be used with an actual hex address or we can type in a function name to seek to that. Since we know that most Linux programs start at the “main” function we can seek to that.
[0x00000540]> s main
[0x0000064a]>
You’ll notice that the address in our cursor changed from 0x00000540 to 0x0000064a. This means our current address is now 0x0000064a and that we are at the main function. I like to analyze code in radare2’s visual mode (right now we are in command mode). To switch to visual mode just hit “v” and press enter.
[0x0000064a]> v
What you’re looking at now is radare2’s hex editor (yes, it has everything!). This isn’t necessarily code though, which is what we want to see. To change the view press “p”. Our view changes to the disassembly view and we’re able to see the assembly code of the program. Notice that radare2 separates functions with little ASCII type “blocks”. The code of the main function looks like this:
/ (fcn) sym.main 19
| sym.main ();
| ; DATA XREF from 0x0000055d (entry0)
| 0x0000064a 55 push rbp
| 0x0000064b 4889e5 mov rbp, rsp
| 0x0000064e 488d3d8f0000. lea rdi, str.Hello_World ; 0x6e4 ; "Hello World"
| 0x00000655 e8d6feffff call sym.imp.puts ;[1] ; int puts(const char *s)
| 0x0000065a 90 nop
| 0x0000065b 5d pop rbp
\ 0x0000065c c3 ret
Now let’s walk through the code. Since this binary is an x64 application we can see that we are putting our string “Hello World” into rdi at the memory address 0x0000064e. We then call the function “sym.imp.puts” (or “puts”), which is the same as “printf”. So this function will print our string. After that the “nop” command does absolutely nothing (like the pass command in python), we then clean up and end the function using “pop rbp” and “ret”. Hence our function is done and, since this is the main function, our program is done as well.
We’re able to tell that this program outputs the string “Hello World” without having to run the program ourselves. This was a very basic application of radare2. In the next article we’ll use radare2 to beat a simple Capture the Flag style program. If you want to learn more about radare2 you can read the “Radare2 Book” at https://www.gitbook.com/@radare. It’s filled with a ton of commands and was really helpful to me when I started learning the tool.
Thanks for reading and happy reversing!