Print Modes

One of the key features of radare2 is displaying information in many formats. The goal is to offer a selection of display choices to interpret binary data in the best possible way.

Binary data can be represented as integers, shorts, longs, floats, timestamps, hexpair strings, or more complex formats like C structures, disassembly listings, decompilation listing, be a result of an external processing…

Below is a list of available print modes listed by p?:

  1. [0x00005310]> p?
  2. |Usage: p[=68abcdDfiImrstuxz] [arg|len] [@addr]
  3. | p[b|B|xb] [len] ([S]) bindump N bits skipping S bytes
  4. | p[iI][df] [len] print N ops/bytes (f=func) (see pi? and pdi)
  5. | p[kK] [len] print key in randomart (K is for mosaic)
  6. | p-[?][jh] [mode] bar|json|histogram blocks (mode: e?search.in)
  7. | p2 [len] 8x8 2bpp-tiles
  8. | p3 [file] print stereogram (3D)
  9. | p6[de] [len] base64 decode/encode
  10. | p8[?][j] [len] 8bit hexpair list of bytes
  11. | p=[?][bep] [N] [L] [b] show entropy/printable chars/chars bars
  12. | pa[edD] [arg] pa:assemble pa[dD]:disasm or pae: esil from hex
  13. | pA[n_ops] show n_ops address and type
  14. | pb[?] [n] bitstream of N bits
  15. | pB[?] [n] bitstream of N bytes
  16. | pc[?][p] [len] output C (or python) format
  17. | pC[aAcdDxw] [rows] print disassembly in columns (see hex.cols and pdi)
  18. | pd[?] [sz] [a] [b] disassemble N opcodes (pd) or N bytes (pD)
  19. | pf[?][.nam] [fmt] print formatted data (pf.name, pf.name $<expr>)
  20. | pF[?][apx] print asn1, pkcs7 or x509
  21. | pg[?][x y w h] [cmd] create new visual gadget or print it (see pg? for details)
  22. | ph[?][=|hash] ([len]) calculate hash for a block
  23. | pj[?] [len] print as indented JSON
  24. | pm[?] [magic] print libmagic data (see pm? and /m?)
  25. | po[?] hex print operation applied to block (see po?)
  26. | pp[?][sz] [len] print patterns, see pp? for more help
  27. | pq[?][is] [len] print QR code with the first Nbytes
  28. | pr[?][glx] [len] print N raw bytes (in lines or hexblocks, 'g'unzip)
  29. | ps[?][pwz] [len] print pascal/wide/zero-terminated strings
  30. | pt[?][dn] [len] print different timestamps
  31. | pu[?][w] [len] print N url encoded bytes (w=wide)
  32. | pv[?][jh] [mode] show variable/pointer/value in memory
  33. | pwd display current working directory
  34. | px[?][owq] [len] hexdump of N bytes (o=octal, w=32bit, q=64bit)
  35. | pz[?] [len] print zoom view (see pz? for help)
  36. [0x00005310]>

Tip: when using json output, you can append the ~{} to the command to get a pretty-printed version of the output:

  1. [0x00000000]> oj
  2. [{"raised":false,"fd":563280,"uri":"malloc://512","from":0,"writable":true,"size":512,"overlaps":false}]
  3. [0x00000000]> oj~{}
  4. [
  5. {
  6. "raised": false,
  7. "fd": 563280,
  8. "uri": "malloc://512",
  9. "from": 0,
  10. "writable": true,
  11. "size": 512,
  12. "overlaps": false
  13. }
  14. ]

For more on the magical powers of ~ see the help in ?@?, and the Command Format chapter earlier in the book.

Hexadecimal View

px gives a user-friendly output showing 16 pairs of numbers per row with offsets and raw representations:

hexprint

Show Hexadecimal Words Dump (32 bits)

wordprint

8 bits Hexpair List of Bytes

  1. [0x00404888]> p8 16
  2. 31ed4989d15e4889e24883e4f0505449

Show Hexadecimal Quad-words Dump (64 bits)

pxq

Date/Time Formats

