Debugging

Remote debugging - gdbserver

If you want to connect to a gdb session from a remote machine, then you can run a gdbserver.

gdbserver 0.0.0.0:22222 program-file-name

The 22222 is the port in this case.

Or, if you want to attach to an existing process:

gdbserver --attach :22222 process_id_here

Connecting with radare2, for example:

r2 -d gdb://host-name-here:22222

Pwntools

You can load the executable in GDB like this:

io = pwn.gdb.debug([executable_filepath, argument1])

It also starts up a gdbserver, but trying to connect to it with radare2 fails (waits forever)

GDB

Although I really prefer Radare2's user interface in just about every way, GDB is the only debugger that actually works consistently.

Watching

You can watch addresses for changes and stop when a change was made to that address. Can be useful if you're not sure where exactly a value is changed.

  • rwatch stops when the specified address is accessed for reading

  • watch stops when it's accessed for writing

  • awatch stops on both reads and writes.

Radare2

Usage tips

Run it in debug mode:

r2 -d filename
r2 -d process_id

Don’t forget to analyze using aaa. Alternatively, you can pass the -A flag when running radare2.

Random Basics

You can pipe with | and redirect with >

You can run commands at certain addresses with @ ( pd @ main)

If you want to modify binaries on disk, then you have to use -w flag.

Help: ? Help about debugging: d?

Running r2 command: :. For example :aaa

You can use ctrl+r to do a reverse search for previous commands

Analysis and Disassembly

You have to analyze before you can disassemble. Analyze everything: aaa

List functions: afl

Rename location: afn new_name_here loc.140011790

Move to location: s?

Move to main: s main

Print stuff: p?

Disassemble the current function: pdf

Disassemble the next N opcodes (pdf might not work when running shellcode on the stack): pd number_of_opcodes

Print stack: pxr optional_byte_amount @ esp (rsp for 64 bit programs). Stack grows downwards, so the latest pushes are at the top.

Debugging

Debugging: d?

Place a breakpoint at either an address or function name: db address_or_function

Remove breakpoint: db - address_or_function

Print registers: dr

Continue: dc

Continue until address: dcu address

Stepping: ds?

Reload process: do (alias for oo)

Reload process in debugger mode with arguments (alias for ood): doo

Set register: dr eax = 0x00000000X

Visuals

Basic visual mode: V , use p to cycle. Not too useful.

Graph view: VV. Zoom: +-

Visual panels: V!

Exit back to command line mode: q

Configuration

Change configuration variables with e.

The utf8 ones create a nicer graph view and nicer arrows.

Show opcode description appends a comment after each instruction to explain what it’s doing.

iocache allows you to modify files that haven’t been opened with the write flag. But it still won’t be written to disk, just in memory.

Forking

Note: I haven’t been able to get forking following working correctly in r2. I’ve used GDB for that. But I’ve probably just been using r2 wrong

Environment variables:

  • e dbg.forks=true

  • e dbg.follow.child = true

Commands:

  • dcf: continue until fork

  • dp: list processes

Finding ROP Gadgets

You can use the /R syntax to find ROP gadgets:

Though, msfelfscan might give much better results. Radare2 didn’t find a jmp esp while msfelfscan did.

Remote usage

On the remote server:

gdbserver 0.0.0.0:22222 program-file-name

On the local server:

r2 -d gdb://host-name-here:22222

Searching

You can search for hex values in the binary like this:

/ \xde\xad\xbe\xef

Rabin2

Rabin2 can be super useful for finding things in a binary.

For example, I used it to find static variable addresses by listing exported symbols:

rabin2 -s executable_name

Feed input from a file

Create a file ~/input.rr2:

Feed input from a file
Create a file ~/input.rr2:

Then put some shellcode in the input file for example:

echo $'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999' > /home/user/level01/exploit/payload

Then run the program using that configuration:

r2 -r /path/to/input.rr2 -d /path/to/executable

You can reload it (and restart the process) with doo

Last updated