Many people feel discouraged or overwhelmed to use radare2 due to its complexity (understandably so). They often use gdb with the downright amazing PEDA extension for their debugging needs and IDA Pro for disassembly (or Hopper/Binary Ninja if the price of IDA is too prohibitive).
But you can do both static and dynamic analysis using radare2, with comparable features to gdb-peda on the dynamic front. In this post, I’m going to illustrate this better; perhaps then r2 won’t seem so daunting to use.
Debugger mode
To open a binary in debug mode, either specify the -d
option in the command line,
Or, if you’ve already performed some analysis, you can reopen it in debug mode using ood
or doo
; all custom flags will still be there.
Diassemble
PEDA
radare2
Checking DEP/PIC and other things
PEDA
In peda, you have the checksec
command, which gives varying information about the security fortification of the debugged binary.
radare2
In radare2, you can view a lot of information about the loaded binary using i
.
We can filter out any information that’s irrelevant to us using the internal grep operator (~
)
(Un)setting ASLR
PEDA
In peda, you can check/disable ASLR using aslr
gdb-peda$ aslr
ASLR is ON
gdb-peda$ aslr off
gdb-peda$ aslr
ASLR is OFF
radare2
You can use rarun2
to run a binary with a custom environment. Again, use radare2
to debug.
The problem with rarun2
is that it tries to write to /proc/sys/kernel/randomize_va_space
; you need to be root to do that. I’m not sure how gdb disables ASLR at a user level.
Function argument detection
PEDA
PEDA does some neat argument guessing whenever a call <function>
instruction is reached:
radare2
It’s pretty close to doing this automatically. You still have to look for them on the stack and registers; see how to dereference below.
ROP gadgets
PEDA
In PEDA, you can use dumprop
to dump all ROP gadgets within a memory range and with a specific maximum depth.
radare2
You can customize a few options for gadget hunting within radare2.
You can search for gadgets using either /R
or /Rl
(display in linear fashion, just like dumprop
). There are also the /R/
and /Rl/
variants which allow the use of regular expressions in your search.
Searching for specific instructions
PEDA
Note: needs nasm
to be installed.
radare2
ELF header information
PEDA
gdb-peda$ elfheader
.interp = 0x8048154
.note.ABI-tag = 0x8048168
.note.gnu.build-id = 0x8048188
.gnu.hash = 0x80481ac
.dynsym = 0x80481cc
.dynstr = 0x804822c
.gnu.version = 0x8048292
.gnu.version_r = 0x80482a0
.rel.dyn = 0x80482d0
.rel.plt = 0x80482d8
.init = 0x80482f0
.plt = 0x8048320
.plt.got = 0x8048360
.text = 0x8048370
.fini = 0x8048604
.rodata = 0x8048618
.eh_frame_hdr = 0x8048648
.eh_frame = 0x804867c
.init_array = 0x8049f08
.fini_array = 0x8049f0c
.jcr = 0x8049f10
.dynamic = 0x8049f14
.got = 0x8049ffc
.got.plt = 0x804a000
.data = 0x804a018
.bss = 0x804a020
radare2
[0x080484de]> iS~ehdr
idx=40 vaddr=0x08048000 paddr=0x00000000 sz=52 vsz=52 perm=m-rw- name=ehdr
[0x080484de]> s 0x08048000
[0x08048000]> pfo elf32 # Load ELF header format
[0x08048000]> pf.elf_header # Print formatted as ELF header struct
ident : 0x08048000 = .ELF...
type : 0x08048010 = type (enum elf_type) = 0x2 ; ET_EXEC
machine : 0x08048012 = machine (enum elf_machine) = 0x3 ; EM_386
version : 0x08048014 = 0x00000001
entry : 0x08048018 = 0x08048370
phoff : 0x0804801c = 0x00000034
shoff : 0x08048020 = 0x0000181c
flags : 0x08048024 = 0x00000000
ehsize : 0x08048028 = 0x0034
phentsize : 0x0804802a = 0x0020
phnum : 0x0804802c = 0x0009
shentsize : 0x0804802e = 0x0028
shnum : 0x08048030 = 0x001f
shstrndx : 0x08048032 = 0x001c
[0x08048000]> pf.elf_phdr @ 0x08048034
type : 0x08048034 = type (enum elf_p_type) = 0x6 ; PT_PHDR
offset : 0x08048038 = 0x00000034
vaddr : 0x0804803c = 0x08048034
paddr : 0x08048040 = 0x08048034
filesz : 0x08048044 = 0x00000120
memsz : 0x08048048 = 0x00000120
flags : 0x0804804c = flags (enum elf_p_flags) = 0x5 ; PF_Read_Exec
align : 0x08048050 = 0x00000004
What about section information?
[0x08048000]> iS
[Sections]
idx=00 vaddr=0x00000000 paddr=0x00000000 sz=0 vsz=0 perm=----- name=
idx=01 vaddr=0x08048154 paddr=0x00000154 sz=19 vsz=19 perm=--r-- name=.interp
idx=02 vaddr=0x08048168 paddr=0x00000168 sz=32 vsz=32 perm=--r-- name=.note.ABI_tag
idx=03 vaddr=0x08048188 paddr=0x00000188 sz=36 vsz=36 perm=--r-- name=.note.gnu.build_id
idx=04 vaddr=0x080481ac paddr=0x000001ac sz=32 vsz=32 perm=--r-- name=.gnu.hash
idx=05 vaddr=0x080481cc paddr=0x000001cc sz=96 vsz=96 perm=--r-- name=.dynsym
idx=06 vaddr=0x0804822c paddr=0x0000022c sz=101 vsz=101 perm=--r-- name=.dynstr
idx=07 vaddr=0x08048292 paddr=0x00000292 sz=12 vsz=12 perm=--r-- name=.gnu.version
idx=08 vaddr=0x080482a0 paddr=0x000002a0 sz=48 vsz=48 perm=--r-- name=.gnu.version_r
idx=09 vaddr=0x080482d0 paddr=0x000002d0 sz=8 vsz=8 perm=--r-- name=.rel.dyn
idx=10 vaddr=0x080482d8 paddr=0x000002d8 sz=24 vsz=24 perm=--r-- name=.rel.plt
idx=11 vaddr=0x080482f0 paddr=0x000002f0 sz=35 vsz=35 perm=--r-x name=.init
idx=12 vaddr=0x08048320 paddr=0x00000320 sz=64 vsz=64 perm=--r-x name=.plt
idx=13 vaddr=0x08048360 paddr=0x00000360 sz=8 vsz=8 perm=--r-x name=.plt.got
idx=14 vaddr=0x08048370 paddr=0x00000370 sz=658 vsz=658 perm=--r-x name=.text
idx=15 vaddr=0x08048604 paddr=0x00000604 sz=20 vsz=20 perm=--r-x name=.fini
idx=16 vaddr=0x08048618 paddr=0x00000618 sz=45 vsz=45 perm=--r-- name=.rodata
idx=17 vaddr=0x08048648 paddr=0x00000648 sz=52 vsz=52 perm=--r-- name=.eh_frame_hdr
idx=18 vaddr=0x0804867c paddr=0x0000067c sz=236 vsz=236 perm=--r-- name=.eh_frame
idx=19 vaddr=0x08049f08 paddr=0x00000f08 sz=4 vsz=4 perm=--rw- name=.init_array
idx=20 vaddr=0x08049f0c paddr=0x00000f0c sz=4 vsz=4 perm=--rw- name=.fini_array
idx=21 vaddr=0x08049f10 paddr=0x00000f10 sz=4 vsz=4 perm=--rw- name=.jcr
idx=22 vaddr=0x08049f14 paddr=0x00000f14 sz=232 vsz=232 perm=--rw- name=.dynamic
idx=23 vaddr=0x08049ffc paddr=0x00000ffc sz=4 vsz=4 perm=--rw- name=.got
idx=24 vaddr=0x0804a000 paddr=0x00001000 sz=24 vsz=24 perm=--rw- name=.got.plt
idx=25 vaddr=0x0804a018 paddr=0x00001018 sz=8 vsz=8 perm=--rw- name=.data
idx=26 vaddr=0x0804a020 paddr=0x00001020 sz=4 vsz=4 perm=--rw- name=.bss
idx=27 vaddr=0x00000000 paddr=0x00001020 sz=52 vsz=52 perm=----- name=.comment
idx=28 vaddr=0x00000000 paddr=0x00001712 sz=266 vsz=266 perm=----- name=.shstrtab
idx=29 vaddr=0x00000000 paddr=0x00001054 sz=1136 vsz=1136 perm=----- name=.symtab
idx=30 vaddr=0x00000000 paddr=0x000014c4 sz=590 vsz=590 perm=----- name=.strtab
idx=31 vaddr=0x08048034 paddr=0x00000034 sz=288 vsz=288 perm=m-r-x name=PHDR
idx=32 vaddr=0x08048154 paddr=0x00000154 sz=19 vsz=19 perm=m-r-- name=INTERP
idx=33 vaddr=0x08048000 paddr=0x00000000 sz=1896 vsz=1896 perm=m-r-x name=LOAD0
idx=34 vaddr=0x08049f08 paddr=0x00000f08 sz=280 vsz=284 perm=m-rw- name=LOAD1
idx=35 vaddr=0x08049f14 paddr=0x00000f14 sz=232 vsz=232 perm=m-rw- name=DYNAMIC
idx=36 vaddr=0x08048168 paddr=0x00000168 sz=68 vsz=68 perm=m-r-- name=NOTE
idx=37 vaddr=0x08048648 paddr=0x00000648 sz=52 vsz=52 perm=m-r-- name=GNU_EH_FRAME
idx=38 vaddr=0x00000000 paddr=0x00000000 sz=0 vsz=0 perm=m-rw- name=GNU_STACK
idx=39 vaddr=0x08049f08 paddr=0x00000f08 sz=248 vsz=248 perm=m-r-- name=GNU_RELRO
idx=40 vaddr=0x08048000 paddr=0x00000000 sz=52 vsz=52 perm=m-rw- name=ehdr
41 sections
Cross-references
This is a very useful feature to find out who calls/references what, whether it be an interesting function or string.
PEDA
radare2
This can also be done in visual mode using x
on a specific symbol.
Patching code/memory
PEDA
gdb-peda$ patch 0x402a00 0x90
Written 1 bytes to 0x402a00
radare2
If opening in read-only mode, you should enable cache-writing via e io.cache = true
. Otherwise, you can use the -w
option when loading the file: r2 -d -w ./binary
.
De Bruijn patterns
PEDA
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ patto AAEA
AAEA found at offset: 34
radare2
In r2, you need to specify the address at which you wish to write the pattern. AFAIK, there is no way to write the pattern to stdout
for copy-pasting it. Also, the offset doesn’t work with string values; must be hex.
Searching in memory
PEDA
gdb-peda$ phelp searchmem
Search for a pattern in memory; support regex search
Usage:
searchmem pattern start end
searchmem pattern mapname
radare2
Shellcoding
PEDA
gdb-peda$ shellcode
Error: missing argument
Generate or download common shellcodes.
Usage:
shellcode generate [arch/]platform type [port] [host]
shellcode search keyword (use % for any character wildcard)
shellcode display shellcodeId (shellcodeId as appears in search results)
shellcode zsc [generate customize shellcode]
For generate option:
default port for bindport shellcode: 16706 (0x4142)
default host/port for connect back shellcode: 127.127.127.127/16706
supported arch: x86
gdb-peda$ shellcode generate
Available shellcodes:
x86/linux exec
x86/linux connect
x86/linux bindport
x86/bsd exec
x86/bsd connect
x86/bsd bindport
gdb-peda$ shellcode generate x86/linux exec
# x86/linux/exec: 24 bytes
shellcode = (
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31"
"\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
)
radare2
You can write your own shellcode for future use and compile it. Also, you can write the shellcode anywhere by using the @
address specifier.
Tracing
PEDA
tracecall
and traceinst
are very useful in a number of situations.
radare2
Sadly broken at the moment.
Virtual memory mapping
Using vmm
in peda? In r2, it’s dm
.
Dereferencing stack and registers (telescoping)
PEDA
radare2
Breakpoint commands
PEDA
gdb-peda$ commands 1
gdb-peda$ commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>set $rax=0xdeadbeef
>set $rbx=0xdeadc0de
>end
gdb-peda$ i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000402a00
breakpoint already hit 1 time
set $rax=0xdeadbeef
set $rbx=0xdeadc0de
radare2
Warning: some commands may not work properly with dbc
.
Closing remarks
Radare2 also has numerous features which PEDA lacks, such as CFG, heap analysis, renaming variables and arguments in the disassembly and many more. One thing which r2 is missing is a nice pwntools integration (although I think this can be easily done on the fly by attaching r2 to the running process. r2pipe + pwntools, however, would be a different story).
Still feel like missing something? Drop me a line or ask on #radare on freenode.