Currently supported timestamp output modes are:

  1. [0x00404888]> pt?
  2. |Usage: pt [dn] print timestamps
  3. | pt. print current time
  4. | pt print UNIX time (32 bit `cfg.bigendian`) Since January 1, 1970
  5. | ptd print DOS time (32 bit `cfg.bigendian`) Since January 1, 1980
  6. | pth print HFS time (32 bit `cfg.bigendian`) Since January 1, 1904
  7. | ptn print NTFS time (64 bit `cfg.bigendian`) Since January 1, 1601

For example, you can ‘view’ the current buffer as timestamps in the ntfs time:

  1. [0x08048000]> e cfg.bigendian = false
  2. [0x08048000]> pt 4
  3. 29:04:32948 23:12:36 +0000
  4. [0x08048000]> e cfg.bigendian = true
  5. [0x08048000]> pt 4
  6. 20:05:13001 09:29:21 +0000

As you can see, the endianness affects the result. Once you have printed a timestamp, you can grep the output, for example, by year:

  1. [0x08048000]> pt ~1974 | wc -l
  2. 15
  3. [0x08048000]> pt ~2022
  4. 27:04:2022 16:15:43 +0000

The default date format can be configured using the cfg.datefmt variable. Formatting rules for it follow the well known strftime(3) format. Check the manpage for more details, but these are the most important:

  1. %a The abbreviated name of the day of the week according to the current locale.
  2. %A The full name of the day of the week according to the current locale.
  3. %d The day of the month as a decimal number (range 01 to 31).
  4. %D Equivalent to %m/%d/%y. (Yecchfor Americans only).
  5. %H The hour as a decimal number using a 24-hour clock (range 00 to 23).
  6. %I The hour as a decimal number using a 12-hour clock (range 01 to 12).
  7. %m The month as a decimal number (range 01 to 12).
  8. %M The minute as a decimal number (range 00 to 59).
  9. %p Either "AM" or "PM" according to the given time value.
  10. %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). (TZ)
  11. %S The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds.)
  12. %T The time in 24-hour notation (%H:%M:%S). (SU)
  13. %y The year as a decimal number without a century (range 00 to 99).
  14. %Y The year as a decimal number including the century.
  15. %z The +hhmm or -hhmm numeric timezone (that is, the hour and minute offset from UTC). (SU)
  16. %Z The timezone name or abbreviation.

Basic Types

There are print modes available for all basic types. If you are interested in a more complex structure, type pf?? for format characters and pf??? for examples:

  1. [0x00499999]> pf??
  2. |pf: pf[.k[.f[=v]]|[v]]|[n]|[0|cnt][fmt] [a0 a1 ...]
  3. | Format:
  4. | b byte (unsigned)
  5. | B resolve enum bitfield (see t?)
  6. | c char (signed byte)
  7. | C byte in decimal
  8. | d 0xHEX value (4 bytes) (see 'i' and 'x')
  9. | D disassemble one opcode
  10. | e temporally swap endian
  11. | E resolve enum name (see t?)
  12. | f float value (4 bytes)
  13. | F double value (8 bytes)
  14. | i signed integer value (4 bytes) (see 'd' and 'x')
  15. | n next char specifies size of signed value (1, 2, 4 or 8 byte(s))
  16. | N next char specifies size of unsigned value (1, 2, 4 or 8 byte(s))
  17. | o octal value (4 byte)
  18. | p pointer reference (2, 4 or 8 bytes)
  19. | q quadword (8 bytes)
  20. | r CPU register `pf r (eax)plop`
  21. | s 32bit pointer to string (4 bytes)
  22. | S 64bit pointer to string (8 bytes)
  23. | t UNIX timestamp (4 bytes)
  24. | T show Ten first bytes of buffer
  25. | u uleb128 (variable length)
  26. | w word (2 bytes unsigned short in hex)
  27. | x 0xHEX value and flag (fd @ addr) (see 'd' and 'i')
  28. | X show formatted hexpairs
  29. | z null terminated string
  30. | Z null terminated wide string
  31. | ? data structure `pf ? (struct_name)example_name`
  32. | * next char is pointer (honors asm.bits)
  33. | + toggle show flags for each offset
  34. | : skip 4 bytes
  35. | . skip 1 byte
  36. | ; rewind 4 bytes
  37. | , rewind 1 byte

