A commandline framework for reverse engineering ala *nix-style
This book aims to cover most usage aspects of radare. A framework for reverse engineering and analyzing binaries.
--pancake
The radare project started in February of 2006 aiming to provide a Free and simple command line interface for an hexadecimal editor supporting 64 bit offsets to make searches and recovering data from hard-disks.
Since then, the project has grown with the aim changed to provide a complete framework for analyzing binaries with some basic *NIX concepts in mind like 'everything is a file', 'small programs that interact together using stdin/out' or 'keep it simple'.
It's mostly a single-person project, but some contributions (in source, patches, ideas or species) have been made and are really appreciated.
The project is composed by an hexadecimal editor as the central point of the project with assembler/disassembler, code analysis, scripting features, analysis and graphs of code and data, easy unix integration, ..
Nowadays the project is composed by a set of small utilities that can be used together or independently from the command line:
radare
The core of the hexadecimal editor and debugger. Allows to open any kind of file from different IO access like disk, network, kernel plugins, remote devices, debugged processes, ... and handle any of them as if they were a simple plain file.
Implements an advanced command line interface for moving around the file, analyzing data, disassembling, binary patching, data comparision, searching, replacing, scripting with ruby, python, lua and perl, ...
rabin
Extracts information from executable binaries like ELF, PE, Java CLASS, MACH-O. It's used from the core to get exported symbols, imports, file information, xrefs, library dependencies, sections, ...
rasm
Commandline assembler and disassembler for multiple architectures (intel[32,64], mips, arm, powerpc, java, msil, ...)
$ rasm -a java 'nop'
00
$ rasm -a x86 -d '90'
nop
rasc
Small utility to prepare buffers or shellcodes for exploiting vulnerabilities. It has an internal hardcoded database of shellcodes and a syscall-proxy interface with some nice helpers like fill-with nops, breakpoints, series of values to find the landing point, etc..
hasher
Implementation of a block-based hasher for small text strings or large disks, supporting multiple algorithms like md4, md5, crc16, crc32, sha1, sha256, sha384, sha512, par, xor, xorpair, mod255, hamdist or entropy.
It can be used to check the integrity or track changes between big files, memory dumps or disks.
radiff
Binary diffing utility with multiple algorithms implemented inside. Supports byte-level or delta diffing for binary files and code-analysis diffing to find changes in basic code blocks from radare code analysis or IDA ones using the idc2rdb rsc script.
rsc
Entrypoint for calling multiple small scripts and utilities that can be used from the shell.
You can get radare from the website http://radare.nopcode.org/
There are binary packages for multiple operating systems and GNU/Linux distributions (ubuntu, maemo, gentoo, windows, iphone, etc..) But I hardly encourage you to get the sources and compile them yourself to better understand the dependencies and have the source code and examples more accessible.
I try to publish a new stable release every month and sometimes publish nightly tarballs.
But as always the best way to use a software is to go upstream and pull the development repository which in radare is commonly more stable than the 'stable' releases O:)
To do this you will need mercurial (a distributed python-based source code management aliased Hg) and type:
$ hg clone http://radare.nopcode.org/hg/radare
This will probably take a while, so take a coffee and continue reading this paper.
To update your local copy of the repository you will have to type these two commands in the root of the recently created 'radare' directory.
$ hg pull
$ hg update
If you have local modifications of the source, you can revert them with:
$ hg revert --all
Or just feed me with a patch
$ hg diff > radare-foo.patch
Currently the core of radare can be compiled in many systems, and architectures, but the main development is done on GNU/Linux and GCC. But it is known to compile with TCC and SunStudio.
People usually wants to use radare as a debugger for reverse engineering, and this is a bit more restrictive portability issue, so if the debugger is not ported to your favorite platform, please, notify it to me or just disable the debugger layer with --without-debugger in the ./configure stage.
Nowadays the debugger layer can be used on Windows, GNU/Linux (intel32, intel64, mips, arm), FreeBSD, NetBSD, OpenBSD (intel32, intel64) and there are plans for Solaris and OSX. And there are some IO plugins to use gdb, gdbremote or wine as backends.
The current build system is 'waf':
$ ./waf distclean
$ ./waf configure
$ ./waf
$ sudo ./waf install
...
The old build system based on ACR/GMAKE stills maintained and usable, but don't relay on it because it is aimed to be removed to only use waf.
$ ./configure --prefix=/usr
$ gmake
$ sudo gmake install
The core accepts multiple flags from the command line to change some configuration or start with different options.
Here's the help message:
$ radare -h
radare [options] [file]
-s [offset] seek to the desired offset (cfg.seek)
-b [blocksize] change the block size (512) (cfg.bsize)
-i [script] interpret radare or ruby/python/perl/lua script
-p [project] load metadata from project file
-l [plugin.so] link against a plugin (.so or .dll)
-e [key=val] evaluates a configuration string
-d [program|pid] debug a program. same as --args in gdb
-f set block size to fit file size
-L list all available plugins
-w open file in read-write mode
-x dump block in hexa and exit
-n do not load ~/.radarerc and ./radarerc
-v same as -e cfg.verbose=false
-V show version information
-u unknown size (no seek limits)
-h this help message
Lot of people ping me some times for a sample usage session of radare to help to understand how the shell works and how to perform the most common tasks like disassembling, seeking, binary patching or debugging.
I hardly encourage you to read the rest of this book to help you understand better how everything works and enhace your skills, the learning curve of radare is usually a bit harder at the beggining, but after an hour of using it you will easily understand how most of the things work and how to get them cooperate together :)
For walking thru the binary file you will use three different kind of basic actions: seek, print and alterate.
To 'seek' there's an specific command abreviated as 's' than accepts an expression as argument that can be something like '10', '+0x25' or '[0x100+ptr_table]'. If you are working with block-based files you may prefer to set up the block size to 4K or the size required with the command 'b' and move forward or backward at seeks aligned to the block size using the '>' and '<' commands.
The 'print' command aliased as 'p', accepts a second letter to specify the print mode selected. The most common ones are 'px' for printing in hexadecimal, 'pd' for disassembling.
To 'write' open the file with 'radare -w'. This should be specified while opening the file, or just type 'eval file.write=true' in runtime to reopen the file in read-write-mode. You can use the 'w' command to write strings or 'wx' for hexpair strings:
> w hello world ; string
> wx 90 90 90 90 ; hexpairs
> wa jmp 0x8048140 ; assemble
> wf inline.bin ; write contents of file
Appending a '?' to the command you will get the help message of it. (p? for example)
Enter the visual mode pressing 'V<enter>', and return to the prompt using the 'q' key.
In the visual mode you should use hjkl keys which are the default ones for scrolling (like left,down,up,right). So entering in cursor mode ('c') you will be able select bytes if using the shift together with HJKL.
In the visual mode you can insert (alterate bytes) pressing 'i' and then <tab> to switch between the hex or string column. Pressing 'q' in hex panel to return into the visual mode.
The format of the commands looks something like that:
[#][!][cmd] [arg] [@ offset| @@ flags] [> file] [| shell-pipe] [ && ...] [; comment]
Some examples:
!step ; call debugger 'step' command
px 200 @ esp ; show 200 hex bytes at esp
pc > file.c ; dump buffer as a C byte array to file
wx 90 @@ sym_* ; write a nop on every symbol
pd 2000 | grep eax ; grep opcodes using 'eax' register
x 20 && s +3 && x 40 ; multiple commands in a single line
The expressions are mathematical representations of a 64 bit numeric value which can be displayed in different formats, compared or used at any command as a numeric argument. They support multiple basic arithmetic operations and some binary and boolean ones. The command used to evaluate these math expressions is the '?'. Here there are some examples:
[0xB7F9D810]> ? 0x8048000
0x8048000 ; 134512640d ; 1001100000o ; 0000 0000
[0xB7F9D810]> ? 0x8048000+34
0x8048022 ; 134512674d ; 1001100042o ; 0010 0010
[0xB7F9D810]> ? 0x8048000+0x34
0x8048034 ; 134512692d ; 1001100064o ; 0011 0100
[0xB7F9D810]> ? 1+2+3-4*3
0x6 ; 6d ; 6o ; 0000 0110
[0xB7F9D810]> ? [0x8048000]
0x464C457F ; 1179403647d ; 10623042577o ; 0111 1111
The supported arithmetic expressions supported are:
+ : addition
- : substraction
* : multiply
/ : division
% : modulus
> : shift right
< : shift left
The binary expressions should be scapped:
\| : logical OR
\& : logical AND
The values can be numbers in many formats:
0x033 : hexadecimal
3334 : decimal
sym_fo : resolve flag offset
10K : KBytes 10*1024
10M : MBytes 10*1024*1024
There are other special syntaxes for the expressions. Here's for example some of them:
$$ ; current seek
$$$ ; size of opcode at current seek
$${file.size} ; file.size (taken from eval variable)
$$j ; jump address (branch of instruction)
$$f ; false address (continuation after branch)
$$r ; data reference from opcode
For example:
[0x4A13B8C0]> :pd 2
0x4A13B8C0, mov eax, esp
0x4A13B8C2 call 0x4a13c000
[0x4A13B8C0]> :? $$+$$$
0x4a13b8c2
[0x4A13B8C0]> :pd 1 @ +$$$
0x4A13B8C2 call 0x4a13c000
The 'rax' utility comes with the radare framework and aims to be a minimalistic expression evaluator for the shell useful for making base conversions easily between floating point values, hexadecimal representations, hexpair strings to ascii, octal to integer. It supports endianness and can be used as a shell if no arguments given.
$ rax -h
Usage: rax [-] | [-s] [-e] [int|0x|Fx|.f|.o] [...]
int -> hex ; rax 10
hex -> int ; rax 0xa
-int -> hex ; rax -77
-hex -> int ; rax 0xffffffb3
float -> hex ; rax 3.33f
hex -> float ; rax Fx40551ed8
oct -> hex ; rax 035
hex -> oct ; rax Ox12 (O is a letter)
bin -> hex ; rax 1100011b
hex -> bin ; rax Bx63
-e swap endianness ; rax -e 0x33
-s swap hex to bin ; rax -s 43 4a 50
- read data from stdin until eof
Some examples:
$ rax 0x345
837
$ rax 837
0x345
$ rax 44.44f
Fx8fc23142
$ rax 0xfffffffd
-3
$ rax -3
0xfffffffd
$ rax -s "41 42 43 44"
ABCD
To start debugging a program use the '-d' flag and append the PID or the program path with arguments.
$ radare -d /bin/ls
The debugger will fork and load the 'ls' program in memory stopping the execution in the 'ld.so', so don't expect to see the entrypoint or the mapped libraries at this point. To change this you can define a new 'break entry point' adding 'e dbg.bep=entry' or 'dbg.bep=main' to your .radarerc.
But take care on this, because some malware or programs can execute code before the main.
Now the debugger prompt should appear and if you press 'enter' ( null command ) the basic view of the process will be displayed with the stack dump, general purpose registers and disassembly from current program counter (eip on intel).
All the debugger commands are handled by a plugin, so the 'system()' interface is hooked by it and you will have to supply them prefixing it with a '!' character.
Here's a list of the most common commands for the debugger:
> !help ; get the help
> !step 3 ; step 3 times
> !bp 0x8048920 ; setup a breakpoint
> !bp -0x8048920 ; remove a breakpoint
> !cont ; continue process execution
> !contsc ; continue until syscall
> !fd ; manipulate file descriptors
> !maps ; show process maps
> !mp ; change page protection permissions
> !reg eax=33 ; change a register
The easiest way to use the debugger is from the Visual mode, so, you will no need to remember much commands or keep states in your mind.
[0xB7F0C8C0]> Visual
After entering this command an hexdump of the current eip will be showed. Now press 'p' one time to get into the debugger view. You can press 'p' and 'P' to rotate thru the most commonly used print modes.
Use F6 or 's' to step into and F7 or 'S' to step over.
With the 'c' key you will toggle the cursor mode and being able to select range of bytes to nop them or set breakpoints using the 'F2' key.
In the visual mode you can enter commands with ':' to dump buffer contents like
x @ esi
To get the help in the visual mode press '?' and for the help of the debugger press '!'.
At this point the most common commands are !reg that can be used to get or set values for the general purpose registers. You can also manipulate the hardware and extended/floating registers.
The core reads ~/.radarerc while starting, so you can setup there some 'eval' commands to set it up in your favorite way.
To avoid parsing this file, use '-n' and to get a cleaner output for using radare in batch mode maybe is better to just drop the verbosity with '-v'.
All the configuration of radare is done with the 'eval' command which allows the user to change some variables from an internal hashtable containing string pairs.
The most common configuration looks like this:
$ cat ~/.radarerc
eval scr.color = true
eval dbg.bep = entry
eval file.id = true
eval file.flag = true
eval file.analyze = true
These configurations can be also defined using the '-e' flag of radare while loading it, so you can setup different initial configurations from the commandline without having to change to rc file.
$ radare -n -e scr.color=true -e asm.syntax=intel -d /bin/ls
All the configuration is stored in a hash table grouped by different root names ([i]cfg., file., dbg., ..[/i])
To get a list of the configuration variables just type 'eval' or 'e' in the prompt. All the basic commands can be reduced to a single char. You can also list the configuration variables of a single eval configruation group ending the command argument with a dot '.'.
There are two enhaced interfaces to help users to interactively configure this hashtable. One is called 'emenu' and provides a shell for walking through the tree and change variables.
To get a help about this command you can type 'e?':
[0x4A13B8C0]> e?
Usage: e[m] key=value
> ereset ; reset configuration
> emenu ; opens menu for eval
> e scr.color = true ; sets color for terminal
Note the 'e' of emenu, which stands for 'eval'. In radare, all basic commands can be reduced to a single char, and you can just type 'e?' to get the help of all the 'subcommands' for the basic command.
[0xB7EF38C0]> emenu
Menu: (q to quit)
- asm
- cfg
- child
- cmd
- dbg
- dir
- file
- graph
- scr
- search
- trace
- zoom
>
There is a easier eval interface accessible from the Visual mode, just typing 'e' after entering this mode (type 'Visual' command before).
Most of the eval tree is quite stable, so don't expect hard changes on this area.
I encourage you to experiment a bit on this to fit the interface to your needs.
The console access is wrapped by an API that permits to show the output of any command as ANSI, w32 console or HTML (more to come ncurses, pango, ...) this allows the core to be flexible enought to run on limited environments like kernels or embedded devices allowing us to get the feedback from the application in our favourite format.
To start, we'll enable the colors by default in our rc file:
$ echo 'e scr.color=true' >> ~/.radarerc
There's a tree of eval variables in scr.pal. to define the color palette for every attribute printed in console:
[0x465D8810]> e scr.pal.
scr.pal.prompt = yellow
scr.pal.default = white
scr.pal.changed = green
scr.pal.jumps = green
scr.pal.calls = green
scr.pal.push = green
scr.pal.trap = red
scr.pal.cmp = yellow
scr.pal.ret = red
scr.pal.nop = gray
scr.pal.metadata = gray
scr.pal.header = green
scr.pal.printable = bwhite
scr.pal.lines0 = white
scr.pal.lines1 = yellow
scr.pal.lines2 = bwhite
scr.pal.address = green
scr.pal.ff = red
scr.pal.00 = white
scr.pal.7f = magenta
If you think these default colors are not correct for any reason. Ping me and i'll change it.
Here's a list of the most common eval configuration variables, you can get the complete list using the 'e' command without arguments or just use 'e cfg.' (ending with dot, to list all the configuration variables of the cfg. space).
asm.arch
Defines the architecture to be used while disassembling (pd, pD commands) and analyzing code ('a' command). Currently it handles 'intel32', 'intel64', 'mips', 'arm16', 'arm' 'java', 'csr', 'sparc', 'ppc', 'msil' and 'm68k'.
It is quite simple to add new architectures for disassembling and analyzing code, so there is an interface adapted for the GNU disassembler and others for udis86 or handmade ones.
Setting asm.arch to 'objdump' the disassembly engine will use asm.objdump to disasemble the current block. For the code analysis the core will use the previous architecture defined in asm.arch.
[0x4A13B8C0]> e asm.objdump
objdump -m i386 --target=binary -D
[0x4A13B8C0]> e asm.arch
intel
[0x4A13B8C0]> pd 2
| 0x4A13B8C0, eip: 89e0 mov eax, esp
| 0x4A13B8C2 e839070000 call 0x4a13c000 ; 1 = 0x4a13c000
[0x4A13B8C0]> e asm.arch =objdump
[0x4A13B8C0]> pd
| 0x4A13B8C0, eip
0: 89 e0 mov eax,esp
2: e8 39 07 00 00 call 0x740
7: 89 c7 mov edi,eax
9: e8 e2 ff ff ff call 0xfffffff0
...
This is useful for disassembling files in architectures not supported by radare. You should understand 'objdump' as 'your-own-disassembler'.
asm.syntax
Defines the syntax flavour to be used while disassembling. This is currently only targeting the udis86 disassembler for the x86 (32/64 bits). The supported values are 'intel' or 'att'.
asm.pseudo
Boolean value that determines which string disassembly engine to use (the native one defined by the architecture) or the one filtered to show pseudocode strings. This is 'eax=ebx' instead of a 'mov eax, ebx' for example.
asm.section
Shows or hides section name (based on flags) at the left of the address.
asm.os
Defines the target operating system of the binary to analyze. This is automatically defined by 'rabin -rI' and it's useful for switching between the different syscall tables and perform different depending on the OS.
asm.flags
If defined to 'true' shows the flags column inside the disassembly.
asm.lines
Draw lines at the left of the offset in the dissassemble print format (pd, pD) to graphically represent jumps and calls inside the current block.
asm.linesout
When defined as 'true', also draws the jump lines in the current block that goes ouside of this block.
asm.linestyle
Can get 'true' or 'false' values and makes the line analysis be performed from top to bottom if false or bottom to top if true. 'false' is the optimal and default value for readability.
asm.offset
Boolean value that shows or hides the offset address of the disassembled opcode.
asm.profile
Set how much information is showed to the user on disassembly. Can get the values 'default', 'simple', 'debug' and 'full'.
This eval will modify other asm. variables to change the visualization properties for the disassembler engine. 'simple' asm.profile will show only offset+opcode, and 'debug' will show information about traced opcodes, stack pointer delta, etc..
asm.trace
Show tracing information at the left of each opcode (sequence number and counter). This is useful to read execution traces of programs.
asm.bytes
Boolean value that shows or hides the bytes of the disassebled opcode.
dbg.focus
Can get a boolean value. If true, radare will ignore events from non selected PIDs.
cfg.bigendian
Choose the endian flavour 'true' for big, 'false' for little.
file.id
When enabled (set it up to '1' or 'true'). Runs rabin -rI after opening the target file and tries to identify the file type and setup the base address and stuff like that.
file.analyze
Runs '.af* @@ sym_' and '.af* @ entrypoint', after resolving the symbols while loading the binary, to determine the maximum information about the code analysis of the program. This will not be used while opening a project file, so it is preloaded. This option requires file.id and file.flag to be true.
file.flag
Finds all the information of the target binary and setup flags to point symbols (imports, exports), sections, maps, strings, etc.
This command is commonly used with file.id.
scr.color
This boolean variable allows to enable or disable the colorized output
scr.seek
This variable accepts an expression, a pointer (eg. eip), etc. radare will automatically seek to make sure its value is always within the limits of the screen.
cfg.fortunes
Enables or disables the 'fortune' message at the begging of the program
The basic set of commands in radare can be mostly grouped by action, and they should be easy to remember and short. This is why they are grouped with a single character, subcommands or related commands are described with a second character. For example '/ foo' for searching plain strings or '/x 90 90' to look for hexpair strings.
The format of the commands looks something like that:
[#][!][cmd] [arg] [@ offset| @@ flags] [> file] [| shell-pipe] [ && ...]
This is: repeat the described command '#' times.
> 3s +1024 ; seeks three times 1024 from the current seek
If the command starts with '!' the string is passed to the plugin hadling the current IO (the debugger for example), if no one handles it calls to posix_system() which is a shell escape, you can prefix the command with two '!!'.
> !help ; handled by the debugger or shell
> !!ls ; runs ls in the shell
The [arg] argument depends on the command, but most of them take a number as argument to specify the number of bytes to work on instead of block size. Other commands accept math expressions, or strings.
> px 0x17 ; show 0x17 bytes in hexa at cur seek
> s base+0x33 ; seeks to flag 'base' plus 0x33
> / lib ; search for 'lib' string.
The '@' is used to specify a temporal seek where the command is executed. This is quite useful to not seeking all the time.
> p8 10 @ 0x4010 ; show 10 bytes at offset 0x4010
> f patata @ 0x10 ; set 'patata' flag at offset 0x10
Using '@@' you can execute a single command on a list of flags matching the glob:
> s 0
> / lib ; search 'lib' string
> p8 20 @@ hit0_* ; show 20 hexpairs at each search hit
The '>' is used to pipe the output of the command to a file (truncating to 0 if exist)
> pr > dump.bin ; dump 'raw' bytes of current block to 'dump.bin' file
> f > flags.txt ; dump flag list to 'flags.txt'
The '|' pipe is used to dump the output of the command to another program.
[0x4A13B8C0]> f | grep section | grep text
0x0805f3b0 512 section__text
0x080d24b0 512 section__text_end
Using the '&&' chars you can concatenate multiple commands in a single line:
> x @ esp && !reg && !bt ; shows stack, regs and backtrace
The command 's' is used to seek. It accepts a math expression as argument that can be composed by shift operations, basic math ones and memory access.
The 's'eek command supports '+-*!' characters as arguments to perform acts on the seek history.
[0x4A13B8C0]> s?
Usage: > s 0x128 ; absolute seek
> s +33 ; relative seek
> sn ; seek to next opcode
> sb ; seek to opcode branch
> sc ; seek to call index (pd)
> sx N ; seek to code xref N
> sX N ; seek to data reference N
> sS N ; seek to section N (fmi: 'S?')
> s- ; undo seek
> s+ ; redo seek
> s* ; show seek history
> .s* ; flag them all
> s! ; reset seek history
The '>' and '<' commands are used to seek into the file using a block-aligned base.
> >>> ; seek 3 aligned blocks forward
> 3> ; 3 times block-seeking
> s +30 ; seek 30 bytes forward from current seek
> s 0x300 ; seek at 0x300
> s [0x400] ; seek at 4 byte dword at offset 0x400
> s 10+0x80 ; seek at 0x80+10
The 'sn' and 'sb' commands uses the code analysis module to determine information about the opcode in the current seek and seek to the next one (sn) or branch where it points (sb).
[0x4A13B8C0]> :pd 1
0x4A13B8C0, mov eax, esp
[0x4A13B8C0]> sn ; seek next opcode
[0x4A13B8C2]> :pd 1
0x4A13B8C2 call 0x4a13c000
[0x4A13B8C2]> sb ; seek to branch address
[0x4A13C000]> :pd 1
0x4A13C000, push ebp
[0x4A13C000]>
To 'query' the math expression you can evaluate them using the '?' command and giving the math operation as argument. And getting the result in hexa, decimal, octal and binary.
> ? 0x100+200
0x1C8 ; 456d ; 710o ; 1100 1000
All the seeks are stored in a linked list as a history of navigation over the file. You can easily go forward backward of the seek history by using the 's-' and 's+' commands.
In visual mode just press 'u' or 'U' to undo or redo inside the seek history.
Here's a seesion example:
[0x00000000]> s 0x100
[0x00000100]> s 0x200
[0x00000200]> s- ; undo last seek done
[0x00000100]>
The block size is the default view size for radare. All commands will work with this constraint, but you can always temporally change the block size just giving a numeric argument to the print commands for example (px 20)
[0xB7F9D810]> b?
Usage: b[f flag]|[size] ; Change block size
> b 200 ; set block size to 200
> bt next @ here ; block size = next-here
> bf sym_main ; block size = flag size
The 'b' command is used to change the block size:
[0x00000000]> b 0x100 ; block size = 0x100
[0x00000000]> b +16 ; ... = 0x110
[0x00000000]> b -32 ; ... = 0xf0
The 'bf' command is used to change the block size to the one specified by a flag. For example in symbols, the block size of the flag represents the size of the function.
[0x00000000]> bf sym_main ; block size = sizeof(sym_main)
[0x00000000]> pd @ sym_main ; disassemble sym_main
...
You can perform these two operations in a single one (pdf):
[0x00000000]> pdf @ sym_main
Another useful block-size related is 'bt' that will set a new block size depending on the current offset and a 'end' address. This is useful when working with io-streams like sockets or serial ports, because you can easily set the block size to fit just a single read. For example
$ radare socket://www.gogle.com:80/
[0x0000000]> w GET /\r\n\r\n
[0x0000000]> bt _sockread_2 @ _sockread_1
You can also use this command to manually get the interpolation between two search hits (for example when looking for headers and footers in a raw disk image).
It is usually on firmware images, bootloaders and binary files to find sections that are loaded in memory at different addresses than the one in the disk.
To solve this issue, radare implements two utilities: 'file.baddr' and 'S'.
The file.baddr specifies the current base address to be used for disassembling and displaying offsets. In the same way all offsets used in expressions are also affected by this eval variable.
For files with more than one base address. The 'S'ection command will do the job. Here's the help message:
[0xB7EE8810]> S?
Usage: S len [base [comment]] @ address
> S ; list sections
> S* ; list sections (in radare commands
> S= ; list sections (in visual)
> S 4096 0x80000 rwx section_text @ 0x8048000 ; adds new section
> S 4096 0x80000 ; 4KB of section at current seek with base 0x.
> S 10K @ 0x300 ; create 10K section at 0x300
> S -0x300 ; remove this section definition
> Sc rwx _text ; add comment to the current section
> Sb 0x100000 ; change base address
> St 0x500 ; set end of section at this address
> Sf 0x100 ; set from address of the current section
This command allows you to manage multiple base addresses depending on the current seek, and enables the possibility to add comments to them. So the debugger information can be imported to the core in a simple way, adding information about the page protections of each section and so.
Here's a sample dummy session.
[0xB7EEA810]> S 10K
[0xB7EE8810]> s +5K
[0xB7EE8810]> S 20K
[0xB7EE9C10]> s +3K
[0xB7EE9C10]> S 5K
We can specify a section in a single line in this way:
S [size] [base-address] [comment] @ [from-address]
For example:
S section_text_end-section_text 0x8048500 r-x section_text @ 0x4300
Displaying the sections information:
[0xB7EEA810]> S
00 * 0xb7ee8810 - 0xb7eeb010 bs=0x00000000 sz=0x00002800 ; eip
01 * 0xb7ee9c10 - 0xb7eeec10 bs=0x00000000 sz=0x00005000
02 * 0xb7eea810 - 0xb7eebc10 bs=0x00000000 sz=0x00001400
[0xB7EEA810]> S=
00 0xb7ee8810 |#################-------------------------| 0xb7eeb010
01 0xb7ee9c10 |---------#################################| 0xb7eeec10
02 0xb7eea810 |--------------########--------------------| 0xb7eebc10
=> 0xb7eea810 |#-----------------------------------------| 0xb7eea874
The first three lines are sections and the last one is the current seek representation based on the proportions over them.
The 's'eek command implements a 'sS' (seek to Section) to seek at the beeginging to the section number N. For example: 'sS 1' in this case will seek to 0xb7ee9c10.
To remove a section definition just prefix the from-address of the section with '-':
[0xB7EE8810]> S -0xb7ee9c10
[0xB7EE8810]> S
00 . 0xb7ee9c10 - 0xb7eeec10 bs=0x00000000 sz=0x00005000
01 . 0xb7eea810 - 0xb7eebc10 bs=0x00000000 sz=0x00001400
After the section definition we can change the parameters of them with the Sf, St, Sc, Sb commands. After this, radare core will automatically setup the file.baddr depending on this section information
Radare IO allows to virtually map contents of files in the same IO space at random offsets. This is useful to open multiple files in a single view or just to 'emulate' an static environment like if it was in the debugger with the program and all its libraries mapped there.
Using the 'S'ections command you'll be able to define different base address for each library loaded at different offsets.
Mapping files is done with the 'o' (open) command. Let's read the help:
[0x00000000]> o?
Usage: o [file] [offset]
> o /bin/ls ; open file
> o /lib/libc.so 0xC848000 ; map file at offset
> o- /lib/libc.so ; unmap
Let's prepare a simple layout:
$ rabin -l ./a.out
libc.so.6
$ radare -u ./a.out
[0x00000000]> o /lib/libc.so.6 0x10000000
[0x00000000]> o /lib/ld-2.7.so 0x465f2000
NOTE: radare has been started with the -u flag to ignore file size limits and being able to seek on far places like where we have mapped our libs.
Listing mapped files:
[0x00000000]> o
0x00000000 0x000018da ./a.out
0x465f2000 0x4660cf28 /lib/ld-2.7.so
0x10000000 0x101370ec /lib/libc.so.6
Let's print some strings from ld.so
[0x00000000]> pa @ 0x465F0000+ 2469
_rtld_global\x00_dl_make_stack_executable\x00__libc_stack_end\x00__libc_memalign\x00malloc\x00_dl_deallocate_tls
\x00__libc_enable_secure\x00_dl_get_tls_static_info\x00calloc\x00_dl_debug_state\x00_dl_argv\x00_dl_allocate_tls
_init\x00_rtld_global_ro\x00realloc\x00_dl_tls_setup\x00_dl_rtld_di_...
To unmap these files just use the 'o-' command giving the mapped file name as argument.
One of the efforts in radare is the way to show the information to the user. This is interpreting the bytes and giving an almost readable output format.
The bytes can be represented as integers, shorts, longs, floats, timestamps, hexpair strings, or things more complex like C structures, disassembly, decompilations, external processors, ..
This is a list of the available print modes listable with 'p?':
[0x08049A80]> p?
Available formats:
a : ascii (null)
A : ascii printable (null)
b : binary N bytes
B : LSB Stego analysis N bytes
c : C format N bytes
d : disassembly N opcodes bsize bytes
D : asm.arch disassembler bsize bytes
f : float 4 bytes
F : windows filetime 8 bytes
i : integer 4 bytes
l : long 4 bytes
L : long long 8 bytes
m : print memory structure 0xHHHH
o : octal N bytes
O : Zoom out view entire file
p : cmd.prompt (null)
% : print scrollbar of seek (null)
r : raw ascii (null)
R : reference (null)
s : asm shellcode (null)
t : unix timestamp 4 bytes
T : dos timestamp 4 bytes
u : URL encoding (null)
U : executes cmd.user (null)
v : executes cmd.vprompt (null)
1 : p16: 16 bit hex word 2 bytes
3 : p32: 32 bit hex dword 4 bytes
6 : p64: 64 bit quad-word 8 bytes
7 : print 7bit block as raw 8bit (null)
8 : p8: 8 bit hex pair N byte
x : hexadecimal byte pairs N byte
z : ascii null terminated (null)
Z : wide ascii null end (null)
User-friendly way:
[0x4A13B8C0]> px
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x4A13B8C0, 89e0 e839 0700 0089 c7e8 e2ff ffff 81c3 ...9............
0x4A13B8D0, eea6 0100 8b83 08ff ffff 5a8d 2484 29c2 ..........Z.$.).
Hexpairs:
[0x4A13B8C0]> p8
89 e0 e8 39 07 00 00 89 c7 e8 e2 ff ff ff 81 c3 ee a6 01 00 8b 83 08 ff ff ff 5a 8d 24 84 29 c2
Basic size types governed by endian:
16 bit words
[0x4A13B8C0]> p16 4
0xe089
0x39e8
32 bit doublewords
[0x4A13B8C0]> p32 4
0x39e8e089
[0x4A13B8C0]> e cfg.bigendian
false
[0x4A13B8C0]> e cfg.bigendian = true
[0x4A13B8C0]> p32 4
0x89e0e839
[0x4A13B8C0]>
64 bit dwords
[0x08049A80]> p8 16
31 ed 5e 89 e1 83 e4 f0 50 54 52 68 60 9e 05 08
[0x08049A80]> p64 16
0x31ed5e89e183e4f0
0x50545268609e0508
The current supported timestamp print modes are:
F : windows filetime 8 bytes
t : unix timestamp 4 bytes
T : dos timestamp 4 bytes
For example, you can 'view' the current buffer as timestamps in dos, unix or windows filetime formats:
[0x08048000]> eval cfg.bigendian = 0
[0x08048000]> pt 4
30:08:2037 12:25:42 +0000
[0x08048000]> eval cfg.bigendian = 1
[0x08048000]> pt 4
17:05:2007 12:07:27 +0000
As you can see, the endianness affects to the print formats. Once printing these filetimes you can grep the results by the year for example:
[0x08048000]> pt | grep 1974 | wc -l
15
[0x08048000]> pt | grep 2022
27:04:2022 16:15:43 +0000
The date format printed can be configured with the 'cfg.datefmt' variable following the strftime(3) format.
Extracted from the manpage:
%a The abbreviated weekday name according to the current locale.
%A The full weekday name according to the current locale.
%b The abbreviated month name according to the current locale.
%B The full month name according to the current locale.
%c The preferred date and time representation for the current locale.
%C The century number (year/100) as a 2-digit integer. (SU)
%d The day of the month as a decimal number (range 01 to 31).
%e Like %d, the day of the month as a decimal number, leading spaces
%E Modifier: use alternative format, see below. (SU)
%F Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)
%g Like %G, but without century, that is, with a 2-digit year (00-99). (TZ)
%h Equivalent to %b. (SU)
%H The hour as a decimal number using a 24-hour clock (range 00 to 23).
%I The hour as a decimal number using a 12-hour clock (range 01 to 12).
%j The day of the year as a decimal number (range 001 to 366).
%k The hour (24-hour clock) as a decimal number (range 0 to 23);
%l The hour (12-hour clock) as a decimal number (range 1 to 12);
%m The month as a decimal number (range 01 to 12).
%M The minute as a decimal number (range 00 to 59).
%n A newline character. (SU)
%O Modifier: use alternative format, see below. (SU)
%p Either ���AM��� or ���PM���
%P Like %p but in lowercase: ���am��� or ���pm���
%r The time in a.m. or p.m. notation. In the POSIX this is to %I:%M:%S %p. (SU)
%R The time in 24-hour notation (%H:%M). (SU) For seconds, see %T below.
%s The number of seconds since the Epoch (1970-01-01 00:00:00 UTC). (TZ)
%S The second as a decimal number (range 00 to 60).
%t A tab character. (SU)
%T The time in 24-hour notation (%H:%M:%S). (SU)
%u The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. (SU)
%w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u.
%W The week number of the current year as a decimal number, range 00 to 53.
%x The preferred date representation for the current locale without the time.
%X The preferred time representation for the current locale without the date.
%y The year as a decimal number without a century (range 00 to 99).
%Y The year as a decimal number including the century.
%z The time-zone as hour offset from GMT. (using "%a, %d %b %Y %H:%M:%S %z"). (GNU)
%Z The time zone or name or abbreviation.
%+ The date and time in date(1) format. (TZ) (Not supported in glibc2.)
%% A literal ���%��� character.
All basic C types are mapped as print modes for float, integer, long and longlong. If you are interested in a more complex structure or just an array definition see 'print memory' section for more information.
Here's the list of the print (p?) modes for basic C types:
f : float 4 bytes
i : integer 4 bytes
l : long 4 bytes
L : long long 8 bytes
Let's see some examples:
[0x4A13B8C0]> pi 32
57
137
255
195
0
255
141
194
[0x4A13B8C0]> pf
-0.000000
0.000000
-119237.992188
nan
-25687860278081448018744180736.000000
-0.000000
nan
c : C format N bytes
s : asm shellcode (null)
[0xB7F8E810]> pc 32
#define _BUFFER_SIZE 32
unsigned char buffer[_BUFFER_SIZE] = {
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 };
[0xB7F8E810]> ps 32
eip:
.byte 0x89, 0xe0, 0xe8, 0x49, 0x02, 0x00, 0x00, 0x89, 0xc7, 0xe8, 0xe2
.byte 0xff, 0xff, 0xff, 0x81, 0xc3, 0xd6, 0xa7, 0x01, 0x00, 0x8b, 0x83
.byte 0x00, 0xff, 0xff, 0xff, 0x5a, 0x8d, 0x24, 0x84, 0x29, 0xc2
.equ eip_len, 32
Strings are probably one of the most important entrypoints while starting to reverse engineer a program because they are usually referencing information about the functions actions ( asserts, debug or info messages, ...).
So it is important for radare to be able to print strings in multiple ways:
..p?..
a : ascii (null)
A : ascii printable (null)
z : ascii null terminated (null)
Z : wide ascii null end (null)
r : raw ascii (null)
Commands 'pa' and 'pA' are pretty similar, but 'pA' protects your console from strange non-printable characters. These two commands are restricted to the block size, so you will have to manually adjust the block size to get a nicer format. If the analyzed strings are zero-terminated or wide-chars, use 'z' or 'Z'.
Most common strings will be just zero-terminated ones. Here's an example by using the debugger to continue the execution of the 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. Which is obviously a zero terminated string.
[0x4A13B8C0]> !contsc open
0x4a14fc24 syscall(5) open ( 0x4a151c91 0x00000000 0x00000000 ) = 0xffffffda
[0x4A13B8C0]> !regs
eax 0xffffffda esi 0xffffffff eip 0x4a14fc24
ebx 0x4a151c91 edi 0x4a151be1 oeax 0x00000005
ecx 0x00000000 esp 0xbfbedb1c eflags 0x200246
edx 0x00000000 ebp 0xbfbedbb0 cPaZstIdor0 (PZI)
[0x4A13B8C0]>
[0x4A13B8C0]> pz @ 0x4a151c91
/etc/ld.so.cache
Finally, the 'pr' is used to raw print the bytes to stdout. These bytes can be redirected to a file by using the '>' character:
[0x4A13B8C0]> pr 20K > file
[0x4A13B8C0]> !!du -h file
20K file
It is possible to print various packed data types in a single line using the 'pm' command (print memory). Here's the help and some examples:
[0x4A13B8C0]> pm
Usage: pm [times][format] [arg0 arg1]
Example: pm 10xiz pointer length string
e - temporally swap endian
f - float value
b - one byte
B - show 10 first bytes of buffer
i - %d integer value (4 byets)
w - word (16 bit hexa)
q - quadword (8 bytes)
p - pointer reference
x - 0x%08x hexadecimal value
z - \0 terminated string
Z - \0 terminated wide string
s - pointer to string
t - unix timestamp string
* - next char is pointer
. - skip 1 byte
The simple use would be like this:
[0xB7F08810]> pm xxs @ esp
0xbf8614d4 = 0xb7f22ff4
0xbf8614d8 = 0xb7f16818
0xbf8614dc = 0xbf8614dc -> 0x00000000 /etc/ld.so.cache
This is sometimes useful for looking at the arguments passed to a function, by just giving the 'format memory string' as argument and temporally changing the current seek with the '@' token.
It is also possible to define arrays of structures with 'pm'. Just prefix the format string with a numeric value.
You can also define a name for each field of the structure by giving them as optional arguments after the format string splitted by spaces.
[0x4A13B8C0]> pm 2xw pointer type @ esp
0xbf87d160 [0] {
pointer : 0xbf87d160 = 0x00000001
type : 0xbf87d164 = 0xd9f3
}
0xbf87d164 [1] {
pointer : 0xbf87d164 = 0xbf87d9f3
type : 0xbf87d168 = 0x0000
}
If you want to store this information as metadata for the binary file just use the same arguments, but instead of using pm, use Cm. To store all the metadata stored while analyzing use the 'Ps <filename>' command to save the project and then run radare -p project-file to restore the session. Read 'projects' section for more information.
A practical example for using pm on a binary GStreamer plugin:
$ radare ~/.gstreamer-0.10/plugins/libgstflumms.so
[0x000028A0]> seek sym_gst_plugin_desc
[0x000185E0]> pm iissxsssss major minor name desc _init version \
license source package origin
major : 0x000185e0 = 0
minor : 0x000185e4 = 10
name : 0x000185e8 = 0x000185e8 flumms
desc : 0x000185ec = 0x000185ec Fluendo MMS source
_init : 0x000185f0 = 0x00002940
version : 0x000185f4 = 0x000185f4 0.10.15.1
license : 0x000185f8 = 0x000185f8 unknown
source : 0x000185fc = 0x000185fc gst-fluendo-mms
package : 0x00018600 = 0x00018600 Fluendo MMS source
origin : 0x00018604 = 0x00018604 http://www.fluendo.com
The 'pd' command is the one used to disassemble code, it accepts a numeric value to specify how many opcodes are wanted to be disassembled. The 'pD' one acts in the same way, but using a number-of-bytes instead of counting instructions.
d : disassembly N opcodes count of opcodes
D : asm.arch disassembler bsize bytes
If you prefer a smarter disassembly with offset and opcode prefix the 'pd' command with ':'. This is used to temporally drop the verbosity while executing a radare command.
[0x4A13B8C0]> pd 1
| 0x4A13B8C0, eip: 89e0 mov eax, esp
[0x4A13B8C0]> :pd 1
0x4A13B8C0, mov eax, esp
The ',' near the offset determines if the address is aligned to 'cfg.addrmod' (this is 4 by default).
The architecture flavour for the disassembly is defined by the 'asm.arch' eval variable. Here's a list of all the supported architectures:
[0xB7F08810]> eval asm.arch = arm
Supported values:
intel
intel16
intel32
intel64
x86
mips
arm
arm16
java
sparc
ppc
m68k
csr
msil
There are multiple options that can be used to configure the output of the disassembly
asm.comments = true ; show/hide comments
asm.cmtmargin = 27 ; comment margins
asm.cmtlines = 0 ; max number of comment lines (0=unlimit)
asm.offset = true ; show offsets
asm.reladdr = false ; show relative addresses
asm.nbytes = 8 ; max number of bytes per opcode
asm.bytes = true ; show bytes
asm.flags = true ; show flags
asm.flagsline = false ; show flags in a new line
asm.functions = true ; show function closures
asm.lines = true ; show jump/call lines
asm.nlines = 6 ; max number of jump lines
asm.lineswide = true ; use wide jump lines
asm.linesout = false ; show jmp lines that go outside the block
asm.linestyle = false ; use secondary jump line style
asm.trace = false ; show opcode trace information
asm.os = linux ; used for syscall resolution and so
asm.split = true ; split end blocks by lines
asm.splitall = false ; split all blocks by lines
asm.size = false ; show size of opcode
The syntax is the flavour of disassembly syntax prefered to be used by the disasm engine.
Actually the x86 disassembler is the more complete one. It's based on udis86 and supports the following syntax flavours:
e asm.syntax = olly
e asm.syntax = intel
e asm.syntax = att
e asm.syntax = pseudo
The 'olly' syntax uses the ollydbg disassembler engine. 'intel' and 'att' are the most common ones and 'pseudo' is an experimental pseudocode disassembly, sometimes useful for reading algorithms.
The zoom is a print mode that allows you to get a global view of the whole file or memory map in a single screen. Each byte represents file_size/block_size bytes of the file. Use the pO (zoom out print mode) to use it, or just toggle 'z' in the visual mode to zoom-out/zoom-in.
The cursor can be used to scroll faster thru the zoom out view and pressing 'z' again to zoom-in where the cursor points.
zoom.byte values:
F : number of 0xFF
f : number of flags
c : code (functions)
s : strings
t : traces (opcode traces)
p : number of printable chars
e : entropy calculation
* : first byte of block
For example. let's see some examples:
[0x08049790]> pO
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00001790, 7fc7 0107 0141 b9e9 559b 3b85 f87d 7f89 ff05 .....A..U.;..}....
0x00007730, 04c0 8505 c78b 7555 7dc3 0584 f8b0 8985 8900 ......uU}.........
0x0000D6D0, 8b55 1485 fbff ffff ff50 83d0 6620 2020 6561 .U.......P..f ea
0x00013670, 6918 7f57 cc74 002e 2400 i..W.t..$.
[0x08049790]> eval zoom.byte = printable
[0x08049790]> pO
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00001790, 7fc7 0107 0141 b9e9 559b 3b85 f87d 7f89 ff05 .....A..U.;..}....
0x00007730, 04c0 8505 c78b 7555 7dc3 0584 f8b0 8985 8900 ......uU}.........
0x0000D6D0, 8b55 1485 fbff ffff ff50 83d0 6620 2020 6561 .U.......P..f ea
0x00013670, 6918 7f57 cc74 002e 2400 i..W.t..$.
[0x08049790]> pO
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00001790, 0202 0304 0505 0505 0505 0505 0505 0605 0505 ..................
0x00007730, 0505 0505 0505 0505 0505 0606 0505 0505 0605 ..................
0x0000D6D0, 0505 0405 0505 0505 0505 0505 0303 0303 0405 ..................
0x00013670, 0403 0405 0404 0304 0303 ..........
[0x08049790]> eval zoom.byte = flags
[0x08049790]> pO
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00001790, 0b04 1706 0400 0000 0000 0000 0000 0000 0000 ..................
0x00007730, 0000 0000 0000 0000 0000 0000 0000 0000 0000 ..................
0x0000D6D0, 0000 0000 0000 0000 0000 000d 1416 1413 165b .................[
0x00013670, 1701 0e23 0b67 2705 0f12 ...#.g'...
[0x08049790]> eval zoom.byte = FF
[0x08049790]> pO
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00001790, 0000 0000 0000 0001 0000 0001 0000 0000 0200 ..................
0x00007730, 0000 0100 0000 0000 0000 0000 0000 0101 0000 ..................
0x0000D6D0, 0000 0001 0201 0202 0100 0000 0000 0000 0000 ..................
0x00013670, 0000 0000 0002 0000 0000 ..........
In the debugger, the zoom.from and zoom.to eval variables are defined by .!maps* to fit the user code sections of memory of the target process.
BTW you can determine the limits for performing a zoom on a range of bytes of the whole bytespace by using the zoom.from and zoom.to eval variables.
[0x465D8810]> e zoom.
zoom.from = 0x08048000
zoom.to = 0x0805f000
zoom.byte = head
NOTE: These values (0x8048000-...) are defined by the debugger to limit the zoom view while debugging to only visualize the user maps of the program.
The flags are bookmarks at a certain offset in the file that can be stored inside 'flag spaces'. A flag space is something like a namespace for flags. They are used to group flags with similar characteristics or of a certain type. Some example of flagspaces could be [i]sections, registers, symbols, search hits[/i], etc.
To create a flag just type:
> f flag_name @ offset
You can remove this flag adding '-' at the begginging of the command. Most commands accept '-' as argument-prefix as a way to delete.
> f -flag_name
To switch/create between flagspaces use the 'fs' command:
[0x4A13B8C0]> fs ; list flag spaces
00 symbols
01 imports
02 sections
03 strings
04 regs
05 maps
> fs symbols
> f ; list only flags in symbols flagspace
...
> fs * ; select all flagspaces
You can create two flags with the same name with 'fn' or rename them with 'fr'.
Sometimes you'll like to add some flags adding a delta base address to each of them. To do this use the command 'ff' (flag from) which is used to specify this base address. Here's an example:
[0x00000000]> f patata
[0x00000000]> ? patata
0x0 ; 0d ; 0o ; 0000 0000
[0x00000000]> ff 0x100
[0x00000000]> f patata
[0x00000000]> ? patata
0x100 ; 256d ; 400o ; 0000 0000
[0x00000000]> ff
0x00000100
[0x00000000]> ff 0 ; reset flag from
The '/' command for searching registers some flags for the hit results. You can use them to draw intersection vectors between these hits and be able to determine block sizes from a header and a footer search keywords.
Here's an example:
[0x00000000]> !cat txt
_head
jklsdfjlksaf
_foot
_body
jeje peeee
_foot
_body
food is lavle
_foot
Let's define the header and the footer keywords:
[0x00000000]> /k0 _body
[0x00000000]> /k1 _foot
[0x00000000]> /k
00 _body
01 _foot
Do the ranged search using keywords 0 and 1:
[0x00000000]> /r 0,1
001 0x00000000 hit0_0 _bodyjklsdfjlksaf
002 0x00000015 hit1_1 _foot_bodyjeje p
003 0x0000001c hit0_2 _bodyjeje peeee-
004 0x0000002f hit1_3 _foot_bodyfood is
005 0x00000036 hit0_4 _bodyfood is lavle
006 0x0000004b hit1_5 _foot
Perform intersection between hits!
[0x00000000]> fi hit0 hit1
hit0_0 (0x00000000) -> hit1_1 (0x00000015) ; size = 21
hit0_2 (0x0000001c) -> hit1_3 (0x0000002f) ; size = 19
hit0_4 (0x00000036) -> hit1_5 (0x0000004b) ; size = 21
Radare can manipulate the file in multiple ways. You can resize the file, move bytes, copy/paste them, insert mode (shifting data to the end of the block or file) or just overwrite some bytes with an address, the contents of a file, a widestring or inline assembling an opcode.
To resize. Use the 'r' command which accepts a numeric argument. Possitive valule sets the new size to the file. A negative one will strip N bytes from the current seek down-sizing the file.
> r 1024 ; resize the file to 1024 bytes
> r -10 @ 33 ; strip 10 bytes at offset 33
To write bytes just use the 'w' command. It accepts multiple input formats like inline assembling, endian-friendly dwords, files, hexpair files, wide strings:
[0x4A13B8C0]> w?
Usage: w[?|*] [argument]
w [string] ; write plain with escaped chars string
wa [opcode] ; write assembly using asm.arch and rasm
wA '[opcode]' ; write assembly using asm.arch and rsc asm
wb [hexpair] ; circulary fill the block with these bytes
wv [expr] ; writes 4-8 byte value of expr (use cfg.bigendian)
ww [string] ; write wide chars (interlace 00s in string)
wf [file] ; write contents of file at current seek
wF [hexfile] ; write hexpair contents of file
wo[xrlaAsmd] [hex] ; operates with hexpairs xor,shiftright,left,add,sub,mul,div
Some examples:
> wx 12 34 56 @ 0x8048300
> wv 0x8048123 @ 0x8049100
> wa jmp 0x8048320
All write changes are recorded and can be listed or undo-ed using the 'u' command which is explained in the 'undo/redo' section.
The 'wo' write command accepts multiple kinds of operations that can be applied on the curren block. This is for example a XOR, ADD, SUB, ...
[0x4A13B8C0]> wo?
Usage: wo[xrlasmd] [hexpairs]
Example: wox 90 ; xor cur block with 90
Example: woa 02 03 ; add 2, 3 to all bytes of cur block
Supported operations:
woa addition +=
wos substraction -=
wom multiply *=
wod divide /=
wox xor ^=
woo or |=
woA and &=
wor shift right >>=
wol shift left <<=
This way it is possible to implement ciphering algorithms using radare core primitives.
A sample session doing a xor(90) + addition(01 02)
[0x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B C D 0123456789ABCD
0x4A13B8C0, 89e0 e839 0700 0089 c7e8 e2ff ffff ...9..........
0x4A13B8CE 81c3 eea6 0100 8b83 08ff ffff 5a8d ............Z.
0x4A13B8DC, 2484 29c2 528b 8344 0000 008d 7494 $.).R..D....t.
0x4A13B8EA 088d 4c24 0489 e583 e4f0 5050 5556 ..L$......PPUV
0x4A13B8F8, 31ed e8f1 d400 008d 93a4 31ff ff8b 1.........1...
0x4A13B906 2424 ffe7 8db6 0000 0000 e8b2 4f01 $$..........O.
0x4A13B914, 0081 c1a7 a601 0055 89e5 5d8d 814c .......U..]..L
0x4A13B922 0600 ..
[0x4A13B8C0]> wox 90
[0x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B C D 0123456789ABCD
0x4A13B8C0, 1970 78a9 9790 9019 5778 726f 6f6f .px.....Wxrooo
0x4A13B8CE 1153 7e36 9190 1b13 986f 6f6f ca1d .S~6.....ooo..
0x4A13B8DC, b414 b952 c21b 13d4 9090 901d e404 ...R..........
0x4A13B8EA 981d dcb4 9419 7513 7460 c0c0 c5c6 ......u.t`....
0x4A13B8F8, a17d 7861 4490 901d 0334 a16f 6f1b .}xaD....4.oo.
0x4A13B906 b4b4 6f77 1d26 9090 9090 7822 df91 ..ow.&....x"..
0x4A13B914, 9011 5137 3691 90c5 1975 cd1d 11dc ..Q76....u....
0x4A13B922 9690 ..
[0x4A13B8C0]> woa 01 02
[0x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B C D 0123456789ABCD
0x4A13B8C0, 1a72 79ab 9892 911b 587a 7371 7071 .ry.....Xzsqpq
0x4A13B8CE 1255 7f38 9292 1c15 9971 7071 cb1f .U.8.....qpq..
0x4A13B8DC, b516 ba54 c31d 14d6 9192 911f e506 ...T..........
0x4A13B8EA 991f ddb6 951b 7615 7562 c1c2 c6c8 ......v.ub....
0x4A13B8F8, a27f 7963 4592 911f 0436 a271 701d ..ycE....6.qp.
0x4A13B906 b5b6 7079 1e28 9192 9192 7924 e093 ..py.(....y$..
0x4A13B914, 9113 5239 3793 91c7 1a77 ce1f 12de ..R97....w....
0x4A13B922 9792 ..
The 'u'ndo command is used to undo or redo write changes done on the file.
> u?
Usage: > u 3 ; undo write change at index 3
> u -3 ; redo write change at index 3
> u ; list all write changes
Here's a sample session working with undo writes:
[0x00000000]> wx 90 90 90 @ 0x100
[0x00000100]> u ; list changes
00 + 3 00000100: 89 90 c4 => 90 90 90
[0x00000000]> p8 3 @ 0x100
90 90 90
[0x00000000]> u 0
[0x00000000]> p8 3 @ 0x100
89 90 c4
[0x00000000]> u -0
[0x00000000]> p8 3 @ 0x100
90 90 90
Note: Read 'undo-seek' for seeking history manipulation.
You can yank/paste bytes in visual mode using the 'y' and 'Y' key bindings that are alias for the 'y' and 'yy' commands of the shell. There is an internal buffer that stores N bytes from the current seek. You can write-back to another seek using the 'yy' one.
[0x4A13B8C0]> y?
Usage: y[ft] [length]
> y 10 @ eip ; yanks 10 bytes from eip
> yy @ edi ; write these bytes where edi points
> yt [len] dst ; copy N bytes from here to dst
Sample session:
> s 0x100 ; seek at 0x100
> y 100 ; yanks 100 bytes from here
> s 0x200 ; seek 0x200
> yy ; pastes 100 bytes
You can perform a yank and paste in a single line by just using the 'yt' command (yank-to). The syntax is the following:
[0x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B 0123456789AB
0x4A13B8C0, 89e0 e839 0700 0089 c7e8 e2ff ...9........
0x4A13B8CC, ffff 81c3 eea6 0100 8b83 08ff ............
0x4A13B8D8, ffff 5a8d 2484 29c2 ..Z.$.).
[0x4A13B8C0]> yt 8 0x4A13B8CC @ 0x4A13B8C0
[0x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B 0123456789AB
0x4A13B8C0, 89e0 e839 0700 0089 c7e8 e2ff ...9........
0x4A13B8CC, 89e0 e839 0700 0089 8b83 08ff ...9........
0x4A13B8D8, ffff 5a8d 2484 29c2 ..Z.$.).
[0x4A13B8C0]>
You can compare data using the 'c' command that accepts different input formats and compares the input against the bytes in the current seek.
> c?
Usage: c[?|d|x|f] [argument]
c [string] - compares a plain with escaped chars string
cd [offset] - compare a doubleword from a math expression
cx [hexpair] - compare hexpair string
cf [file] - compare contents of file at current seek
An example of memory comparision:
[0x08048000]> p8 4
7f 45 4c 46
[0x08048000]> cx 7f 45 90 46
Compare 3/4 equal bytes
0x00000002 (byte=03) 90 ' ' -> 4c 'L'
[0x08048000]>
This is also useful for comparing memory pointers at certain offsets. The variable cfg.bigendian is used to change the value in the proper way to be compared against the contents at the '0x4A13B8C0' offset:
[0x4A13B8C0]> cd 0x39e8e089 @ 0x4A13B8C0
Compare 4/4 equal bytes
[0x4A13B8C0]> p8 4
89 e0 e8 39
It takes 4 bytes from the current seek (0x4A13B8C0) and compares them to the number given. This number can be an math expressions using flag names and so:
[0x08048000]> cx 7f 45 90 46
Compare 3/4 equal bytes
0x00000002 (byte=03) 90 ' ' -> 4c 'L'
[0x08048000]>
We can use the compare command against a file previously dumped to disk from the contents of the current block.
$ radare /bin/true
[0x08049A80]> s 0
[0x08048000]> cf /bin/true
Compare 512/512 equal bytes
The visual mode is a user-friendlier interface for the commandline prompt of radare which accepts HJKL movement keys, a cursor for selecting bytes and some keybindings to ease the use of the debugger.
In this mode you can change the configuration in a easy way using the 'e' (eval) key. Or just track the flags and walk thru the flagspaces pressing 't'.
To get a help of all the keybindings hooked in visual mode you can press '?':
Visual keybindings:
:<cmd> radare command (vi like)
; edit or add comment
,. ',' marks an offset, '.' seeks to mark or eip if no mark
g,G seek to beggining or end of file
+-*/ +1, -1, +width, -width -> block size
<> seek block aligned (cursor mode = folder code)
[] adjust screen width
a,A,= insert patch assembly, rsc asm or !hack
i insert mode (tab to switch btw hex,asm,ascii, 'q' to normal)
f,F seek between flag list (f = forward, F = backward)
t visual track/browse flagspaces and flags
e visual eval configuration variables
c toggle cursor mode
C toggle scr.color
d convert cursor selected bytes to ascii, code or hex
m applies rfile magic on this block
I invert block (same as pIx or so)
y,Y yank and Yankee aliases for copy and paste
f,F go next, previous flag (cursor mode to add/remove)
h,j,k,l scroll view to left, down, up, right.
J,K up down scroll one block.
H,L scroll left, right by 2 bytes (16 bits).
p,P switch between hex, bin and string formats
x show xrefs of the current offset
q exits visual mode
Debugger keybindings:
! show debugger commands help
F1 commands help
F2 set breakpoint (execute)
F3 set watchpoint (read)
F4 continue until here (!contuh)
F6 continue until syscall (!contsc)
F7 step in debugger user code (!step)
F8 step over in debugger (!stepo)
F9 continue execution (!cont)
F10 continue until user code (!contu)
From the visual mode you can toggle the insert and cursor modes with the 'i' and 'c' keys.
Pressing lowercase 'c' makes the cursor appear or disappear. The cursor is used to select a range of bytes or just point to a byte to flag it (press 'f' to create a new flag where the cursor points to)
If you select a range of bytes press 'w' and then a byte array to overwrite the selected bytes with the ones you choose in a circular copy way. For example:
<select 10 bytes in visual mode>
<press 'w' and then '12 34'>
The 10 bytes selected will become: 12 34 12 34 12 34 12 34 12 34
The byte range selection can be used together with the 'd' key to change the data type of the selected bytes into a string, code or a byte array.
That's useful to enhace the disassembly, add metadata or just align the code if there are bytes mixed with code.
In cursor mode you can set the block size by simply moving it to the position you want and pressing '_'. Then block_size = cursor.
The insert mode allows you to write bytes at nibble-level like most common hexadecimal editors. In this mode you can press '<tab>' to switch between the hexa and ascii columns of the hexadecimal dump.
To get back to the normal mode, just press '<tab>' to switch to the hexadecimal view and press 'q'. (NOTE: if you press 'q' in the ascii view...it will insert a 'q' instead of quit this mode)
There are other keys for inserting and writing data in visual mode. Basically by pressing 'w' key you'll be prompted for an hexpair string or use 'a' for writing assembly where the cursor points.
radare implements many user-friendly features for the visual interface to walk thru the assembly code. One of them is the 'x' key that popups a menu for selecting the xref (data or code) against the current seek and then jump there. In this example, we are displaying the import getenv and displaying the CODE xreferences to this external symbol.
[0x08048700]> pd @ imp_getenv
; CODE xref 0x08048e30 (sym_otf_patch+0x1d9)
; CODE xref 0x08048d53 (sym_otf_patch+0xfc)
; CODE xref 0x08048c90 (sym_otf_patch+0x39)
| 0x08048700, imp_getenv:
| 0x08048700 jmp dword near [0x804c00c]
| 0x08048706 push dword 0x18 ; oeax+0xd
`==< 0x0804870B jmp 0x80486c0 ; 1 = section__plt
Use the 'sx' and 'sX' command to seek tot he xrefs for code and Xrefs for data indexed by numbers.
All the calls and jumps are numbered (1, 2, 3...) these numbers are the keybindings for seeking there from the visual mode.
[0x4A13B8C0]> pd 4
0x4A13B8C0, eip: mov eax, esp
0x4A13B8C2 call 0x4a13c000 ; 1 = 0x4a13c000
0x4A13B8C7 mov edi, eax
0x4A13B8C9 call 0x4a13b8b0 ; 2 = 0x4a13b8b0
All the seek history is stored, by pressing 'u' key you will go back in the seek history time :)
The search engine of radare is based on the work done by esteve plus multiple features on top of it that allows multiple keyword searching with binary masks and automatic flagging of results.
This powerful command is '/'.
[0x00000000]> /?
/ \x7FELF ; plain string search (supports \x).
/. [file] ; search using the token file rules
/s [string] ; strip strings matching optional string
/x A0 B0 43 ; hex byte pair binary search.
/k# keyword ; keyword # to search
/m# FF 0F ; Binary mask for search '#' (optional)
/a [opcode] ; Look for a string in disasembly
/A ; Find expanded AES keys from current seek(*)
/w foobar ; Search a widechar string (f\0o\0o\0b\0..)
/r 0,2-10 ; launch range searches 0-10
/p len ; search pattern of length = len
// ; repeat last search
The search is performed from the current seek until the end of the file or 'cfg.limit' if != 0. So in this way you can perform limited searches between two offsets of a file or the process memory.
With radare everything is handled as a file, it doesn't matters if it is a socket, a remote device, the process memory, etc..
A basic search for a plain string in a whole file would be something like:
$ echo "/ lib" | radare -nv /bin/ls
001 0x00000135 hit0_0 lib/ld-linux.so.2
002 0x00000b71 hit0_1 librt.so.1__gmon_st
003 0x00000bad hit0_2 libselinux.so.1_ini
004 0x00000bdd hit0_3 libacl.so.1acl_exte
005 0x00000bfb hit0_4 libc.so.6_IO_stdin_
006 0x00000f2a hit0_5 libc_start_maindirf
$
As you can see, radare generates a 'hit' flag for each search result found. You you can just use the 'pz' command to visualize the strings at these offsets in this way:
[0x00000000]> / ls
...
[0x00000000]> pz @ hit0_0
lib/ld-linux.so.2
We can also search wide-char strings (the ones containing zeros between each letter) using the '/w' in this way:
[0x00000000]> /w Hello
0 results found.
It is also possible to mix hexadecimal scape sequences in the search string:
$ radare -u /dev/mem
[0x00000000]> / \x7FELF
But if you want to perform an hexadecimal search you will probably prefer an hexpair input with '/x':
[0x00000000]> /x 7F 45 4C 46
Once the search is done, the results are stored in the 'search' flag space.
[0x00000000]> fs search
[0x00000000]> f
0x00000135 512 hit0_0
0x00000b71 512 hit0_1
0x00000bad 512 hit0_2
0x00000bdd 512 hit0_3
0x00000bfb 512 hit0_4
0x00000f2a 512 hit0_5
To remove these flags, you can just use the 'f -hit*' command.
Sometimes while working long time in the same file you will need to launch the last search more than once and you will probably prefer to use the '//' command instead of typing all the string again.
[0x00000f2a]> // ; repeat last search
The search engine can be configured by the 'eval' interface:
[0x08048000]> eval search.
search.from = 0
search.to = 0
search.align = 0
search.flag = true
search.verbose = true
The search.[from|to] is used to define the offset range limits for the searches.
'search.align' variable is used to determine that the only 'valid' search hits must have to fit in this alignement. For example. you can use 'e search.align=4' to get only the hits found in 4-byte aligned addresses.
The 'search.flag' boolean variable makes the engine setup flags when finding hits. If the search is stopped by the user with a ^C then a 'search_stop' flag will be added.
The search command allows you to throw repeated pattern searchs against the IO backend to be able to identify repeated sequences of bytes without specifying them. The only property to perform this search is to manually define the minimum length of these patterns.
Here's an example:
[0x00000000]> /p 10
The output of the command will show the different patterns found and how many times they are repeated.
The cmd.hit eval variable is used to define a command that will be executed when a hit is reached by the search engine. If you want to run more than one command use '&&' or '. script-file-name' for including a file as a script.
For example:
[0x08048000]> eval cmd.hit = p8 8
[0x08048000]> / lib
6c 69 62 2f 6c 64 2d 6c
1001 0x00000155 hit0_0 lib/ld-linux
6c 69 62 72 74 2e 73 6f
2002 0x00013a25 hit0_1 librt.so.1c
6c 69 62 63 2e 73 6f 2e
3003 0x00013a61 hit0_2 libc.so.6st
6c 69 62 63 5f 73 74 61
4004 0x00013d6c hit0_3 libc_start_m
6c 69 62 70 74 68 72 65
5005 0x00013e13 hit0_4 libpthread.s
6c 69 62 2f 6c 64 2d 6c
6006 0x00013e24 hit0_5 lib/ld-linux
6c 69 62 6c 69 73 74 00
7read err at 0x0001542c
007 0x00014f22 hit0_6 liblist.gnu
A simple and practical example for using cmd.hit can be for replacing some bytes for another ones, by setting 'wx ..' in cmd.hit. This example shows how to drop the selinux dependency on binaries compiled on selinux-enabled distributions to make the dynamic elf run on other systems without selinux:
$ for file in bin/* ; do \
echo "/ libselinux" | radare -nvwe "cmd.hit=wx 00" $file \
done
This shell command will run radare looking for the string 'libselinux' on the target binary. It ignores the user preferences with '-n', drops verbosity with '-v' and enables write mode with '-w'. Then it setups the 'cmd.hit' variable to run a 'wx 00' command so. it will truncate the 'libselinux' string to be 0length. This way the loader will ignore the loading because of the null-name.
TODO (not yet implemented)
To define multiple keywords you should use the '/k' command which accepts a string with hexa scaped characters. Here's an example of use:
[0x08048000]> /k0 lib
[0x08048000]> /k1 rt
[0x08048000]> /k ; list introduced keywords
00 lib
01 rt
To search these two keywords just use the '/r' (ranged search) command:
[0x08048000]> /r 0-1
001 0x00000135 hit0_0 lib/ld-linux.so.2
002 0x00000b71 hit0_1 librt.so.1__gmon_st
003 0x00000b74 hit1_2 rt.so.1__gmon_start
...
In the same way you setup keywords to search it is possible to define binary masks for each of them with the '/m' command. Here's an example of use:
[0x08048000]> /k0 lib
[0x08048000]> /m0 ff 00 00
[0x08048000]> /m
0 ff 00 00
[0x08048000]> /k
00 lib
Now just use '/r 0' to launch the k0 keyword with the associated m0 binary mask and get the 3-byte hit starting by an 'l' because 'il' is ignored by the binary mask.
This case is quite stupid, but if you work with JPEGs or on ARM for example, you can type more fine-grained binary masks to collect some bits from certain headers or just get the opcodes matching a certain conditional.
You can specify a list of keywords in a single file with its binary mask and use the search engine to find them.
The file format should be something like this:
$ cat token
token: Library token
string: lib
mask: ff 00 ff
token: Realtime
string: rt
mask: ff ff
Note that tab is used to indent the 'string' and 'mask' tokens. The first line specifies the keyword name which have nothing to do with the search.
[0x08049A80]> /. /tmp/token
Using keyword(Library token,lib,ff 00 ff)
Using keyword(Realtime,rt,ff ff)
Keywords: 2
29 hits found
Now you can move to the 'search' flag space and list the hits with the 'f' command.
[0x08049A80]> fs search
[0x08049A80]> f
...
Use the '/n' command to seek between the hits. Or just 'n' and 'N' keys in visual mode.
TODO: pd | grep foo
Thanks to Victor Mu��oz i have added support to the algorithm he developed to find expanded AES keys. It runs the search from the current seek to the cfg.limit or the end of the file. You can always stop the search pressing ^C.
$ sudo radare /dev/mem
[0x00000000]> /A
0 AES keys found
Disassembling in radare is just a way to represent a bunch of bytes. So it is handled as a print mode with the 'p' command.
In the old times when radare core was smaller. The disassembler was handled by an external rsc file, so radare was dumping the current block into a file, and the script was just calling objdump in a proper way to disassemble for intel, arm, etc...
Obviously this is a working solution, but takes too much cpu for repeating just the same task so many times, because there are no caches and the scrolling was absolutely slow.
Nowadays, the disassembler is one of the basics in radare allowing you to choose the architecture flavour and some To disassemble use the 'pd' command.
The 'pd' command accepts a numeric argument to specify how many opcodes of the current block do you want to disassemble. Most of the commands in radare are restricted by the block size. So if you want to disassemble more bytes you should use the 'b' command to specify the new block size.
[0x00000000]> b 100 ; set block size to 100
[0x00000000]> pd ; disassemble 100 bytes
[0x00000000]> pd 3 ; disassemble 3 opcodes
[0x00000000]> pD 30 ; disassemble 30 bytes
The 'pD' command works like 'pd' but gets the number of bytes instead of the number of opcodes.
The 'pseudo' syntax is closer to the humans, but it can be anoying if you are reading lot of code:
[0xB7FB8810]> e asm.syntax=pseudo
[0xB7FB8810]> pd 3
0xB7FB8810, eax = esp
0xB7FB8812 v call 0xB7FB8A60
0xB7FB8817 edi += eax
[0xB7FB8810]> e asm.syntax=intel
[0xB7FB8810]> pd 3
0xB7FB8810, mov eax, esp
0xB7FB8812 call 0xb7fb8a60
0xB7FB8817 add edi, eax
[0xB7FB8810]> e asm.syntax=att
[0xB7FB8810]> pd 3
0xB7FB8810, mov %esp, %eax
0xB7FB8812 call 0xb7fb8a60
0xB7FB8817 add %eax, %edi
[0xB7FB8810]>
The work on binary files makes the task of taking notes and defining information on top of the file quite important. Radare offers multiple ways to retrieve and adquire this information from many kind of file types.
Following some *nix principles becomes quite easy to write a small utility in shellscript that using objdump, otool, etc.. to get information from a binary and import it into radare just making echo's of the commands script.
You can have a look on one of the many 'rsc' scripts that are distributed with radare like 'idc2rdb':
$ cat src/rsc/pool/idc2rdb
while(<STDIN>) {
$str=$_;
if ($str=~/MakeName[^X]*.([^,]*)[^"]*.([^"]*)/) {
print "f idc_$2 @ 0x$1\n";
}
elsif ($str=~/MakeRptCmt[^X]*.([^,]*)[^"]*.([^"]*)/) {
$cmt = $2;
$off = $1;
$cmt=~s/\\n//g;
print "CC $cmt @ 0x$off\n";
}
}
This script is called with 'rsc idc2rdb < file.idc > file.rdb'. It reads an IDC file exported from an IDA database and imports the comments and the names of the functions.
We can import the 'file.rdb' using the '.' command of radare (similar to the shell):
[0x00000000]> . file.rdb
The command '.' is used to interpret data from external resources like files, programs, etc.. In the same way we can do the same without writing a file.
[0x00000000]> .!rsc idc2rdb < file.idc
The 'C' command is the one used to manage comments and data conversions. So you can define a range of bytes to be interpreted as code, or a string. It is also possible to define flags and execute code in a certain seek to fetch a comment from an external file or database.
Here's the help:
[0x4A13B8C0]> C?
Usage: C[op] [arg] <@ offset>
CC [-][comment] @ here - add/rm comment
CF [-][len] @ here - add/rm function
Cx [-][addr] @ here - add/rm code xref
CX [-][addr] @ here - add/rm data xref
Cm [num] [expr] ; define memory format (pm?)
Cc [num] ; converts num bytes to code
Cd [num] ; converts to data bytes
Cs [num] ; converts to string
Cf [num] ; folds num bytes
Cu [num] ; unfolds num bytes
C* ; list metadata database
For example, if you want to add a comment just type:
[0x00000000]> CC this guy seems legit @ 0x8048536
You can execute code inside the disassembly just placing a flag and assigning a command to it:
[0x00000000]> fc !regs @ eip
This way radare will show the registers of the cpu printing the opcode at the address where 'eip' points.
In the same way you can interpret structures or fetch information from external files. If you want to execute more than one command in a single address you will have to type them in a file and use the '.' command as explained before.
[0x00000000]> fc . script @ eip
The 'C' command allows us to change the type of data. The three basic types are: code (disassembly using asm.arch), data (byte array) or string.
In visual mode is easier to manage this because it is hooked to the 'd' key trying to mean 'data type change'. Use the cursor to select a range of bytes ('c' key to toggle cursor mode and HJKL to move with selection) and then press 'ds' to convert to string.
You can use the Cs command from the shell also:
[0x00000000]> pz 0x800
HelloWorld
[0x00000000]> f string_foo @ 0x800
[0x00000000]> Cs 10 @ string_foo
The folding/unfolding is quite premature but the idea comes from the 'folder' concepts in vim. So you can select a range of bytes in the disassembly view and press '<' to fold these bytes in a single line or '>' to unfold them. Just to ease the readability of the code.
The Cm command is used to define a memory format string (the same used by the pm command). Here's a example:
[0x4A13B8C0]> Cm 16 2xi foo bar
[0x4A13B8C0]> pd
0x4A13B8C0, eip: (pm 2xi foo bar)
0x4a13b8c0 [0] {
foo : 0x4a13b8c0 = 0x39e8e089
bar : 0x4a13b8c4 = -1996488697
}
0x4a13b8c8 [1] {
foo : 0x4a13b8c8 = 0xffe2e8c7
bar : 0x4a13b8cc = -1014890497
}
.==< 0x4A13B927 7600 jbe 0x4a13b8c2 ; 1 = eip+0x69
`--> 0x4A13B929 8dbc2700000000 lea edi, [edi+0x0]
0x4A13B930, 55 push ebp
0x4A13B931 89e5 mov ebp, esp
This way it is possible to define structures by just using simple oneliners. See 'print memory' for more information.
All those C* commands can also be accessed from the visual mode by pressing 'd' (data conversion) key.
Actually the dwarf support is activated by rabin when the binary have this information. This is just asm.dwarf=true, so when loading radare will add comments inside the assembly lines referencing the C/C++/Vala/Java.. sources lines.
Here's an example:
$ cat hello.c
main() {
printf("Hello World\n");
}
$ gcc -g hello.c
$ rabin -rI ~/a.out| grep dwarf
e dbg.dwarf = true
$ rsc dwarf-lines a.out
CC 1 main() { @ 0x8048374
CC 2 printf("Hello World\n"); @ 0x8048385
CC 3 } @ 0x8048391
CC 3 } @ 0x804839a
This rsc script uses addr2line to get the correspondencies between source code line and memory address when the program is loaded in memory by the ELF loader.
And the result is:
[0x080482F0]> pdf @ sym_main
; 1 main() {
0x08048374, / sym_main: lea ecx, [esp+0x4]
0x08048378, | and esp, 0xf0
0x0804837b | push dword [ecx-0x4]
0x0804837e | push ebp
0x0804837f | mov ebp, esp
0x08048381 | push ecx
; Stack size +4
0x08048382 | sub esp, 0x4
; 2 printf("Hello World\n");
0x08048385 | mov dword [esp], 0x8048460 ; str_Hello_World
0x0804838c, | call 0x80482d4 ; 1 = imp_puts
; Stack size -4
; 3 }
0x08048391 | add esp, 0x4
0x08048394, | pop ecx
0x08048395 | pop ebp
0x08048396 | lea esp, [ecx-0x4]
0x08048399 \ ret
0x08048399 ; ------------------------------------
; 3 }
When you are working more than once on the same file you will probably be interested in not losing your comments, flags, xrefs analysis and so.
To solve this problem, radare implements 'project' support which can be specified with the '-p' flag. The project files are stored in '~/.radare/rdb' by default which is configured in 'eval dir.project'.
The 'P' command is the one used inside the core to store and load project files. It also can information about the project file.
These files are just radare scripts with some extra metadata as comments ';'.
If you want to make a full analysis when opening a file try setting 'e file.analyze=true' in your .radarerc. It will run '.af* @@ sym_' and more..
Once the program is analyzed (there is no difference between opening the program as a file or debug it) you can store this information in a project file:
$ radare -e file.id=1 -e file.flag=1 -e file.analyze=1 -d rasc
...
[0x4A13B8C0]> P?
Po [file] open project
Ps [file] save project
Pi [file] info
[0x4A13B8C0]> Ps rasc
Project saved
[0x4A13B8C0]> Pi rasc
e file.project = rasc
e dir.project = /home/pancake/.radare/rdb/
; file = /usr/bin/rasc
This database is stored in:
$ du -hs ~/.radare/rdb/rasc
24K
Now you can reopen this project in any directory by typing:
$ radare -p rasc
And if you prefer you can debug it.
$ radare -p rasc -d
The path to the filename is stored inside the project file, so you dont have to bother about typing it all the time.
The user will be prompted for re-saving the project before exiting.
Radare can be extended in many ways. The most common is by using stdin/stdout get input from a file an interpret the output of the program execution as radare commands. stderr is used for direct user messaging, because it is not handled by the core and it is directly printed in the terminal.
But with this kind of plugins are not directly interactive, because the communication is one-way from the external program to radare. and the only way to get feedback from radare is by using pipes and files. For example:
$ cat interactive.rsc
#!/bin/sh
addr=$1
if [ -z "${addr}" ]; then
echo "No address given"
exit 1
fi
echo "p8 4 > tmpfile"
sleep 1
bytes=`cat tmpfile`
echo "wx ${bytes} @ ${addr}+4"
What this 'dummy' script does is get an address as argument, read 4 bytes from there, and write them at address+4.
As you see this simple task becomes quite 'ugly' using this concepts, so its better to write a native plugin to get full access to the radare internals
All the access to files, network, debugger, etc.. is wrapped by an IO abstraction layer that allows to interpret all the data as if it was a single file.
The IO backend is implement as IO plugins. They are selected depending on the uri file.
# debug this file using the debug io plugin
$ radare dbg:///bin/ls
# allocate 10MB in a malloc buffer
$ radare malloc://10M
# allocate 10MB in a malloc buffer
$ radare malloc://10M
# connect to remote host
$ radare connect://192.168.3.33:9999
IO plugins are the ones used to wrap the open, read, write and 'system' on virtual file systems.
The cool thing of IO plugins is that you can make radare understand that any thing can be handled as a plain file. A socket connection, a remote radare session, a file, a process, a device, a gdb session, etc..
So, when radare reads a block of bytes, is the task of the IO plugin to get these bytes from any place and put them in the internal buffer.
IO plugins are selected while opening a file by its URI. Here'r some examples:
# Debugging URIs
$ radare dbg:///bin/ls
$ radare pid://1927
# Remote sessions
$ radare listen://:9999
$ radare connect://localhost:9999
# Virtual buffers
$ radare malloc://1024
You can get a list of the radare IO plugins by typing 'radare -L':
$ radare -L
haret Read WCE memory ( haret://host:port )
debug Debugs or attach to a process ( dbg://file or pid://PID )
gdb Debugs/attach with gdb (gdb://file, gdb://PID, gdb://host:port)
gdbx GDB shell interface 'gdbx://program.exe args' )
shm shared memory ( shm://key )
mmap memory mapped device ( mmap://file )
malloc memory allocation ( malloc://size )
remote TCP IO ( listen://:port or connect://host:port )
winedbg Wine Debugger interface ( winedbg://program.exe )
socket socket stream access ( socket://host:port )
gxemul GxEmul Debugger interface ( gxemul://program.arm )
posix plain posix file access
The hack plugins are just shared libraries that have access to some internal apis of radare. The most important one "radare_cmd" which accepts a command string and returns the string representing the output of the execution.
In this way it is possible to perform any action in the core just formatting command strings and parsing its output.
All language bindings (python, lua, ...) are implemented as hack plugins. See 'scripting' section for detailed information.
The basic radare distribution comes with two plugins to manipulate jumps (actually only x86) but wouldn't be hard to port it to ARM for example.
These ones are: nj and fj. They stand for 'Negate Jump' and 'Force Jump'.
Here's an example of use:
[0x465D8AB7]> :pd 1
0x465D8AB7 ^ jle 0x465D8AA3
[0x465D8AB7]> H nj
0x465D8AB7 ^ jg 0x465D8AA3
[0x465D8AB7]> H fj
0x465D8AB7 ^ jmp 0x465D8AA3
Radare is a very versatile application which supports many kinds of scripting features in different languages.
I have already explained how you can write scripts using radare commands (called 'radare scripts'). Or just interpret the output of external applications as radare commands. This kind of unidirectional scripting is interesting for data adquisition, but probably is a mess if you want to make something more interactive or complex.
For this reason radare have a pluggable interface for scripting languages using the plugin-hack API (See 'language bindings' chapter for more information)
Radare scripts are just unidirectional scripts that are parsed in the core from a file or from the output of a program.
This methodology is quite used for automatizing simple tasks or for data adquisition.
[0x00000000]> !cat binpatch.rsc
wx 90 90 @ 0x300
[0x00000000]> . file ; interpret this file
You can obviously do the same by interpreting the output of a command:
[0x00000000]> .! rsc syms-dbg-flag ${FILE}
These expressions can be checked for equality for later make conditional execution of commands.
Here is an example that checks if current eip is 0x8048404 and skips this instruction (!jmp eip+2) if matches.
> ? eip == 0x8048404
> ??!jmp eip+2
You can check the last comparision result with the '???' command. Which is the substraction of the first part of the expression and the second part of it.
> ? 1==1 ; check equality (==)
> ???
0x0
> ? 1==2 ; check equality (==)
> ???
0x1
> ? 1!=2 ; check difference (!=)
> ???
0x0
The conditional command is given after the '??' command. Which is the help of the '?' command when no arguments given:
[0xB7F9D810]> ??
Usage: ?[?[?]] <expr>
> ? eip ; get value of eip flag
> ? 0x80+44 ; calc math expression
> ? eip-23 ; ops with flags and numbers
> ? eip==sym_main ; compare flags
The '??' is used for conditional executions after a comparision
> ? [foo] = 0x44 ; compare memory read with byte
> ??? ; show result of comparision
> ?? s +3 ; seek current seek + 3 if equal
The radare shell support macro definitions and these ones can be used to make up your own set of commands into a macro and then use it from the shell by just giving the name and arguments. You can understand a macro as a function.
Let's see how to define a macro:
[0x465D8810]> (?
Usage: (foo\n..cmds..\n)
Record macros grouping commands
(foo args\n ..) ; define a macro
(-foo) ; remove a macro
.(foo) ; to call it
Argument support:
(foo x y\n$1 @ $2) ; define fun with args
.(foo 128 0x804800) ; call it with args
The command to manage macros is '('. The first thing we can do is a hello world:
[0x465D8810]> (hello
.. !echo Hello World
.. !echo ===========
.. )
[0x465D8810]> .(hello)
Hello World
===========
[0x465D8810]>
Macros supports arguments, and they are referenced with $# expressions.
Here's an example of how to define a simple oneliner function called 'foo' accepting two arguments to be used to print 8bit values from an address.
; Create our macro
[0x465D8810]> (dump addr len
.. p8 $1 @ $0)
; List defined macros
[0x465D8810]> (
0 dump: p8 $1 @ $0
; Call the macro
[0x465D8810]> .(dump esp 10)
01 00 00 00 e4 17 e6 bf 00 00
; Remove it!
[0x465D8810]> (-dump)
We can define these macros in our ~/.radarerc
$ cat ~/.radarerc
(dump addr len
p8 $1 @ $0)
It is also possible to recursively call a macro to emulate a loop. Here's a simple example of a recursive loop using macros in radare:
(loop times cmd
? $0 == 0
?? ()
$1
.(loop $0-1 $1))
Here there are two macro implementations for a user-defined disassembler:
(disasm-recursive times
? $0 == 0 ; check if arg0 == 0
?? () ; if matches break
pd 1 ; disassemble 1 opcode
s +$$$ ; seek curseek+opcodesize
.(disasm-recursive $0-1)) ; recursive call to me
The problem with the recursive implementation is that will easily eat the stack if you plan to feed the macro with a large number as argument.
It is also possible to write the same loop in an iterative format:
(disasm-iterative x
f foo @ $0 ; foo = arg0
label: ; define label
pd 1 ; disasm 1 opcode
s +$$$ ; seek to next opcode
f foo @ foo-1 ; foo--
? foo != 0 ; if (foo != 0)
??.label: ; goto label
)
I know that this syntax looks like a mix of lisp, perl and brainfuck :) cool huh? ;)
All language bindings supported by radare to script some actions are implemented as hack plugins.
LUA is probably the cleaner implementation of a language binding for radare, i recommend you to read the source at 'src/plug/hack/lua.c'. Here's the structure to register the plugin:
int radare_plugin_type = PLUGIN_TYPE_HACK;
struct plugin_hack_t radare_plugin = {
.name = "lua",
.desc = "lua plugin",
.callback = &lua_hack_cmd
};
The 'lua_hack_cmd' accepts a string as argument which is the argument given when calling the plugin from the radare shell:
[0x00000000]> H lua my-script.lua
If no arguments given, the plugin will loop in a prompt executing the lines given as lua statements.
The same happens with other language bindings like ruby, python or perl.
In the same directory where the plugins are installed, there's a "radare.py" or "radare.lua" which describes the API for that language.
The APIs in radare for language bindings are just wrappers for the basic 'r.cmd()' function handled by the core which is hooked to 'radare_cmd()'.
Here's a small part of radare.py to exemplify this:
def flag_get(name):
return r.cmd("? %s"%name).split(" ")[0].strip()
def flag_set(name, addr=None):
if addr == None:
r.cmd("f %s"%name)
else:
r.cmd("f %s @ 0xx"%name, addr)
def analyze_opcode(addr=None):
"""
Returns a hashtable containing the information of the analysis of the opcode in the current seek.
This is: 'opcode', 'size', 'type', 'bytes', 'offset', 'ref', 'jump' and 'fail'
"""
if addr == None:
return __str_to_hash(r.cmd("ao"))
return __str_to_hash(r.cmd("ao @ 0x%x"%addr))
The use of these functions is quite natural:
from radare import *
aop = analyze_opcode(flag_get("eip"))
if aop["type"] == "jump":
print "Jumping to 0x%08x"%aop["jump"]
Read the 'scripting' chapter to get a deeper look on this topic.
The clearest example about how to implement a language binding for radare is done in Ruby. Read it at src/plug/hack/ruby.c
The LUA language aims to be small, simple and fast dynamic language with a well designed core. This was the first language binding implemented in radare for this obvious reasons, and there are some scripts and API available in 'scripts/'.
The main problem of LUA is the lack of libraries and community, so.. sadly for those copypasta developers it is not a productive language.
TODO:...
The second scripting language implemented in radare was 'python'. Lot of people ping me for adding support for python scripting. The python interface for C is not as nice as the LUA one, and it is obviously not as optimal as LUA, but it gives a very handy syntax and provides a full-featured list of libraries and modules to extend your script.
Actually in python it is possible to write a radare frontend in GTK+ (for example) just calling this from inside the commandline.
The basics of the scripting for any language is the same. The entrypoint between the language and the core is a 'str=r.cmd(str)' function which accepts a string representing a radare command and returns the output of this command as a string.
The file 'radare.py' implements the API for accessing the raw 'r' module which is only loaded from inside the core. (So you cannot use radare-python scripts outside radare (obviously)).
The file 'radapy.py' implements a pure-python radare-remote server and enables a simple interface for extending the basic IO operations thru the network in python. Read 'networking' section for more information.
to start we will write a small python script for radare to just test some of the features of the API.
$ cat hello.py
print "Hello World"
seek(0)
print hex(3)
write("90 90 90")
print hex(3)
quit()
$ echo patata > file # prepare the dummy file
$ radare -i hello.py -wnv file # launch the script
Hello World
70 61 74
90 90 90
If you want a better interface for writing your scripts inside radare use the scriptedit plugin that depends on GTK+ offering a simple editor with language selector and allows to run scripts from there.
You can also use radare programatically from the python shell:
[0x4A13B8C0]> H python
python> print dir(r)
['__doc__', '__name__', 'cmd', 'eval']
python> print(r.cmd("p8 4"))
89 e0 e8 39
Use it like in python by refering a global variable called '$r'.
[0x465D8810]> H ruby
Load done
==> Loading radare ruby api... ok
irb(main):001:0> $r
=> #<Radare:0xb703ad38>
irb(main):002:0> print $r.cmd("p8 3 @ esp")
01 00 00
irb(main):003:0>
Read radare.rb for more information about the API.
Under this bunny-arabic-like name, radare hides the power of a wonderful tool to handle binary files and get information to show it in the command line or import it into the core.
Rabin is able to handle multiple file formats like Java CLASS, ELF, PE, MACH-O, etc.. and it is able to get symbol import/exports, library dependencies, strings of data sections, xrefs, address of entrypoint, sections, architecture type, etc.
$ rabin -h
rabin [options] [bin-file]
-e shows entrypoints one per line
-i imports (symbols imported from libraries)
-s symbols (exports)
-c header checksum
-S show sections
-l linked libraries
-L [lib] dlopen library and show address
-z search for strings in elf non-executable sections
-x show xrefs of symbols (-s/-i/-z required)
-I show binary info
-r output in radare commands
-v be verbose
The output of every flag is intended to be easily parseable, they can be combined with -v or -vv for a more readable and verbose human output, and -r for using this output from the radare core. Furtheremore, we can combine -s, -i and -z with -x to get xrefs.
The file identification is done through the -I flag, it will output information regarding binary class, encoding, OS, type, etc.
$ rabin -I /bin/ls
[Information]
class=ELF32
enconding=2's complement, little endian
os=linux
machine=Intel 80386
arch=intel
type=EXEC (Executable file)
stripped=Yes
static=No
baddr=0x0804800
As it was said we can add the -r flag to use all this information in radare:
$ rabin -Ir /bin/ls
e file.type = elf
e file.baddr = 0x08048000
e cfg.bigendian = false
e dbg.dwarf = false
e asm.os = linux
e asm.arch = intel
This is automatically done at startup if we append to our configuration file (.radarerc) the eval command "eval file.id = true".
The flag "-e" lets us know the program entrypoint.
$ rabin -e /bin/ls
0x08049a40
Again, if we mix it with -v we get a better human readable output.
$ rabin -ev /bin/ls
[Entrypoint]
Memory address: 0x08049a40
With -vv we will get more information, in this case the memory location as well as the file offset.
$ rabin -evv /bin/ls
[Entrypoint]
Memory address: 0x08049a40
File offset: 0x00001a40
Combined with -r radare will create a new flag space called "symbols", and it will add a flag named "entrypoint" which points to the program's entrypoint. Thereupon, radare will seek it.
$ rabin -er /bin/ls
fs symbols
f entrypoint @ 0x08049a40
s entrypoint
Rabin is able to get all the imported objects, as well as their offset at the PLT, this information is quite useful, for example, to recognize wich function is called by a call instruction.
$ rabin -i /bin/ls | head
[Imports]
address=0x08049484 offset=0x00001484 bind=GLOBAL type=FUNC name=abort
address=0x08049494 offset=0x00001494 bind=GLOBAL type=FUNC name=__errno_location
address=0x080494a4 offset=0x000014a4 bind=GLOBAL type=FUNC name=sigemptyset
address=0x080494b4 offset=0x000014b4 bind=GLOBAL type=FUNC name=sprintf
address=0x080494c4 offset=0x000014c4 bind=GLOBAL type=FUNC name=localeconv
address=0x080494d4 offset=0x000014d4 bind=GLOBAL type=FUNC name=dirfd
address=0x080494e4 offset=0x000014e4 bind=GLOBAL type=FUNC name=__cxa_atexit
address=0x080494f4 offset=0x000014f4 bind=GLOBAL type=FUNC name=strcoll
address=0x08049504 offset=0x00001504 bind=GLOBAL type=FUNC name=fputs_unlocked
(...)
The flag -v will output human readable output.
$ rabin -iv /bin/ls
[Imports]
Memory address File offset Name
0x08049484 0x00001484 abort
0x08049494 0x00001494 __errno_location
0x080494a4 0x000014a4 sigemptyset
0x080494b4 0x000014b4 sprintf
0x080494c4 0x000014c4 localeconv
0x080494d4 0x000014d4 dirfd
0x080494e4 0x000014e4 __cxa_atexit
0x080494f4 0x000014f4 strcoll
0x08049504 0x00001504 fputs_unlocked
(...)
Combined with -vv, we get two new columns, bind (LOCAL, GLOBAL, etc.) and type (OBJECT, FUNC, SECTION, FILE, etc.)
$ rabin -ivv /bin/ls
[Imports]
Memory address File offset Bind Type Name
0x08049484 0x00001484 GLOBAL FUNC abort
0x08049494 0x00001494 GLOBAL FUNC __errno_location
0x080494a4 0x000014a4 GLOBAL FUNC sigemptyset
0x080494b4 0x000014b4 GLOBAL FUNC sprintf
0x080494c4 0x000014c4 GLOBAL FUNC localeconv
0x080494d4 0x000014d4 GLOBAL FUNC dirfd
0x080494e4 0x000014e4 GLOBAL FUNC __cxa_atexit
0x080494f4 0x000014f4 GLOBAL FUNC strcoll
0x08049504 0x00001504 GLOBAL FUNC fputs_unlocked
(...)
Again, with -r we can automatically flag them in radare.
$ rabin -ir /bin/ls
In rabin, symbols list works in a very similar way as exports do. With the flag -i it will list all the symbols present in the file in a format that can be parsed easily.
$ rabin -s /bin/ls
[Symbols]
address=0x0805e3c0 offset=0x000163c0 size=00000004 bind=GLOBAL type=OBJECT name=stdout
address=0x08059b04 offset=0x00011b04 size=00000004 bind=GLOBAL type=OBJECT name=_IO_stdin_used
address=0x0805e3a4 offset=0x000163a4 size=00000004 bind=GLOBAL type=OBJECT name=stderr
address=0x0805e3a0 offset=0x000163a0 size=00000004 bind=GLOBAL type=OBJECT name=optind
address=0x0805e3c4 offset=0x000163c4 size=00000004 bind=GLOBAL type=OBJECT name=optarg
With -v, rabin will print a simpler output.
$ rabin -sv /bin/ls
[Symbols]
Memory address File offset Name
0x0805e3c0 0x000163c0 stdout
0x08059b04 0x00011b04 _IO_stdin_used
0x0805e3a4 0x000163a4 stderr
0x0805e3a0 0x000163a0 optind
0x0805e3c4 0x000163c4 optarg
5 symbols
Using -vv, we will get their size, bind and type too.
$ rabin -svv /bin/ls
[Symbols]
Memory address File offset Size Bind Type Name
0x0805e3c0 0x000163c0 00000004 GLOBAL OBJECT stdout
0x08059b04 0x00011b04 00000004 GLOBAL OBJECT _IO_stdin_used
0x0805e3a4 0x000163a4 00000004 GLOBAL OBJECT stderr
0x0805e3a0 0x000163a0 00000004 GLOBAL OBJECT optind
0x0805e3c4 0x000163c4 00000004 GLOBAL OBJECT optarg
5 symbols
And, finally, with -r radare core can flag automatically all these symbols and define function and data blocks.
$ rabin -sr /bin/ls
fs symbols
b 4 && f sym_stdout @ 0x0805e3c0
b 4 && f sym__IO_stdin_used @ 0x08059b04
b 4 && f sym_stderr @ 0x0805e3a4
b 4 && f sym_optind @ 0x0805e3a0
b 4 && f sym_optarg @ 0x0805e3c4
b 512
5 symbols added
Rabin can list the libraries used by a binary with the flag -l.
$ rabin -l /bin/ls
[Libraries]
librt.so.1
libselinux.so.1
libacl.so.1
libc.so.6
There is another flag related to libraries, -L, it dlopens a library and show us the address where it has been loaded.
$ rabin -L /usr/lib/librt.so
0x0805e020 /usr/lib/librt.so
The -z flag is used to list all the strings located in the section .rodata for ELF binaries, and .text for PE ones.
$ rabin -z /bin/ls
[Strings]
address=0x08059b08 offset=0x00011b08 size=00000037 type=A name=Try `%s --help' for more...
address=0x08059b30 offset=0x00011b30 size=00000031 type=A name=Usage: %s [OPTION]... [FILE]...
(...)
Using -zv we will get a simpler and more readable output.
$ rabin -zv /bin/ls
[Strings]
Memory address File offset Name
0x08059b08 0x00011b08 Try `%s --help' for more information.
0x08059b30 0x00011b30 Usage: %s [OPTION]... [FILE]...
(...)
Combined with -vv, rabin will look for strings within all non-exectable sections (not only .rodata) and print the string size as well as its encoding (Ascii, Unicode).
$ rabin -zvv /bin/ls
[Strings]
Memory address File offset Size Type Name
0x08048134 0x00000134 00000018 A /lib/ld-linux.so.2
0x08048154 0x00000154 00000003 A GNU
0x08048b5d 0x00000b5d 00000010 A librt.so.1
0x08048b68 0x00000b68 00000014 A __gmon_start__
0x08048b77 0x00000b77 00000019 A _Jv_RegisterClasses
0x08048b8b 0x00000b8b 00000013 A clock_gettime
0x08048b99 0x00000b99 00000015 A libselinux.so.1
(...)
With -r all this information is converted to radare commands, which will create a flag space called "strings" filled with flags for all those strings. Furtheremore, it will redefine them as strings insted of code.
$ rabin -zr /bin/ls
fs strings
b 37 && f str_Try___s___help__for_more_information_ @ 0x08059b08
Cs 37 @ 0x08059b08
b 31 && f str_Usage___s__OPTION______FILE____ @ 0x08059b30
Cs 31 @ 0x08059b30
(...)
Rabin give us complete information about the program sections. We can know their index, offset, size, align, type and permissions, as we can see in the next example.
$ rabin -Svv /bin/ls
[Sections]
Section index Memory address File offset Size Align Privileges Name
00 0x08048000 0x00000000 00000000 0x00000000 ---
01 0x08048134 0x00000134 00000019 0x00000001 r-- .interp
02 0x08048148 0x00000148 00000032 0x00000004 r-- .note.ABI-tag
03 0x08048168 0x00000168 00000808 0x00000004 r-- .hash
04 0x08048490 0x00000490 00000092 0x00000004 r-- .gnu.hash
05 0x080484ec 0x000004ec 00001648 0x00000004 r-- .dynsym
06 0x08048b5c 0x00000b5c 00001127 0x00000001 r-- .dynstr
07 0x08048fc4 0x00000fc4 00000206 0x00000002 r-- .gnu.version
08 0x08049094 0x00001094 00000176 0x00000004 r-- .gnu.version_r
09 0x08049144 0x00001144 00000040 0x00000004 r-- .rel.dyn
10 0x0804916c 0x0000116c 00000728 0x00000004 r-- .rel.plt
11 0x08049444 0x00001444 00000048 0x00000004 r-x .init
12 0x08049474 0x00001474 00001472 0x00000004 r-x .plt
13 0x08049a40 0x00001a40 00065692 0x00000010 r-x .text
14 0x08059adc 0x00011adc 00000028 0x00000004 r-x .fini
15 0x08059b00 0x00011b00 00015948 0x00000020 r-- .rodata
16 0x0805d94c 0x0001594c 00000044 0x00000004 r-- .eh_frame_hdr
17 0x0805d978 0x00015978 00000156 0x00000004 r-- .eh_frame
18 0x0805e000 0x00016000 00000008 0x00000004 rw- .ctors
19 0x0805e008 0x00016008 00000008 0x00000004 rw- .dtors
20 0x0805e010 0x00016010 00000004 0x00000004 rw- .jcr
21 0x0805e014 0x00016014 00000232 0x00000004 rw- .dynamic
22 0x0805e0fc 0x000160fc 00000008 0x00000004 rw- .got
23 0x0805e104 0x00016104 00000376 0x00000004 rw- .got.plt
24 0x0805e280 0x00016280 00000272 0x00000020 rw- .data
25 0x0805e390 0x00016390 00001132 0x00000020 rw- .bss
26 0x0805e390 0x00016390 00000208 0x00000001 --- .shstrtab
27 sections
Also, using -r, radare will flag the beginning and end of each section, as well as comment each one with the previous information.
$ rabin -Sr /bin/ls
fs sections
f section_ @ 0x08048000
f section__end @ 0x08048000
CC [00] 0x08048000 size=00000000 align=0x00000000 --- @ 0x08048000
f section__interp @ 0x08048134
f section__interp_end @ 0x08048147
CC [01] 0x08048134 size=00000019 align=0x00000001 r-- .interp @ 0x08048134
f section__note_ABI_tag @ 0x08048148
f section__note_ABI_tag_end @ 0x08048168
CC [02] 0x08048148 size=00000032 align=0x00000004 r-- .note.ABI-tag @ 0x08048148
f section__hash @ 0x08048168
f section__hash_end @ 0x08048490
CC [03] 0x08048168 size=00000808 align=0x00000004 r-- .hash @ 0x08048168
f section__gnu_hash @ 0x08048490
f section__gnu_hash_end @ 0x080484ec
CC [04] 0x08048490 size=00000092 align=0x00000004 r-- .gnu.hash @ 0x08048490
f section__dynsym @ 0x080484ec
f section__dynsym_end @ 0x08048b5c
(...)
Take care of adding "eval file.flag = true" to .radarerc radare executes rabin -risSz at startup, automatically flaging the file.
Radare have some interesting features in the networking area. It can be used as a hexadecimal netcat-like application using the io socket plugin which offers a file-like interface to access a TCP/IP connection.
The radare remote protocol allows to remotelly expand the IO of radare using a TCP connection. There's a pure-python implementation that has been used to implement python-based debuggers or just to offer a radare access to Bochs, vtrace or Immunity debugger for example.
The IO plugin called 'socket' generates a virtual file using a malloc-ed buffer which grows when receiving data from the socket and writing data to it in.
$ radare socket://av.com:80/
[0x00000000]> x
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00000000, ffff ffff ffff ffff ffff ffff ffff ffff ffff ..................
0x00000012, ffff ffff ffff ffff ffff ffff ffff ffff ffff ..................
...
When writing the socket:// plugin redirects it to the socket.
[0x00000000]> w GET / HTTP/1.1\r\nHost: av.com\r\n\r\n
[0x00000000]> x
offset 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 0123456789ABCDEF01
0x00000000, 4854 5450 2f31 2e31 2033 3031 204d 6f76 6564 HTTP/1.1 301 Moved
0x00000012 2050 6572 6d61 6e65 6e74 6c79 0d0a 4461 7465 Permanently..Date
0x00000024, 3a20 4d6f 6e2c 2032 3920 5365 7020 3230 3038 : Mon, 29 Sep 2008
0x00000036 2031 313a 3035 3a34 3320 474d 540d 0a4c 6f63 11:05:43 GMT..Loc
0x00000048, 6174 696f 6e3a 2068 7474 703a 2f2f 7777 772e ation: http://www.
0x0000005A 616c 7461 7669 7374 612e 636f 6d2f 0d0a 436f altavista.com/..Co
0x0000006C, 6e6e 6563 7469 6f6e 3a20 636c 6f73 650d 0a54 nnection: close..T
0x0000007E 7261 6e73 6665 722d 456e 636f 6469 6e67 3a20 ransfer-Encoding:
0x00000090, 6368 756e 6b65 640d 0a43 6f6e 7465 6e74 2d54 chunked..Content-T
0x000000A2 7970 653a 2074 6578 742f 6874 6d6c 3b20 6368 ype: text/html; ch
0x000000B4, 6172 7365 743d 7574 662d 380d 0a0d 0a39 3720 arset=utf-8....97
0x000000C6 2020 2020 0d0a 5468 6520 646f 6375 6d65 6e74 ..The document
0x000000D8, 2068 6173 206d 6f76 6564 203c 4120 4852 4546 has moved <A HREF
0x000000EA 3d22 6874 7470 3a2f 2f77 7777 2e61 6c74 6176 ="http://www.altav
0x000000FC, 6973 7461 2e63 6f6d 2f22 3e68 6572 653c 2f41 ista.com/">here</A
0x0000010E 3e2e 3c50 3e0a 3c21 2d2d 2070 332e 7263 2e72 >.<P>.<!-- p3.rc.r
0x00000120, 6534 2e79 6168 6f6f 2e63 6f6d 2075 6e63 6f6d e4.yahoo.com uncom
0x00000132 7072 6573 7365 642f 6368 756e 6b65 6420 4d6f pressed/chunked Mo
0x00000144, 6e20 5365 7020 3239 2030 343a 3035 3a34 3320 n Sep 29 04:05:43
0x00000156 5044 5420 3230 3038 202d 2d3e 0a0d 0a30 0d0a PDT 2008 -->...0..
0x00000168, 0d0a ffff ffff ffff ffff ffff ffff ffff ffff ..................
The contents of the file are updated automatically while the socket is feeded by bytes. You can understand this plugin as a raw hexadecimal netcat with a nice interface ;)
All reads from the socket are stored as flags pointing to the last read packet:
[0x00000000]> f
0x00000000 512 _sockread_0
0x00000000 512 _sockread_last
The 'io/remote' plugin implements a simple binary protocol for connecting client/server radare implementation and extend the basic IO operations over the network.
An example of use would be:
(alice)$ radare listen://:9999
Listening at port 9999
(bob)$ radare connect://alice:9999/dbg:///bin/ls
...
Once bob connects to alice using the listen/connect URIs (both handled by the remote plugin) the listening one loads the nested uri and tries to load it "dbg:///bin/ls". Both radares will be working in debugger mode and all the debugger commands will be wrapped by network.
In the same way it is possible to nest multiple socket connections between radare.
The radapy is the python implementation for the radare remote protocol. This module is distributed in the scripts/ directory of radare. For better understanding, here's an example:
$ cat scripts/radapy-example.py
import radapy
from string import *
PORT = 9999
def fun_system(str):
print "CURRENT SEEK IS %d"%radapy.offset
return str
def fun_open(file,flags):
return str
def fun_seek(off,type):
return str
def fun_write(buf):
print "WRITING %d bytes (%s)"%(len(buf),buf)
return 6
def fun_read(len):
print "READ %d bytes from %d\n"% (len, radapy.offset)
str = "patata"
str = str[radapy.offset:]
return str
#radapy.handle_cmd_close = fun_close
radapy.handle_cmd_system = fun_system
radapy.handle_cmd_read = fun_read
radapy.handle_cmd_write = fun_write
radapy.size = 10
radapy.listen_tcp (PORT)
As you see, you just need to implement the 'read' command and all the rest will mostly work. Here's a shorter implementation for immunity debugger:
import immlib
import radapy
def fun_read(len):
return immlib.Debugger().readMemory(radapy.offset, len)
radapy.handle_cmd_read = fun_read
radapy.listen_tcp ( 9999 )
For the other side you just have to connect a radare to this port to get the fun:
$ radare connect://127.0.0.1:9999/dbg://immunity
TODO
RSC stands for 'radare scripts' which are a set of scripts accessible thru the 'rsc' command and allow to perform different tasks or provide small utilities that can interact with radare in some way.
There are two rsc scripts that emulate 'rasm' to assemble and disassemble single opcodes for multiple architectures from the command line.
$ rsc asm 'mov eax,33'
b8 21 00 00 00
$ rsc dasm 'b8 21 00 00 00'
0: b8 21 00 00 00 mov $0x21,%eax
If you pay attention to the output you'll notice that it's AT&T syntax and the formatting is the objdump one. Looking the scripts will make you understand that it's using 'gas' and 'nasm' for assembling and objdump for disassembling.
Compare this with rasm:
$ rasm 'mov eax,33'
b8 21 00 00 00
$ rasm -d 'b8 21 00 00 00'
mov eax, 0x21
Use this script to convert IDC scripts exported from an IDA database to import all the metadata into radare.
$ rsc idc2rdb < my-database.idc > mydb.radare.script
Gokolu is a perl script that strips strings from a program and find them in google code search to try to identify which libraries or files has been linked against the target binary.
Here's an usage example:
pancake@flubox:~$ rsc gokolu /bin/ls Usage
The Go*g*e Kode Lurker v0.1
=> Usage: %s [OPTION]... [FILE]...
12 ftp://alpha.gnu.org/gnu/coreutils/coreutils-4.5.4.tar.bz2
0 ftp://alpha.gnu.org/gnu/coreutils/coreutils-4.5.3.tar.gz
Nice huh? ;)
FMI: http://www.openrce.org/blog/view/1001/Gokolu_-_Binary_string_source_identifier
The inline assembler/disassembler. Initially 'rasm' was designed to be used for binary patching, just to get the bytes of a certain opcode. Here's the help
$ rasm -h
Usage: rasm [-elvV] [-f file] [-s offset] [-a arch] [-d bytes] "opcode"|-
if 'opcode' is '-' reads from stdin
-v enables debug
-d [bytes] disassemble from hexpair bytes
-f [file] compiles assembly file to 'file'.o
-s [offset] offset where this opcode is suposed to be
-a [arch] selected architecture (x86, olly, ppc, arm, java, rsc)
-e use big endian
-l list all supported opcodes and architectures
-V show version information
The basic 'portable' assembler instructions can be listed with 'rasm -l':
$ rasm -l
Usage: rasm [-elvV] [-f file] [-s offset] [-a arch] [-d bytes] "opcode"|-
Architectures:
olly, x86, ppc, arm, java
Opcodes:
call [addr] - call to address
jmp [addr] - jump to relative address
jz [addr] - jump if equal
jnz - jump if not equal
trap - trap into the debugger
nop - no operation
push 33 - push a value or reg in stack
pop eax - pop into a register
int 0x80 - system call interrupt
ret - return from subroutin