The Official Radare2 Book — страница 39 из 64

[0x7f133f022fb0]> dm.

0x00007f947eed9000 # 0x00007f947eefe000 * usr 148K s r-x /usr/lib/ld-2.27.so /usr/lib/ld-2.27.so ; map.usr_lib_ld_2.27.so.r_x

Using dmm we can "List modules (libraries, binaries loaded in memory)", this is quite a handy command to see which modules were loaded.

[0x7fa80a19dfb0]> dmm

0x55ca23a4a000 /tmp/helloworld

0x7fa80a19d000 /usr/lib/ld-2.27.so

Note that the output of dm subcommands, and dmm specifically, might be different in various systems and different binaries.

We can see that along with our helloworld binary itself, another library was loaded which is ld-2.27.so. We don't see libc yet and this is because radare2 breaks before libc is loaded to memory. Let's use dcu (debug continue until) to execute our program until the entry point of the program, which radare flags as entry0.

[0x7fa80a19dfb0]> dcu entry0

Continue until 0x55ca23a4a520 using 1 bpsize

hit breakpoint at: 55ca23a4a518

[0x55ca23a4a520]> dmm

0x55ca23a4a000 /tmp/helloworld

0x7fa809de1000 /usr/lib/libc-2.27.so

0x7fa80a19d000 /usr/lib/ld-2.27.so

Now we can see that libc-2.27.so was loaded as well, great!

Speaking of libc, a popular task for binary exploitation is to find the address of a specific symbol in a library. With this information in hand, you can build, for example, an exploit which uses ROP. This can be achieved using the dmi command. So if we want, for example, to find the address of system() in the loaded libc, we can simply execute the following command:

[0x55ca23a4a520]> dmi libc system

514 0x00000000 0x7fa809de1000 LOCAL FILE 0 system.c

515 0x00043750 0x7fa809e24750 LOCAL FUNC 1221 do_system

4468 0x001285a0 0x7fa809f095a0 LOCAL FUNC 100 svcerr_systemerr

5841 0x001285a0 0x7fa809f095a0 LOCAL FUNC 100 svcerr_systemerr

6427 0x00043d10 0x7fa809e24d10 WEAK FUNC 45 system

7094 0x00043d10 0x7fa809e24d10 GLBAL FUNC 45 system

7480 0x001285a0 0x7fa809f095a0 GLBAL FUNC 100 svcerr_systemerr

Similar to the dm. command, with dmi. you can see the closest symbol to the current address.

Another useful command is to list the sections of a specific library. In the following example we'll list the sections of ld-2.27.so:

[0x55a7ebf09520]> dmS ld-2.27

[Sections]

00 0x00000000 0 0x00000000 0 ---- ld-2.27.so.

01 0x000001c8 36 0x4652d1c8 36 -r-- ld-2.27.so..note.gnu.build_id

02 0x000001f0 352 0x4652d1f0 352 -r-- ld-2.27.so..hash

03 0x00000350 412 0x4652d350 412 -r-- ld-2.27.so..gnu.hash

04 0x000004f0 816 0x4652d4f0 816 -r-- ld-2.27.so..dynsym

05 0x00000820 548 0x4652d820 548 -r-- ld-2.27.so..dynstr

06 0x00000a44 68 0x4652da44 68 -r-- ld-2.27.so..gnu.version

07 0x00000a88 164 0x4652da88 164 -r-- ld-2.27.so..gnu.version_d

08 0x00000b30 1152 0x4652db30 1152 -r-- ld-2.27.so..rela.dyn

09 0x00000fb0 11497 0x4652dfb0 11497 -r-x ld-2.27.so..text

10 0x0001d0e0 17760 0x4654a0e0 17760 -r-- ld-2.27.so..rodata

11 0x00021640 1716 0x4654e640 1716 -r-- ld-2.27.so..eh_frame_hdr

12 0x00021cf8 9876 0x4654ecf8 9876 -r-- ld-2.27.so..eh_frame

13 0x00024660 2020 0x46751660 2020 -rw- ld-2.27.so..data.rel.ro

14 0x00024e48 336 0x46751e48 336 -rw- ld-2.27.so..dynamic

15 0x00024f98 96 0x46751f98 96 -rw- ld-2.27.so..got

16 0x00025000 3960 0x46752000 3960 -rw- ld-2.27.so..data

17 0x00025f78 0 0x46752f80 376 -rw- ld-2.27.so..bss

18 0x00025f78 17 0x00000000 17 ---- ld-2.27.so..comment

19 0x00025fa0 63 0x00000000 63 ---- ld-2.27.so..gnu.warning.llseek

20 0x00025fe0 13272 0x00000000 13272 ---- ld-2.27.so..symtab

21 0x000293b8 7101 0x00000000 7101 ---- ld-2.27.so..strtab

22 0x0002af75 215 0x00000000 215 ---- ld-2.27.so..shstrtab

Heap