Use triple-question-mark pf??? to get some examples using print format strings.

  1. [0x00499999]> pf???
  2. |pf: pf[.k[.f[=v]]|[v]]|[n]|[0|cnt][fmt] [a0 a1 ...]
  3. | Examples:
  4. | pf 3xi foo bar 3-array of struct, each with named fields: 'foo' as hex, and 'bar' as int
  5. | pf B (BitFldType)arg_name` bitfield type
  6. | pf E (EnumType)arg_name` enum type
  7. | pf.obj xxdz prev next size name Define the obj format as xxdz
  8. | pf obj=xxdz prev next size name Same as above
  9. | pf *z*i*w nb name blob Print the pointers with given labels
  10. | pf iwq foo bar troll Print the iwq format with foo, bar, troll as the respective names for the fields
  11. | pf 0iwq foo bar troll Same as above, but considered as a union (all fields at offset 0)
  12. | pf.plop ? (troll)mystruct Use structure troll previously defined
  13. | pfj.plop @ 0x14 Apply format object at the given offset
  14. | pf 10xiz pointer length string Print a size 10 array of the xiz struct with its field names
  15. | pf 5sqw string quad word Print an array with sqw struct along with its field names
  16. | pf {integer}? (bifc) Print integer times the following format (bifc)
  17. | pf [4]w[7]i Print an array of 4 words and then an array of 7 integers
  18. | pf ic...?i foo bar "(pf xw yo foo)troll" yo Print nested anonymous structures
  19. | pf ;..x Print value located 6 bytes from current offset
  20. | pf [10]z[3]i[10]Zb Print an fixed size str, widechar, and var
  21. | pfj +F @ 0x14 Print the content at given offset with flag
  22. | pf n2 print signed short (2 bytes) value. Use N instead of n for printing unsigned values
  23. | pf [2]? (plop)structname @ 0 Prints an array of structs
  24. | pf eqew bigWord beef Swap endianness and print with given labels
  25. | pf.foo rr (eax)reg1 (eip)reg2 Create object referencing to register values
  26. | pf tt troll plop print time stamps with labels troll and plop

Some examples are below:

  1. [0x4A13B8C0]> pf i
  2. 0x00404888 = 837634441
  1. [0x4A13B8C0]> pf
  2. 0x00404888 = 837634432.000000

High-level Languages Views

Valid print code formats for human-readable languages are:

  • pc C
  • pc* print ‘wx’ r2 commands
  • pch C half-words (2 byte)
  • pcw C words (4 byte)
  • pcd C dwords (8 byte)
  • pci C array of bytes with instructions
  • pca GAS .byte blob
  • pcA .bytes with instructions in comments
  • pcs string
  • pcS shellscript that reconstructs the bin
  • pcj json
  • pcJ javascript
  • pco Objective-C
  • pcp python
  • pck kotlin
  • pcr rust
  • pcv JaVa
  • pcV V (vlang.io)
  • pcy yara
  • pcz Swift

If we need to create a .c file containing a binary blob, use the pc command, that creates this output. The default size is like in many other commands: the block size, which can be changed with the b command.

We can also just temporarily override this block size by expressing it as an argument.

  1. [0xB7F8E810]> pc 32
  2. #define _BUFFER_SIZE 32
  3. unsigned char buffer[_BUFFER_SIZE] = {
  4. 0x89, 0xe0, 0xe8, 0x49, 0x02, 0x00, 0x00, 0x89, 0xc7, 0xe8, 0xe2, 0xff, 0xff, 0xff, 0x81, 0xc3, 0xd6, 0xa7, 0x01, 0x00, 0x8b, 0x83, 0x00, 0xff, 0xff, 0xff, 0x5a, 0x8d, 0x24, 0x84, 0x29, 0xc2 };

That cstring can be used in many programming languages, not just C.

  1. [0x7fcd6a891630]> pcs
  2. "\x48\x89\xe7\xe8\x68\x39\x00\x00\x49\x89\xc4\x8b\x05\xef\x16\x22\x00\x5a\x48\x8d\x24\xc4\x29\xc2\x52\x48\x89\xd6\x49\x89\xe5\x48\x83\xe4\xf0\x48\x8b\x3d\x06\x1a

Strings

