[0x004028c2]> dtsf records_for_test
session: 0, 0x4028a0 diffs: 0
session: 1, 0x4028c2 diffs: 0
Moreover, you can do reverse debugging in ESIL mode. In ESIL mode, program state can be managed by aets commands.
[0x00404870]> aets+
And step back by aesb:
[0x00404870]> aer rip
0x00404870
[0x00404870]> 5aeso
[0x00404870]> aer rip
0x0040487d
[0x00404870]> aesb
[0x00404870]> aer rip
0x00404879
In addition to the native reverse debugging capabilities in radare2, it's also possible to use gdb's remote protocol to reverse debug a target gdbserver that supports it. =!dsb and =!dcb are available as dsb and dcb replacementments for this purpose, see remote gdb's documentation for more information.
Windows Messages
On Windows, you can use dbW while debugging to set a breakpoint for the message handler of a specific window.
Get a list of the current process windows with dW :
[0x7ffe885c1164]> dW
.----------------------------------------------------.
| Handle | PID | TID | Class Name |
)----------------------------------------------------(
| 0x0023038e | 9432 | 22432 | MSCTFIME UI |
| 0x0029049e | 9432 | 22432 | IME |
| 0x002c048a | 9432 | 22432 | Edit |
| 0x000d0474 | 9432 | 22432 | msctls_statusbar32 |
| 0x00070bd6 | 9432 | 22432 | Notepad |
`----------------------------------------------------'
Set the breakpoint with a message type, together with either the window class name or its handle:
[0x7ffe885c1164]> dbW WM_KEYDOWN Edit
Breakpoint set.
Or
[0x7ffe885c1164]> dbW WM_KEYDOWN 0x002c048a
Breakpoint set.
If you aren't sure which window you should put a breakpoint on, use dWi to identify it with your mouse:
[0x7ffe885c1164]> dWi
Move cursor to the window to be identified. Ready? y
Try to get the child? y
.--------------------------------------------.
| Handle | PID | TID | Class Name |
)--------------------------------------------(
| 0x002c048a | 9432 | 22432 | Edit |
`--------------------------------------------'
Remote Access Capabilities
Radare can be run locally, or it can be started as a server process which is controlled by a local radare2 process. This is possible because everything uses radare's IO subsystem which abstracts access to system(), cmd() and all basic IO operations so to work over a network.
Help for commands useful for remote access to radare:
[0x00405a04]> =?
Usage: =[:!+-=ghH] [...] # connect with other instances of r2
remote commands:
| = list all open connections
| =<[fd] cmd send output of local command to remote fd
| =[fd] cmd exec cmd at remote 'fd' (last open is default one)
| =! cmd run command via r_io_system
| =+ [proto://]host:port connect to remote host:port (*rap://, raps://, tcp://, udp://, http://)
| =-[fd] remove all hosts or host 'fd'
| ==[fd] open remote session with host 'fd', 'q' to quit
| =!= disable remote cmd mode
| !=! enable remote cmd mode
servers:
| .:9000 start the tcp server (echo x|nc ::1 9090 or curl ::1:9090/cmd/x)
| =:port start the rap server (o rap://9999)
| =g[?] start the gdbserver
| =h[?] start the http webserver
| =H[?] start the http webserver (and launch the web browser)
other:
| =&:port start rap server in background (same as '&_=h')
| =:host:port cmd run 'cmd' command on remote server
examples:
| =+tcp://localhost:9090/ connect to: r2 -c.:9090 ./bin
| =+rap://localhost:9090/ connect to: r2 rap://:9090
| =+http://localhost:9090/cmd/ connect to: r2 -c'=h 9090' bin
| o rap://:9090/ start the rap server on tcp port 9090
You can learn radare2 remote capabilities by displaying the list of supported IO plugins: radare2 -L.
A little example should make this clearer. A typical remote session might look like this:
At the remote host1:
$ radare2 rap://:1234
At the remote host2:
$ radare2 rap://:1234
At localhost:
$ radare2 -
Add hosts
[0x004048c5]> =+ rap://
Connected to:
waiting... ok
[0x004048c5]> =
0 - rap://
You can open remote files in debug mode (or using any IO plugin) specifying URI when adding hosts:
[0x004048c5]> =+ =+ rap://
Connected to:
waiting... ok
0 - rap://
1 - rap://
To execute commands on host1:
[0x004048c5]> =0 px
[0x004048c5]> = s 0x666
To open a session with host2:
[0x004048c5]> ==1
fd:6> pi 1
...
fd:6> q
To remove hosts (and close connections):
[0x004048c5]> =-
You can also redirect radare output to a TCP or UDP server (such as nc -l). First, Add the server with '=+ tcp://' or '=+ udp://', then you can redirect the output of a command to be sent to the server:
[0x004048c5]> =+ tcp://
Connected to:
5 - tcp://
[0x004048c5]> =<5 cmd...
The =< command will send the output from the execution of cmd to the remote connection number N (or the last one used if no id specified).
Debugging with gdbserver
radare2 allows remote debugging over the gdb remote protocol. So you can run a gdbserver and connect to it with radare2 for remote debugging. The syntax for connecting is:
$ r2 -d gdb://
Note that the following command does the same, r2 will use the debug plugin specified by the uri if found.
$ r2 -D gdb gdb://
The debug plugin can be changed at runtime using the dL or Ld commands.
Or if the gdbserver is running in extended mode, you can attach to a process on the host with:
$ r2 -d gdb://
It is also possible to start debugging after analyzing a file using the doof command which rebases the current session's data after opening gdb
[0x00404870]> doof gdb://
After connecting, you can use the standard r2 debug commands as normal.
radare2 does not yet load symbols from gdbserver, so it needs the binary to be locally present to load symbols from it. In case symbols are not loaded even if the binary is present, you can try specifying the path with e dbg.exe.path:
$ r2 -e dbg.exe.path=
If symbols are loaded at an incorrect base address, you can try specifying the base address too with e bin.baddr:
$ r2 -e bin.baddr=
Usually the gdbserver reports the maximum packet size it supports. Otherwise, radare2 resorts to sensible defaults. But you can specify the maximum packet size with the environment variable R2_GDB_PKTSZ. You can also check and set the max packet size during a session with the IO system, =!.
$ export R2_GDB_PKTSZ=512
$ r2 -d gdb://
= attach
Assuming filepath
[0x7ff659d9fcc0]> =!pktsz
packet size: 512 bytes
[0x7ff659d9fcc0]> =!pktsz 64
[0x7ff659d9fcc0]> =!pktsz
packet size: 64 bytes
The gdb IO system provides useful commands which might not fit into any standard radare2 commands. You can get a list of these commands with =!?. (Remember, =! accesses the underlying IO plugin's system()).
[0x7ff659d9fcc0]> =!?
Usage: =!cmd args
=!pid - show targeted pid
=!pkt s - send packet 's'
=!monitor cmd - hex-encode monitor command and pass to target interpreter
=!rd - show reverse debugging availability
=!dsb - step backwards
=!dcb - continue backwards
=!detach [pid] - detach from remote/detach specific pid
=!inv.reg - invalidate reg cache
=!pktsz - get max packet size used
=!pktsz bytes - set max. packet size as 'bytes' bytes
=!exec_file [pid] - get file which was executed for current/specified pid
Note that =!dsb and =!dcb are only available in special gdbserver implementations such as Mozilla's rr, the default gdbserver doesn't include remote reverse debugging support. Use =!rd to print the currently available reverse debugging capabilities.
If you are interested in debugging radare2's interaction with gdbserver you can use =!monitor set remote-debug 1 to turn on logging of gdb's remote protocol packets in gdbserver's console and =!monitor set debug 1 to show general debug messages from gdbserver in it's console.
radare2 also provides its own gdbserver implementation:
$ r2 -
[0x00000000]> =g?
|Usage: =[g] [...] # gdb server
| gdbserver:
| =g port file [args] listen on 'port' debugging 'file' using gdbserver
| =g! port file [args] same as above, but debug protocol messages (like gdbserver --remote-debug)