radare2's dm subcommands can also display a map of the heap which is useful for those who are interested in inspecting the heap and its content. Simply execute dmh to show a map of the heap:

[0x7fae46236ca6]> dmh

Malloc chunk @ 0x55a7ecbce250 [size: 0x411][allocated]

Top chunk @ 0x55a7ecbce660 - [brk_start: 0x55a7ecbce000, brk_end: 0x55a7ecbef000]

You can also see a graph layout of the heap:

[0x7fae46236ca6]> dmhg

Heap Layout

.────────────────────────────────────.

│ Malloc chunk @ 0x55a7ecbce000 │

│ size: 0x251 │

│ fd: 0x0, bk: 0x0 │

`────────────────────────────────────'

.───'

.─────────────────────────────────────────────.

│ Malloc chunk @ 0x55a7ecbce250 │

│ size: 0x411 │

│ fd: 0x57202c6f6c6c6548, bk: 0xa21646c726f │

`─────────────────────────────────────────────'

.───'

.────────────────────────────────────────────────────.

│ Top chunk @ 0x55a7ecbce660 │

│ [brk_start:0x55a7ecbce000, brk_end:0x55a7ecbef000] │

`────────────────────────────────────────────────────'

Another heap commands can be found under dmh, check dmh? for the full list.

[0x00000000]> dmh?

|Usage: dmh # Memory map heap

| dmh List chunks in heap segment

| dmh [malloc_state] List heap chunks of a particular arena

| dmha List all malloc_state instances in application

| dmhb Display all parsed Double linked list of main_arena's bins instance

| dmhb [bin_num|bin_num:malloc_state] Display parsed double linked list of bins instance from a particular arena

| dmhbg [bin_num] Display double linked list graph of main_arena's bin [Under developemnt]

| dmhc @[chunk_addr] Display malloc_chunk struct for a given malloc chunk

| dmhf Display all parsed fastbins of main_arena's fastbinY instance

| dmhf [fastbin_num|fastbin_num:malloc_state] Display parsed single linked list in fastbinY instance from a particular arena

| dmhg Display heap graph of heap segment

| dmhg [malloc_state] Display heap graph of a particular arena

| dmhi @[malloc_state]Display heap_info structure/structures for a given arena

| dmhm List all elements of struct malloc_state of main thread (main_arena)

| dmhm [malloc_state] List all malloc_state instance of a particular arena

| dmht Display all parsed thead cache bins of main_arena's tcache instance

| dmh? Show map heap help

To print safe-linked lists (glibc >= 2.32) with demangled pointers, the variable dbg.glibc.demangle must be true.

Files

The radare2 debugger allows the user to list and manipulate the file descriptors from the target process.

This is a useful feature, which is not found in other debuggers, the functionality is similar to the lsof command line tool, but have extra subcommands to change the seek, close or duplicate them.

So, at any time in the debugging session you can replace the stdio file descriptors to use network sockets created by r2, or replace a network socket connection to hijack it.

This functionality is also available in r2frida by using the dd command prefixed with a backslash. In r2 you may want to see the output of dd? for proper details.

Reverse Debugging

Radare2 has reverse debugger, that can seek the program counter backward. (e.g. reverse-next, reverse-continue in gdb) Firstly you need to save program state at the point that you want to start recording. The syntax for recording is:

[0x004028a0]> dts+

You can use dts commands for recording and managing program states. After recording the states, you can seek pc back and forth to any points after saved address. So after recording, you can try single step back:

[0x004028a0]> 2dso

[0x004028a0]> dr rip

0x004028ae

[0x004028a0]> dsb

continue until 0x004028a2

hit breakpoint at: 4028a2

[0x004028a0]> dr rip

0x004028a2

When you run dsb, reverse debugger restore previous recorded state and execute program from it until desired point.

Or you can also try continue back:

[0x004028a0]> db 0x004028a2

[0x004028a0]> 10dso

[0x004028a0]> dr rip

0x004028b9

[0x004028a0]> dcb

[0x004028a0]> dr rip

0x004028a2

dcb seeks program counter until hit the latest breakpoint. So once set a breakpoint, you can back to it any time.

You can see current recorded program states using dts:

[0x004028a0]> dts

session: 0 at:0x004028a0 ""

session: 1 at:0x004028c2 ""

NOTE: Program records can be saved at any moments. These are diff style format that save only different memory area from previous. It saves memory space rather than entire dump.

And also can add comment:

[0x004028c2]> dtsC 0 program start

[0x004028c2]> dtsC 1 decryption start

[0x004028c2]> dts

session: 0 at:0x004028a0 "program start"

session: 1 at:0x004028c2 "decryption start"

You can leave notes for each records to keep in your mind. dsb and dcb commands restore the program state from latest record if there are many records.

Program records can exported to file and of course import it. Export/Import records to/from file:

[0x004028c2]> dtst records_for_test

Session saved in records_for_test.session and dump in records_for_test.dump