Strings are probably one of the most important entry points when starting to reverse engineer a program because they usually reference information about functions’ actions (asserts, debug or info messages…). Therefore, radare supports various string formats:

  1. [0x00000000]> ps?
  2. |Usage: ps[bijqpsuwWxz+] [N] Print String
  3. | ps print string
  4. | ps+[j] print libc++ std::string (same-endian, ascii, zero-terminated)
  5. | psb print strings in current block
  6. | psi print string inside curseek
  7. | psj print string in JSON format
  8. | psp[j] print pascal string
  9. | psq alias for pqs
  10. | pss print string in screen (wrap width)
  11. | psu[zj] print utf16 unicode (json)
  12. | psw[j] print 16bit wide string
  13. | psW[j] print 32bit wide string
  14. | psx show string with escaped chars
  15. | psz[j] print zero-terminated string

Most strings are zero-terminated. Below there is an example using the debugger to continue the execution of a program until it executes the ‘open’ syscall. When we recover the control over the process, we get the arguments passed to the syscall, pointed by %ebx. In the case of the ‘open’ call, it is a zero terminated string which we can inspect using psz.

  1. [0x4A13B8C0]> dcs open
  2. 0x4a14fc24 syscall(5) open ( 0x4a151c91 0x00000000 0x00000000 ) = 0xffffffda
  3. [0x4A13B8C0]> dr
  4. eax 0xffffffda esi 0xffffffff eip 0x4a14fc24
  5. ebx 0x4a151c91 edi 0x4a151be1 oeax 0x00000005
  6. ecx 0x00000000 esp 0xbfbedb1c eflags 0x200246
  7. edx 0x00000000 ebp 0xbfbedbb0 cPaZstIdor0 (PZI)
  8. [0x4A13B8C0]>
  9. [0x4A13B8C0]> psz @ 0x4a151c91
  10. /etc/ld.so.cache

Print Memory Contents

It is also possible to print various packed data types using the pf command:

  1. [0xB7F08810]> pf xxS @ rsp
  2. 0x7fff0d29da30 = 0x00000001
  3. 0x7fff0d29da34 = 0x00000000
  4. 0x7fff0d29da38 = 0x7fff0d29da38 -> 0x0d29f7ee /bin/ls

This can be used to look at the arguments passed to a function. To achieve this, simply pass a ‘format memory string’ as an argument to pf, and temporally change the current seek position/offset using @. It is also possible to define arrays of structures with pf. To do this, prefix the format string with a numeric value. You can also define a name for each field of the structure by appending them as a space-separated arguments list.

  1. [0x4A13B8C0]> pf 2*xw pointer type @ esp
  2. 0x00404888 [0] {
  3. pointer :
  4. (*0xffffffff8949ed31) type : 0x00404888 = 0x8949ed31
  5. 0x00404890 = 0x48e2
  6. }
  7. 0x00404892 [1] {
  8. (*0x50f0e483) pointer : 0x00404892 = 0x50f0e483
  9. type : 0x0040489a = 0x2440
  10. }

A practical example for using pf on a binary of a GStreamer plugin:

  1. $ radare2 /usr/lib/gstreamer-1.0/libgstflv.so
  2. [0x00006020]> aa; pdf @ sym.gst_plugin_flv_get_desc
  3. [x] Analyze all flags starting with sym. and entry0 (aa)
  4. sym.gst_plugin_flv_get_desc ();
  5. [...]
  6. 0x00013830 488d0549db0000 lea rax, section..data.rel.ro ; 0x21380
  7. 0x00013837 c3 ret
  8. [0x00006020]> s section..data.rel.ro
  9. [0x00021380]> pf ii*z*zp*z*z*z*z*z*z major minor name desc init version license source package origin release_datetime
  10. major : 0x00021380 = 1
  11. minor : 0x00021384 = 18
  12. name : (*0x19cf2)0x00021388 = "flv"
  13. desc : (*0x1b358)0x00021390 = "FLV muxing and demuxing plugin"
  14. init : 0x00021398 = (qword)0x0000000000013460
  15. version : (*0x19cae)0x000213a0 = "1.18.2"
  16. license : (*0x19ce1)0x000213a8 = "LGPL"
  17. source : (*0x19cd0)0x000213b0 = "gst-plugins-good"
  18. package : (*0x1b378)0x000213b8 = "GStreamer Good Plugins (Arch Linux)"
  19. origin : (*0x19cb5)0x000213c0 = "https://www.archlinux.org/"
  20. release_datetime : (*0x19cf6)0x000213c8 = "2020-12-06"

Disassembly

The pd command is used to disassemble code. It accepts a numeric value to specify how many instructions should be disassembled. The pD command is similar but instead of a number of instructions, it decompiles a given number of bytes.

  • d : disassembly N opcodes count of opcodes
  • D : asm.arch disassembler bsize bytes
  1. [0x00404888]> pd 1
  2. ;-- entry0:
  3. 0x00404888 31ed xor ebp, ebp

Selecting Target Architecture

The architecture flavor for the disassembler is defined by the asm.arch eval variable. You can use e asm.arch=?? to list all available architectures.

  1. [0x00005310]> e asm.arch=??
  2. _dAe _8_16 6502 LGPL3 6502/NES/C64/Tamagotchi/T-1000 CPU
  3. _dAe _8 8051 PD 8051 Intel CPU
  4. _dA_ _16_32 arc GPL3 Argonaut RISC Core
  5. a___ _16_32_64 arm.as LGPL3 as ARM Assembler (use ARM_AS environment)
  6. adAe _16_32_64 arm BSD Capstone ARM disassembler
  7. _dA_ _16_32_64 arm.gnu GPL3 Acorn RISC Machine CPU
  8. _d__ _16_32 arm.winedbg LGPL2 WineDBG's ARM disassembler
  9. adAe _8_16 avr GPL AVR Atmel
  10. adAe _16_32_64 bf LGPL3 Brainfuck
  11. _dA_ _32 chip8 LGPL3 Chip8 disassembler
  12. _dA_ _16 cr16 LGPL3 cr16 disassembly plugin
  13. _dA_ _32 cris GPL3 Axis Communications 32-bit embedded processor
  14. adA_ _32_64 dalvik LGPL3 AndroidVM Dalvik
  15. ad__ _16 dcpu16 PD Mojang's DCPU-16
  16. _dA_ _32_64 ebc LGPL3 EFI Bytecode
  17. adAe _16 gb LGPL3 GameBoy(TM) (z80-like)
  18. _dAe _16 h8300 LGPL3 H8/300 disassembly plugin
  19. _dAe _32 hexagon LGPL3 Qualcomm Hexagon (QDSP6) V6
  20. _d__ _32 hppa GPL3 HP PA-RISC
  21. _dAe _0 i4004 LGPL3 Intel 4004 microprocessor
  22. _dA_ _8 i8080 BSD Intel 8080 CPU
  23. adA_ _32 java Apache Java bytecode
  24. _d__ _32 lanai GPL3 LANAI
  25. ...

Configuring the Disassembler

There are multiple options which can be used to configure the output of the disassembler. All these options are described in e? asm.

  1. [0x00005310]> e? asm.
  2. asm.anal: Analyze code and refs while disassembling (see anal.strings)
  3. asm.arch: Set the arch to be used by asm
  4. asm.assembler: Set the plugin name to use when assembling
  5. asm.bbline: Show empty line after every basic block
  6. asm.bits: Word size in bits at assembler
  7. asm.bytes: Display the bytes of each instruction
  8. asm.bytespace: Separate hexadecimal bytes with a whitespace
  9. asm.calls: Show callee function related info as comments in disasm
  10. asm.capitalize: Use camelcase at disassembly
  11. asm.cmt.col: Column to align comments
  12. asm.cmt.flgrefs: Show comment flags associated to branch reference
  13. asm.cmt.fold: Fold comments, toggle with Vz
  14. ...

Currently there are 136 asm. configuration variables so we do not list them all.

Disassembly Syntax

The asm.syntax variable is used to change the flavor of the assembly syntax used by a disassembler engine. To switch between Intel and AT&T representations:

  1. e asm.syntax = intel
  2. e asm.syntax = att

You can also check asm.pseudo, which is an experimental pseudocode view, and asm.esil which outputs ESIL (‘Evaluable Strings Intermediate Language’). ESIL’s goal is to have a human-readable representation of every opcode semantics. Such representations can be evaluated (interpreted) to emulate effects of individual instructions.