R 2 Book
R 2 Book
Introduction 14
Book Editions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Toolchain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
User Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Iaito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
WebUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
r2con . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Contribute! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Installation 23
Building from Source . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Building with meson + ninja . . . . . . . . . . . . . . . . . . . 24
Helper Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Cleaning Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Portability in Mind . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Home builds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Static Build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Meson build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Docker build . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Windows Builds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Crosscompiling . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Step-by-Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Install Visual Studio 2019 (or higher) . . . . . . . . . . 28
Install Python 3 . . . . . . . . . . . . . . . . . . . . . . 28
Install Git for Windows . . . . . . . . . . . . . . . . . . 28
Pull the code . . . . . . . . . . . . . . . . . . . . . . . . 28
Compile Radare2 Code . . . . . . . . . . . . . . . . . . 29
Compiling for Android . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Step-by-step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Download and Install Termux App . . . . . . . . . . . . 29
Update & Upgrade . . . . . . . . . . . . . . . . . . . . . 29
Build and Installation . . . . . . . . . . . . . . . 30
Flatpak releases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
CLI Configuration . . . . . . . . . . . . . . . . . . . . . . . . . 32
Sandbox Configuration . . . . . . . . . . . . . . . . . . . . . . . 32
Snap releases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Docker containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Available images . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2
Stable version . . . . . . . . . . . . . . . . . . . . . . . . 34
GIT version . . . . . . . . . . . . . . . . . . . . . . . . . 35
Run a container as r2web server . . . . . . . . . . . . . . . . . . 35
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Using Radare2 37
Commandline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Common Uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Command Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Repetitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Shell Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Output Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . 45
Temporal Seek . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Basic Debugger Session . . . . . . . . . . . . . . . . . . . . . . . . . 48
Tooling 49
Rax2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Rafind2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Rarun2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Sample rarun2 script . . . . . . . . . . . . . . . . . . . . . . . . 55
Using a program via TCP/IP . . . . . . . . . . . . . . . . . . . 56
Debugging a Program Redirecting the stdio into Another Ter-
minal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
r2pm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Package Database . . . . . . . . . . . . . . . . . . . . . . . . . 57
Sample Session . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Rabin2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
File Properties Identification . . . . . . . . . . . . . . . . . . . 60
Code Entrypoints . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Exports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Symbols and Exports . . . . . . . . . . . . . . . . . . . . . . . . 63
Debug Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
List Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Radiff2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Practical examples . . . . . . . . . . . . . . . . . . . . . . . . . 71
Generating and Applying Patches . . . . . . . . . . . . . . . . . 71
3
Data Diffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Code Diffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Binary Diffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Binary Diffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Rasm2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Assembler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Visual mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Disassembler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
pd N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
pD N . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
pda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
pi, pI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Disassembler Configuration . . . . . . . . . . . . . . . . . . . . 84
ragg2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Help message . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
First Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Injectable machine code in different forms . . . . . . . . . . . . 86
Syntax of the language . . . . . . . . . . . . . . . . . . . . . . . 91
Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . 91
Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Includes . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Hashbang . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Function definition . . . . . . . . . . . . . . . . . . . . . 92
Function signatures . . . . . . . . . . . . . . . . . . . . 92
Function types . . . . . . . . . . . . . . . . . . . . . . . 92
Syscalls . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Core library . . . . . . . . . . . . . . . . . . . . . . . . . 93
Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Virtual registers . . . . . . . . . . . . . . . . . . . . . . 93
Math operations . . . . . . . . . . . . . . . . . . . . . . 93
Return values . . . . . . . . . . . . . . . . . . . . . . . . 94
Traps . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Inline assembly . . . . . . . . . . . . . . . . . . . . . . . 94
Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4
Control flow . . . . . . . . . . . . . . . . . . . . . . . . . 94
Comments . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Shellcode Encoders . . . . . . . . . . . . . . . . . . . . . . . . . 95
Padding and Patching . . . . . . . . . . . . . . . . . . . . . . . 95
rahash2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Hashing by blocks . . . . . . . . . . . . . . . . . . . . . . . . . 97
Hashing with rabin2 . . . . . . . . . . . . . . . . . . . . . . . . 97
Obtaining hashes within radare2 session . . . . . . . . . . . . . 97
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Configuration 100
Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
RC Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
System Wide . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Home Directories . . . . . . . . . . . . . . . . . . . . . . . . . . 104
File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Themes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Configuration Variables . . . . . . . . . . . . . . . . . . . . . . . . . 107
asm.arch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
asm.bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
asm.syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
asm.pseudo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.os . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.lines.call . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.lines.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.linestyle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
asm.offset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
asm.trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
asm.bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
asm.sub.reg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
asm.sub.jmp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
asm.sub.rel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
asm.sub.section . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
asm.sub.varonly . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
cfg.bigendian . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
cfg.newtab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
scr.color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
scr.seek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
scr.scrollbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
scr.utf8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
cfg.fortunes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5
cfg.fortunes.type . . . . . . . . . . . . . . . . . . . . . . . . . . 111
stack.size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
IO Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
io.unalloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
io.cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
io.pcache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
io.va . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Commandline 113
Dietline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Autocompletion . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Emacs (default) mode . . . . . . . . . . . . . . . . . . . . . . . 115
Moving . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Deleting . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Killing and Yanking . . . . . . . . . . . . . . . . . . . . 115
History . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Vi mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Entering command modes . . . . . . . . . . . . . . . . . 116
Moving . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Deleting and Yanking . . . . . . . . . . . . . . . . . . . 116
Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Seeking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Open file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Seeking at any position . . . . . . . . . . . . . . . . . . . . . . 120
Partial Seeks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Dereferencing pointers . . . . . . . . . . . . . . . . . . . . . . . 121
Block Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Mapping Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Print Modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Hexadecimal View . . . . . . . . . . . . . . . . . . . . . . . . . 127
Show Hexadecimal Words Dump (32 bits) . . . . . . . . 127
Show Hexadecimal Quad-words Dump (64 bits) . . . . . 128
Date/Time Formats . . . . . . . . . . . . . . . . . . . . . . . . 128
Basic Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
High-level Languages Views . . . . . . . . . . . . . . . . . . . . 131
Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Print Memory Contents . . . . . . . . . . . . . . . . . . . . . . 133
Disassembly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Selecting Target Architecture . . . . . . . . . . . . . . . . . . . 134
Configuring the Disassembler . . . . . . . . . . . . . . . . . . . 135
Disassembly Syntax . . . . . . . . . . . . . . . . . . . . . . . . 136
Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
6
Local flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Flag Zones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Writing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Write Over . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Rapatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Patch format . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Rapatch Example . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Applying rapatches . . . . . . . . . . . . . . . . . . . . . . . . . 141
Zoom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Yank/Paste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Comparing Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Comparison Watchers . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Basic watcher usage . . . . . . . . . . . . . . . . . . . . . . . . 146
Reverting State . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Overlapping areas . . . . . . . . . . . . . . . . . . . . . . . . . 147
Watching for code modification . . . . . . . . . . . . . . . . . . 148
SDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Usage example . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
So what ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
More Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
7
Visual Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Vv visual analysis . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Ve visual config . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Vd as in define . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Panels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Basic Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Split Screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Window Mode Commands . . . . . . . . . . . . . . . . . . . . . 172
Edit Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Saving layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Searching 173
Search Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Basic Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Configuring Search Options . . . . . . . . . . . . . . . . . . . . . . . 177
Pattern Matching Search . . . . . . . . . . . . . . . . . . . . . . . . 178
Search Automation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Searching Backwards . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Assembler Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Searching for Cryptography materials . . . . . . . . . . . . . . . . . 180
Searching expanded keys . . . . . . . . . . . . . . . . . . . . . . 180
Searching private keys and certificates . . . . . . . . . . . . . . 181
Entropy analysis . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Searching data matching hash digest . . . . . . . . . . . . . . . 182
Disassembling 182
Decompilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
PseudoDecompiler . . . . . . . . . . . . . . . . . . . . . . . . . 184
r2dec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
R2Ghidra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Adding Metadata to Disassembly . . . . . . . . . . . . . . . . . . . . 188
Disassembling 191
Using r2 with 8051 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
r2 configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Address spaces and memory mapping . . . . . . . . . . . . . . 193
Tips & tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Adding support for new 8051 variants . . . . . . . . . . . . . . 195
8
Analysis 196
Code Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Analyze functions . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Hand craft function . . . . . . . . . . . . . . . . . . . . . . . . . 200
Recursive analysis . . . . . . . . . . . . . . . . . . . . . . . . . 203
Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Control flow configuration . . . . . . . . . . . . . . . . . 206
Reference control . . . . . . . . . . . . . . . . . . . . . . 207
Analysis ranges . . . . . . . . . . . . . . . . . . . . . . . 207
Jump tables . . . . . . . . . . . . . . . . . . . . . . . . . 208
Platform specific controls . . . . . . . . . . . . . . . . . 208
Visuals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Analysis hints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Managing variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Type inference . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Loading types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Printing types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Linking Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Structure Immediates . . . . . . . . . . . . . . . . . . . . . . . 220
Managing enums . . . . . . . . . . . . . . . . . . . . . . . . . . 220
Internal representation . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Function prototypes . . . . . . . . . . . . . . . . . . . . . . . . 223
Calling Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Virtual Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Syscalls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Signatures 227
Finding Best Matches zb . . . . . . . . . . . . . . . . . . . . . . . . 230
Graph 231
Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Graph Output Formats . . . . . . . . . . . . . . . . . . . . . . . . . 233
Ascii Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Interactive Ascii Art . . . . . . . . . . . . . . . . . . . . . . . . 233
Tiny Ascii Art . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Graphviz dot . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Graph Modelling Language . . . . . . . . . . . . . . . . . . . . 234
SDB key-value . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Create your own graph . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9
Web / image . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Emulation 235
Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Introduction to ESIL . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Using ESIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
ESIL Commands . . . . . . . . . . . . . . . . . . . . . . . . . . 240
ESIL Instruction Set . . . . . . . . . . . . . . . . . . . . . . . . 241
ESIL Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Syntax and Commands . . . . . . . . . . . . . . . . . . . . . . . 252
Arguments Order for Non-associative Operations . . . . . . . . 252
Special Instructions . . . . . . . . . . . . . . . . . . . . . . . . . 253
Quick Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
CPU Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Bit Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
Arithmetics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
Bit Arithmetics . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
Floating Point Unit Support . . . . . . . . . . . . . . . . . . . . 254
Handling x86 REP Prefix in ESIL . . . . . . . . . . . . . . . . 255
Usage Example . . . . . . . . . . . . . . . . . . . . . . . 255
Unimplemented/Unhandled Instructions . . . . . . . . . . . . . 255
ESIL Disassembly Example . . . . . . . . . . . . . . . . . . . . 255
Introspection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
API HOOKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Emulation in the Analysis Loop . . . . . . . . . . . . . . . . . . . . . 257
Debugging with ESIL . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Scripting 258
Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
r2js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
The REPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
R2Pipe.r2js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
R2Papi.r2js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
R2FridaCompile . . . . . . . . . . . . . . . . . . . . . . . . . . 263
TypeScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
10
Command Aliases . . . . . . . . . . . . . . . . . . . . . 268
File Aliases . . . . . . . . . . . . . . . . . . . . . . . . . 269
Variable Aliases . . . . . . . . . . . . . . . . . . . . . . . 269
R2pipe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
NodeJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Go . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Rust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Erlang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Haskell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Dotnet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Swift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Vala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
NewLisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Dlang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
R2Pipe2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
R2pipe2 Example . . . . . . . . . . . . . . . . . . . . . . . . . . 276
R2pipe2 APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Debugger 276
Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Small session in radare2 debugger . . . . . . . . . . . . . . . . . 278
Migration from IDA, GDB or WinDBG . . . . . . . . . . . . . . . . 279
How to run the program using the debugger . . . . . . . . . . . 279
How do I attach/detach to running process ? (gdb -p) . . . . . 279
How to set args/environment variable/load a specific libraries
for the debugging session of radare . . . . . . . . . . . . 279
How to script radare2 ? . . . . . . . . . . . . . . . . . . . . . . 279
How to list Source code as in gdb list ? . . . . . . . . . . . . . . 280
Reference Commands . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Equivalent of “set-follow-fork-mode” gdb command . . . . . . . 284
Common features . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Register Profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Reading The Profile . . . . . . . . . . . . . . . . . . . . . . . . 287
Custom Register Profiles . . . . . . . . . . . . . . . . . . . . . . 288
Understanding Each Row . . . . . . . . . . . . . . . . . . . . . 289
Register Naming and Aliases . . . . . . . . . . . . . . . . . . . 289
Alias Register . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
11
Register Groups . . . . . . . . . . . . . . . . . . . . . . . . . . 290
Column Meanings . . . . . . . . . . . . . . . . . . . . . . . . . 290
Endianness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Memory Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Tweaking descriptors . . . . . . . . . . . . . . . . . . . . . . . . 297
Reverse Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Windows Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Remote Access Capabilities . . . . . . . . . . . . . . . . . . . . . . . 300
Debugging with gdbserver . . . . . . . . . . . . . . . . . . . . . 302
WinDBG Kernel-mode Debugging (KD) . . . . . . . . . . . . . 304
Setting Up KD on Windows . . . . . . . . . . . . . . . . 304
Serial Port . . . . . . . . . . . . . . . . . . . . . . . . . 304
Network . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Connecting to KD interface on r2 . . . . . . . . . . . . . 305
Serial Port . . . . . . . . . . . . . . . . . . . . . . 305
Using KD . . . . . . . . . . . . . . . . . . . . . . . . . . 306
WinDBG Backend for Windows (DbgEng) . . . . . . . . 306
Using the plugin . . . . . . . . . . . . . . . . . . . . . . 307
Plugins 307
Most Famous Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Skeletons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Listing plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
IO plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Arch Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Moving it into the main tree . . . . . . . . . . . . . . . . . . . . 315
Implementing a new pseudo architecture . . . . . . . . . . . . . 316
Analysis plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
RBin plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
To enable virtual addressing . . . . . . . . . . . . . . . . . . . . 318
Create a folder with file format name in libr/bin/format . . . . 318
Some Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
Charset Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
R2JS Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
Plugins in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
Implementing new format plugin in Python . . . . . . . . . . . 324
Debugger plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
More to come . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
12
Testing the plugin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
Packaging your plugins . . . . . . . . . . . . . . . . . . . . . . . . . . 328
r2frida 329
Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
First Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
Process Info . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Basic information about the app and environemnt . . . . . . . 331
Enumerating symbols . . . . . . . . . . . . . . . . . . . . . . . 331
Enumerating loaded libraries . . . . . . . . . . . . . . . . . . . 332
Enumerating memory ranges . . . . . . . . . . . . . . . . . . . 332
Objective-C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Crackmes 333
IOLI CrackMes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
IOLI 0x00 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Hints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
IOLI 0x01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
Hints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
IOLI 0x02 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
IOLI 0x03 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
IOLI 0x04 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
IOLI 0x05 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
IOLI 0x06 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
IOLI 0x07 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
IOLI 0x08 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
IOLI 0x09 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Avatao R3v3rs3 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
.radare2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
.first_steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
.main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
.vmloop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
instr_A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
instr_S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
instr_I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
instr_D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
instr_P . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
instr_X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
instr_J . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
.instructionset . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
13
.bytecode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
.outro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
R2Wars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Supported Architectures . . . . . . . . . . . . . . . . . . . . . . 403
Writing Warriors . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Battle Mechanics . . . . . . . . . . . . . . . . . . . . . . . . . . 404
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
Introduction
This is the official book of the radare project.
This is a collaborative and community-driven project, if you want to improve
the status of the documentation check out the contributing chapter and submit
pullrequests to the repository
• GitHub
• PDF
• ePUB
• Online Html - built with mdbook
• Gemini Capsule - md2gmi
The minimum version of radare2 required to follow this book is r2-5.8.x, but
it is recommended to always use the last release or build it from git.
Book Editions
This book was written with Halibut in 2009 by pancake focusing on radare.
The initial implementation of the tooling, unfortunately the code evolved
14
faster than the documentation did, and the book became obsolete, for histor-
ical reasons this version can be found in this webpage:
• radare1 book pdf
During 2014, Maijin reorganized and updated the contents, other contributors
over the Internet also helped to get new stuff in and after some reviews the
book was now readily available for the first time in PDF, ePUB and Hardcover
printed versions.
• https://book.rada.re
Unfornately, the documentation part of the project got stuck again; and 10
years later, in 2024, pancake worked back updating and polish its contents.
Looking towards the 3rd edition that may be ready by the end of the same
year.
History
In 2006, Sergi Àlvarez (aka pancake) while working as a forensic analyst he
decided to write a small tool to recover some deleted files from an HFS+
disk by accident. As long as using the privative software from work it was a
good toy project, following the concept of a block-based hexadecimal editor
interface with a very simple repl to enter commands to search for byte patterns
and dump the results to disk. And have the following characteristics:
• be extremely portable (unix friendly, command line, c, small)
• open disk devices, this is using 64bit offsets
• search for a string or hexpair
• review and dump the results to disk
After three years of intense development (in 2009) the project was too bloated
to keep it as a monolitic tool and pancake decided to redesign the tool into a
more pluggable and modular form. This way it was possible to create scripts,
bindings and write plugins to add support for more architectures, debugging
targets or improve the analysis capabilities by keeping the core intact.
Since then, the project has evolved to provide a complete framework for an-
alyzing binaries, while making use of basic UNIX concepts. Those concepts
include the famous “everything is a file”, “small programs that interact using
stdin/stdout”, and “keep it simple” paradigms.
The need for scripting showed the fragility of the initial design: a monolithic
tool made the API hard to use, and so a deep refactoring was needed. In
2009 radare2 (r2) was born as a fork of radare1. The refactor added flexibility
and dynamic features. This enabled much better integration, paving the way
to use r2 from different programming languages. Later on, the r2pipe API
15
allowed access to radare2 via pipes from any language, and the r2papi provided
an idiomatic and high level interface to use r2 through r2pipe from a large
list of programming languages.
What started as a one-man project, with some eventual contributions, grad-
ually evolved into a big community-based project around 2014. The number
of users was growing fast, changing roles and contribution rules to ease the
maintenance as much as possible.
It’s important to instruct users to report their issues, as well as help developers
willing to contribute to understand the codebase. The whole development is
managed in radare2’s GitHub and discussed in the Telegram and Discord
channels.
There are several side projects that provide, among other things, a graph-
ical user interface (Iaito), a decompiler (r2dec, r2ghidra), Frida integration
(r2frida), Yara (r2yara), Unicorn, Keystone, and many other projects indexed
in the r2pm, the radare2 package manager.
Since 2016, the community gathers once a year in r2con, a congress around
radare2 that takes place in Barcelona.
Toolchain
The Radare2 project provides a collection of command-line tools, APIs and
scripting capabilities that focus on several aspects of reverse engineering.
This chapter will give you a quick understanding of them, but you can check
the dedicated sections for each tool at the end of this book.
radare2
When you run the radare2 command, you’re presented with an interactive
shell that gives you access to all the functionalities of the radare2 framework
by running mnemonic commands or scripts.
At its core, radare2 lets you open various types of files and data sources,
treating them all as if they were simple binary files. This includes executables,
disk images, memory dumps, and even live processes or network connections.
Once you’ve opened a file, radare2 provides a wide array of commands for
exploration and analysis. You can navigate through the file’s contents, view
disassembled code, examine data structures, and even modify the binary on
the fly.
Some key features accessible through the radare2 command include:
• Hex editing capabilities
16
• Advanced code analysis and disassembly
• Debugging functionality
• Binary patching
• Data visualization tools
• Scripting support for automation and extending functionality
The radare2 command serves as the primary interface to these features, of-
fering a flexible and powerful environment for reverse engineering, malware
analysis, exploit development, and general binary exploration.
rax2
A minimalistic mathematical expression evaluator for the shell that is useful
for making base conversions between floating point values, hexadecimal rep-
resentations, hexpair strings to ASCII, octal to integer, and more. It also
supports endianness settings and can be used as an interactive shell if no
arguments are given.
Examples
$ rax2 1337
0x539
$ rax2 0x400000
4194304
$ rax2 −b 01111001
y
$ rax2 −S radare2
72616461726532
rabin2
Another important tool distributed with radare2, rabin2 is designed to analyze
binary files and extract various types of information from them. It supports a
wide range of file formats (depending on which plugins are loaded or compiled
in), the most famous ones are:
• ELF (Executable and Linkable Format)
• PE (Portable Executable)
• Mach-O (Mach Object)
• Java CLASS files
Key features and uses of rabin2 include:
• Extracting metadata: File type, architecture, OS, subsystem, etc.
17
• Listing symbols: Both imported and exported symbols.
• Displaying section information: Names, sizes, permissions, etc.
• Showing library dependencies.
• Extracting strings from the binary.
• Identifying entry points and constructor/destructors.
• Listing header structures and information.
rabin2 can be used standalone from the command line or integrated within
other radare2 tools. It’s particularly useful for quick analysis of binaries with-
out the need to fully load them into a debugger or disassembler. The informa-
tion provided by rabin2 is often used by other parts of the radare2 framework
to enhance analysis and provide context during reverse engineering tasks.
rasm2
The command-line assembler and disassembler. It supports a wide range of
architectures and can be used independently of the main radare2 tool. Key
features include:
• Multi-architecture support: Can handle numerous architectures includ-
ing x86, x86-64, ARM, MIPS, PowerPC, SPARC, and many others.
• Bi-directional operation: Functions as both an assembler (converting
human-readable assembly code to machine code) and a disassembler
(converting machine code back to assembly).
• Flexible input/output: Accepts input as hexadecimal strings, raw binary
files, or text files containing assembly code.
• Shellcode generation: Useful for security research and exploit develop-
ment.
• Inline assembly: Allows for quick assembly of individual instructions or
small code snippets.
• Syntax highlighting: Provides colored output for better readability when
disassembling.
• Plugins: Supports architecture-specific plugins for extended functional-
ity.
For example assembling and disassembling a nop for java:
$ rasm2 −a java ' nop '
00
18
rahash2
Versatile command-line hashing tool that is part of the radare2 framework.
It’s designed to compute and verify cryptographic hashes and checksums for
files, strings, or even large data streams like hard disks or network traffic.
• Supports a wide range of hash algorithms
– MD4, MD5, SHA1, SHA256, SHA384, SHA512, CRC16, CRC32,
and more.
• Input data from files, stdin, or command-line strings.
• Block-based hashing
• Incremental hashing for large files
• Hash verification
• Various output formats, including raw bytes, hexadecimal strings, or
radare2 commands.
• Basic encryption capabilities
Here are few usage examples:
$ rahash2 f i l e
f i l e : 0x00000000−0x00000007 sha256 :
887 cfbd0d44aaff69f7bdbedebd282ec96191cce9d7fa7336298a18efc3c7a5a
radiff2
The commandline Binary Diffing utility of the radare2 reverse engineering
framework. It is designed to compare and analyze differences between binary
files or sections of binary data.
Key features and capabilities of radiff2 include:
• Compare byte-per-byte changes between two files
• Delta diffing on files with different sizes, finding common sections
• Code Analysis diffing, finding functions in common
• Binary header comparing libraries, exports, etc
• Visualization options: graphs, ascii art, plain text, json
• Integration with radare2: Using the c command or running it with the
−r flag.
• Patch generation, writing r2 scripts that patch one file to update it like
the other.
radiff2 is particularly useful for cases where you need to identify and under-
stand changes between different versions of binary files or compare potentially
malicious files with known good versions.
19
rafind2
rafind2 is a command-line utility designed to search for byte patterns, strings,
or hexadecimal values within binary files or any other type of file.
This tool implements the most common subcommands of the radare2’s /
(search) operation.
• Search for patterns, strings, binary data and regular expression
• Run across multiple files
• Output formats, showing offsets, json and even r2 commands
ragg2
Ragg2 is a versatile tool primarily serving as a shellcode compiler.
The tool is written on top of the r_egg library which can construct exploit
payloads from the commandline, adding paddings, nops, sequences of bytes,
compile small relocatable programs and even apply transformations to avoid
some specific characters.
The ragg2−cc tool can compile C programs into raw linear instructions that
are relocatable and are useful for injecting them in target processes or use
them in exploits.
This feature is conceptually based on shellforge4, but only linux/osx x86-32/64
platforms are supported.
It can also compile a specific low level domain specific language and gener-
ate tiny binaries without the need of any system compiler or toolchain as
exemplified below:
$ cat h i . r
/∗ h e l l o world i n r_egg ∗/
w r i t e @ s y s c a l l ( 4 ) ; //x64 w r i t e @ s y s c a l l ( 1 ) ;
e x i t @ s y s c a l l ( 1 ) ; //x64 e x i t @ s y s c a l l ( 6 0 ) ;
main@global (128) {
. var0 = ” h i ! \ n ” ;
w r i t e ( 1 , . var0 , 4) ;
exit (0) ;
}
$ ragg2 −O −F h i . r
$ ./ hi
hi !
$ cat h i . c
main@global ( 0 , 6 ) {
w r i t e ( 1 , ” Hello0 ” , 6) ;
exit (0) ;
}
$ ragg2 h i . c
20
$ . / h i . c . bin
Hello
rarun2
A launcher for running programs within different environments, with different
arguments, permissions, directories, and overridden default file descriptors.
User Interfaces
Radare2 has seen many different user interfaces being developed over the
years.
Maintaining a GUI is far from the scope of developing the core machinery of
a reverse engineering toolkit; It is preferred to have a separate project and
community, allowing both projects to collaborate and improve alongside each
other. This allows individual developers to focus entirely on implementing a
CLI or GUI feature instead of trying to juggle both graphical implementation
and the low-level logic of the core CLI.
In the past, there have been at least 5 different native user interfaces (ragui,
r2gui, gradare, r2net, bokken) but none of them got enough maintenance
power to take off and they all died.
Iaito
The current main radare2 GUI is Iaito. It is written in C++ using Qt and
was originally authored by Hugo Teso.
• Download: https://github.com/radareorg/iaito
WebUI
In addition, r2 includes an embedded webserver with a basic HTML/JS in-
terface. Add −c=H to your command-line flags to automatically start the
webserver and open it in your browser.
$ r2 −c=H / bin / l s
r2con
Starting in 2016 we organized the first public and international congress about
radare.
Highlighting all aspects of radare2, this congress brings the oportunity to ev-
eryone to learn more about manual and automated reverse engineering, static
21
Figure 1: Iaito screenshot
Contribute!
If you want to contribute to the Radare2 book, you can do it at the Github
repository.
Suggested contributions include:
• Crackme writeups
22
• CTF writeups
• Explain how to use Radare2
• Documentation to help developers
• Conference presentations/workshops using Radare2
• Missing content from the Radare1 book updated to Radare2
Please get permission to port any content you do not own/did not create
before you put it in the Radare2 book.
See https://github.com/radareorg/radare2/blob/master/DEVELOPERS.md
for general help on contributing to radare2.
Installation
Radare2 is available for a wide range of target operating systems and archi-
tectures, making it a versatile tool for reverse engineering tasks.
Whether you are using Windows, Linux, macOS, or even mobile or embed-
ded operating systems, radare2 can be installed and utilized effectively. This
chapter provides a comprehensive guide on how to get radare2 up and running
on your system, covering various methods from downloading and installing bi-
nary distributions to compiling the software from source code. This flexibility
ensures that users can tailor the installation process to their specific needs
and system configurations.
To install radare2, users can choose from several options. One straightforward
method is to download precompiled binary distributions, which are available
for many platforms and can be installed quickly with minimal setup.
But usually the recommended way to install is by compiling it from the git
repository, the upstream branch is always stable and ready to use for everyone.
The chapter also delves into specific configuration options and post-
installation setup to optimize radare2 for different use cases, ensuring that
you have a fully functional and efficient reverse engineering environment
which is key to follow up with the rest of contents in the book.
23
dencies, to make examples more accessible and, of course, to have the most
recent version.
A new stable release is typically published every month.
The radare development repository is often more stable than the ‘stable’ re-
leases. To obtain the latest version:
$ g i t c l o n e https : / / github . com/ radareorg / radare2 . g i t
This will probably take a while, so take a coffee break and continue reading
this book.
To update your local copy of the repository, use git pull anywhere in the
radare2 source code tree:
$ git pull
If you have local modifications of the source, you can revert them (and lose
them!) with:
$ g i t r e s e t −−hard HEAD
Or send us a patch:
$ g i t d i f f > radare−f o o . patch
The most common way to get r2 updated and installed system wide is by
using:
$ s y s / i n s t a l l . sh
Helper Scripts
Take a look at the scripts in sys/, they are used to automate stuff related to
syncing, building and installing r2 and its bindings.
The most important one is sys/install .sh. It will pull, clean, build and symstall
r2 system wide.
24
Symstalling is the process of installing all the programs, libraries, documen-
tation and data files using symlinks instead of copying the files.
By default it will be installed in /usr/local, but you can specify a different
prefix using the argument −−prefix.
This is useful for developers, because it permits them to just run ‘make’ and
try changes without having to run make install again.
Cleaning Up
Cleaning up the source tree is important to avoid problems like linking to old
objects files or not updating objects after an ABI change.
The following commands may help you to get your git clone up to date:
$ g i t c l e a n −xdf
$ g i t r e s e t −−hard o r i g i n / master
$ git pull
If you want to remove previous installations from your system, you must run
the following commands:
$ . / c o n f i g u r e −−p r e f i x=/usr / l o c a l
$ make purge
Portability in Mind
One of the main development principles of radare2 is its portability, therefor
radare2 can be compiled on many systems and architectures. In order to
achieve that and to extend flexibility we are maintaining two build systems:
GNU Make and Meson.
Most contributors use GNU/Linux with GCC or macOS with Clang, so those
would be the better supported platforms, or at least the most tested. But it
is also possible to build with TinyCC, Emscripten, Microsoft Visual Studio,
SunStudio, …)
The debugger feature can be opt-out at compile time, this is because some-
times you are ont interested in having such feature in a specific build (web
assembly, specific sandbox usage, etc) or maybe it is because you are port-
ing radare2 on a platform that the debugger is not yet supported. Use the
−−without−debugger configure flag to do that.
25
Note that there are I/O plugins that use GDB, WinDbg, or Wine as back-
ends, and therefore rely on presence of corresponding third-party tools (in
case of remote debugging - just on the target machine).
To build on a system using acr and GNU Make (e.g. on BSD systems):
$ . / c o n f i g u r e −−p r e f i x=/usr
$ gmake
$ sudo gmake i n s t a l l
Home builds
To build and run radare2 in your home just run the sys/user.sh script.
$ s y s / u s e r . sh
Static Build
You can build radare2 statically along with all other tools with the command:
$ s y s / s t a t i c . sh
Meson build
You can use meson/ninja to build (or muon/samu):
$ meson b && n i n j a −C b
There’s a helper script in sys/ to make the meson experience a little bit
simpler:
$ s y s /meson . py −−p r e f i x=/usr −−shared −−i n s t a l l
Docker build
Radare2 repository ships a Dockerfile that you can use with Docker.
You can read more regarding the this build process as well as how to run it
in the Docker containers section.
26
Windows Builds
To build r2 on Windows you have to use the Meson build system. Despite
being able to build r2 on Windows using cygwin, mingw or WSL using the
acr/make build system it is not the recommended/official/supported method
and may result on unexpected results.
Binary builds can be downloaded from the release page or when logged in,
access the github CI artifacts that are built on every commit.
Crosscompiling
The mingw builds are also possible, but release builds are made with the
Microsoft compiler for maximum compatibility and standarization with other
software you can use.
If you want to build r2 for windows on linux you can use the sys/mingw32.sh
script that will autodetect the mingw toolchain from your system and build
all the .exe and .dll.
Note that cygwin support was kind of removed some years ago and nowadays
most users will opt for WSL or purely native builds that will work well even
on ReactOS and many different versions of windows without special software
installed.
Prerequisites
Building radare2 on Windows using Microsoft Visual Studio involves setting
up several key tools. You will need to install Microsoft Visual Studio, along
with the Meson build system and the Ninja build tool. These tools are neces-
sary for configuring and compiling the radare2 source code.
These are the requirements to get the environment ready.
• 3 GB of free disk space
• Visual Studio (2019 or higher)
• Python 3
• Meson
• Ninja
• Git
Step-by-Step
Follow these instructions to pull the build tools to get the project compiled
on your Windows machine.
27
Install Visual Studio 2019 (or higher) Visual Studio must be installed
with a Visual C++ compiler, supporting C++ libraries, and the appropriate
Windows SDK for the target platform version.
You can find a copy of Visual Studio (the Community versions are free for
download) in here:
• Download Visual Studio 2019
Install Python 3 Conda is our probably the best Python distribution for
Windows. But you can skip the next steps if you have Python installed already
You can install Python3 for Windows using Conda, but also the standard
distribution, choco, winget, etc. Choose the one you like the most
When python is installed ensure to set the bin directory in your PATH, so
you can launch a CMD or Powershell and run python3.
Now you are ready to install meson and ninja, the radare2 build tools with
pip:
pip i n s t a l l n i n j a
pip i n s t a l l meson
Install Git for Windows All Radare2 code is managed via the Git version
control system and hosted on GitHub.
Follow these steps to install Git for Windows.
Download Git for Windows from the official website
Check the following options during the Wizard steps.
• Use a TrueType font in all console windows
• Use Git from the Windows Command Prompt
• Use the native Windows Secure Channel library (instead of OpenSSL)
• Checkout Windows-style, commit Unix-style line endings (core.autocrlf=true)
• Use Windows’ default console window (instead of Mintty)
• Ensure git −−version works after install
Pull the code Follow these steps to clone the Radare2 git repository.
g i t c l o n e https : / / github . com/ radareorg / radare2
28
Compile Radare2 Code The build process on windows has been heavily
simplified to just 3 batch scripts:
• preconfigure.bat : find vscode, checks for python installation etc
• configure.bat : run the meson configure step.
• make.bat : build radare2 and create prefix directory with the dis-
tributable folder.
You can run make from the root directory of the project everytime you modify
the source code in case you are developing to get the new binaries ready to
test in that directory.
Prerequisites
• Python 3
• Make
• Git
• Binutils
• pkg-config
Step-by-step
Download and Install Termux App Download the Termux application
from the official site and install it.
Update & Upgrade First time installation of termux require updating the
repo to fetch all the available packages.
$ pkg update && pkg upgrade −y
build-essential contains all the required build tool like make,gcc etc.
If you are limited by disk space, you can either clone the repository with a
depth of 1 by adding −−depth 1 in clone command or build from a tarball.
29
Cloning the repository provides the most up-to-date code, whereas tarballs
are only generated during releases, which may not contains latest update and
bug fixes.
Build and Installation Building and installing Radare2 after cloning the
repository is straightforward using the following commands:
cd radare2
sh s y s / i n s t a l l . sh
It will install required packages if you already didn’t and start the installation.
~/ radare2 $ sh s y s / i n s t a l l . sh
/ data / data /com . termux/ f i l e s /home/ radare2
Termux environment d e t e c t e d . I n s t a l l i n g n e c e s s a r y packages
No mirror or mirror group s e l e c t e d . You might want to s e l e c t one by
running ' termux−change−repo '
Checking a v a i l a b i l i t y o f c u r r e n t mirror :
[ ∗ ] https : / / packages−c f . termux . dev/ apt /termux−main : ok
Hit : 1 https : / / packages−c f . termux . dev/ apt /termux−main s t a b l e InRelease
Reading package l i s t s . . . Done
Building dependency t r e e . . . Done
Reading s t a t e i n f o r m a ti o n . . . Done
A l l packages are up to date .
No mirror or mirror group s e l e c t e d . You might want to s e l e c t one by
running ' termux−change−repo '
Checking a v a i l a b i l i t y o f c u r r e n t mirror :
[ ∗ ] https : / / packages−c f . termux . dev/ apt /termux−main : ok
Reading package l i s t s . . . Done
Building dependency t r e e . . . Done
Reading s t a t e i n f o r m a ti o n . . . Done
g i t i s a l r e a d y the newest v e r s i o n ( 2 . 4 5 . 2 ) .
build−e s s e n t i a l i s a l r e a d y the newest v e r s i o n ( 4 . 1 ) .
b i n u t i l s i s a l r e a d y the newest v e r s i o n ( 2 . 4 2 ) .
pkg−c o n f i g i s a l r e a d y the newest v e r s i o n (0.29.2 −2) .
0 upgraded , 0 newly i n s t a l l e d , 0 to remove and 0 not upgraded .
/ data / data /com . termux/ f i l e s /home/ radare2
From https : / / github . com/ radareorg / radare2
∗ branch master −> FETCH_HEAD
Already up to date .
[ ∗ ] Finding make i s / data / data /com . termux/ f i l e s / usr / bin /make OK
[ ∗ ] Configuring the b u i l d system . . . OK
[ ∗ ] Checking out capstone . . . OK
[ ∗ ] Checking out vector35−arm64 . . . OK
[ ∗ ] Checking out vector35−armv7 . . . OK
[ ∗ ] Running c o n f i g u r e . . . OK
[ ∗ ] Ready . You can now run 'make ' .
c o n f i g u r e −p l u g i n s : Loading . / p l u g i n s . c f g . .
c o n f i g u r e −p l u g i n s : Generating l i b r / c o n f i g . h
c o n f i g u r e −p l u g i n s : Generating l i b r /asm/d/ c o n f i g . i n c
30
c o n f i g u r e −p l u g i n s : Generating l i b r / c o n f i g .mk
........
........
cd ”/ data / data /com . termux/ f i l e s / usr / l i b / radare2 /” && rm −f l a s t &&
l n −f s 5 . 9 . 3 l a s t
cd ”/ data / data /com . termux/ f i l e s / usr / share / radare2 /” && rm −f l a s t &&
l n −f s 5 . 9 . 3 l a s t
mkdir −p ”/ data / data /com . termux/ f i l e s / usr / share / radare2 / 5 . 9 . 3 / ”
/ data / data /com . termux/ f i l e s / usr / bin /sh . / c o n f i g u r e −p l u g i n s
−−rm−s t a t i c // data / data /com . termux/ f i l e s / usr / l i b / radare2 / l a s t /
c o n f i g u r e −p l u g i n s : Loading . / p l u g i n s . c f g . .
Removed 0 shared p l u g i n s that are a l r e a d y s t a t i c
~/ radare2 $ r2 −v
radare2 5 . 9 . 3 275 @ linux−arm−64
b i r t h : g i t .5.9.2 −146 − g13ea460 2024−06−28__20: 2 2 : 1 0
commit : 13 ea460b3ea28ef37361eb1d679561037c521d27
o p t i o n s : gpl −O? c s : 5 c l : 2 make
Flatpak releases
The easiest way to get iaito and radare2 installed in your Linux distro is by
using Flatpak.
This method ensures a well-tested, sandboxed environment that doesn’t inter-
fere with your system dependencies. In this section, we will guide you through
the steps to install and configure iaito using Flatpak.
First, ensure that Flatpak is installed and configured on your system. If
Flatpak is not already installed, you can add it through your distribution’s
package manager. For example, on Debian-based systems, you can install
Flatpak with the following command:
sudo apt i n s t a l l f l a t p a k
Next, you need to add the Flathub repository, which hosts iaito and many
other applications. Run the following command to add Flathub:
f l a t p a k remote−add −−i f −not−e x i s t s f l a t h u b
https : / / f l a t h u b . org / repo / f l a t h u b . f l a t p a k r e p o
With Flatpak and the Flathub repository set up, you can install iaito by
executing the following command in your terminal:
f l a t p a k i n s t a l l f l a t h u b org . radare . i a i t o
During the installation process, you may be prompted to confirm the instal-
lation and to enter your user password. Flatpak will handle all necessary
dependencies for iaito, ensuring a smooth installation process. Once the in-
stallation is complete, you can launch iaito using the following command:
31
f l a t p a k run org . radare . i a i t o
CLI Configuration
To allow usage of CLI radare applications you need to define the following
aliases:
a l i a s r2=' f l a t p a k run −−command=r2 org . radare . i a i t o '
a l i a s r2agent=' f l a t p a k run −−command=r2agent org . radare . i a i t o '
a l i a s r2p=' f l a t p a k run −−command=r2p org . radare . i a i t o '
a l i a s r2pm=' f l a t p a k run −−command=r2pm −−share=network −−d e v e l
org . radare . i a i t o '
a l i a s r 2 r=' f l a t p a k run −−command=r 2 r org . radare . i a i t o '
a l i a s rabin2=' f l a t p a k run −−command=rabin2 org . radare . i a i t o '
a l i a s radare2=' f l a t p a k run −−command=radare2 org . radare . i a i t o '
a l i a s r a d i f f 2=' f l a t p a k run −−command=r a d i f f 2 org . radare . i a i t o '
a l i a s r a f i n d 2=' f l a t p a k run −−command=r a f i n d 2 org . radare . i a i t o '
a l i a s ragg2=' f l a t p a k run −−command=ragg2 org . radare . i a i t o '
a l i a s rahash2=' f l a t p a k run −−command=rahash2 org . radare . i a i t o '
a l i a s rarun2=' f l a t p a k run −−command=rarun2 org . radare . i a i t o '
a l i a s r a s i g n 2=' f l a t p a k run −−command=r a s i g n 2 org . radare . i a i t o '
a l i a s rasm2=' f l a t p a k run −−command=rasm2 org . radare . i a i t o '
a l i a s ravc2=' f l a t p a k run −−command=ravc2 org . radare . i a i t o '
a l i a s rax2=' f l a t p a k run −−command=rax2 org . radare . i a i t o '
Sandbox Configuration
To manage the sandbox permissions for iaito, you can use the Flatseal utility.
Flatseal allows you to configure Flatpak application permissions easily.
Install Flatseal with the following command:
f l a t p a k i n s t a l l f l a t h u b com . github . tchx84 . F l a t s e a l
Alternatively this can be configured via CLI using flatpak override, here there
are some examples on how to configure it:
32
• To allow radare plugins to connect to your network or Internet:
f l a t p a k o v e r r i d e −−u s e r −−share=network org . radare . i a i t o
The Flatpak version of iaito comes bundled with several useful plugins: r2dec,
r2ghidra, r2frida, and r2yara. These plugins enhance the functionality of
radare2, providing additional capabilities for decompilation, integration with
Ghidra, dynamic analysis with Frida, and YARA rule matching.
Snap releases
The Snap package system is a cross-platform solution for packaging and dis-
tributing software on Linux. Snaps bundle all necessary dependencies, ensur-
ing they work on any Linux distribution. This makes Snap an ideal choice for
distributing radare2.
Radare2 is distributed via Snap by building it from the continuous integration
(CI) system for each release. This means every new official release is pack-
aged and made available to Snap users automatically. While the builds are
automated, they are only done for official releases, not for every git commit.
This ensures that Snap users have a stable and tested version of radare2.
Snap packages can run in a sandboxed environment, isolating them from the
rest of the system. This enhances security and prevents conflicts with other
software. Sandboxed snaps can request permissions for specific resources, but
they remain contained within their sandbox, ensuring stability and security.
To use radare2 Snap builds, note that they have different program names to
avoid conflicts with other installations. Snap versions of radare2 programs
are prefixed with radare2.. For example, to run the stable build, use:
sudo snap i n s t a l l radare2 −−c l a s s i c
radare2 . radare2 / bin / l s
radare2 . rabin2 −z / bin / s l e e p
33
This way, you can maintain a stable version alongside a development version
without conflicts.
But to allow using this radare commands without this prefix, it can be solved
either by using shell alias or by adding /snap/radare2/current/bin to your PATH
environment. Also if r2pm gets used it can also be useful to add the user local
prefix ~/.local/share/radare2/prefix/bin.
So as an example could be somthing like this:
PATH=”$HOME/ . l o c a l / share / radare2 / p r e f i x / bin : / snap/ radare2 / c u r r e n t / bin :$PATH”
Docker containers
Docker is a software that use OS-level virtualization to deliver software in
packages called images and containers when running them. Containers bun-
dle their own software and are isolated from the host system, this prevents
conflicts with other installed software.
There are several implamentations to run Docker images but radare2 images
only have been tested with docker, podman and nerdctl.
Available images
There are 2 mantained docker images, one for the official releases and one
targeted to be build locally from GIT. Both can be used similarly.
Stable version This docker image can be found in Docker Hub and contain
the latest radare2 stable version. This image is based on Ubuntu and the
same radare2 snap build. The Dockerfile used to build it can be found in this
dedicated repository.
The resulting build includes the following projects:
• radare2
• r2ghidra
• r2frida (only in supported platforms)
• r2dec
• r2yara
• r2pipe (for Python)
To use this docker image you can use either:
docker run −t i radare / radare2
podman run −t i docker . i o / radare / radare2
n e r d c t l run −t i radare / radare2
34
To use the docker image as one shot so it removes everything inside the con-
tainer on exit just add −−rm as follows:
docker run −−rm −t i radare / radare2
Also, you can select the architecture (amd64 / arm64) to compile the image by
using the ARCH make variable.
This Dockerfile also used by Remnux distribution from SANS, and is available
on the Docker Hub, but it might not contain latest changes.
35
version : ”3.8”
services :
radare2 :
image : radare / radare2
command : r2 −c '=h ' −
network_mode : b r i d g e
ports :
− ”9090:9090”
Troubleshooting
Sometimes, old builds or conflicting versions can cause problems, such as
tools using the wrong version of libraries, plugins not loading, or crashes with
segmentation faults at startup. Here are some steps to help you resolve these
issues.
We will assume you have tried to build radare2 with meson and make:
• your builddir doesnt contain spaces
• the repository is a clean clone
• you read the error messages carefully
• you have at least make, gcc, git, patch working
First, if you encounter issues during startup, you can use the R2_DEBUG=1
environment variable to see detailed debugging information. This can help
you understand what is going wrong during the initialization of radare2.
export R2_DEBUG=1
radare2 −
To remove old builds of radare2 from your system, you can run the make
purge command. This command will remove previous installations of radare2
from various common prefix paths.
36
. / c o n f i g u r e −−p r e f i x=/old / r2 / p r e f i x / i n s t a l l a t i o n
make purge
Additionally, you may need to remove the plugin directory from your home
directory to ensure no old or incompatible plugins are causing issues. You can
do this by deleting the local/share/radare2/plugins directory.
rm −r f ~ / . l o c a l / share / radare2 / p l u g i n s
If you use r2pm (radare2 package manager), it is also a good idea to clear the
r2pm cache to free up some disk space and remove potentially problematic
cached files. You can do this by deleting the ~/.local/share/radare2/r2pm
directory.
rm −r f ~ / . l o c a l / share / radare2 /r2pm
By following these steps, you can clean up old installations and resolve com-
mon issues that might arise during the installation and usage of radare2.
Using Radare2
The learning curve is usually somewhat steep at the beginning. Although
after an hour of using it you should easily understand how most things work,
and how to combine the various tools radare offers. You are encouraged to
read the rest of this book to understand how some non-trivial things work,
and to ultimately improve your skills.
Navigation, inspection and modification of a loaded binary file is performed
using three simple actions: seek (to position), print (buffer), and alternate
(write, append).
The ‘seek’ command is abbreviated as s and accepts an expression as its
argument. The expression can be something like 10, +0x25, or [0x100+ptr_table].
If you are working with block-based files, you may prefer to set the block size
to a required value with b command, and seek forward or backwards with
positions aligned to it. Use s++ and s−− commands to navigate this way.
If radare2 opens an executable file, by default it will open the file in Virtual
Addressing (VA) mode and the sections will be mapped to their virtual ad-
dresses. In VA mode, seeking is based on the virtual address and the starting
position is set to the entry point of the executable. Using −n option you
can suppress this default behavior and ask radare2 to open the file in non-
VA mode for you. In non-VA mode, seeking is based on the offset from the
beginning of the file.
37
Figure 2: learning_curve
Appending a ? to a command will show its help message, for example, p?.
Appending ?∗ will show commands starting with the given string, e.g. p?∗.
To enter visual mode, press V<enter>. Use q to quit visual mode and return
to the prompt.
In visual mode you can use HJKL keys to navigate (left, down, up, and right,
respectively). You can use these keys in cursor mode toggled by c key. To
select a byte range in cursor mode, hold down SHIFT key, and press navigation
keys HJKL to mark your selection.
While in visual mode, you can also overwrite bytes by pressing i . You can
press TAB to switch between the hex (middle) and string (right) columns.
38
Pressing q inside the hex panel returns you to visual mode. By pressing p
or P you can scroll different visual mode representations. There is a second
most important visual mode - curses-like panels interface, accessible with V!
command.
Commandline
Radare2 can be used directly from the command line, allowing you to run
commands without entering the interactive mode. This is handy for quick
tasks or when you want to include radare2 in shell scripts. You can perform
analyses, extract information, or manipulate binary files with just a single
line in your terminal.
For example, if we want to show 10 bytes from the entrypoint directly from
the system shell we can use:
$ r2 −q −c ' p8 10 @ entry0 ' / bin / l s
The −q flag is by definition the quiet mode, but when combined with −c it will
return to the shell right after executing the specified commands.
Command-line flags are options you add when starting radare2. These flags
let you customize how radare2 behaves from the start. You can tell radare2
to analyze a file immediately, use a specific configuration, or set various other
parameters. Understanding these flags helps you set up radare2 efficiently for
different tasks.
We can set some options at startup time with the −e flag like this:
r2 −e s c r . c o l o r=0 −e i o . cache=true / bin / l s
The help message, accessed by running radare2 with the -h flag, shows all
available options. It’s a quick reference for radare2’s capabilities. By exploring
this message, you can discover features you might not know about.
$ radare2 −h
Usage : r2 [−ACdfjLMnNqStuvwzX ] [−P patch ] [−p p r j ] [−a arch ] [−b
b i t s ] [−c cmd ]
[− s addr ] [−B baddr ] [−m maddr ] [− i s c r i p t ] [−e k=v ]
f i l e | pid|−|−−|=
−− run radare2 without opening any f i l e
− same as ' r2 malloc : / / 5 1 2 '
= read f i l e from s t d i n ( use −i and −c to run cmds )
−= perform !=! command to run a l l commands remotely
−0 p r i n t \x00 a f t e r i n i t and every command
−2 c l o s e s t d e r r f i l e d e s c r i p t o r ( s i l e n t warning messages )
−a [ arch ] s e t asm . arch
−A run ' aaa ' command to analyze a l l r e f e r e n c e d code
−b [ b i t s ] s e t asm . b i t s
39
−B [ baddr ] s e t base address f o r PIE b i n a r i e s
−c 'cmd . . ' execute radare command
−C f i l e i s host : port ( a l i a s f o r −c+=http ://% s /cmd/)
−d debug the e x e c u t a b l e ' f i l e ' or running p r o c e s s ' pid '
−D [ backend ] enable debug mode ( e c f g . debug=t r u e )
−e k=v e v a l u a t e c o n f i g var
−f block s i z e = f i l e s i z e
−F [ binplug ] f o r c e to use that r b i n p l u g i n
−h , −hh show help message , −hh f o r long
−H ( [ var ] ) display variable
−i [ f i l e ] run s c r i p t f i l e
−I [ f i l e ] run s c r i p t f i l e b e f o r e the f i l e i s opened
−j use j s o n f o r −v , −L and maybe o t h e r s
−k [OS/ kern ] s e t asm . os ( linux , macos , w32 , netbsd , . . . )
−l [ l i b ] load p l u g i n f i l e
−L , −LL l i s t supported IO p l u g i n s (−LL l i s t c o r e p l u g i n s )
−m [ addr ] map f i l e at given address ( loadaddr )
−M do not demangle symbol names
−n , −nn do not load RBin i n f o (−nn only load bin s t r u c t u r e s )
−N do not load u s e r s e t t i n g s and s c r i p t s
−NN do not load any s c r i p t or p l u g i n
−q q u i e t mode ( no prompt ) and q u i t a f t e r −i
−qq q u i t a f t e r running a l l −c and −i
−Q q u i e t mode ( no prompt ) and q u i t f a s t e r ( quickLeak=t r u e )
−p [ p r j ] use p r o j e c t , l i s t i f no arg , load i f no f i l e
−P [ f i l e ] apply rapatch f i l e and q u i t
−r [ rarun2 ] s p e c i f y rarun2 p r o f i l e to load ( same as −e
dbg . p r o f i l e=X)
−R [ r r 2 r u l e ] s p e c i f y custom rarun2 d i r e c t i v e
−s [ addr ] i n i t i a l seek
−S s t a r t r2 i n sandbox mode
−t load rabin2 i n f o i n thread
−u s e t bin . f i l t e r=f a l s e to get raw sym/ s e c / c l s names
−v , −V show radare2 v e r s i o n (−V show l i b v e r s i o n s )
−w open f i l e i n w r i t e mode
−x open without exec−f l a g (asm . emu w i l l not work ) , See
i o . exec
−X same as −e bin . u s e x t r=f a l s e ( u s e f u l f o r dyldcache )
−z , −zz do not load s t r i n g s or load them even i n raw
Common Uses
At first sight it may seem like there are so many options and without some
practical use cases it may feel a bit overwhelming, this sections aims to address
that by sharing some of the most common ways to get started.
Open a file in write mode and do not parse the headers (raw mode).
$ r2 −nw f i l e
Quickly get into the r2 shell opening a 1KB malloc virtual file, handy for
testing things. note that a single dash is an alias for malloc://1024
40
$ r2 −
Specify which sub-binary you want to select when opening a fatbin file:
$ r2 −a ppc −b 32 l s . f a t
Command Syntax
In a single line we can describe the syntax of the radare2 commands like this:
.− i g n o r e s p e c i a l c h a r a c t e r s , same as f u l l command quotes ”? e h i >
ho”
| .− i n t e r p r e t the output o f the command or run a s c r i p t `.? `
| / .−− the r e p e a t p r e f i x operator , run a command N times
.−−−−−−−−−−−−.
| | / . the command to run | ,
= csv |
| | | / . command s u f f i x output m o d i f i e r −−−−−−−−−−−−−−< j
= json |
| | | | / | ∗
= r2cmds |
| | | | |
`−−−−−−−−−−−−'
[ ' ] [ . ] [ N ] [ cmd[ , ? ∗ j ] ] [ ~ f i l t e r ] [@[@[@] ] addr ! s i z e ] [ | > pipe ] ; another
command
| | | | \________/ | | |
| | | | | | \ `−−− cmd
separator
41
output f i l t e r m o d i f i e r _. ' / | | | \ `−− r e d i r e c t to
file
@ temporal seek −−−−−−−−' / | \ `−−− pipe to
system s h e l l
@@ f o r e a c h o p e r a to r −−−' | `−−− f o r e a c h m o d i f i e r s @?
@@? @@@?
`−−− advanced f o r e a c h ( addr+s i z e
on items )
People who use Vim daily and are familiar with its commands will find them-
selves at home. You will see this format used throughout the book. Com-
mands are identified by a single case-sensitive character [a-zA-Z].
As an exercise for the reader you may want to read the following lines and
understand the purpose of the syntax with examples.
ds ; c a l l the debugger ' s ' step ' command
px 200 @ esp ; show 200 hex bytes at esp
pc > file .c ; dump b u f f e r as a C byte array to f i l e . c
wx 90 @@ sym . ∗ ; w r i t e a nop on every symbol
pd 2000 | grep eax ; grep opcodes that use the ' eax ' r e g i s t e r
px 20 ; pd 3 ; px 40 ; m u l t i p l e commands i n a s i n g l e l i n e
Repetitions
To repeatedly execute a command, prefix the command with a number:
px # run px
3px # run px 3 times
An useful way to use this command is to draw the classic donut animation
with 100?3d or perform an specific amount of steps when debugging like: 10ds
(that will do the same as ds 10
Shell Execution
The ! prefix is used to execute a command in shell context. If you want to
use the cmd callback from the I/O plugin you must prefix with : .
Note that a single exclamation mark will run the command and print the out-
put through the RCons API. This means that the execution will be blocking
and not interactive. Use double exclamation marks – !! – to run a standard
system call.
All the socket, filesystem and execution APIs can be restricted with the
cfg.sandbox configuration variable.
42
Environment
When executing system commands from radare2, we will get some special
environment variables that can be used to script radare2 from shellscripts
without the need to depend on r2pipe.
The environment variables can be listed and modified with the % command.
Note that the environment variables will be different depending on how we
execute code with radare2:
• runtime environment (R2CORE tells where the instance is in memory)
• debugger environment (as clean as described in a rarun2 profile)
• spawning processes with ! (get some context details, like offset, file, ..)
• r2pipe environment (R2PIPE_IN and R2PIPE_OUT with the pipe descrip-
tors)
[ 0 x00000000]> ! export | grep R2_
export R2_ARCH=”arm”
export R2_BITS=”64”
export R2_BSIZE=”256”
export R2_COLOR=”0”
export R2_DEBUG=”0”
export R2_ENDIAN=” l i t t l e ”
export R2_FILE=”malloc ://512”
export R2_IOVA=”1”
export R2_OFFSET=”0”
export R2_SIZE=”512”
export R2_UTF8=”1”
export R2_XOFFSET=”0x00000000 ”
[ 0 x00000000]>
We can also find the location in memory of the RCore instance in the current
process. This can be useful when injecting code inside radare2 (like when
injecting r2 via r2frida or using native api calls on live runtimes without
having to pass pointers or depend on RLang setups) We may learn more
about this in the scripting chapter.
[ 0 x00000000]> %~R2
R2CORE=0x140018000
[ 0 x00000000]>
Pipes
The standard UNIX pipe | is also available in the radare2 shell. You can use
it to filter the output of an r2 command with any shell program that reads
from stdin, such as grep, less , wc. If you do not want to spawn anything, or
you can’t, or the target system does not have the basic UNIX tools you need
(Windows or embedded users), you can also use the built-in grep (~).
43
Filtering
The ~ is a special character that is used by the console filtering features. It
can be chained multiple times to perform multiple filters like grepping, xml
or json indentation, head/tail operations, select column of output, etc
You may find that ~ is very similar to using the unix | pipe, but this
As you may expect appending a question mark will display the help message.
[ 0 x00000000]> ~?
Usage : [ command ] ~ [ m o d i f i e r ] [ word , word ] [ endmodifier ] [ [ column ] ] [ : l i n e ]
modifier :
| & a l l words must match to grep the l i n e
| $[n] s o r t n u m e r i c a l l y / a l p h a b e t i c a l l y the Nth column
| $ s o r t i n a l p h a b e t i c order
| $$ s o r t + uniq
| $! inverse alphabetical sort
| $!! r e v e r s e the l i n e s ( l i k e the ` tac ` t o o l )
| , token to d e f i n e another keyword
| + c a s e i n s e n s i t i v e grep ( grep −i )
| ∗ zoom l e v e l
| ^ words must be placed at the beginning o f l i n e
| ! negate grep
| ? count number o f matching l i n e s
| ?. count number chars
| ?? show t h i s help message
| ? ea convert t e x t i n t o seven segment s t y l e a s c i i a r t
| :s .. e show l i n e s s−e
| .. internal ' less '
| ... i n t e r n a l ' hud ' ( l i k e V_)
| .... i n t e r n a l ' hud ' i n one l i n e
| :) parse C−l i k e output from decompiler
| :) ) code syntax h i g h l i g h t
| <50 perform zoom to the given t e x t width on the b u f f e r
| <> xml i n d e n t a t i o n
| {: human f r i e n d l y i n d e n t a t i o n ( yes , i t ' s a smiley )
| {:.. l e s s the output o f { :
| {:... hud the output o f { :
| {} json indentation
| {}.. l e s s json indentation
| {}... hud j s o n i n d e n t a t i o n
| {=} gron−l i k e output ( key=value )
| {path} j s o n path grep
endmodifier :
| $ words must be placed at the end o f l i n e
column :
| [n] show only column n
| [ n−m] show column n to m
| [ n−] show a l l columns s t a r t i n g from column n
| [ i , j ,k] show the columns i , j and k
Examples :
| i ~:0 show f i r s t l i n e o f ' i ' output
| i ~:−2 show the second to l a s t l i n e o f ' i ' output
44
| i ~:0..3 show f i r s t t h r e e l i n e s o f ' i ' output
| pd~mov disasm and grep f o r mov
| pi ~ [ 0 ] show only opcode
| i ~0x400$ show l i n e s ending with 0x400
The ~ character enables internal grep-like function used to filter output of any
command:
pd 20~ c a l l ; d i s a s s e m b l e 20 i n s t r u c t i o n s and grep output
for ' call '
This internal grep function is a key feature for scripting radare2, because it
can be used to iterate over a list of offsets or data generated by disassembler,
ranges, or any other command. Refer to the loops section (iterators) for more
information.
Output Evaluation
The . character at the begining of the command is used to interpret or evaluate
the output of the command you execute.
The purpose of this syntax rings some bells when you use the ∗ suffix or the
−rflag in all the r2 shell commands.
For example, we can load the symbols from a binary in disk by running the
following line:
> . ! rabin2 −r s $R2_FILE
Temporal Seek
The @ character is used to specify a temporary offset at which the command
to its left will be executed. The original seek position in a file is then restored.
For example, pd 5 @ 0x100000fce to disassemble 5 instructions at address
0x100000fce.
45
Most of the commands offer autocompletion support using <TAB> key, for
example seek or f lags commands.
It offers autocompletion using all possible values, taking flag names in this
case.
The command history can be interactively inspected with !~... .
To extend the autocompletion support to handle more commands or enable
autocompletion to your own commands defined in core, I/O plugins you must
use the !!! command.
Expressions
Expressions are mathematical representations of 64-bit numerical values.
These are handled anywhere RNum API is used, the api takes a string
that can contain multiple math operations with different numeric bases and
operations and computes the resulting value.
They can be displayed in different formats, be compared or used with all
commands accepting numeric arguments. Expressions can use traditional
arithmetic operations, as well as binary and boolean ones.
To evaluate mathematical expressions prepend them with command ?:
[ 0 xb7f9d810]> ? v i 0x8048000
134512640
[ 0 xv7f9d810]> ? v i 0x8048000+34
134512674
[ 0 xb7f9d810]> ? v i 0x8048000+0x34
134512692
[ 0 xb7f9d810]> ? 1+2+3−4∗3
hex 0xfffffffffffffffa
octal 01777777777777777777772
unit 17179869184.0G
segment f f f f f 0 0 0 : 0 f f a
int64 −6
s t r i n g ”\ xfa \ x f f \ x f f \ x f f \ x f f \ x f f \ x f f \ x f f ”
binary
0 b1111111111111111111111111111111111111111111111111111111111111010
f v a l u e : −6.0
f l o a t : nanf
double : nan
trits 0 t11112220022122120101211020120210210211201
46
% modulus
& binary and
| binary or
^ binary xor
>> shift right
<< shift left
For example, using the ?vi command we the the integer (base10) value result-
ing it from evaluating the given math expression
[ 0 x00000000]> ? v i 1+2+3
6
To use of binary OR should quote the whole command to avoid executing the
| pipe:
[ 0 x00000000]> ”? 1 | 2”
hex 0x3
octal 03
unit 3
segment 0000:0003
int32 3
s t r i n g ”\ x03”
binary 0b00000011
fvalue : 2.0
f l o a t : 0.000000 f
double : 0.000000
trits 0 t10
Note that on modern r2 versions you can use the single quote at the begining
of the command to avoid evaluating the rest of the expression:
'? 1 | 2 is the equivalent to ”? 1 | 2”
Numbers can be displayed in several formats:
0x033 : hexadecimal can be d i s p l a y e d
3334 : decimal
sym . f o : resolve flag offset
10K : KBytes 10∗1024
10M : MBytes 10∗1024∗1024
You can also use variables and seek positions to build complex expressions.
Use the ?$? command to list all the available commands or read the refcard
chapter of this book.
$$ here ( the c u r r e n t v i r t u a l seek )
$l opcode l e n g t h
$s f i l e size
$j jump address ( e . g . jmp 0x10 , j z 0x10 => 0x10 )
$f jump f a i l address ( e . g . j z 0x10 => next i n s t r u c t i o n )
47
$m opcode memory r e f e r e n c e ( e . g . mov eax , [ 0 x10 ] => 0x10 )
$b block s i z e
In the second case, the debugger will fork and load the debugee ls program
in memory.
It will pause its execution early in ld.so dynamic linker. As a result, you will
not yet see the entrypoint or any shared libraries at this point.
You can override this behavior by setting another name for an entry break-
point. To do this, add a radare command e dbg.bep=entry or e dbg.bep=main to
your startup script, usually it is ~/.config/radare2/radare2rc.
Another way to continue until a specific address is by using the dcu command.
Which means: “debug continue until” taking the address of the place to stop
at. For example:
dcu main
Be warned that certain malware or other tricky programs can actually exe-
cute code before main() and thus you’ll be unable to control them. (Like the
program constructor or the tls initializers)
Below is a list of most common commands used with debugger:
48
> d? ; get help on debugger commands
> ds 3 ; s t e p 3 times
> db 0x8048920 ; setup a breakpoint
> db −0x8048920 ; remove a breakpoint
> dc ; continue p r o c e s s e x e c u t i o n
> dcs ; continue u n t i l s y s c a l l
> dd ; manipulate f i l e d e s c r i p t o r s
> dm ; show p r o c e s s maps
> dmp A S rwx ; change p e r m i s s i o n s o f page at A and s i z e S
> dr eax=33 ; s e t r e g i s t e r value . eax = 33
There is another option for debugging in radare, which may be easier: using
visual mode.
That way you will neither need to remember many commands nor to keep
program state in your mind.
To enter visual debugger mode use Vpp:
[ 0 xb7f0c8c0 ]> Vpp
The initial view after entering visual mode is a hexdump view of the current
target program counter (e.g., EIP for x86). Pressing p will allow you to cycle
through the rest of visual mode views. You can press p and P to rotate through
the most commonly used print modes. Use F7 or s to step into and F8 or
S to step over current instruction. With the c key you can toggle the cursor
mode to mark a byte range selection (for example, to later overwrite them
with nop). You can set breakpoints with F2 key.
In visual mode you can enter regular radare commands by prepending them
with : . For example, to dump a one block of memory contents at ESI:
<Press ': ' >
x @ esi
To get help on visual mode, press ?. To scroll the help screen, use arrows. To
exit the help view, press q.
A frequently used command is dr, which is used to read or write values of
the target’s general purpose registers. For a more compact register value
representation you might use dr= command. You can also manipulate the
hardware and the extended/floating point registers.
Tooling
Radare2 is not just the only tool provided by the radare2 project. The rest
if chapters in this book are focused on explaining the use of the radare2 tool,
49
this chapter will focus on explaining all the other companion tools that are
shipped inside the radare2 project.
All the functionalities provided by the different APIs and plugins have also
different tools to allow to use them from the commandline and integrate them
with shellscripts easily.
Thanks to the ortogonal design of the framework it is possible to do all the
things that r2 is able from different places:
• These companion tools
• Native library APIs
• The r2 shell
• Using the high level R2Papi
• Scripting with r2pipe/r2js
Rax2
The rax2 utility comes with the radare framework and aims to be a minimalistic
expression evaluator for the shell. It is useful for making base conversions
between floating point values, hexadecimal representations, hexpair strings to
ascii, octal to integer. It supports endianness conversion.
This is the help message of rax2, this tool can be used in the command-line or
interactively (reading the values from stdin), so it can be used as a multi-base
calculator.
Inside r2, the functionality of rax2 is available under the ? command. For
example:
[ 0 x00000000]> ? 3+4
As you can see, the numeric expressions can contain mathematical expressions
like addition, subtraction, .. as well as group operations with parenthesis.
The syntax in which the numbers are represented define the base, for example:
• 3 : decimal, base 10
• 0xface : hexadecimal, base 16
• 0472 : octal, base 8
• 2M : units, 2 megabytes
• …
This is the help message of rax2 -h, which will show you a bunch more syntaxes
$ rax2 −h
Usage : rax2 [ o p t i o n s ] [ expr . . . ]
=[ base ] ; rax2 =10 0x46 −> output i n base 10
int −> hex ; rax2 10
50
hex −> i n t ; rax2 0xa
−i n t −> hex ; rax2 −77
−hex −> i n t ; rax2 0 x f f f f f f b 3
int −> bin ; rax2 b30
int −> t e r n a r y ; rax2 t42
bin −> i n t ; rax2 1010d
t e r n a ry −> i n t ; rax2 1010 dt
float −> hex ; rax2 3 . 3 3 f
hex −> f l o a t ; rax2 Fx40551ed8
oct −> hex ; rax2 35o
hex −> oct ; rax2 Ox12 (O i s a l e t t e r )
bin −> hex ; rax2 1100011b
hex −> bin ; rax2 Bx63
t e r n a ry −> hex ; rax2 212 t
hex −> t e r n a r y ; rax2 Tx23
raw −> hex ; rax2 −S < / b i n f i l e
hex −> raw ; rax2 −s 414141
−l ; append newline to output ( f o r
−E/−D/−r / . .
−a show a s c i i t a b l e ; rax2 −a
−b bin −> s t r ; rax2 −b 01000101 01110110
−B s t r −> bin ; rax2 −B hello
−d force integer ; rax2 −d 3 −> 3 i n s t e a d o f 0x3
−e swap endianness ; rax2 −e 0x33
−D base64 decode ;
−E base64 encode ;
−f f l o a t i n g point ; rax2 −f 6.3+2.1
−F s t d i n s l u r p code hex ; rax2 −F < s h e l l c o d e . [ c/py/ j s ]
−h help ; rax2 −h
−i dump as C byte array ; rax2 −i < bytes
−k keep base ; rax2 −k 33+3 −> 36
−K randomart ; rax2 −K 0x34 1020304050
−L bin −> hex ( bignum ) ; rax2 −L 111111111 # 0 x 1 f f
−n binary number ; rax2 −n 0x1234 # 34120000
−N binary number ; rax2 −N 0x1234 # \x34\x12\x00\x00
−r r2 s t y l e output ; rax2 −r 0x1234
−s h e x s t r −> raw ; rax2 −s 43 4a 50
−S raw −> h e x s t r ; rax2 −S < / bin / l s > l s . hex
−t tstamp −> s t r ; rax2 −t 1234567890
−x hash s t r i n g ; rax2 −x l i n u x osx
−u units ; rax2 −u 389289238 # 317.0M
−w s i g n e d word ; rax2 −w 16 0 x f f f f
−v version ; rax2 −v
Some examples:
Calculator:
$ rax2 3+0x80
0x83
$ rax2 −d ”1<<8”
256
51
Base conversion:
$ rax2 '=2 ' 73303325
100010111101000010100011101b
The single quote for '=2' is not mandatory for bash but is necessary for some
shell like zsh.
Conversion in hex string
$ rax2 −s 4142
AB
$ rax2 −S AB
4142
$ rax2 −S < bin . f o o
...
Endianness conversion:
$ rax2 −e 33
0x21000000
$ rax2 −e 0x21000000
33
Base64 decoding
$ rax2 −D ZQBlAA== | rax2 −S
65006500
Randomart:
$ rax2 −K 90203010
+−−[0x10302090]−−−+
| Eo . . |
| . . . . |
| o |
| . |
| S |
| |
| |
| |
| |
+−−−−−−−−−−−−−−−−−+
Rafind2
Rafind2 is the command line fronted of the r_search library. Which allows you
to search for strings, sequences of bytes with binary masks, etc
$ r a f i n d 2 −h
Usage : r a f i n d 2 [−mXnzZhqv ] [−a a l i g n ] [−b s z ] [− f / t from/ to ]
[ −[ e | s | S ] s t r ] [−x hex ] −| f i l e | d i r . .
52
−a [ align ] only accept a l i g n e d h i t s
−b [ size ] s e t block s i z e
−e [ regex ] se a r c h f o r regex matches ( can be used m u l t i p l e times )
−f [ from ] s t a r t s e a r c h i n g from address ' from '
−h show t h i s help
−i i d e n t i f y f i l e t y p e ( r2 −nqcpm f i l e )
−j output i n JSON
−m magic search , f i l e −type c a r v e r
−M [ str ] s e t a binary mask to be a p p l i e d on keywords
−n do not stop on read e r r o r s
−r p r i n t using radare commands
−s [ str ] se a r c h f o r a s p e c i f i c s t r i n g ( can be used m u l t i p l e times )
−S [ str ] s ea r c h f o r a s p e c i f i c wide s t r i n g ( can be used m u l t i p l e
times ) . Assumes s t r i s UTF−8.
−t [ to ] stop s e a r c h at address ' to '
−q q u i e t − do not show headings ( f i l e n a m e s ) above matching
contents ( default f o r searching a s i n g l e f i l e )
−v p r i n t v e r s i o n and e x i t
−x [ hex ] s ea r c h f o r hexpair s t r i n g (909090) ( can be used m u l t i p l e
times )
−X show hexdump o f s e ar c h r e s u l t s
−z se a r c h f o r zero−terminated s t r i n g s
−Z show s t r i n g found on each s e a r c h h i t
That’s how to use it, first we’ll search for “lib” inside the /bin/ls binary.
$ r a f i n d 2 −s l i b / bin / l s
0 x5f9
0x675
0x679
...
$
Note that the output is pretty minimal, and shows the offsets where the string
lib is found. We can then use this output to feed other tools.
Counting results:
$ r a f i n d 2 −s l i b / bin / l s | wc −l
53
0x000006e1 6 c69 6253 7973 7465 . . libSystem .B. d y l i
0 x000006ef 6 c69 6200 0000 0000 . . l i b . . . . . . & . . . . . .
Also works as a strings replacement, similar to what you do with rabin2 -z,
but without caring about parsing headers and obeying binary sections.
$ r a f i n d 2 −z / bin / l s | grep http
0x000076e5 %http : / /www. apple . com/ appleca / r o o t . c r l 0 \ r
0x00007ae6 https : / /www. apple . com/ appleca /0
0 x00007fa9 ) http : / /www. apple . com/ c e r t i f i c a t e a u t h o r i t y 0
0x000080ab $http : / / c r l . apple . com/ c o d e s i g n i n g . c r l 0
Rarun2
Rarun2 is a tool allowing to setup a specified execution environment - redefine
stdin/stdout, pipes, change the environment variables and other settings use-
ful to craft the boundary conditions you need to run a binary for debugging.
$ rarun2 −h
Usage : rarun2 −v|− t | s c r i p t . r r 2 [ d i r e c t i v e . . ]
It takes the text file in key=value format to specify the execution environment.
Rarun2 can be used as both separate tool or as a part of radare2.
To load the rarun2 profile in radare2 you need to use either −r to load the
profile from file or −R to specify the directive from string.
The format of the profile is very simple. Note the most important keys -
program and arg∗
One of the most common usage cases - redirect the output of debugged pro-
gram in radare2. For this you need to use stdio, stdout, stdin, input, and a couple
similar keys.
Here is the basic profile example:
program=/bin / l s
arg1=/bin
# arg2=h e l l o
# arg3=”h e l l o \ nworld ”
# arg4 =:048490184058104849
# arg5 =:! ragg2 −p n50 −d 10:0 x8048123
# arg6=@arg . t x t
# arg7=@300@ABCD # 300 chars f i l l e d with ABCD p a t t e r n
54
# system=r2 −
# a s l r=no
setenv=FOO=BAR
# unsetenv=FOO
# c l e a r e n v=t r u e
# e n v f i l e=environ . t x t
timeout=3
# t i m e o u t s i g=SIGTERM # or 15
# connect=l o c a l h o s t :8080
# l i s t e n =8080
# pty=f a l s e
# f o r k=t r u e
# b i t s =32
# pid=0
# p i d f i l e =/tmp/ foo . pid
# #s l e e p=0
# #maxfd=0
# #execve=f a l s e
# #maxproc=0
# #maxstack=0
# #core=f a l s e
# #s t d i o=b l a h . t x t
# #s t d e r r=foo . t x t
# s t d o u t=foo . t x t
# s t d i n=input . t x t # or ! program to r e d i r e c t input from another
program
# input=input . t x t
# c h d i r=/
# chroot=/mnt/ chroot
# l i b p a t h=$PWD: / tmp/ l i b
# r2preload=yes
# preload=/ l i b / l i b f o o . so
# s e t u i d =2000
# s e t e u i d =2000
# s e t g i d =2001
# s e t e g i d =2001
# nice=5
55
#!/ usr / bin / rarun2
program=./pp400
arg0=10
s t d i n=f o o . t x t
c h d i r=/tmp
#chroot =.
./ foo . rr2
2 - Create a new file containing the following rarun2 profile named foo.rr2:
#! / usr / bin /rarun2
program=/bin / l s
s t d i o=/dev/ t t y s 0 1 0
r2pm
Radare2 has its own package manager for managing external plugins or
tools that have a close relationship to radare2.
• Most packages are tested and maintained for UNIX systems
• Some of them support Windows and even wasm (r2js)
• Installs by default in your home, use −g to do it system-wide
• Most of them are building it from source, but others have support for
binary builds
The radare2-extras repository contains a lot of third-party packages that aim
to be updated and maintained (but also less used than the ones shipped in
the main repository), so it’s a great place to check before writing your own
plugin as maybe this thing was done already by someone else.
56
Package Database
$ r2pm −U
$R2PM_DBDIR: No such f i l e or d i r e c t o r y .
Run 'r2pm i n i t ' to i n i t i a l i z e the package r e p o s i t o r y
$ r2pm i n i t
g i t c l o n e https : / / github . com/ radareorg / radare2−pm
Cloning i n t o ' radare2−pm ' . . .
remote : Counting o b j e c t s : 147 , done .
remote : Compressing o b j e c t s : 100% (139/139) , done .
remote : Total 147 ( d e l t a 26) , reused 57 ( d e l t a 7) , pack−reused 0
Receiving o b j e c t s : 100% (147/147) , 42.68 KiB | 48.00 KiB/s , done .
Resolving d e l t a s : 100% (26/26) , done .
/home/ u s e r / . l o c a l / share / radare2 /r2pm/ g i t / radare2−pm
r2pm database i n i t i a l i z e d . Use 'r2pm −U' to update l a t e r today
The packages database is pulled from the radare2-pm repository. At any point
of the time we can update the database using r2pm −U:
$ r2pm −U
HEAD i s now at 7522928 Fix syntax
Updating 7 5 2 2 9 2 8 . . 1 c139e0
Fast−forward
db/ l d i d 2 | 18 ++++++++++++++++++
1 f i l e changed , 18 i n s e r t i o n s (+)
c r e a t e mode 100644 db/ l d i d 2
Updating /home/ u s e r / . l o c a l / share / radare2 /r2pm/db . . .
Already up to date .
There are many commands available to let you install or uninstall anything
easily:
$ r2pm −h
Usage : r2pm [− f l a g s ] [ pkgs . . . ]
Commands :
−a [ r e p o s i t o r y ] add or −d e l e t e e x t e r n a l r e p o s i t o r y
−c ( [ g i t / d i r ] ) c l e a r s o u r c e cache (R2PM_GITDIR)
−c i <pkgname> clean + i n s t a l l
−cp c l e a n the user ' s home p l u g i n d i r e c t o r y
−d , doc [ pkgname ] show documentation and s o u r c e f o r given package
−e [ pkgname ] e d i t using $EDITOR the given package s c r i p t
−f f o r c e o p e r a t i o n ( Use i n combination o f −U, −i ,
−u , . . )
−g i <pkg> g l o b a l i n s t a l l ( system−wide )
−h d i s p l a y t h i s help message
−H v a r i a b l e show the value o f given i n t e r n a l environment
v a r i a b l e ( See −HH)
−HH show a l l the i n t e r n a l environment v a r i a b l e v a l u e s
−i <pkgname> i n s t a l l /update package and i t s dependencies ( s e e
−c , −g )
−I i n f o r m a t i on about r e p o s i t o r y and i n s t a l l e d
packages
−l l i s t i n s t a l l e d packages
57
−q be q u i e t
−r [ cmd . . . a r g s ] run s h e l l command with R2PM_BINDIR i n PATH
−s [<keyword>] s e a r c h a v a i l a b l e packages i n database matching a
string
−t [YYYY−MM−DD] f o r c e a moment i n time to p u l l the code from the
g i t packages
−u <pkgname> r2pm −u b a l e f u l ( See −f to f o r c e u n i n s t a l l )
−u c i <pkgname> u n i n s t a l l + clean + i n s t a l l
−u i <pkgname> uninstall + install
−U i n i t i a l i z e /update database and upgrade a l l
outdated packages
−v show v e r s i o n
Sample Session
For example lang−python3 (which is used for writing r2 plugins in Python):
$ r2pm −i lang−python3
...
mkdir −p ~ / . c o n f i g / radare2 / p l u g i n s
cp −f lang_python3 . so ~ / . c o n f i g / radare2 / p l u g i n s
...
Note that if we used −i switch it installs the plugin in the $HOME directory,
in case of −gi it will install the plugin systemwide (requires sudo).
After this we will be able to see the plugin in the list of installed:
$ r2pm −l
lang−python3
Rabin2
Under this bunny-arabic-like name, radare hides a powerful tool to handle
binary files, to get information on imports, sections, headers and other data.
Rabin2 can present it in several formats accepted by other tools, including
radare2 itself. Rabin2 understands many file formats: Java CLASS, ELF,
PE, Mach-O or any format supported by plugins, and it is able to obtain
symbol import/exports, library dependencies, strings of data sections, xrefs,
entrypoint address, sections, architecture type.
Usage : rabin2 [−AcdeEghHiIjlLMqrRsSUvVxzZ ] [−@ at ] [−a arch ] [−b
b i t s ] [−B addr ]
[−C F :C:D] [− f s t r ] [−m addr ] [−n s t r ] [−N m:M]
[−P[−P] pdb ]
58
[−o s t r ] [−O help ] [−k query ] [−D lang mangledsymbol ]
file
−@ [ addr ] show s e c t i o n , symbol or import at addr
−A l i s t sub−b i n a r i e s and t h e i r arch−b i t s p a i r s
−a [ arch ] s e t arch ( x86 , arm , . . or <arch>_<b i t s >)
−b [ b i t s ] s e t b i t s ( 3 2 , 64 . . . )
−B [ addr ] o v e r r i d e base address ( p i e b i n s )
−c l i s t classes
−cc l i s t c l a s s e s i n header format
−C [ fmt :C:D] c r e a t e [ e l f , mach0 , pe ] with Code and Data h e x p a i r s
( s e e −a )
−d show debug/dwarf i n f o r m a t i o n
−D lang name demangle symbol name (−D a l l f o r bin . demangle=t r u e )
−e program e n t r y p o i n t
−ee constructor / destructor entrypoints
−E g l o b a l l y e x p o r t a b l e symbols
−f [ s t r ] s e l e c t sub−bin named s t r
−F [ binfmt ] f o r c e to use that bin p l u g i n ( i g n o r e header check )
−g same as −SMZIHVResizcld −SS −SSS −ee ( show a l l i n f o )
−G [ addr ] load address . o f f s e t to header
−h t h i s help message
−H header f i e l d s
−i imports ( symbols imported from l i b r a r i e s )
−I binary i n f o
−j output i n j s o n
−k [ sdb−query ] run sdb query . f o r example : ' ∗ '
−K [ a l g o ] c a l c u l a t e checksums (md5, sha1 , . . )
−l linked l i b r a r i e s
−L [ p l u g i n ] l i s t supported bin p l u g i n s or p l u g i n d e t a i l s
−m [ addr ] show s o u r c e l i n e at addr
−M main ( show address o f main symbol )
−n [ s t r ] show s e c t i o n , symbol or import named s t r
−N [ min : max ] f o r c e min : max number o f chars per s t r i n g ( s e e −z
and −zz )
−o [ s t r ] output f i l e / f o l d e r f o r w r i t e o p e r a t i o n s ( out by
default )
−O [ s t r ] w r i t e / e x t r a c t o p e r a t i o n s (−O help )
−p show always p h y s i c a l a d d r e s s e s
−P show debug/pdb i n f o r m a t i o n
−PP download pdb f i l e f o r binary
−q be quiet , j u s t show fewer data
−qq show l e s s i n f o ( no o f f s e t / s i z e f o r −z f o r ex . )
−Q show load address used by dlopen ( non−a s l r l i b s )
−r radare output
−R relocations
−s symbols
−S sections
−SS segments
−SSS s e c t i o n s mapping to segments
−t d i s p l a y f i l e hashes
−T display f i l e signature
−u u n f i l t e r e d ( no rename d u p l i c a t e d symbols/ s e c t i o n s )
−U resoUrces
59
−v d i s p l a y v e r s i o n and q u i t
−V show binary v e r s i o n i n f o r m a t i o n
−w d i s p l a y t r y / catch b l o c k s
−x e x t r a c t b i n s contained i n f i l e
−X [ fmt ] [ f ] . . package i n f a t or z i p the given f i l e s and b i n s
contained i n f i l e
−z s t r i n g s ( from data s e c t i o n )
−zz s t r i n g s ( from raw b i n s [ e bin . s t r . raw=1])
−zzz dump raw s t r i n g s to stdout ( f o r huge f i l e s )
−Z guess s i z e o f binary program
Environment :
R2_NOPLUGINS: 1|0| # do not load shared p l u g i n s
( speedup l o a d i n g )
RABIN2_ARGS: # i g n o r e c l i and use t h e s e
program arguments
RABIN2_CHARSET: e cfg . charset # s e t d e f a u l t value c h a r s e t
f o r −z s t r i n g s
RABIN2_DEBASE64: e bin . s t r . debase64 # t r y to debase64 a l l s t r i n g s
RABIN2_DEMANGLE=0: e bin . demangle # do not demangle symbols
RABIN2_DMNGLRCMD: e bin . demanglercmd # t r y to purge f a l s e p o s i t i v e s
RABIN2_LANG: e bin . lang # assume lang f o r demangling
RABIN2_MAXSTRBUF: e bin . s t r . maxbuf # s p e c i f y maximum b u f f e r s i z e
RABIN2_PDBSERVER: e pdb . s e r v e r # use a l t e r n a t i v e PDB s e r v e r
RABIN2_PREFIX: e bin . p r e f i x # prefix
symbols/ s e c t i o n s / r e l o c s with a s p e c i f i c s t r i n g
RABIN2_STRFILTER: e bin . s t r . f i l t e r # r2 −qc ' e bin . s t r . f i l t e r =??'
−
RABIN2_MACHO_NOFUNCSTARTS=0|1 # i f s e t i t w i l l i g n o r e the
FUNCSTART i n f o rm a ti o n
RABIN2_MACHO_NOSWIFT=0|1
RABIN2_MACHO_SKIPFIXUPS=0|1
RABIN2_CODESIGN_VERBOSE=0|1
RABIN2_STRPURGE: e bin . s t r . purge # t r y to purge f a l s e p o s i t i v e s
RABIN2_SYMSTORE: e pdb . symstore # path to downstream symbol
store
RABIN2_SWIFTLIB: 1|0| # load S w i f t l i b s to demangle
( default : true )
RABIN2_VERBOSE: e bin . verbose # show debugging messages from
the p a r s e r
60
class ELF64
crypto false
endian little
havecode true
intrp / l i b 6 4 / ld−linux−x86 −64. so . 2
lang c
linenum false
lsyms false
machine AMD x86−64 a r c h i t e c t u r e
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic true
relocs false
relro partial
rpath NONE
static false
stripped true
subsys linux
va true
To make rabin2 output information in format that the main program, radare2,
can understand, pass −Ir option to it:
$ rabin2 −I r / bin / l s
e c f g . bigendian=f a l s e
e asm . b i t s =64
e asm . dwarf=t r u e
e bin . lang=c
e f i l e . type=e l f
e asm . os=l i n u x
e asm . arch=x86
e asm . p c a l i g n=0
Code Entrypoints
The −e option passed to rabin2 will show entrypoints for given binary. Two
examples:
$ rabin2 −e / bin / l s
[ Entrypoints ]
vaddr=0x00005310 paddr=0x00005310 baddr=0x00000000 laddr=0x00000000
haddr=0x00000018 type=program
1 entrypoints
$ rabin2 −e r / bin / l s
f s symbols
f entry0 1 @ 0x00005310
f entry0_haddr 1 @ 0x00000018
61
s entry0
Imports
Rabin2 is able to find imported objects by an executable, as well as their
offsets in its PLT. This information is useful, for example, to understand
what external function is invoked by call instruction. Pass −i flag to rabin2
to get a list of imports. An example:
$ rabin2 −i / bin / l s
[ Imports ]
nth vaddr bind type l i b name
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 0x000032e0 GLOBAL FUNC __ctype_toupper_loc
2 0 x000032f0 GLOBAL FUNC getenv
3 0x00003300 GLOBAL FUNC sigprocmask
4 0x00003310 GLOBAL FUNC __snprintf_chk
5 0x00003320 GLOBAL FUNC r a i s e
6 0x00000000 GLOBAL FUNC f r e e
7 0x00003330 GLOBAL FUNC abort
8 0x00003340 GLOBAL FUNC __errno_location
9 0x00003350 GLOBAL FUNC strncmp
10 0x00000000 WEAK NOTYPE _ITM_deregisterTMCloneTable
11 0x00003360 GLOBAL FUNC l o c a l t i m e _ r
12 0x00003370 GLOBAL FUNC _exit
13 0x00003380 GLOBAL FUNC s t r c p y
14 0x00003390 GLOBAL FUNC __fpending
15 0x000033a0 GLOBAL FUNC i s a t t y
16 0x000033b0 GLOBAL FUNC s i g a c t i o n
17 0x000033c0 GLOBAL FUNC i s w c n t r l
18 0x000033d0 GLOBAL FUNC wcswidth
19 0x000033e0 GLOBAL FUNC l o c a l e c o n v
20 0 x000033f0 GLOBAL FUNC mbstowcs
21 0x00003400 GLOBAL FUNC r e a d l i n k
...
Exports
Rabin2 is able to find exports. For example:
$ rabin2 −E / usr / l i b / l i b r _ b i n . so | head
[ Exports ]
62
214 0 x000ae600 0 x000ae600 GLOBAL FUNC 175
r_bin_java_print_fieldref_cp_summary
215 0x000ad880 0x000ad880 GLOBAL FUNC 144
r_bin_java_print_constant_value_attr_summary
216 0x000b7330 0x000b7330 GLOBAL FUNC 679
r_bin_java_print_element_value_summary
217 0 x000af170 0 x000af170 GLOBAL FUNC 65
r_bin_java_create_method_fq_str
218 0x00079b00 0x00079b00 GLOBAL FUNC 15 LZ4_createStreamDecode
With the −sr option rabin2 produces a radare2 script instead. It can later be
passed to the core to automatically flag all symbols and to define correspond-
ing byte ranges as functions and data blocks.
$ rabin2 −s r / bin / l s | head
f s symbols
f sym . obstack_allocated_p 56 0x000150a0
f sym . program_invocation_name 8 0 x0021f600
f sym . s t d e r r 8 0 x0021f620
f sym . obstack_begin_1 21 0 x00014f90
f sym . program_invocation_name 8 0 x0021f600
f sym . obstack_alloc_failed_handler 8 0 x0021f5c0
f sym . optarg 8 0 x 0 0 2 1f 5 f 8
f sym . stdout 8 0 x0021f5e8
f sym . program_invocation_short_name 8 0 x0021f5e0
Debug Symbols
Radare2 automatically parses available imports and exports sections in the
binary, moreover, it can load additional debugging information if present. Two
63
main formats are supported: DWARF and PDB (for Windows binaries). Note
that, unlike many tools radare2 doesn’t rely on Windows API to parse PDB
files, thus they can be loaded on any other supported platform - e.g. Linux
or OS X.
DWARF debug info loads automatically by default because usually it’s stored
right in the executable file. PDB is a bit of a different beast - it is always
stored as a separate binary, thus the different logic of handling it.
At first, one of the common scenarios is to analyze the file from Windows
distribution. In this case, all PDB files are available on the Microsoft server,
which is by default is in options. See all pdb options in radare2:
pdb . autoload = 0
pdb . e x t r a c t = 1
pdb . s e r v e r = https : / / msdl . m i c r o s o f t . com/download/symbols
pdb . useragent = Microsoft−Symbol−Server / 6 . 1 1 . 0 0 0 1 . 4 0 2
Using the variable pdb.server you can change the address where radare2 will
try to download the PDB file by the GUID stored in the executable header.
You can make use of multiple symbol servers by separating each URL with a
space:
e pdb . s e r v e r = https : / / msdl . m i c r o s o f t . com/download/symbols
https : / / symbols . m o z i l l a . org
On Windows, you can also use local network share paths (UNC paths) as
symbol servers.
Usually, there is no reason to change default pdb.useragent, but who knows
where could it be handy?
Because those PDB files are stored as “cab” archives on the server,
pdb.extract=1 says to automatically extract them.
Note that for the automatic downloading to work you need “cabextract” tool,
and wget/curl installed.
Sometimes you don’t need to do that from the radare2 itself, thus - two handy
rabin2 options:
−P show debug/pdb i n f o r m a t i o n
−PP download pdb f i l e f o r binary
where −PP automatically downloads the pdb for the selected binary, using
those pdb.∗ config options. −P will dump the contents of the PDB file, which
is useful sometimes for a quick understanding of the symbols stored in it.
Apart from the basic scenario of just opening a file, PDB information can be
additionally manipulated by the id commands:
64
[ 0 x000051c0]> i d ?
| Usage : i d Debug i n f or m at i o n
| Output mode :
| '∗ ' Output i n radare commands
| id Source l i n e s
| idp [ f i l e . pdb ] Load pdb f i l e i n f o r m a t i o n
| i d p i [ f i l e . pdb ] Show pdb f i l e i n f o r m a t i o n
| idpd Download pdb f i l e on remote s e r v e r
Where idpi is basically the same as rabin2 −P. Note that idp can be also used
not only in the static analysis mode, but also in the debugging mode, even if
connected via WinDbg.
For simplifying the loading PDBs, especially for the processes with many
linked DLLs, radare2 can autoload all required PDBs automatically - you
need just set the e pdb.autoload=true option. Then if you load some file in
debugging mode in Windows, using r2 −d file.exe or r2 −d 2345 (attach to pid
2345), all related PDB files will be loaded automatically.
DWARF information loading, on the other hand, is completely automated.
You don’t need to run any commands/change any options:
r2 `which rabin2 `
[ 0 x00002437 8% 300 / usr / l o c a l / bin / rabin2 ]> pd $r
0x00002437 j n e 0x2468 ;[1]
0x00002439 cmp qword r e l o c . __cxa_finalize_224 , 0
0x00002441 push rbp
0x00002442 mov rbp , rsp
0x00002445 j e 0x2453 ;[2]
0x00002447 l e a r d i , obj . __dso_handle ; 0x207c40 ; ”@| ”
0x0000244e c a l l 0x2360 ;[3]
0x00002453 c a l l sym . deregister_tm_clones ; [ 4 ]
0x00002458 mov byte [ obj . completed . 6 9 9 1 ] , 1 ; obj .__TMC_END__ ;
[ 0 x2082f0 :1]=0
0 x0000245f pop rbp
0x00002460 r e t
0x00002461 nop dword [ rax ]
0x00002468 r e t
0x0000246a nop word [ rax + rax ]
;−− entry1 . i n i t :
;−− frame_dummy :
0x00002470 push rbp
0x00002471 mov rbp , rsp
0x00002474 pop rbp
0x00002475 jmp sym . register_tm_clones ; [ 5 ]
;−− blob_version :
0x0000247a push rbp ; . . / blob / v e r s i o n . c : 1 8
0x0000247b mov rbp , rsp
0x0000247e sub rsp , 0x10
0x00002482 mov qword [ rbp − 8 ] , r d i
0x00002486 mov eax , 0x32 ; . . / blob / v e r s i o n . c : 2 4 ; ' 2 '
0x0000248b t e s t al , a l ; . . / blob / v e r s i o n . c : 1 9
65
0x0000248d j e 0x2498 ;[6]
0 x0000248f l e a rax , s t r . 2 . 0 . 1 _182_gf1aa3aa4d ; 0x60b8 ;
”2.0.1−182− gf1aa3aa4d ”
0x00002496 jmp 0 x249f ;[7]
0x00002498 l e a rax , 0x000060cd
0 x0000249f mov r s i , qword [ rbp − 8 ]
0x000024a3 mov r8 , rax
0x000024a6 mov ecx , 0x40 ; section_end . ehdr
0x000024ab mov edx , 0x40c0
0x000024b0 l e a rd i , s t r . _s_2 . 1 . 0 _git__d___linux_x86__d_git . _s_n ;
0x60d0 ; ”%s 2.1.0 − g i t %d @ linux−x86−%d g i t .%s \n”
0x000024b7 mov eax , 0
0x000024bc c a l l 0x2350 ;[8]
0x000024c1 mov eax , 0x66 ; . . / blob / v e r s i o n . c : 2 5 ; ' f '
0x000024c6 t e s t al , a l
0x000024c8 j e 0x24d6 ;[9]
0x000024ca l e a rd i ,
s t r . commit : _f1aa3aa4d2599c1ad60e3ecbe5f4d8261b282385_build : _2017_11_06__12 :
; . . / blob / v e r s i o n . c : 2 6 ; 0 x60f8 ; ”commit :
f1aa3aa4d2599c1ad60e3ecbe5f4d8261b282385 b u i l d : 2017−11−06__1
0x000024d1 c a l l sym . imp . puts ;[?]
0x000024d6 mov eax , 0 ; . . / blob / v e r s i o n . c : 2 8
0x000024db l e a v e ; . . / blob / v e r s i o n . c : 2 9
0x000024dc r e t
;−− rabin_show_help :
0x000024dd push rbp ; . / / rabin2 . c : 2 7
As you can see, it loads function names and source line information.
List Libraries
Rabin2 can list libraries used by a binary with the −l option:
$ rabin2 −l `which r2 `
[ Linked l i b r a r i e s ]
l i b r _ c o r e . so
l i b r _ p a r s e . so
l i b r _ s e a r c h . so
li b r_ co n s . so
l i b r _ c o n f i g . so
l i b r _ b i n . so
libr_debug . so
l i b r _ a n a l . so
l i b r _ r e g . so
libr_bp . so
l i b r _ i o . so
l i b r _ f s . so
libr_asm . so
l i b r _ s y s c a l l . so
libr_hash . so
libr_magic . so
l i b r _ f l a g . so
libr_egg . so
66
l i b r _ c r y p t o . so
l i b r _ u t i l . so
l i b p t h r e a d . so . 0
l i b c . so . 6
22 l i b r a r i e s
If you compare the outputs of rabin2 −l and ldd, you will notice that rabin2
lists fewer libraries than ldd. The reason is that rabin2 does not follow and
does not show dependencies of libraries. Only direct binary dependencies are
shown.
67
Strings
The −z option is used to list readable strings found in the .rodata section of
ELF binaries, or the .text section of PE files. Example:
$ rabin2 −z / bin / l s | head
[ Strings ]
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
000 0 x000160f8 0 x000160f8 11 12 ( . rodata ) a s c i i dev_ino_pop
001 0x00016188 0x00016188 10 11 ( . rodata ) a s c i i s o r t _ f i l e s
002 0x00016193 0x00016193 6 7 ( . rodata ) a s c i i posix−
003 0x0001619a 0x0001619a 4 5 ( . rodata ) a s c i i main
004 0x00016250 0x00016250 10 11 ( . rodata ) a s c i i ?pcdb−lswd
005 0x00016260 0x00016260 65 66 ( . rodata ) a s c i i # C o nf ig u ra t i o n
f i l e f o r d i r c o l o r s , a u t i l i t y to help you s e t the
006 0x000162a2 0x000162a2 72 73 ( . rodata ) a s c i i # LS_COLORS
environment v a r i a b l e used by GNU l s with the −−c o l o r option .
007 0x000162eb 0x000162eb 56 57 ( . rodata ) a s c i i # Copyright (C)
1996−2018 Free Software Foundation , Inc .
008 0x00016324 0x00016324 70 71 ( . rodata ) a s c i i # Copying and
d i s t r i b u t i o n o f t h i s f i l e , with or without m o d i f i c a t i o n ,
009 0x0001636b 0x0001636b 76 77 ( . rodata ) a s c i i # are permitted
provided the c o p y r i g h t n o t i c e and t h i s n o t i c e are p r es er v ed .
Sections
Rabin2 called with the −S option gives complete information about the sec-
tions of an executable. For each section the index, offset, size, alignment, type
and permissions, are shown. The next example demonstrates this:
$ rabin2 −S / bin / l s
[ Sections ]
68
nth paddr s i z e vaddr v s i z e perm name
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
00 0x00000000 0 0x00000000 0 −−−−
01 0x00000238 28 0x00000238 28 −r−− . i n t e r p
02 0x00000254 32 0x00000254 32 −r−− . note . ABI_tag
03 0x00000278 176 0x00000278 176 −r−− . gnu . hash
04 0x00000328 3000 0x00000328 3000 −r−− . dynsym
05 0 x00000ee0 1412 0 x00000ee0 1412 −r−− . dynstr
06 0x00001464 250 0x00001464 250 −r−− . gnu . v e r s i o n
07 0x00001560 112 0x00001560 112 −r−− . gnu . version_r
08 0x000015d0 4944 0x000015d0 4944 −r−− . r e l a . dyn
09 0x00002920 2448 0x00002920 2448 −r−− . r e l a . p l t
10 0x000032b0 23 0x000032b0 23 −r−x . i n i t
11 0x000032d0 1648 0x000032d0 1648 −r−x . p l t
12 0x00003940 24 0x00003940 24 −r−x . p l t . got
13 0x00003960 73931 0x00003960 73931 −r−x . t e x t
14 0 x00015a2c 9 0x00015a2c 9 −r−x . f i n i
15 0x00015a40 20201 0x00015a40 20201 −r−− . rodata
16 0 x0001a92c 2164 0 x0001a92c 2164 −r−− . eh_frame_hdr
17 0x0001b1a0 11384 0x0001b1a0 11384 −r−− . eh_frame
18 0 x0001e390 8 0x0021e390 8 −rw− . i n i t _ a r r a y
19 0 x0001e398 8 0x0021e398 8 −rw− . f i n i _ a r r a y
20 0 x0001e3a0 2616 0 x0021e3a0 2616 −rw− . data . r e l . ro
21 0x0001edd8 480 0x0021edd8 480 −rw− . dynamic
22 0 x0001efb8 56 0 x0021efb8 56 −rw− . got
23 0 x0001f000 840 0 x0021f000 840 −rw− . got . p l t
24 0 x0001f360 616 0 x0021f360 616 −rw− . data
25 0 x0001f5c8 0 0 x0021f5e0 4824 −rw− . bss
26 0 x0001f5c8 232 0x00000000 232 −−−− . s h s t r t a b
With the −Sr option, rabin2 will flag the start/end of every section, and will
pass the rest of information as a comment.
$ rabin2 −Sr / bin / l s | head
fs sections
” f s e c t i o n . 1 0x00000000 ”
” f s e c t i o n . . i n t e r p 1 0x000002a8 ”
” f s e c t i o n . . note . gnu . build_id 1 0 x000002c4 ”
” f s e c t i o n . . note . ABI_tag 1 0 x000002e8 ”
” f s e c t i o n . . gnu . hash 1 0x00000308 ”
” f s e c t i o n . . dynsym 1 0x000003b8 ”
” f s e c t i o n . . dynstr 1 0 x00000fb8 ”
” f s e c t i o n . . gnu . v e r s i o n 1 0x00001574 ”
” f s e c t i o n . . gnu . version_r 1 0x00001678 ”
Radiff2
radiff2 is a powerful tool within the radare2 suite designed for binary diffing.
It can be somehow compared to the well known diff utility from UNIX, but
with focus on comparing binary files.
69
It supports several types of diffing, including 1:1 binary diffing, delta diffing,
code analysis diffing, and binary data (bindata) diffing.
These features allow users to compare two binaries at various levels, from raw
data to disassembled code, providing insights into changes and differences
between them. Additionally, radiff2 supports architecture and bits specifica-
tion, graph diffing, and more, making it a versatile tool for reverse engineering
tasks.
Many of these diffing features are also available in the c command within the
radare2 shell. Opening the door to compare data from disk or process memory
when using any io backend at any time without leaving the current session.
You can learn more about this tool by checking the help message or reading
the manpage with man radiff2.
$ r a d i f f 2 −h
Usage : r a d i f f 2 [−abBcCdjrspOxuUvV ] [−A[A ] ] [−g sym ] [−m
graph_mode][ − t %] [ f i l e ] [ f i l e ]
−a [ arch ] s p e c i f y a r c h i t e c t u r e p l u g i n to use ( x86 , arm , . . )
−A [−A] run aaa or aaaa a f t e r l o a d i n g each binary ( s e e −C)
−b [ b i t s ] s p e c i f y r e g i s t e r s i z e f o r arch (16 (thumb) , 32 , 64 , . . )
−B output i n binary d i f f (GDIFF)
−c count o f changes
−C g r a p h d i f f code ( columns : o f f −A, match−r a t i o , o f f −B)
( s e e −A)
−d use d e l t a d i f f i n g
−D show disasm i n s t e a d o f h e x p a i r s
−e [ k=v ] s e t e v a l c o n f i g var value f o r a l l RCore i n s t a n c e s
−g [ sym | o f f 1 , o f f 2 ] graph d i f f o f given symbol , or between two
offsets
−G [ cmd ] run an r2 command on every RCore i n s t a n c e c r e a t e d
−i d i f f imports o f t a r g e t f i l e s ( s e e −u , −U and −z )
−j output i n j s o n format
−n p r i n t bare a d d r e s s e s only ( d i f f . bare=1)
−m [ a d i t s j J ] choose the graph output mode
−O code d i f f i n g with opcode bytes only
−p use p h y s i c a l a d d r e s s i n g ( i o . va=0)
−q q u i e t mode ( d i s a b l e c o l o r s , reduce output )
−r output i n radare commands
−s compute e d i t d i s t a n c e ( no s u b s t i t u t i o n , Eugene W. Myers
O(ND) d i f f algorithm )
−s s compute Levenshtein e d i t d i s t a n c e ( s u b s t i t u t i o n i s
allowed , O(N^2) )
−S [ name ] s o r t code d i f f (name , namelen , addr , s i z e , type , d i s t )
( only f o r −C or −g )
−t [0 −100] s e t t h r e s h o l d f o r code d i f f ( d e f a u l t i s 70%)
−x show two column hexdump d i f f i n g
−X show two column h e x I I d i f f i n g
−u u n i f i e d output (−−−+++)
−U u n i f i e d output using system ' d i f f '
−v show v e r s i o n i n f o r m a t i o n
70
−V be verbose ( c u r r e n t only f o r −s )
−z d i f f on e x t r a c t e d s t r i n g s
−Z d i f f code comparing z i g n a t u r e s
Practical examples
Here are a few practical examples of how to use radiff2:
To compare two binaries:
r a d i f f 2 bin1 bin2
71
Note the −r flag will generate an r2 script, which can then be used to generate
one binary from the other one using radare2 like this:
$ rahash2 −a md5 1 2
1 : 0x00000000−0x00000005 md5: b1946ac92492d2347c6235b4d2611184
2 : 0x00000000−0x00000005 md5: aee97cb3ad288ef0add6c6b5b5fae48a
$ r a d i f f 2 −r 1 2 > patch . r2
$ radare2 −qnw −i patch . r2 1
$ rahash2 −a md5 1 2
1 : 0x00000000−0x00000005 md5: aee97cb3ad288ef0add6c6b5b5fae48a
2 : 0x00000000−0x00000005 md5: aee97cb3ad288ef0add6c6b5b5fae48a
Data Diffing
Data diffing with radiff2 allows you to compare binary data between files
of different sizes. This is useful for identifying differences at the byte level,
regardless of file length.
For example, comparing two files with radiff2 −x shows the differences in two
column hexdump+ascii format:
$ cat 1
hello
$ cat 2
hallo
$ r a d i f f 2 −x 1 2
offset 0 1 2 3 4 5 6 7 01234567 0 1 2 3 4 5 6 7 01234567
0x00000000 ! 68656 c 6 c 6 f 0 a hello . 68616 c 6 c 6 f 0 a hallo .
72
Let’s understand the output because in your terminal you’ll see some green
and red highlighting the added or removed bytes from the byte-to-byte com-
parison.
• ! sign after the offset explains if the block is equal or not
• hexdump portion of file 1
• hexdump portion of file 2
When comparing files of different sizes, we will need to use the −d flag which
performs a delta-diffing algorithm, trying to find the patterns of bytes that
has been added or removed when a specific change is found.
$ cat 1
hello
$ cat 3
helloworld
$ radiff2 1 3
INFO: F i l e s i z e d i f f e r s 6 vs 11
INFO: B u f f e r truncated to 6 byte ( s ) (5 not compared )
0x00000005 0a => 77 0x00000005
$ r a d i f f 2 −d 1 3
INFO: F i l e s i z e d i f f e r s 6 vs 11
0x00000000 68656 c 6 c 6 f 0 a => 68656 c6c6f776f726c640a 0x00000000
$
For JSON output, use radiff2 -j -d to get detailed diff information in JSON
format:
$ r a d i f f 2 −j −d 1 3 | j q .
INFO: F i l e s i z e d i f f e r s 6 vs 11
{
” f i l e s ”: [
{
” f i l e n a m e ” : ”1” ,
” size ”: 6 ,
” sha256 ” :
”5891 b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03 ”
},
{
” f i l e n a m e ” : ”3” ,
” s i z e ” : 11 ,
” sha256 ” :
”8 cd07f3a5ff98f2a78cfc366c13fb123eb8d29c1ca37c79df190425d5b9e424d ”
}
],
” changes ” : [
{
” addr ” : 0 ,
”from ” : ”68656 c 6 c 6 f 0 a ” ,
” to ” : ”68656 c6c6f776f726c640a ”
}
]
73
}
$
Code Diffing
This tool can be also used to compare code, which can be really handy when
analyzing two shellcodes, functions or libraries, looking for changes in its code.
To understand this feature we will start by using the basic delta diffing from
the previous data analysis example but using the −D flag to display the
changes in assembly instead of hexadecimal data.
Note that radiff2 permits to specify the arch/bits/.. settings using these flags:
$ r a d i f f 2 −h | grep −e arch −e b i t s
−a [ arch ] s p e c i f y a r c h i t e c t u r e p l u g i n to use ( x86 , arm , . . )
−b [ b i t s ] s p e c i f y r e g i s t e r s i z e f o r arch (16 (thumb) , 32 , 64 , . . )
So we can see that the second file added an extra push rax + pop rax which is
basically a nop, and maybe this was introduced to bypass some signatures to
avoid being detected.
If you are looking for some more advanced bindiffing tool for code you may
want to have a look at the r2diaphora and the zignatures features under the z
command in the radare2 shell.
74
It’s also possible to compare the changes between two functions using the −g
flag, but you’ll need to analize both binaries using the −A flag, and tell the
symbol name as target.
Binary Diffing
radiff2 is also able to compare binaries by checking the differences between
the output of rabin2. This is, the symbols, libraries, strings, etc.
The relevant flags for this feature are:
• -A/-AA analy
• -i [ifscm] -> compare imports, fields, symbols, classes,..
Binary Diffing
This section is based on the https://radare.today article “binary diffing”
Without any parameters, radiff2 by default shows what bytes are changed and
their corresponding offsets:
$ r a d i f f 2 genuine cracked
0x000081e0 85 c00f94c0 => 9090909090 0x000081e0
0x0007c805 85 c00f84c0 => 9090909090 0x0007c805
$ rasm2 −d 85 c00f94c0
t e s t eax , eax
sete al
If you want more concrete data, it’s also possible to count the differences,
with the −c option:
$ r a d i f f 2 −c genuine cracked
2
If you are unsure whether you are dealing with similar binaries, with −C flag
you can check there are matching functions. It this mode, it will give you
three columns for all functions: “First file offset”, “Percentage of matching”
and “Second file offset”.
75
$ r a d i f f 2 −C / bin / f a l s e / bin / t r u e
entry0 0x4013e8 | MATCH ( 0 . 9 0 4 7 6 2 ) | 0x4013e2 entry0
sym . imp . __libc_start_main 0x401190 | MATCH ( 1 . 0 0 0 0 0 0 ) |
0x401190 sym . imp . __libc_start_main
f c n .00401196 0x401196 | MATCH ( 1 . 0 0 0 0 0 0 ) | 0x401196
f c n .00401196
f c n .0040103 c 0x40103c | MATCH ( 1 . 0 0 0 0 0 0 ) | 0x40103c
f c n .0040103 c
f c n .00401046 0x401046 | MATCH ( 1 . 0 0 0 0 0 0 ) | 0x401046
f c n .00401046
f c n .000045 e0 24 0x45e0 | UNMATCH ( 0 . 9 1 6 6 6 7 ) | 0 x45f0 24
f c n .000045 f 0
...
Moreover, we can ask radiff2 to perform analysis first - adding −A option will
run aaa on the binaries. And we can specify binaries architecture for this
analysis too using
$ r a d i f f 2 −AC −a x86 / bin / t r u e / bin / f a l s e | grep UNMATCH
[ x ] Analyze a l l f l a g s s t a r t i n g with sym . and entry0 ( aa )
[ x ] Analyze l e n bytes o f i n s t r u c t i o n s f o r r e f e r e n c e s ( aar )
[ x ] Analyze f u n c t i o n c a l l s ( aac )
[ ] [ ∗ ] Use −AA or aaaa to perform a d d i t i o n a l experimental a n a l y s i s .
[ x ] Constructing a f u n c t i o n name f o r f c n . ∗ and sym . func . ∗ f u n c t i o n s
( aan ) )
[ x ] Analyze a l l f l a g s s t a r t i n g with sym . and entry0 ( aa )
[ x ] Analyze l e n bytes o f i n s t r u c t i o n s f o r r e f e r e n c e s ( aar )
[ x ] Analyze f u n c t i o n c a l l s ( aac )
[ ] [ ∗ ] Use −AA or aaaa to perform a d d i t i o n a l experimental a n a l y s i s .
[ x ] Constructing a f u n c t i o n name f o r f c n . ∗ and sym . func . ∗ f u n c t i o n s
( aan ) )
sub . f i l e n o _ 5 0 0 86 0x4500 | UNMATCH
( 0 . 9 6 5 1 1 6 ) | 0x4510 86 sub . f i l e n o _ 5 1 0
sub . __freading_4c0 59 0x44c0 | UNMATCH
( 0 . 9 4 9 1 5 3 ) | 0x44d0 59 sub . __freading_4d0
sub . f i l e n o _ 4 4 0 120 0x4440 | UNMATCH
( 0 . 2 0 0 0 0 0 ) | 0x4450 120 sub . f i l e n o _ 4 5 0
sub . s e t l o c a l e _ f a 0 64 0 x3fa0 | UNMATCH
( 0 . 1 0 4 6 5 1 ) | 0 x3fb0 64 sub . s e t l o c a l e _ f b 0
f c n .00003 a50 120 0x3a50 | UNMATCH
( 0 . 1 2 5 0 0 0 ) | 0x3a60 120 f c n .00003 a60
76
Figure 3: /bin/true vs /bin/false
77
a perfect match. The orange one highlights a strong difference. If you look
closely, you will see that the left part of the picture has mov eax, 0x1; pop rbx;
pop rbp; ret, while the right one has xor edx, edx; pop rbx; pop rbp; ret.
Rasm2
The command-line assembler and disassembler that is part of the radare2
framework. It supports a wide range of architectures and can be used inde-
pendently of the main radare2 tool. Key features include:
• Multi-architecture support: Can handle numerous architectures includ-
ing x86, x86-64, ARM, MIPS, PowerPC, SPARC, and many others.
• Bi-directional operation: Functions as both an assembler (converting
human-readable assembly code to machine code) and a disassembler
(converting machine code back to assembly).
• Flexible input/output: Accepts input as hexadecimal strings, raw binary
files, or text files containing assembly code.
• Shellcode generation: Useful for security research and exploit develop-
ment.
• Inline assembly: Allows for quick assembly of individual instructions or
small code snippets.
• Syntax highlighting: Provides colored output for better readability when
disassembling.
• Plugins: Supports architecture-specific plugins for extended functional-
ity.
Help
$ rasm2 −h
Usage : rasm2 [−ACdDehLBvw] [−a arch ] [−b b i t s ] [−o addr ] [− s syntax ]
[− f f i l e ] [−F f i l : t e r ] [− i s k i p ] [− l l e n ]
' code ' | hex |0101 b|−
−a [ arch ] s e t a r c h i t e c t u r e to assemble / d i s a s s e m b l e ( s e e −L)
−A show Anal ysi s i n f o r m a t i o n from given h e x p a i r s
−b [ b i t s ] s e t cpu r e g i s t e r s i z e ( 8 , 16 , 32 , 64) (RASM2_BITS)
−B binary input / output (− l i s mandatory f o r binary input )
78
−c [ cpu ] s e l e c t s p e c i f i c CPU ( depends on arch )
−C output i n C format
−d , −D d i s a s s e m b l e from hexpair bytes (−D show h e x p a i r s )
−e use big endian i n s t e a d o f l i t t l e endian
−E d i s p l a y ESIL e x p r e s s i o n ( same input as i n −d)
−f [ file ] read data from f i l e
−F [ i n : out ] s p e c i f y input and/ or output f i l t e r s ( a t t 2 i n t e l ,
x86 . pseudo , . . . )
−h , −hh show t h i s help , −hh f o r long
−i [ l e n ] i g n o r e / s k i p N bytes o f the input b u f f e r
−j output i n j s o n format
−k [ k e r n e l ] s e l e c t o p e r a t i n g system ( linux , windows , darwin , . . )
−l [ l e n ] input /Output l e n g t h
−L l i s t RAsm p l u g i n s : ( a=asm , d=disasm , A=analyze , e=ESIL )
−LL l i s t RAnal p l u g i n s ( s e e anal . arch=?) combines with −j
−o,−@ [ addr ] s e t s t a r t address f o r code ( d e f a u l t 0)
−O [ f i l e ] output f i l e name ( rasm2 −Bf a . asm −O a )
−N same as r2 −N ( or R2_NOPLUGINS) ( not load any p l u g i n )
−p run SPP over input f o r assembly
−q q u i e t mode
−r output i n radare commands
−s [ syntax ] s e l e c t syntax ( i n t e l , a t t )
−v show v e r s i o n i n f or ma t i o n
−x use hex dwords i n s t e a d o f hex p a i r s when assembling .
−w what ' s t h i s i n s t r u c t i o n f o r ? d e s c r i b e opcode
I f '− l ' value i s g r e a t e r than output length , output i s padded with
nops
I f the l a s t argument i s ' − ' reads from s t d i n
Environment :
R2_NOPLUGINS do not load shared p l u g i n s ( speedup l o a d i n g )
R2_LOG_LEVEL=X change the l o g l e v e l
R2_DEBUG i f defined , show e r r o r messages and crash s i g n a l
R2_DEBUG_ASSERT=1 l l d b −− r2 to get proper backtrace o f the runtime
assert
RASM2_ARCH same as rasm2 −a
RASM2_BITS same as rasm2 −b
Plugins
Plugins for supported target architectures can be listed with the −L option.
Knowing a plugin name, you can use it by specifying its name to the −a option
$ rasm2 −L
_dAe 8 16 6502 LGPL3 6502/NES/C64/Tamagotchi/T−1000
CPU
_dAe 8 8051 PD 8051 I n t e l CPU
_dA_ 16 32 arc GPL3 Argonaut RISC Core
a___ 16 32 64 arm . as LGPL3 as ARM Assembler ( use ARM_AS
environment )
adAe 16 32 64 arm BSD Capstone ARM d i s a s s e m b l e r
_dA_ 16 32 64 arm . gnu GPL3 Acorn RISC Machine CPU
_d__ 16 32 arm . winedbg LGPL2 WineDBG' s ARM d i s a s s e m b l e r
adAe 8 16 avr GPL AVR Atmel
79
adAe 16 32 64 bf LGPL3 Brainfuck ( by pancake , n i b b l e )
v4 . 0 . 0
_dA_ 32 chip8 LGPL3 Chip8 d i s a s s e m b l e r
_dA_ 16 cr16 LGPL3 cr16 disassembly p l u g i n
_dA_ 32 cris GPL3 Axis Communications 32− b i t
embedded p r o c e s s o r
adA_ 32 64 dalvik LGPL3 AndroidVM Dalvik
ad__ 16 dcpu16 PD Mojang ' s DCPU−16
_dA_ 32 64 ebc LGPL3 EFI Bytecode
adAe 16 gb LGPL3 GameBoy(TM) ( z80−l i k e )
_dAe 16 h8300 LGPL3 H8/300 disassembly p l u g i n
_dAe 32 hexagon LGPL3 Qualcomm Hexagon (QDSP6) V6
_d__ 32 hppa GPL3 HP PA−RISC
_dAe i4004 LGPL3 I n t e l 4004 m i c r o p r o c e s s o r
_dA_ 8 i8080 BSD I n t e l 8080 CPU
adA_ 32 java Apache Java bytecode
_d__ 32 lanai GPL3 LANAI
_d__ 8 lh5801 LGPL3 SHARP LH5801 d i s a s s e m b l e r
_d__ 32 lm32 BSD disassembly p l u g i n f o r L a t t i c e
Micro 32 ISA
_dA_ 16 32 m68k BSD Capstone M68K d i s a s s e m b l e r
_dA_ 32 malbolge LGPL3 Malbolge Ternary VM
_d__ 16 mcs96 LGPL3 c o n dr e t s car
adAe 16 32 64 mips BSD Capstone MIPS d i s a s s e m b l e r
adAe 32 64 mips . gnu GPL3 MIPS CPU
_dA_ 16 msp430 LGPL3 msp430 disassembly p l u g i n
_dA_ 32 nios2 GPL3 NIOS I I Embedded P r o c e s s o r
_dAe 8 pic LGPL3 PIC d i s a s s e m b l e r
_dAe 32 64 ppc BSD Capstone PowerPC d i s a s s e m b l e r
_dA_ 32 64 ppc . gnu GPL3 PowerPC
_d__ 32 propeller LGPL3 p r o p e l l e r disassembly p l u g i n
_dA_ 32 64 riscv GPL RISC−V
_dAe 32 rsp LGPL3 Reality Signal Processor
_dAe 32 sh GPL3 SuperH−4 CPU
_dA_ 8 16 sn e s LGPL3 SuperNES CPU
_dAe 32 64 sparc BSD Capstone SPARC d i s a s s e m b l e r
_dA_ 32 64 sparc . gnu GPL3 Scalable Processor Architecture
_d__ 16 spc700 LGPL3 spc700 , snes ' sound−chip
_d__ 32 sysz BSD SystemZ CPU d i s a s s e m b l e r
_dA_ 32 tms320 LGPLv3 TMS320 DSP f a m i l y
( c54x , c55x , c55x+,c64x )
_d__ 32 tricore GPL3 Siemens TriCore CPU
_dAe 32 v810 LGPL3 v810 disassembly p l u g i n
_dAe 32 v850 LGPL3 v850 disassembly p l u g i n
_dAe 8 32 vax GPL VAX
adA_ 32 wasm MIT WebAssembly ( by cgvwzq ) v0 . 1 . 0
_dA_ 32 ws LGPL3 Whitespace e s o t h e r i c VM
a___ 16 32 64 x86 . as LGPL3 I n t e l X86 GNU Assembler
_dAe 16 32 64 x86 BSD Capstone X86 d i s a s s e m b l e r
a___ 16 32 64 x86 . nasm LGPL3 X86 nasm assembler
a___ 16 32 64 x86 . nz LGPL3 x86 handmade assembler
_dA_ 16 xap PD XAP4 RISC (CSR)
_dA_ 32 xcore BSD Capstone XCore d i s a s s e m b l e r
80
_dAe 32 xtensa GPL3 XTensa CPU
adA_ 8 z80 GPL Z i l o g Z80
NOTE the “ad” in the first column means both assembler and disassembler
are offered by a corresponding plugin. “d” indicates disassembler, ”a” means
only assembler is available.
Assembler
Assembling is the action to take a computer instruction in human readable
form (using mnemonics) and convert that into a bunch of bytes that can be
executed by a machine.
In radare2, the assembler and disassembler logic is implemented in the
r_asm_* API, and can be used with the pa and pad commands from the
commandline as well as using rasm2.
Rasm2 can be used to quickly copy-paste hexpairs that represent a given
machine instruction. The following line is assembling this mov instruction for
x86/32.
$ rasm2 −a x86 −b 32 'mov eax , 33 '
b821000000
Apart from the specifying the input as an argument, you can also pipe it to
rasm2:
$ echo ' push eax ; nop ; nop ' | rasm2 −f −
5090
As you have seen, rasm2 can assemble one or many instructions. In line by
separating them with a semicolon ; , but can also read that from a file, using
generic nasm/gas/.. syntax and directives. You can check the rasm2 manpage
for more details on this.
The pa and pad are a subcommands of print, what means they will only print
assembly or disassembly. In case you want to actually write the instruction
it is required to use wa or wx commands with the assembly string or bytes
appended.
The assembler understands the following input languages and their flavors:
x86 (Intel and AT&T variants), olly (OllyDBG syntax), powerpc (PowerPC),
arm and java. For Intel syntax, rasm2 tries to mimic NASM or GAS.
There are several examples in the rasm2 source code directory. Consult them
to understand how you can assemble a raw binary file from a rasm2 descrip-
tion.
81
Lets create an assembly file called selfstop .rasm:
;
; S e l f −Stop s h e l l c o d e w r i t t e n i n rasm f o r x86
;
; −−pancake
;
. arch x86
. equ base 0x8048000
. org 0x8048000 ; the o f f s e t where we i n j e c t the 5 byte jmp
selfstop :
push 0x8048000
pusha
mov eax , 20
i n t 0x80
ret
Visual mode
Assembling also is accessible in radare2 visual mode through pressing A key
to insert the assembly in the current offset.
82
The cool thing of writing assembly using the visual assembler interface that
the changes are done in memory until you press enter.
So you can check the size of the code and which instructions is overlapping
before committing the changes.
Disassembler
Disassembling is the inverse action of assembling. Rasm2 takes hexpair as an
input (but can also take a file in binary form) and show the human readable
form.
To do this we can use the −d option of rasm2 like this:
$ rasm2 −a x86 −b 32 −d ' 9 0 '
nop
or for java:
$ rasm2 −a java ' nop '
00
``` c o n s o l e
$ rasm2 −a x86 −b 32 'mov eax , 33 '
b821000000
You might be interested in trying if you want different outputs for later parsing
with your scripts, or just grep to find what you are looking for:
pd N Disassemble N instructions
pD N Disassemble N bytes
83
Disassembler Configuration
The assembler and disassembler have many small switches to tweak the out-
put.
Those configurations are available through the e command. Here there are
the most common ones:
• asm.bytes - show/hide bytes
• asm.offset - show/hide offset
• asm.lines - show/hide lines
• asm.ucase - show disasm in uppercase
• …
Use the e??asm. for more details.
ragg2
ragg2 stands for radare2's egg compiler, it’s the basic tool to compile relocatable
snippets of code and modify paddings and inject sequences in order to be used
for injection in target processes when doing exploiting.
ragg2 compiles programs written in a simple high-level language into tiny
binaries for x86, x86-64, and ARM.
The final bytestream can be rendered in a variety of output formats, including
raw binary, C arrays, and various executable formats. This flexibility allows
users to generate code that can be easily integrated into different types of
projects or testing scenarios. Additionally, ragg2 can perform operations like
encoding and encryption on the generated shellcode, which can be useful
for evading detection or bypassing security measures in controlled testing
environments.
Example
By default it will compile it’s own ragg2 language, but you can also compile
C code using GCC or Clang shellcodes depending on the file extension. Lets
create C file called a.c:
int main ( ) {
w r i t e ( 1 , ” H e l l o World\n” , 13) ;
return 0 ;
}
84
$ rasm2 −a x86 −b 32 −D
e900000000488d3516000000bf01000000b80400000248c7c20d0000000f0531c0c348656c6
0x00000000 5 e900000000 jmp 5
0x00000005 1 48 dec eax
0x00000006 6 8d3516000000 l e a e s i , [ 0 x16 ]
0x0000000c 5 bf01000000 mov edi , 1
0x00000011 5 b804000002 mov eax , 0x2000004
0x00000016 1 48 dec eax
0x00000017 6 c7c20d000000 mov edx , 0xd
0x0000001d 2 0 f05 s y s c a l l
0 x0000001f 2 31 c0 xor eax , eax
0x00000021 1 c3 r e t
0x00000022 1 48 dec eax
0x00000023 2 656 c i n s b byte e s : [ e d i ] , dx
0x00000025 1 6c i n s b byte e s : [ e d i ] , dx
0x00000026 1 6 f outsd dx , dword [ e s i ]
0x00000027 3 20576 f and byte [ e d i + 0 x6f ] , d l
0x0000002a 2 726 c jb 0x98
0x0000002c 3 640 a00 or al , byte f s : [ eax ]
Help message
Checking the help from the commandline will give you a wide understanding
of what’s the tool about and its capabilities
Usage : ragg2 [−FOLsrxhvz ] [−a arch ] [−b b i t s ] [−k os ] [−o f i l e ] [− I
path ]
[− i s c ] [−E enc ] [−B hex ] [−c k=v ] [−C f i l e ] [−p pad ]
[−q o f f ]
[−S s t r i n g ] [− f fmt ] [−nN dword ] [−dDw o f f : hex ] [−e
expr ] f i l e | f . asm|−
−a [ arch ] s e l e c t a r c h i t e c t u r e ( x86 , mips , arm)
−b [ b i t s ] r e g i s t e r s i z e ( 3 2 , 64 , . . )
−B [ h e x p a i r s ] append some hexpair bytes
−c [ k=v ] set configuration options
−C [ f i l e ] append c on t e n t s o f f i l e
−d [ o f f : dword ] patch dword (4 bytes ) at given o f f s e t
−D [ o f f : qword ] patch qword (8 bytes ) at given o f f s e t
−e [ egg−expr ] take egg program from s t r i n g i n s t e a d o f f i l e
−E [ encoder ] use s p e c i f i c encoder . s e e −L
−f [ format ] output format ( raw , c , pe , e l f , mach0 , python ,
javascript )
−F output n a t i v e format ( osx=mach0 , l i n u x=e l f , . . )
−h show t h i s help
−i [ s h e l l c o d e ] i n c l u d e s h e l l c o d e plugin , u s e s o p t i o n s . s e e −L
−I [ path ] add i n c l u d e path
−k [ os ] o p e r a t i n g system ' s k e r n e l ( linux , bsd , osx , w32)
−L l i s t a l l p l u g i n s ( s h e l l c o d e s and encoders )
−n [ dword ] append 32 b i t number (4 bytes )
−N [ dword ] append 64 b i t number (8 bytes )
−o [ f i l e ] output f i l e
85
−O use d e f a u l t output f i l e ( f i l e n a m e without e x t e n s i o n
or a . out )
−p [ padding ] add padding a f t e r compilation ( padding=n10s32 )
ntas : begin nop , trap , ' a ' , sequence
NTAS : same as above , but at the end
−P [ size ] prepend d e b r u i j n pattern
−q [ fragment ] d e b r u i j n pattern o f f s e t
−r show raw bytes i n s t e a d o f h e x p a i r s
−s show assembler
−S [ string ] append a s t r i n g
−v show v e r s i o n
−w [ o f f : hex ] patch h e x p a i r s at given o f f s e t
−x execute
−X [ hexpairs ] execute rop chain , using the s t ac k provided
−z output i n C s t r i n g syntax
First Example
$ cat h e l l o . r
exit@syscall (1) ;
main@global ( ) {
exit (2) ;
}
$ ragg2 −a x86 −b 64 h e l l o . r
48 c7c00200000050488b3c2448c7c0010000000f054883c408c3
0x00000000 1 48 dec eax
0x00000001 6 c7c002000000 mov eax , 2
0x00000007 1 50 push eax
0x00000008 1 48 dec eax
0x00000009 3 8b3c24 mov edi , dword [ esp ]
0x0000000c 1 48 dec eax
0x0000000d 6 c7c001000000 mov eax , 1
0x00000013 2 0 f05 s y s c a l l
0x00000015 1 48 dec eax
0x00000016 3 83 c408 add esp , 8
0x00000019 1 c3 r e t
$ rasm2 −a x86 −b 64 −D
48 c7c00200000050488b3c2448c7c0010000000f054883c408c3
0x00000000 7 48 c7c002000000 mov rax , 2
0x00000007 1 50 push rax
0x00000008 4 488 b3c24 mov r d i , qword [ rsp ]
0x0000000c 7 48 c7c001000000 mov rax , 1
0x00000013 2 0 f05 s y s c a l l
0x00000015 4 4883 c408 add rsp , 8
0x00000019 1 c3 r e t
86
$ cat code1 . c
int main ( )
{
w r i t e ( 1 , ” H e l l o World\n” , 13) ;
exit (0) ;
}
One can get raw machine code of the above program like this:
$ ragg2 code1 . c
eb0e66666666662e0f1f84000000000050bf01000000488d359f000000ba0d000000e8190000003
If you want it in a file, you may use the ‘-O’ flag which uses the default
filename or you may specify the output filename using ‘-o’ option.
$ ragg2 −O code1 . c
$ cat code1
eb0e66666666662e0f1f84000000000050bf01000000488d359f000000ba0d000000e8190000003
Printing as in raw
$ ragg2 −o code1 . raw code1 . c
$ cat code1 . raw
eb0e66666666662e0f1f84000000000050bf01000000488d359f000000ba0d000000e8190000003
The above is a basic ‘raw’ output. ragg2 offers a number of output format
options via −f. One can find it through ragg2 −h or ragg2’s manpage.
−f format output format ( raw , c , pe , e l f , mach0 , python ,
javascript )
The following is ‘c’ format output - shellcode which can be readily used in
your C program.
$ ragg2 −f c −o code1 . c . c code1 . c
$ cat code1 . c . c
const unsigned char c s t r [ 2 0 1 ] = ””\
”\ x31\ x f f \x89\x44\x24\x04\xe8\x5e\x00\x00\x00\x31\xd2\x89\x04\x24\x89\xd0\x
”\ xc1\x89\x4c\x24\xc8\x8b\x44\x24\xc8\xc3\x89\x7c\x24\ x f c \x8b\x7c\x24\ x f c \x
87
”\ x89\x4c\x24\xe8\x8b\x44\x24\xe8\xc3\x48\x65\x6c\x6c\ x6f \x20\x57\ x6f \x72\x
”\x31\ x f f \x89\x44\x24\x04\xe8\x5e\x00\x00\x00\x31\xd2\x89\x04\x24\x89\xd0\x
”\xc1\x89\x4c\x24\xc8\x8b\x44\x24\xc8\xc3\x89\x7c\x24\ x f c \x8b\x7c\x24\ x f c \x
void (∗ func ) ( ) = c s t r ;
func ( ) ;
return 0 ;
}
Similar to how the above code is readily usable in C programs, ragg2 can emit
python-ready and js-ready code too(using the ‘-f python’ and -f javascript’
options).
To generate an executable binary for your native architecture, you may use
the ‘-F’ option.
$ ragg2 −F −o code1 . e l f code1 . c
$ . / code1 . e l f
88
H e l l o World
or
$ ragg2 −f mach0 −o code1_f . mach0 code1 . c
$ f i l e code1_f . mach0
code1_f . mach0 : Mach−O 64− b i t x86_64 e x e c u t a b l e
The ‘-b’ option can be used to specify the bits. One can see the supported
architectures from ragg2’s help or manpage.
−a [ arch ] s e l e c t a r c h i t e c t u r e ( x86 , mips , arm)
−b [ b i t s ] r e g i s t e r s i z e ( 3 2 , 64 , . . )
The ‘-r’ flag can be used to generate binary output instead of the above hex-
string style output.
$ ragg2 −f raw −r code1 . c | rax2 −S
efbfbd31efbfbdefbfbd4424efbfbd5e31d28924efbfbdefbfbd59efbfbd44efbfbd7c24efbfbd4
7424 e f b f b d e f b f b d 5 4 2 4 e f b f b d e f b f b d 5 4 2 4 e f b f b d e f b f b d 5 4 2 4 e f b f b d 4 8 e f b f b d 7 4 2 4 e f b f b d 4 8 e
24 d08b5424efbfbdefbfbd5424cc8b7c24efbfbd48efbfbd7424d08b5424ccb848efbfbd4424efb
bfbd4424efbfbdefbfbdefbfbdefbfbd4c24c88b4424efbfbdc3897c24efbfbdefbfbd7c24efbfb
7 c24efbfbdefbfbd7c24efbfbdefbfbd3c48efbfbd4424efbfbd48efbfbd4424efbfbdefbfbdefb
bd4c24efbfbdefbfbd4424efbfbdefbfbd48656c6c6f20576f726c640a
89
000000b0 : f089 c189 4 c24 e88b 4424 e8c3 4865 6 c6c . . . . L$ . . D$ . . H e l l
000000 c0 : 6 f 2 0 576 f 726 c 640a 00 o World . .
Using ‘-z’ flag instead of ‘-r’ would generate a C-style hex-string output.
$ ragg2 −f raw −z code1 . c
”\ xeb\x0e\x66\x66\x66\x66\x66\x2e\ x0f \ x1f \x84\x00\x00\x00\x00\x00\x50\ xbf \x01\x
Instead of using C, a domain specific language designed for ragg2 can also be
used - you may refer to this page.
The −e option can be used if you want to input the code as an argument to
ragg2 and not as a file. Note that you can only use ragg2 language here(and
not C).
$ ragg2 −e ” e x i t @ s y s c a l l ( 6 0 ) ; w r i t e @ s y s c a l l ( 4 ) ; main@global (128)
{ w r i t e ( 1 , \” H e l l o World\n \” , 13) ; e x i t ( 0 ) ; } ”
554889 e54881ec8000000048c7c00d00000050c7452048656c6cc745246f20576fc74528726c640a
Other options like architecture, bits, output file format etc., can be used here
too.
$ ragg2 −e ” e x i t @ s y s c a l l ( 6 0 ) ; w r i t e @ s y s c a l l ( 4 ) ; main@global (128)
{ w r i t e ( 1 , \” H e l l o World\n \” , 13) ; e x i t ( 0 ) ; } ” −f e l f −o
output . e l f
$ f i l e output . e l f
output . e l f : ELF 64− b i t LSB executable , x86 −64, v e r s i o n 1 (SYSV) ,
s t a t i c a l l y li n ke d , corrupted s e c t i o n header s i z e
$ ragg2 −e ” e x i t @ s y s c a l l ( 6 0 ) ; w r i t e @ s y s c a l l ( 4 ) ; main@global (128)
{ w r i t e ( 1 , \” H e l l o World\n \” , 13) ; e x i t ( 0 ) ; } ” −f c
const unsigned char c s t r [ 1 3 9 ] = ””\
”\ x00\x00\x48\x8d\x45\x20\x48\x89\x85\x18\x00\x00\x00\x48\x8b\x45\x18\x50\x
”\ x00\x00\x00\x50\x48\x8b\x3c\x24\x48\x8b\x74\x24\x08\x48\x8b\x54\x24\x10\x
In case you just want to execute the input, you may use the −x option.
−x execute ( j u s t −in−time )
$ cat code1 . c
i n t main ( )
{
90
w r i t e ( 1 , ” H e l l o World\n ” , 13) ;
exit (0) ;
}
$ ragg2 −x code1 . c
H e l l o World
Preprocessor ragg2 uses the spp preprocessor. So you can use defines, build
conditionals and so on.
Aliases Sometimes you just need to replace at compile time a single entity
on multiple places. Aliases are translated into ‘equ’ statements in assembly
language. This is just an assembler-level keyword redefinition.
• AF_INET@alias(2);
• printf@alias(0x8053940);
91
Main The execution of the code is done as in a flow. The first function to
be defined will be the first one to be executed. If you want to run main() just
do like this:
#! / usr / bin / ragg2 −X
main ( ) ;
...
main@global ( 1 2 8 , 6 4 ) {
...
}
Function definition You may like to split up your code into several code
blocks. Those blocks are bound to a label followed by root brackets ‘{ … }’
Function signatures
• name@type(stackframesize,staticframesize) { body }
• name : name of the function to define
• type : see function types below
• stackframesize : get space from stack to store local variables
• staticframesize : get space from stack to store static variables (strings)
• body : code of the function
Function types
• alias: Used to create aliases
• data: the body of the block is defined in .data
• inline: the function body is inlined when called
• global: make the symbol global
• fastcall: function that is called using the fast calling convention
• syscall: define syscall calling convention signature
Syscalls r_egg offers a syntax sugar for defining syscalls. The syntax is like
this:
exit@syscall (1) ;
@syscall () {
: mov eax , . arg
: i n t 0x80
}
main@global ( ) {
exit (0) ;
}
92
Libraries At the moment there is no support for linking r_egg programs
to system libraries. but if you inject the code into a program (disk/memory)
you can define the address of each function using the @alias syntax.
Variables
• .arg
• .arg0
• .arg1
• .arg2
• .var0
• .var2
• . fix
• . ret ; eax for x86, r0 for arm
• .bp
• .pc
• .sp
Attention: All the numbers after .var and .arg mean the offset with the
top of stack, not variable symbols.
Tracing Sometimes r_egg programs will break or just not work as expected.
Use the ‘trace’ architecture to get a arch-backend call trace:
$ ragg2 −a t r a c e −s yourprogram . r
Virtual registers TODO: a0, a1, a2, a3, sp, fp, bp, pc
93
Return values The return value is stored in the a0 register, this register
is set when calling a function or when typing a variable name without assign-
ment.
$ cat t e s t . r
add@global ( 4 ) {
. var0 = . arg0 + . arg1 ;
. var0 ;
}
main@global ( ) {
add ( 3 , 4 ) ;
}
$ ragg2 −F −o t e s t t e s t . r
$ ./ test
$ echo $?
7
Inline assembly Lines prefixed with ‘:’ char are just inlined in the output
assembly.
• : jmp 0x8048400
• : .byte 33,44
Labels You can define labels using the : keyword like this:
• :label_name:
• /∗ loop forever ∗/
• goto(label_name)
Control flow
• goto (addr) – branch execution
• while (cond)
• if (cond)
• if (cond) { body } else { body }
• break () – executes a trap instruction
94
Comments Supported syntax for comments are the multiline:
• /∗ multiline comment ∗/'
and for singline line comments use these:
• // single line comment
• # single line comment
Shellcode Encoders
ragg2 offers a few ready-made shellcodes and encoders.
$ ragg2 −L
shellcodes :
exec : execute cmd=/bin /sh s u i d=f a l s e
encoders :
xor : xor encoder f o r s h e l l c o d e
Using the ‘-i’ option, one can generate specify and generate the shellcode.
$ ragg2 −i exec
31 c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05
Similar to the previous section, the output format(c, raw, elf etc.,) can be
specified here too along with the architecture and bits.
ragg2 offers an xor encoder too. The following are the relevant flags/options.
$ ragg2 −h
−c [ k=v ] set configuration options
−E [ encoder ] use s p e c i f i c encoder . s e e −L
−L l i s t a l l p l u g i n s ( s h e l l c o d e s and encoders )
The same can be done with a .c or .r file output. The first one is the normal
output(machine code) and the second is xor encoded.
$ ragg2 −a x86 −f raw code1 . c
eb0e66666666662e0f1f84000000000050bf01000000488d359f000000ba0d000000e8190000003
95
• Appending Data:
– Append hex bytes (-B)
– Append file contents (-C)
– Append 32-bit or 64-bit numbers (-n, -N)
– Append strings (-S)
• Patching Existing Data:
– Patch dword or qword at a given offset (-d, -D)
– Patch hex pairs at a given offset (-w)
• Adding Padding:
– Add padding after compilation (-p)
– Options include NOP, trap instructions, or specific byte sequences
From ragg2 −h:
−B [ hexpairs ] append some hexpair bytes
−C [ file ] append c on t e n t s o f f i l e
−d [ o f f : dword ] patch dword (4 bytes ) at given o f f s e t
−D [ o f f : qword ] patch qword (8 bytes ) at given o f f s e t
−n [ dword ] append 32 b i t number (4 bytes )
−N [ dword ] append 64 b i t number (8 bytes )
−p [ padding ] add padding a f t e r compilation ( padding=n10s32 )
ntas : begin nop , trap , ' a ' , sequence
NTAS : same as above , but at the end
−S [ s t r i n g ] append a s t r i n g
−w [ o f f : hex ] patch h e x p a i r s at given o f f s e t
rahash2
Versatile command-line hashing tool that is part of the radare2 framework.
It’s designed to compute and verify cryptographic hashes and checksums for
files, strings, or even large data streams like hard disks or network traffic.
Key features of rahash2 include:
Multiple algorithms Supports a wide range of hash algorithms, including
MD4, MD5, SHA1, SHA256, SHA384, SHA512, CRC16, CRC32, and more.
Flexible input Can hash data from files, standard input, or directly from
command-line strings.
Block-based hashing Can compute hashes for specific blocks or ranges
within a file, which is ideal for forensics and checksuming large data.
Incremental hashing Supports hashing of data streams or large files in
chunks, useful for processing data that doesn’t fit in memory.
Hash verification and integrity checks comparing computed and provided
hash.
96
Multiple hash outputs at once Can compute and display multiple hash
types simultaneously for the same input.
**Integration with radare2: While it’s a standalone tool, it integrates well
with other radare2 utilities and can be used within r2 sessions.
Customizable output Offers various output formats, including raw bytes,
hexadecimal strings, or radare2 commands.
Encryption capabilities Besides hashing, it also supports some basic en-
cryption and decryption operations.
This is an example usage:
$ rahash2 −a md5 −s ” h e l l o world ”
Note that rahash2 also permits to read from stdin in a stream, so you don’t
need 4GB of ram to compute the hash of a 4GB file.
Hashing by blocks
When doing forensics, it is useful to compute partial checksums. The reason
for that is because you may want to split a huge file into small portions that
are easier to identify by contents or regions in the disk.
This will spot the same hash for blocks containing the same contents. For
example, if is filled with zeros.
It can also be used to find which blocks have changed between more than one
sample dump.
This can be useful when analyzing ram dumps from a virtual machine for
example. Use this command for this:
$ rahash2 −B 1M −b −a sha256 / bin / l s
97
$ radare2 / bin / l s
[ 0 x08049790]> bf entry0
[ 0 x08049790]> ph md5
d2994c75adaa58392f953a448de5fba7
98
a71b087d8166c99869c9781e2edcf183
[ 0 x08049A80]> ph md5 1024
a933cc94cd705f09a41ecc80c0041def
Examples
The rahash2 tool can be used to calculate checksums and has functions of
byte streams, files, text strings.
$ rahash2 −h
Usage : rahash2 [−rBhLkv ] [−b S ] [−a A] [−c H] [−E A] [− s S ] [− f O]
[− t O] [ f i l e ] . . .
−a a l g o comma separated l i s t o f a lg o ri t hm s ( d e f a u l t i s ' sha256 ' )
−b b s i z e s p e c i f y the s i z e o f the block ( i n s t e a d o f f u l l f i l e )
−B show per−block hash
−c hash compare with t h i s hash
−e swap endian ( use l i t t l e endian )
−E a l g o encrypt . Use −S to s e t key and −I to s e t IV
−D a l g o decrypt . Use −S to s e t key and −I to s e t IV
−f from s t a r t hashing at given address
−i num r e p e a t hash N i t e r a t i o n s
−I i v use g i v e i n i t i a l i z a t i o n v e c t o r ( IV ) ( hexa or s : s t r i n g )
−S seed use given seed ( hexa or s : s t r i n g ) use ^ to p r e f i x ( key
f o r −E)
(− w i l l s l u r p the key from stdin , the @ p r e f i x p o i n t s
to a f i l e
−k show hash using the openssh ' s randomkey algorithm
−q run i n q u i e t mode (−qq to show only the hash )
−L l i s t a l l a v a i l a b l e al g or i th m s ( s e e −a )
−r output radare commands
−s s t r i n g hash t h i s s t r i n g i n s t e a d o f f i l e s
−t to stop hashing at given address
−x h e x s t r hash t h i s hexpair s t r i n g i n s t e a d o f f i l e s
−v show v e r s i o n i n f o r m a t i o n
It is possible to calculate hash values for contents of files. But do not attempt
to do it for very large files because rahash2 buffers the whole input in memory
before computing the hash.
To apply all algorithms known to rahash2, use all as an algorithm name:
$ rahash2 −a a l l / bin / l s
/ bin / l s : 0x00000000−0x000268c7 md5 : 767 f 0 f f f 1 1 6 b c 6 5 8 4 d b f c 1 a f 6 f d 4 8 f c 7
/ bin / l s : 0x00000000−0x000268c7 sha1 :
404303 f3960f196f42f8c2c12970ab0d49e28971
/ bin / l s : 0x00000000−0x000268c7 sha256 :
74 ea05150acf311484bddd19c608aa02e6bf3332a0f0805a4deb278e17396354
99
/ bin / l s : 0x00000000−0x000268c7 sha384 :
c6f811287514ceeeaabe73b5b2f54545036d6fd3a192ea5d6a1fcd494d46151df4117e1c62d
/ bin / l s : 0x00000000−0x000268c7 sha512 :
53 e4950a150f06d7922a2ed732060e291bf0e1c2ac20bc72a41b9303e1f2837d50643761030d
/ bin / l s : 0x00000000−0x000268c7 md4 : f d f e 7 c 7 1 1 8 a 5 7 c 1 f f 8 c 8 8 a 5 1 b 1 6 f c 7 8 c
/ bin / l s : 0x00000000−0x000268c7 xor : 42
/ bin / l s : 0x00000000−0x000268c7 x o r p a i r : d391
/ bin / l s : 0x00000000−0x000268c7 p a r i t y : 00
/ bin / l s : 0x00000000−0x000268c7 entropy : 5.95471783
/ bin / l s : 0x00000000−0x000268c7 hamdist : 00
/ bin / l s : 0x00000000−0x000268c7 p c p r i n t : 22
/ bin / l s : 0x00000000−0x000268c7 mod255 : e f
/ bin / l s : 0x00000000−0x000268c7 xxhash : 76554666
/ bin / l s : 0x00000000−0x000268c7 a d l e r 3 2 : 7704 f e 6 0
/ bin / l s : 0x00000000−0x000268c7 luhn : 01
/ bin / l s : 0x00000000−0x000268c7 crc8smbus : 8d
/ bin / l s : 0x00000000−0x000268c7 crc15can : 1cd5
/ bin / l s : 0x00000000−0x000268c7 crc16 : d940
/ bin / l s : 0x00000000−0x000268c7 c r c 1 6 h d l c : 7847
/ bin / l s : 0x00000000−0x000268c7 crc16usb : 17bb
/ bin / l s : 0x00000000−0x000268c7 c r c 1 6 c i t t : 67 f 7
/ bin / l s : 0x00000000−0x000268c7 crc24 : 3 e7053
/ bin / l s : 0x00000000−0x000268c7 crc32 : c 7 1 3 f 7 8 f
/ bin / l s : 0x00000000−0x000268c7 c r c 3 2 c : 6 cfba67c
/ bin / l s : 0x00000000−0x000268c7 crc32ecma267 : b4c809d6
/ bin / l s : 0x00000000−0x000268c7 c r c 3 2 b z i p 2 : a1884a09
/ bin / l s : 0x00000000−0x000268c7 crc32d : d1a9533c
/ bin / l s : 0x00000000−0x000268c7 crc32mpeg2 : 5 e77b5f6
/ bin / l s : 0x00000000−0x000268c7 c r c 3 2 p o s i x : 6ba0dec3
/ bin / l s : 0x00000000−0x000268c7 crc32q : 3166085 c
/ bin / l s : 0x00000000−0x000268c7 crc32jamcrc : 38 ec0870
/ bin / l s : 0x00000000−0x000268c7 c r c 3 2 x f e r : 7504089d
/ bin / l s : 0x00000000−0x000268c7 crc64 : b6471d3093d94241
/ bin / l s : 0x00000000−0x000268c7 crc64ecma : b6471d3093d94241
/ bin / l s : 0x00000000−0x000268c7 crc64we : 8 fe37d44a47157bd
/ bin / l s : 0x00000000−0x000268c7 crc64xz : ea83e12c719e0d79
/ bin / l s : 0x00000000−0x000268c7 c r c 6 4 i s o : d243106d9853221c
Configuration
The core reads ~/.config/radare2/radare2rc while starting. You can add e com-
mands to this file to tune the radare2 configuration to your taste.
To prevent radare2 from parsing this file at startup, pass it the −N option.
All the configuration of radare2 is done with the eval commands. A typical
startup configuration file looks like this:
$ cat ~ / . r a d a r e 2 r c
e scr . color = 1
e dbg . bep = loader
100
The configuration can also be changed with −e <config=value> command-line
option. This way you can adjust configuration from the command line, keep-
ing the .radare2rc file intact. For example, to start with empty configuration
and then adjust scr.color and asm.syntax the following line may be used:
$ radare2 −N −e s c r . c o l o r=1 −e asm . syntax=i n t e l −d / bin / l s
> anal
asm
scr
asm
101
bin
cfg
diff
dir
dbg
cmd
fs
hex
http
graph
hud
scr
search
io
For configuration values that can take one of several values, you can use the
=? operator to get a list of valid values:
[ 0 x00000000]> e s c r . nkey = ?
s c r . nkey = fun , h i t , f l a g
Environment
Radare2 uses several environment variables to determine where to look for
important files and directories. You can view these variables and their current
values by running the command “r2 -H” in your terminal.
This will display information such as:
• The version of radare2 you’re using
• Installation prefix path
• Locations of various resource directories (e.g. for plugins, scripts, con-
figuration files)
• File paths for things like the radare2 history file and cache
• Extensions used for shared libraries on your system
The exact values will depend on your operating system and how radare2
was built and installed. Understanding these variables can be helpful for
troubleshooting or customizing your radare2 setup.
Some key variables to note include those pointing to plugin directories, con-
figuration paths, and build flags. By examining the output of “r2 -H”, you
can see exactly where radare2 is looking for various resources on your system.
This information can be particularly useful if you are writing installation
recipes for Makefiles.
$ r2 −H
R2_VERSION=5.8.9
102
R2_PREFIX=/usr / l o c a l
R2_MAGICPATH=/usr / l o c a l / share / radare2 / 5 . 8 . 9 / magic
R2_INCDIR=/usr / l o c a l / i n c l u d e / l i b r
R2_BINDIR=/usr / l o c a l / bin
R2_LIBDIR=/usr / l o c a l / l i b
R2_LIBEXT=d y l i b
R2_RCFILE=/Users /pancake / . r a d a r e 2 r c
R2_RDATAHOME=/Users /pancake / . l o c a l / share / radare2
R2_HISTORY=/Users /pancake / . cache / radare2 /history
R2_CONFIG_HOME=/Users /pancake / . c o n f i g // radare2
R2_CACHE_HOME=/Users /pancake / . cache / radare2
R2_LIBR_PLUGINS=/usr / l o c a l / l i b / radare2 / 5 . 8 . 9
R2_USER_PLUGINS=/Users /pancake / . l o c a l / share / radare2 / p l u g i n s
R2_ZIGNS_HOME=/Users /pancake / . l o c a l / share // radare2 / z i g n s
RC Files
RC files in radare2 are configuration scripts that are automatically loaded
when the tool starts up. They allow users to customize the default behavior
and settings of radare2 without having to manually enter commands each
time.
These files typically contain a series of radare2 commands that are executed
sequentially on startup. This can include things like setting color schemes,
defining custom commands, adjusting display options, or loading plugins.
RC files for radare2 are usually placed in specific locations where the tool looks
for them by default. While I can’t specify exact locations, users generally have
options to place RC files in system-wide locations, user home directories, or
project-specific folders.
Those files must be in 3 different places:
System Wide
When initializing, radare2 first checks for a system-wide configuration file. By
default, it looks for a file named radare2rc in the /usr/share/radare2/ directory.
This allows administrators to set up default configurations that will apply for
all users on the system.
This system-wide script is loaded before any user-specific configurations, pro-
viding a baseline setup that can then be customized further by individual
users if needed.
radare2 will first try to load /usr/share/radare2/radare2rc
103
Home Directories
Radare2 allows users to customize their experience through configuration files.
These files contain r2 commands that are executed on startup, allowing users
to set preferences like color schemes and other options.
The main configuration files are typically located in the user’s home directory:
• ~/.radare2rc
• ‘~/.config/radare2/radare2rc
• ‘~/.config/radare2/radare2rc.d/
An important feature is the R2_RCFILE environment variable. This variable
allows users to specify a custom path to their radare2 configuration file. By
setting this variable, users can override the default locations and use a config-
uration file from any location on their system.
This flexibility in configuration allows users to tailor radare2 to their specific
needs and preferences, enhancing their workflow and user experience.
If scripting with r2 commands doesn’t fit your needs you can also write it
in r2js, the embedded javascript interpreter inside radare2, or in any other
language like Python or C, you can just run the . foo.r2. js command to evaluate
the specified file.
See the scripting chapter for more details.
File
Radare2 offers a convenient way to automatically execute scripts when open-
ing specific files. This feature is particularly useful for customizing your anal-
ysis environment for different types of files or projects. To take advantage
of this functionality, you can create a script file with the same name as the
target file, but with an additional .r2 extension.
For example, if you frequently work with a file named “example.bin”, you
can create a corresponding script file called “example.bin.r2”. Whenever you
open “example.bin” in radare2, it will automatically detect and execute the
commands contained in “example.bin.r2”. This allows you to set up predefined
configurations, run specific analysis commands, or perform any other desired
operations tailored to that particular file.
This automatic script execution feature provides a seamless way to stream-
line your workflow and ensure consistent analysis setups for specific files or
file types. By leveraging this capability, you can save time and effort by au-
tomating repetitive tasks and applying custom configurations without manual
intervention each time you open a file in radare2.
104
Colors
Console access is wrapped in API that permits to show the output of any
command as ANSI, W32 Console or HTML formats. This allows radare’s core
to run inside environments with limited displaying capabilities, like kernels or
embedded devices. It is still possible to receive data from it in your favorite
format.
To enable colors support by default, add a corresponding configuration option
to the .radare2 configuration file:
$ echo ' e s c r . c o l o r =1' >> ~ / . r a d a r e 2 r c
Themes
You can create your own color theme, but radare2 have its own predefined
ones. Use the eco command to list or select them.
After selecting one, you can compare between the color scheme of the shell
and the current theme by pressing Ctrl-Shift and then right arrow key for the
toggle.
In visual mode use the R key to randomize colors or choose the next theme
in the list.
105
Figure 4: img
106
Configuration Variables
Below is a list of the most frequently used configuration variables. You can
get a complete list by issuing e command without arguments. For example, to
see all variables defined in the “cfg” namespace, issue e cfg. (mind the ending
dot). You can get help on any eval configuration variable by using e? cfg.
The e?? command to get help on all the evaluable configuration variables of
radare2. As long as the output of this command is pretty large you can
combine it with the internal grep ~ to filter for what you are looking for:
Figure 5: e??~color
The Visual mode has an eval browser that is accessible through the Vbe com-
mand.
asm.arch
Defines the target CPU architecture used for disassembling (pd, pD commands)
and code analysis (a command). You can find the list of possible values by
looking at the result of e asm.arch=? or rasm2 −L. It is quite simple to add
new architectures for disassembling and analyzing code. There is an interface
for that. For x86, it is used to attach a number of third-party disassembler
engines, including GNU binutils, Udis86 and a few handmade ones.
asm.bits
Determines width in bits of registers for the current architecture. Supported
values: 8, 16, 32, 64. Note that not all target architectures support all com-
binations for asm.bits.
asm.syntax
Changes syntax flavor for disassembler between Intel and AT&T. At the mo-
ment, this setting affects Udis86 disassembler for Intel 32/Intel 64 targets
only. Supported values are intel and att.
107
asm.pseudo
A boolean value to set the pseudo syntax in the disassembly. “False” in-
dicates a native one, defined by the current architecture, “true” activates a
pseudocode strings format. For example, it’ll transform :
| 0 x080483ff e832000000 c a l l 0x8048436
| 0x08048404 31 c0 xor eax , eax
| 0x08048406 0205849 a0408 add al , byte [ 0 x8049a84 ]
| 0x0804840c 83 f800 cmp eax , 0
| 0 x0804840f 7405 j e 0x8048416
to
| 0 x080483ff e832000000 0x8048436 ( )
| 0x08048404 31 c0 eax = 0
| 0x08048406 0205849 a0408 a l += byte [ 0 x8049a84 ]
| 0x0804840c 83 f800 var = eax − 0
| 0 x0804840f 7405 i f ( ! var ) goto 0x8048416
asm.os
Selects a target operating system of currently loaded binary. Usually, OS is
automatically detected by rabin −rI. Yet, asm.os can be used to switch to a
different syscall table employed by another OS.
asm.flags
If defined to “true”, disassembler view will have flags column.
asm.lines.call
If set to “true”, draw lines at the left of the disassemble output (pd, pD
commands) to graphically represent control flow changes (jumps and calls)
that are targeted inside current block. Also, see asm.lines.out.
asm.lines.out
When defined as “true”, the disassembly view will also draw control flow lines
that go outside of the block.
asm.linestyle
A boolean value which changes the direction of control flow analysis. If set
to “false”, it is done from top to bottom of a block; otherwise, it goes from
108
bottom to top. The “false” setting seems to be a better choice for improved
readability and is the default one.
asm.offset
Boolean value which controls the visibility of offsets for individual disassem-
bled instructions.
asm.trace
A boolean value that controls displaying of tracing information (sequence
number and counter) at the left of each opcode. It is used to assist with
programs trace analysis.
asm.bytes
A boolean value used to show or hide displaying of raw bytes of instructions.
asm.sub.reg
A boolean value used to replace register names with arguments or their asso-
ciated role alias.
For example, if you have something like this:
| 0x080483ea 83 c404 add esp , 4
| 0x080483ed 68989 a0408 push 0x8049a98
| 0 x080483f7 e870060000 c a l l sym . imp . s c a n f
| 0 x080483fc 83 c408 add esp , 8
| 0x08048404 31 c0 xor eax , eax
asm.sub.jmp
A boolean value used to substitute jump, call and branch targets in disassem-
bly.
For example, when turned on, it’d display jal 0x80001a40 as jal fcn.80001a40 in
the disassembly.
109
asm.sub.rel
A boolean value which substitutes pc relative expressions in disassembly.
When turned on, it shows the references as string references.
For example:
0x5563844a0181 488 d3d7c0e00 . l e a r d i , [ r i p + 0 xe7c ] ;
s t r . argv__2d_ :__s
When turned on, this variable lets you display the above instruction as:
0x5563844a0181 488 d3d7c0e00 . l e a r d i , s t r . argv__2d_ :__s ;
0x5563844a1004 ; ” argv[%2d ] : %s \n”
asm.sub.section
Boolean which shows offsets in disassembly prefixed with the name of the
section or map.
That means, from something like:
0x000067ea 488 d0def0c01 . l e a rcx , [ 0 x000174e0 ]
asm.sub.varonly
Boolean which substitutes the variable expression with the local variable
name.
For example: var_14h as rbp − var_14h, in the disassembly.
cfg.bigendian
Change endianness. “true” means big-endian, “false” is for little-endian.
“file.id” and “file.flag” both to be true.
cfg.newtab
If this variable is enabled, help messages will be displayed along with command
names in tab completion for commands.
110
scr.color
This variable specifies the mode for colorized screen output: “false” (or 0)
means no colors, “true” (or 1) means 16-colors mode, 2 means 256-colors
mode, 3 means 16 million-colors mode. If your favorite theme looks weird, try
to bump this up.
scr.seek
This variable accepts a full-featured expression or a pointer/flag (eg. eip). If
set, radare will set seek position to its value on startup.
scr.scrollbar
If you have set up any flagzones ( fz?), this variable will let you display the
scrollbar with the flagzones, in Visual mode. Set it to 1 to display the scrollbar
at the right end, 2 for the top and 3 to display it at the bottom.
scr.utf8
A boolen variable to show UTF-8 characters instead of ANSI.
cfg.fortunes
Enables or disables “fortune” messages displayed at each radare start.
cfg.fortunes.type
Fortunes are classified by type. This variable determines which types are
allowed for displaying when cfg.fortunes is true, so they can be fine-tuned on
what’s appropriate for the intended audience. Current types are tips , fun, nsfw,
creepy.
stack.size
This variable lets you set the size of stack in bytes.
IO Configuration
The IO implementation is very complex and can be configured in many ways
to serve the way the user needs. This chapter will introduce you to some of
the most important configuration options under the eval.
[ 0 x100003a84]> e ?? i o .
i o . 0 x f f : use t h i s value i n s t e a d o f 0 x f f to f i l l
unallocated areas
111
i o . a s l r : d i s a b l e ASLR f o r spawn and such
i o . autofd : change fd when opening a new f i l e
i o . basemap : c r e a t e a map at base address 0 when opening a
file
i o . cache : change both o f i o . cache . { read , w r i t e }
i o . cache . auto : automatic cache a l l reads i n the IO backend
i o . cache . nodup : do not cache d u p l i c a t e d cache w r i t e s
i o . cache . read : enable read cache f o r vaddr ( or paddr when
i o . va=0)
i o . cache . w r i t e : enable w r i t e cache f o r vaddr ( or paddr when
i o . va=0)
i o . exec : s e e ! ! r2 −h~−x
io . f f : f i l l i n v a l i d b u f f e r s with 0 x f f i n s t e a d o f
returning error
i o . mask : mask a d d r e s s e s b e f o r e r e s o l v i n g as maps
io . overlay : honor i o o v e r l a y
i o . pava : use EXPERIMENTAL paddr −> vaddr address mode
i o . pcache : i o . cache f o r p−l e v e l
i o . pcache . read : enable read−cache
i o . pcache . w r i t e : enable write−cache
io . unalloc : check each byte i f i t ' s a l l o c a t e d
i o . u n a l l o c . ch : char to d i s p l a y i f byte i s u n a l l o c a t e d
i o . va : use v i r t u a l address layout
io.unalloc
When set to true it will be showing ? instead of 0xff in the hexdump/disasm
views if there’s no associated map. This causes the dump to be a bit slower,
but probably more real.
See io.0 xff and io .unalloc.ch for reference
io.cache
Enables the cache layer for the whole memory address space. This means that
you can write and patch anywhere in memory and the underlying files won’t
be modified.
See io .cache.read and io .cache.write
Note that enabling the read cache will speedup readings from slow or remote
endpoints, this is handy when performing analysis via GDB, so the read data
from the remote process will be read once.
io.pcache
Enables a physical layer cache associated with each map. This way it is
possible to keep the correct behaviour when accessing unallocated regions or
multi-map regions honoring the proper permissions, unlike io .cache.
112
See io .pcache.read and io .pcache.write
io.va
When set to false, it will seek around physical addresses on the currently
selected file descriptor, instead of the whole virtual address.
Commandline
Most command names in radare are derived from action names. They should
be easy to remember, as they are short. Actually, all commands are single
letters. Subcommands or related commands are specified using the second
character of the command name. For example, / foo is a command to search
plain string, while /x 90 90 is used to look for hexadecimal pairs.
The general format for a valid command (as explained in the Command For-
mat chapter) looks like this:
[ . ] [ times ] [ cmd ] [ ~ grep ] [@[ @iter ] addr ! s i z e ] [ | > pipe ] ; . . .
For example,
> 3 s +1024 ; s e e k s t h r e e times 1024 from the c u r r e n t seek
If a command starts with =!, the rest of the string is passed to the currently
loaded IO plugin (a debugger, for example). Most plugins provide help mes-
sages with =!? or =!help.
$ r2 −d / bin / l s
> =! help ; handled by the IO p l u g i n
The meaning of the arguments (iter, addr, size) depends on the specific com-
mand. As a rule of thumb, most commands take a number as an argument
to specify the number of bytes to work with, instead of the currently defined
block size. Some commands accept math expressions or strings.
> px 0x17 ; show 0x17 bytes i n hexs at c u r r e n t seek
> s base+0x33 ; s e e k s to f l a g ' base ' p l u s 0x33
> / lib ; s ea rc h f o r ' l i b ' s t r i n g .
113
> p8 10 @ 0x4010 ; show 10 bytes at o f f s e t 0x4010
> f patata @ 0x10 ; s e t ' patata ' f l a g at o f f s e t 0x10
Using @@ you can execute a single command on a list of flags matching the
glob. You can think of this as a foreach operation:
> s 0
> / lib ; search ' lib ' s t r i n g
> p8 20 @@ hit0_∗ ; show 20 h e x p a i r s at each s e a r ch h i t
The > operation is used to redirect the output of a command into a file
(overwriting it if it already exists).
> pr > dump . bin ; dump ' raw ' bytes o f c u r r e n t block to f i l e named
'dump . bin '
> f > f l a g s . txt ; dump f l a g l i s t to ' f l a g s . txt '
The | operation (pipe) is similar to what you are used to expect from it in a
*NIX shell: an output of one command as input to another.
[ 0 x4A13B8C0]> f | grep s e c t i o n | grep t e x t
0 x0805f3b0 512 s e c t i o n . _text
0x080d24b0 512 s e c t i o n . _text_end
You can pass several commands in a single line by separating them with a
semicolon ; :
> px ; dr
Using _, you can print the result that was obtained by the last command.
[ 0 x00001060]> axt 0x00002004
main 0x1181 [DATA] l e a r d i , s t r . argv__2d_ : __s
[ 0 x00001060]> _
main 0x1181 [DATA] l e a r d i , s t r . argv__2d_ : __s
Dietline
Radare2 comes with the lean readline-like input capability through the lean
library to handle the command edition and history navigation. It allows users
to perform cursor movements, search the history, and implements autocomple-
tion. Moreover, due to the radare2 portability, dietline provides the uniform
experience among all supported platforms. It is used in all radare2 subshells
- main prompt, SDB shell, visual prompt, and offsets prompt. It also imple-
ments the most common features and keybindings compatible with the GNU
Readline.
Dietline supports two major configuration modes : Emacs-mode and Vi-mode.
It also supports the famous Ctrl−R reverse history search. Using TAB key it
allows to scroll through the autocompletion options.
114
Autocompletion
In the every shell and radare2 command autocompletion is supported. There
are multiple modes of it - files, flags, and SDB keys/namespaces. To provide
the easy way to select possible completion options the scrollable popup widget
is available. It can be enabled with scr .prompt.popup, just set it to the true.
Moving
• Ctrl−a - move to the beginning of the line
• Ctrl−e - move to the end of the line
• Ctrl−b - move one character backward
• Ctrl−f - move one character forward
Deleting
• Ctrl−w - delete the previous word
• Ctrl−u - delete the whole line
• Ctrl−h - delete a character to the left
• Ctrl−d - delete a character to the right
• Alt−d - cuts the character after the cursor
History
• Ctrl−r - the reverse search in the command history
115
Vi mode
Radare2 also comes with in vi mode that can be enabled by toggling
scr.prompt.vi. The various keybindings available in this mode are:
Moving
• j - acts like up arrow key
• k - acts like down arrow key
• a - move cursor forward and enter into insert mode
• I - move to the beginning of the line and enter into insert mode
• A - move to the end of the line and enter into insert mode
• ^ - move to the beginning of the line
• 0 - move to the beginning of the line
• $ - move to the end of the line
• h - move one character backward
• l - move one character forward
• b - move cursor to the beginning of the current word, of if between word
boundaries, to the beginning of the previous word.
• B - same as b, but only counting white-space as word boundary
• e - move cursor the end of the current word, or if between boundaries,
to the end of the next word
• E - same as e, but only counting white-space as word boundary
• w - move cursor to the beginning of the next word
• W - same as w, but only counting white-space as word boundary
• f<char> - move cursor forward to the first <char> found. For example fj
will move the cursor to the first j character found (if it found one)
• F<char> - same as f<char>, but search backwards
• t<char> - same as f<char> but stop before <char>. For example tj will
move the cursor forward to the character just before j
• T<char> - same as t<char>, but search backwards
116
• C - same as D, but enter insert mode after
• dd - delete the whole line (from any position)
• cc - same as dd, but enter insert mode after
• dh - delete a character to the left
• dl - delete a character to the right
• d$ - same as D
• d^ - delete from the current cursor position to the beginning of line
• de - kill from point to the end of the current word, or if between words,
to the end of the next word. Word boundaries are the same as forward-
word.
• df<char> - delete from current position to the position of the first <char>
encountered
• dF<char> - same as df<char>, but delete backwards
• dt<char> - delete from current position to the position of the character
right before the first <char> encountered
• dT<char> - same as dt<char>, but delete backwards
• di” - delete everything between two ” characters
• di' - delete everything between two ' characters
• di( - delete everything between ( and ) characters
• di[ - delete everything between [ and ] characters
• di{ - delete everything between { and } characters
• di< - delete everything between < and > characters
• p - yank the top of the kill ring into the buffer at point.
• c - all d commands have their c counterpart which enters insert mode
after deleting
Other
• ~ - swap the case of the current character and move one character for-
ward
If you are finding it hard to keep track of which mode you are in, just set
scr.prompt.mode=true to update the color of the prompt based on the vi-mode.
Seeking
To move around the file we are inspecting we will need to change the offset at
which we are using the s command.
The argument is a math expression that can contain flag names, parenthesis,
addition, subtraction, multiplication of immediates of contents of memory
using brackets.
Some example commands:
117
[ 0 x00000000]> s 0x10
[ 0 x00000010]> s+4
[ 0 x00000014]> s−
[ 0 x00000010]> s+
[ 0 x00000014]>
Observe how the prompt offset changes. The first line moves the current offset
to the address 0x10.
The second does a relative seek 4 bytes forward.
And finally, the last 2 commands are undoing, and redoing the last seek op-
erations.
Instead of using just numbers, we can use complex expressions, or basic arith-
metic operations to represent the address to seek.
To do this, check the ?$? Help message which describes the internal variables
that can be used in the expressions. For example, this is the same as doing
s+4 .
[ 0 x00000000]> s $$+4
From the debugger (or when emulating) we can also use the register names as
references. They are loaded as flags with the .dr∗ command, which happens
under the hood.
[ 0 x00000000]> s rsp+0x40
Here’s the full help of the s command. We will explain in more detail below.
[ 0 x00000000]> s ?
Usage : s # Help f o r the seek commands . See ?$? to s e e a l l v a r i a b l e s
| s p r i n t c u r r e n t address
| s addr seek to address
| s . [ ? ] hexoff seek honoring a base from core−>o f f s e t
| s : pad p r i n t c u r r e n t address with N padded z e r o s
( d e f a u l t s to 8)
| s− undo seek
| s−∗ r e s e t undo seek h i s t o r y
| s− n seek n bytes backward
| s−−[n ] seek b l o c k s i z e bytes backward (/=n)
| s+ redo seek
| s+ n seek n bytes forward
| s++[n ] seek b l o c k s i z e bytes forward (/=n)
| s [ j ∗=!] l i s t undo seek h i s t o r y (JSON, =l i s t , ∗r2 , !=names ,
s==)
| s / DATA s e a r c h f o r next o c c u r r e n c e o f 'DATA' ( s e e /?)
| s /x 9091 s e a r c h f o r next o c c u r r e n c e o f \x90\x91
| sa ([+−] addr ) seek to block−s i z e a l i g n e d address ( addr=$$ i f not
specified )
| sb ( [ addr ] ) seek to the beginning o f the b a s i c block
118
| sC [ ? ] s t r i n g seek to comment matching given s t r i n g
| sd ( [ addr ] ) show d e l t a seek compared to a l l p o s s i b l e r e f e r e n c e
bases
| sf seek to next f u n c t i o n ( f−>addr+f−>s i z e )
| s f function seek to address o f s p e c i f i e d f u n c t i o n
| sf . seek to the beginning o f c u r r e n t f u n c t i o n
| sfp seek to the f u n c t i o n prelude checking back
b l o c k s i z e bytes
| sff seek to the n e a r e s t f l a g backwards ( u s e s fd and
ignored the d e l t a )
| sg /sG seek begin ( sg ) or end (sG) o f s e c t i o n or f i l e
| sh open a b a s i c s h e l l ( aims to support b a s i c p o s i x
syntax )
| s l [ ? ] [+−] l i n e seek to l i n e
| sn/sp ( [ nkey ] ) seek to next / prev l o c a t i o n , as s p e c i f i e d by
s c r . nkey
| snp seek to next f u n c t i o n prelude
| spp seek to prev f u n c t i o n prelude
| so ( [ [ − ]N] ) seek to N opcode ( s ) forward ( or backward when N i s
n e g a t i v e ) , N=1 by d e f a u l t
| s r PC seek to r e g i s t e r ( or r e g i s t e r a l i a s ) value
| ss [ ? ] seek s i l e n t l y ( without adding an entry to the seek
history )
| sort [ f i l e ] s o r t the c on t e n t s o f the f i l e
If you want to inspect the result of a math expression, you can evaluate it
using the ? command. Simply pass the expression as an argument. The result
can be displayed in hexadecimal, decimal, octal or binary formats.
> ? 0x100+200
0x1C8 ; 456d ; 710o ; 1100 1000
There are also subcommands of ? that display the output in one specific format
(base 10, base 16 ,…). See ?v and ?vi.
In the visual mode, you can press u (undo) or U (redo) inside the seek history
to return back to previous or forward to the next location.
Open file
As a test file, let’s use a simple hello_world.c compiled in Linux ELF format.
After we compile it let’s open it with radare2:
$ r2 hello_world
119
And it is time to go deeper.
Partial Seeks
Another important s subcommand is the s .. one which permits to seek to
another address taking the higher nibbles of the current address as reference,
this technique works great for kernel, aslr or large binaries where you really
don’t want to type different or large numbers everytime.
120
[ 0 x100003a84]> s ..00
[ 0 x100003a00]> s . . 3 b00
[ 0 x100003b00]> s ..0000
[ 0 x100000000]> s 0
[ 0 x00000000]>
Dereferencing pointers
Sometimes programs store pointers in memory, these needs to be derefenced
in order to follow them and see what are they pointing at.
The r2 shell provides many ways to do this, that’s because reading pointers
from memory can be tricky and powerful it gives the power to the user to do
it in the way that works the best for them.
Use the ∗ command, which acts like in C. It reads the the value from the given
address ($$ stands for current seek) and honors asm.bits and cfg.bigendian.
[ 0 x004000c8]> s `∗$$ `
[ 0 x0040032e]>
This is the help message from the * command, which can be used as an alias
for wv to write a value or to read from memory like the brackets syntax would
do on any math expression in r2:
[ 0 x100003a84]> ∗
Usage : ∗<addr >[=[0x ] value ] Pointer read / w r i t e data / v a l u e s
| ∗ entry0=cc w r i t e trap i n e n t r y p o i n t
| ∗ entry0+10=0x804800 w r i t e value i n d e l t a address
| ∗ entry0 read byte at given address
| ∗/ end m u l t i l i n e comment . ( use ' / ∗ ' to s t a r t
m u l i t i l i n e comment
[ 0 x100003a84]>
Note that * can be also expressed as a math expression using the brackets
syntax:
[ 0 x100003a84]> ?v [ $$ ]
0 xa9ba6ffcd503237f
[ 0 x100003a84]>
Alternatively you can always use data analysis (ad) and the periscoped hex-
dump (pxr) to analyze linked lists, nested structures, pointers and more!
There are several more commands and features to follow and analyze pointers:
• aav : analyze all values pointing to code or data in a given range
• aaw : analyze all meta words (defined by Cd) as pointers to code
• pdp : disassemble following pointers in stack for ropchain gadgets
121
• pxw/pxq : word/qword hexdumps
• ahp : set pointer hints for analysis
• :iP : diversity pointer infromation from
• pxt : delta pointer table dumping, handy for manual switch table anal-
ysis
Block Size
The block size determines how many bytes radare2 commands will process
when not given an explicit size argument. You can temporarily change the
block size by specifying a numeric argument to the print commands. For
example px 20.
[ 0 x00000000]> b?
Usage : b [ f ] [ arg ] # Get/ Set block s i z e
| b 33 s e t block s i z e to 33
| b e i p+4 numeric argument can be an e x p r e s s i o n
| b d i s p l a y c u r r e n t block s i z e
| b+3 i n c r e a s e b l o c k s i z e by 3
| b−16 d e c r e a s e b l o c k s i z e by 16
| b∗ d i s p l a y c u r r e n t block s i z e i n r2 command
| bf f o o s e t block s i z e to f l a g s i z e
| bj d i s p l a y block s i z e i n f o r m a t i o n i n JSON
| bm 1M s e t max block s i z e
The bf command is used to change the block size to value specified by a flag.
For example, in symbols, the block size of the flag represents the size of the
function. To make that work, you have to either run function analysis af
(which is included in aa) or manually seek and define some functions e.g. via
Vd.
[ 0 x00000000]> bf sym . main # block s i z e = s i z e o f (sym . main )
[ 0 x00000000]> pD @ sym . main # d i s a s s e m b l e sym . main
You can combine two operations in a single pdf command. Except that pdf
neither uses nor affects global block size.
[ 0 x00000000]> pdf @ sym . main # d i s a s s e m b l e sym . main
Another way around is to use special variables $FB and $FS which denote
Function’s Beginning and Size at the current seek. Read more about Usable
variables.
122
[ 0 x00000000]> s sym . main + 0x04
[ 0 x00001ec9]> pD @ $FB ! $FS # d i s a s s e m b l e c u r r e n t f u n c t i o n
/ 2 1 1 : i n t main ( i n t argc , char ∗∗ argv , char ∗∗envp ) ;
| 0 x00001ec5 55 push rbp
| 0 x00001ec6 4889 e5 mov rbp , rsp
| 0 x00001ec9 4881 ecc0000000 sub rsp , 0xc0
...
\ 0 x00001f97 c3 ret
Note: don’t put space after ! size designator. See also Command Format.
Sections
The concept of sections is tied to the information extracted from the binary.
We can display this information by using the i command.
Displaying information about sections:
[ 0 x00005310]> i S
[ Sections ]
00 0x00000000 0 0x00000000 0 −−−−
01 0x00000238 28 0x00000238 28 −r−− . interp
02 0x00000254 32 0x00000254 32 −r−− . note . ABI_tag
03 0x00000278 176 0x00000278 176 −r−− . gnu . hash
04 0x00000328 3000 0x00000328 3000 −r−− . dynsym
05 0 x00000ee0 1412 0 x00000ee0 1412 −r−− . dynstr
06 0x00001464 250 0x00001464 250 −r−− . gnu . v e r s i o n
07 0x00001560 112 0x00001560 112 −r−− . gnu . version_r
08 0x000015d0 4944 0x000015d0 4944 −r−− . r e l a . dyn
09 0x00002920 2448 0x00002920 2448 −r−− . rela . plt
10 0x000032b0 23 0x000032b0 23 −r−x . init
...
As you may know, binaries have sections and maps. The sections define the
contents of a portion of the file that can be mapped in memory (or not). What
is mapped is defined by the segments.
Before the IO refactoring done by condret, the S command was used to manage
what we now call maps. Currently the S command is deprecated because iS
and om should be enough.
Firmware images, bootloaders and binary files usually place various sections of
a binary at different addresses in memory. To represent this behavior, radare
offers the iS. Use iS? to get the help message. To list all created sections use iS
(or iSj to get the json format). The iS= will show the region bars in ascii-art.
You can create a new mapping using the om subcommand as follows:
om fd vaddr [ s i z e ] [ paddr ] [ rwx ] [ name ]
For Example:
123
[ 0 x0040100]> om 4 0x00000100 0x00400000 0x0001ae08 rwx t e s t
You can also use om command to view information about mapped sections:
[ 0 x00401000]> om
6 fd : 4 +0x0001ae08 0x00000100 − 0 x004000ff rwx test
5 fd : 3 +0x00000000 0x00000000 − 0 x0000055f r−− fmap .LOAD0
4 fd : 3 +0x00001000 0x00001000 − 0x000011e4 r−x fmap .LOAD1
3 fd : 3 +0x00002000 0x00002000 − 0 x0000211f r−− fmap .LOAD2
2 fd : 3 +0x00002de8 0x00003de8 − 0 x0000402f r−− fmap .LOAD3
1 fd : 4 +0x00000000 0x00004030 − 0x00004037 rw− mmap.LOAD3
Use om? to get all the possible subcommands. To list all the defined maps use
om (or omj to get the json format or om∗ to get the r2 commands format). To
get the ascii art view use om=.
It is also possible to delete the mapped section using the om−mapid command.
For Example:
[ 0 x00401000]> om−6
Mapping Files
Radare’s I/O subsystem allows you to map the contents of files into the same
I/O space used to contain a loaded binary. New contents can be placed at
random offsets.
The o command permits the user to open a file, this is mapped at offset 0
unless it has a known binary header and then the maps are created in virtual
addresses.
Sometimes, we want to rebase a binary, or maybe we want to load or map the
file in a different address.
When launching r2, the base address can be changed with the −B flag. But
you must notice the difference when opening files with unknown headers, like
bootloaders, so we need to map them using the −m flag (or specifying it as
argument to the o command).
radare2 is able to open files and map portions of them at random places in
memory specifying attributes like permissions and name. It is the perfect
basic tooling to reproduce an environment like a core file, a debug session, by
also loading and mapping all the libraries the binary depends on.
Opening files (and mapping them) is done using the o (open) command. Let’s
read the help:
124
[ 0 x00000000]> o?
| Usage : o [ com− ] [ f i l e ] ( [ offset ])
| o l i s t opened f i l e s
| o−1 close f i l e descriptor 1
| o−!∗ c l o s e a l l opened f i l e s
| o−− close a l l f i l e s , analysis , b i n f i l e s ,
f l a g s , same as ! r2 −−
| o [ file ] open [ f i l e ] f i l e i n read−only
| o+ [ f i l e ] open f i l e i n read−w r i t e mode
| o [ f i l e ] 0x4000 rwx map f i l e at 0x4000
| oa [ −] [A] [B] [ f i l e n a m e ] S p e c i f y arch and b i t s f o r given f i l e
| oq l i s t a l l open f i l e s
| o∗ l i s t opened f i l e s i n r2 commands
| o . [ len ] open a malloc : / / [ l e n ] copying the bytes
from c u r r e n t o f f s e t
| o= list opened f i l e s ( a s c i i −a r t bars )
| ob [ ? ] [ lbdos ] [ . . . ] list opened binary f i l e s backed by fd
| oc [ f i l e ] open c o r e f i l e , l i k e r e l a u n c h i n g r2
| of [ f i l e ] open f i l e and map i t at addr 0 as
read−only
| o i [ −| idx ] a l i a s f o r o , but using index i n s t e a d o f
fd
| oj [ ? ] l i s t opened f i l e s i n JSON format
| oL l i s t a l l IO plugins registered
| om [ ? ] create , l i s t , remove IO maps
| on [ f i l e ] 0x4000 map raw f i l e at 0x4000 ( no r_bin
involved )
| oo [ ? ] reopen c u r r e n t f i l e ( k i l l+f o r k i n
debugger )
| oo+ reopen c u r r e n t f i l e i n read−w r i t e
| ood [ r ] [ a r g s ] reopen i n debugger mode ( with a r g s )
| oo [bnm] [ . . . ] s e e oo? f o r help
| op [ fd ] p r i o r i t i z e given fd ( s e e a l s o ob )
| ox fd fdx exchange the d e s c s o f fd and fdx and
keep the mapping
4 libraries
Map a file:
[ 0 x00001190]> o / bin / zsh 0x499999
125
[ 0 x00000000]> o
− 6 / bin / l s @ 0x0 ; r
− 10 / l i b / ld−l i n u x . so . 2 @ 0x100000000 ; r
− 14 / bin / zsh @ 0x499999 ; r
Unmap files using the o− command. Pass the required file descriptor to it as
an argument:
[ 0 x00000000]> o−14
You can also view the ascii table showing the list of the opened files:
[ 0 x00000000]> ob=
Print Modes
One of the key features of radare2 is displaying information in many formats.
The goal is to offer a selection of display choices to interpret binary data in
the best possible way.
Binary data can be represented as integers, shorts, longs, floats, timestamps,
hexpair strings, or more complex formats like C structures, disassembly list-
ings, decompilation listing, be a result of an external processing…
Below is a list of available print modes listed by p?:
[ 0 x00005310]> p?
| Usage : p[=68 abcdDfiImrstuxz ] [ arg | l e n ] [ @addr ]
| p [ b |B| xb ] [ l e n ] ( [ S ] ) bindump N b i t s s k i p p i n g S bytes
| p [ i I ] [ df ] [ l e n ] p r i n t N ops / bytes ( f=func ) ( s e e p i ? and
pdi )
| p [kK] [ l e n ] p r i n t key i n randomart (K i s f o r mosaic )
| p − [ ? ] [ jh ] [ mode ] bar | j s o n | histogram b l o c k s (mode :
e ? s e a r ch . i n )
| p2 [ l e n ] 8x8 2bpp−t i l e s
| p3 [ f i l e ] p r i n t stereogram (3D)
| p6 [ de ] [ l e n ] base64 decode / encode
| p8 [ ? ] [ j ] [ l e n ] 8 b i t hexpair l i s t o f bytes
| p = [ ? ] [ bep ] [N] [ L ] [ b ] show entropy / p r i n t a b l e chars / chars bars
| pa [ edD ] [ arg ] pa : assemble pa [dD ] : disasm or pae : e s i l
from hex
| pA[ n_ops ] show n_ops address and type
| pb [ ? ] [ n ] bitstream o f N b i t s
| pB [ ? ] [ n ] bitstream o f N bytes
| pc [ ? ] [ p ] [ l e n ] output C ( or python ) format
| pC [ aAcdDxw ] [ rows ] p r i n t disassembly i n columns ( s e e hex . c o l s
and pdi )
126
| pd [ ? ] [ s z ] [ a ] [ b ] d i s a s s e m b l e N opcodes ( pd ) or N bytes (pD)
| pf [ ? ] [ . nam ] [ fmt ] p r i n t formatted data ( pf . name , pf . name
$<expr >)
| pF [ ? ] [ apx ] p r i n t asn1 , pkcs7 or x509
| pg [ ? ] [ x y w h ] [ cmd ] c r e a t e new v i s u a l gadget or p r i n t i t ( s e e
pg? f o r d e t a i l s )
| ph [ ? ] [ = | hash ] ( [ l e n ] ) c a l c u l a t e hash f o r a block
| pj [ ? ] [ l e n ] p r i n t as indented JSON
| pm[ ? ] [ magic ] p r i n t l i b m a g i c data ( s e e pm? and /m?)
| po [ ? ] hex p r i n t o p e r a t i o n a p p l i e d to block ( s e e po ?)
| pp [ ? ] [ s z ] [ l e n ] p r i n t patterns , s e e pp? f o r more help
| pq [ ? ] [ i s ] [ l e n ] p r i n t QR code with the f i r s t Nbytes
| pr [ ? ] [ g l x ] [ l e n ] p r i n t N raw bytes ( i n l i n e s or hexblocks ,
' g ' unzip )
| ps [ ? ] [ pwz ] [ l e n ] p r i n t p a s c a l /wide/ zero−terminated s t r i n g s
| pt [ ? ] [ dn ] [ l e n ] p r i n t d i f f e r e n t timestamps
| pu [ ? ] [ w] [ l e n ] p r i n t N u r l encoded bytes (w=wide )
| pv [ ? ] [ jh ] [ mode ] show v a r i a b l e / p o i n t e r / value i n memory
| pwd d i s p l a y c u r r e n t working d i r e c t o r y
| px [ ? ] [ owq ] [ l e n ] hexdump o f N bytes ( o=o c t a l , w=32b i t ,
q=64 b i t )
| pz [ ? ] [ l e n ] p r i n t zoom view ( s e e pz? f o r help )
[ 0 x00005310]>
Tip: when using json output, you can append the ~{} to the command to get
a pretty-printed version of the output:
[ 0 x00000000]> o j
[ { ” r a i s e d ” : f a l s e , ” fd ” : 5 6 3 2 8 0 , ” u r i ” : ” malloc : / / 5 1 2 ” , ” from ” : 0 , ” w r i t a b l e ” : true , ” s i z
[ 0 x00000000]> o j ~{}
[
{
” raised ”: false ,
” fd ” : 563280 ,
” u r i ” : ” malloc : / / 5 1 2 ” ,
”from ” : 0 ,
” w r i t a b l e ” : true ,
” s i z e ” : 512 ,
” overlaps ”: f a l s e
}
]
For more on the magical powers of ~ see the help in ?@?, and the Command
Format chapter earlier in the book.
Hexadecimal View
px gives a user-friendly output showing 16 pairs of numbers per row with
offsets and raw representations:
127
Figure 6: hexprint
Figure 7: wordprint
[ 0 x00404888]> p8 16
31 ed4989d15e4889e24883e4f0505449
Figure 8: pxq
Date/Time Formats
Currently supported timestamp output modes are:
[ 0 x00404888]> pt ?
| Usage : pt [ dn ] p r i n t timestamps
| pt . p r i n t c u r r e n t time
| pt p r i n t UNIX time (32 b i t ` c f g . bigendian `) Since January 1 , 1970
| ptd p r i n t DOS time (32 b i t ` c f g . bigendian `) Since January 1 , 1980
| pth p r i n t HFS time (32 b i t ` c f g . bigendian `) Since January 1 , 1904
| ptn p r i n t NTFS time (64 b i t ` c f g . bigendian `) Since January 1 , 1601
For example, you can ‘view’ the current buffer as timestamps in the ntfs time:
[ 0 x08048000]> e c f g . bigendian = f a l s e
128
[ 0 x08048000]> pt 4
2 9 : 0 4 : 3 2 9 4 8 2 3 : 1 2 : 3 6 +0000
[ 0 x08048000]> e c f g . bigendian = t r u e
[ 0 x08048000]> pt 4
2 0 : 0 5 : 1 3 0 0 1 0 9 : 2 9 : 2 1 +0000
As you can see, the endianness affects the result. Once you have printed a
timestamp, you can grep the output, for example, by year:
[ 0 x08048000]> pt ~1974 | wc −l
15
[ 0 x08048000]> pt ~2022
2 7 : 0 4 : 2 0 2 2 1 6 : 1 5 : 4 3 +0000
The default date format can be configured using the cfg.datefmt variable. For-
matting rules for it follow the well known strftime(3) format. Check the
manpage for more details, but these are the most important:
%a The abbreviated name o f the day o f the week according to the
current l o c a l e .
%A The f u l l name o f the day o f the week according to the c u r r e n t
locale .
%d The day o f the month as a decimal number ( range 01 to 31) .
%D Equivalent to %m/%d/%y . (—Yecchfor Americans only ) .
%H The hour as a decimal number using a 24−hour c l o c k ( range 00 to
23) .
%I The hour as a decimal number using a 12−hour c l o c k ( range 01 to
12) .
%m The month as a decimal number ( range 01 to 12) .
%M The minute as a decimal number ( range 00 to 59) .
%p Either ”AM” or ”PM” according to the given time value .
%s The number o f seconds s i n c e the Epoch , 1970−01−01 0 0 : 0 0 : 0 0
+0000 (UTC) . (TZ)
%S The second as a decimal number ( range 00 to 60) . (The range i s
up to 60 to allow f o r o c c a s i o n a l l e a p seconds . )
%T The time i n 24−hour n o t a t i o n (%H:%M:%S) . (SU)
%y The year as a decimal number without a century ( range 00 to 99) .
%Y The year as a decimal number i n c l u d i n g the century .
%z The +hhmm or −hhmm numeric timezone ( that i s , the hour and
minute o f f s e t from UTC) . (SU)
%Z The timezone name or a b b r e v i a t i o n .
Basic Types
There are print modes available for all basic types. If you are interested in a
more complex structure, type pf?? for format characters and pf??? for examples:
[ 0 x00499999]> pf ??
| pf : pf [ . k [ . f [=v ] ] | [ v ] ] | [ n ] | [ 0 | cnt ] [ fmt ] [ a0 a1 . . . ]
| Format :
| b byte ( unsigned )
129
| B r e s o l v e enum b i t f i e l d ( s e e t ?)
| c char ( s i g n e d byte )
| C byte i n decimal
| d 0xHEX value (4 bytes ) ( s e e ' i ' and ' x ' )
| D d i s a s s e m b l e one opcode
| e temporally swap endian
| E r e s o l v e enum name ( s e e t ?)
| f f l o a t value (4 bytes )
| F double value (8 bytes )
| i s i g n e d i n t e g e r value (4 bytes ) ( s e e ' d ' and ' x ' )
| n next char s p e c i f i e s s i z e o f s i g n e d value ( 1 , 2 , 4 or 8
byte ( s ) )
| N next char s p e c i f i e s s i z e o f unsigned value ( 1 , 2 , 4 or 8
byte ( s ) )
| o o c t a l value (4 byte )
| p p o i n t e r r e f e r e n c e ( 2 , 4 or 8 bytes )
| q quadword (8 bytes )
| r CPU r e g i s t e r ` pf r ( eax ) plop `
| s 32 b i t p o i n t e r to s t r i n g (4 bytes )
| S 64 b i t p o i n t e r to s t r i n g (8 bytes )
| t UNIX timestamp (4 bytes )
| T show Ten f i r s t bytes o f b u f f e r
| u uleb128 ( v a r i a b l e l e n g t h )
| w word (2 bytes unsigned s h o r t i n hex )
| x 0xHEX value and f l a g ( fd @ addr ) ( s e e ' d ' and ' i ' )
| X show formatted h e x p a i r s
| z n u l l terminated s t r i n g
| Z n u l l terminated wide s t r i n g
| ? data s t r u c t u r e ` pf ? ( struct_name ) example_name`
| ∗ next char i s p o i n t e r ( honors asm . b i t s )
| + t o g g l e show f l a g s f o r each o f f s e t
| : s k i p 4 bytes
| . s k i p 1 byte
| ; rewind 4 bytes
| , rewind 1 byte
Use triple-question-mark pf??? to get some examples using print format strings.
[ 0 x00499999]> pf ???
| pf : pf [ . k [ . f [=v ] ] | [ v ] ] | [ n ] | [ 0 | cnt ] [ fmt ] [ a0 a1 . . . ]
| Examples :
| pf 3 x i f o o bar 3−array o f s t r u c t ,
each with named f i e l d s : ' foo ' as hex , and ' bar ' as i n t
| pf B ( BitFldType )arg_name` b i t f i e l d type
| pf E (EnumType)arg_name` enum type
| pf . obj xxdz prev next s i z e name Define the obj format
as xxdz
| pf obj=xxdz prev next s i z e name Same as above
| pf ∗z∗ i ∗w nb name blob Print the p o i n t e r s
with given l a b e l s
| pf iwq f o o bar t r o l l Print the iwq format
with foo , bar , t r o l l as the r e s p e c t i v e names f o r the f i e l d s
| pf 0iwq f o o bar t r o l l Same as above , but
c o n s i d e r e d as a union ( a l l f i e l d s at o f f s e t 0)
130
| pf . plop ? ( t r o l l ) mystruct Use s t r u c t u r e t r o l l
previously defined
| p f j . plop @ 0x14 Apply format o b j e c t
at the given o f f s e t
| pf 10 x i z p o i n t e r l e n g t h s t r i n g Print a s i z e 10 array
o f the x i z s t r u c t with i t s f i e l d names
| pf 5sqw s t r i n g quad word Print an array with
sqw s t r u c t along with i t s f i e l d names
| pf { i n t e g e r }? ( b i f c ) Print i n t e g e r times
the f o l l o w i n g format ( b i f c )
| pf [ 4 ]w[ 7 ] i Print an array o f 4
words and then an array o f 7 i n t e g e r s
| pf i c . . . ? i f o o bar ”( pf xw yo f o o ) t r o l l ” yo Print nested
anonymous s t r u c t u r e s
| pf ; . . x Print value l o c a t e d 6
bytes from c u r r e n t o f f s e t
| pf [ 1 0 ] z [ 3 ] i [ 1 0 ] Zb Print an f i x e d s i z e
s t r , widechar , and var
| p f j +F @ 0x14 Print the content at
given o f f s e t with f l a g
| pf n2 p r i n t s i g n e d s h o r t (2
bytes ) value . Use N i n s t e a d o f n f o r p r i n t i n g unsigned v a l u e s
| pf [ 2 ] ? ( plop ) structname @ 0 P r i n t s an array o f
structs
| pf eqew bigWord b e e f Swap endianness and
p r i n t with given l a b e l s
| pf . f o o r r ( eax ) reg1 ( e i p ) reg2 Create o b j e c t
r e f e r e n c i n g to r e g i s t e r v a l u e s
| pf t t t r o l l plop p r i n t time stamps
with l a b e l s t r o l l and plop
[ 0 x4A13B8C0]> pf
0x00404888 = 837634432.000000
131
• pcA .bytes with instructions in comments
• pcs string
• pcS shellscript that reconstructs the bin
• pcj json
• pcJ javascript
• pco Objective-C
• pcp python
• pck kotlin
• pcr rust
• pcv JaVa
• pcV V (vlang.io)
• pcy yara
• pcz Swift
Strings
Strings are probably one of the most important entry points when starting to
reverse engineer a program because they usually reference information about
functions’ actions (asserts, debug or info messages…). Therefore, radare sup-
ports various string formats:
[ 0 x00000000]> ps ?
| Usage : ps [ bijqpsuwWxz+] [N] Print S t r i n g
| ps print string
| ps+[ j ] p r i n t l i b c++ std : : s t r i n g ( same−endian , a s c i i ,
zero−terminated )
| psb p r i n t s t r i n g s i n c u r r e n t block
| psi p r i n t s t r i n g i n s i d e c ur s e e k
132
| psj p r i n t s t r i n g i n JSON format
| psp [ j ] print pascal string
| psq a l i a s f o r pqs
| pss p r i n t s t r i n g i n s c r e e n ( wrap width )
| psu [ z j ] p r i n t u t f 1 6 unicode ( j s o n )
| psw [ j ] p r i n t 16 b i t wide s t r i n g
| psW[ j ] p r i n t 32 b i t wide s t r i n g
| psx show s t r i n g with escaped chars
| psz [ j ] p r i n t zero−terminated s t r i n g
Most strings are zero-terminated. Below there is an example using the debug-
ger to continue the execution of a program until it executes the ‘open’ syscall.
When we recover the control over the process, we get the arguments passed
to the syscall, pointed by %ebx. In the case of the ‘open’ call, it is a zero
terminated string which we can inspect using psz.
[ 0 x4A13B8C0]> dcs open
0 x4a14fc24 s y s c a l l ( 5 ) open ( 0x4a151c91 0x00000000 0x00000000 ) =
0xffffffda
[ 0 x4A13B8C0]> dr
eax 0 x f f f f f f d a esi 0 x f f f f f f f f eip 0 x4a14fc24
ebx 0x4a151c91 e d i 0x4a151be1 oeax 0x00000005
ecx 0x00000000 esp 0 xbfbedb1c e f l a g s 0x200246
edx 0x00000000 ebp 0xbfbedbb0 cPaZstIdor0 ( PZI )
[ 0 x4A13B8C0]>
[ 0 x4A13B8C0]> psz @ 0x4a151c91
/ e t c / l d . so . cache
This can be used to look at the arguments passed to a function. To achieve this,
simply pass a ‘format memory string’ as an argument to pf, and temporally
change the current seek position/offset using @. It is also possible to define
arrays of structures with pf. To do this, prefix the format string with a numeric
value. You can also define a name for each field of the structure by appending
them as a space-separated arguments list.
[ 0 x4A13B8C0]> pf 2∗xw p o i n t e r type @ esp
0x00404888 [ 0 ] {
pointer :
(∗0 x f f f f f f f f 8 9 4 9 e d 3 1 ) type : 0x00404888 = 0x8949ed31
0x00404890 = 0x48e2
}
133
0x00404892 [ 1 ] {
(∗0 x50f0e483 ) p o i n t e r : 0x00404892 = 0 x50f0e483
type : 0x0040489a = 0x2440
}
Disassembly
The pd command is used to disassemble code. It accepts a numeric value to
specify how many instructions should be disassembled. The pD command is
similar but instead of a number of instructions, it decompiles a given number
of bytes.
• d : disassembly N opcodes count of opcodes
• D : asm.arch disassembler bsize bytes
[ 0 x00404888]> pd 1
;−− entry0 :
0x00404888 31ed xor ebp , ebp
134
[ 0 x00005310]> e asm . arch=??
_dAe _8_16 6502 LGPL3 6502/NES/C64/Tamagotchi/T−1000
CPU
_dAe _8 8051 PD 8051 I n t e l CPU
_dA_ _16_32 arc GPL3 Argonaut RISC Core
a___ _16_32_64 arm . as LGPL3 as ARM Assembler ( use ARM_AS
environment )
adAe _16_32_64 arm BSD Capstone ARM d i s a s s e m b l e r
_dA_ _16_32_64 arm . gnu GPL3 Acorn RISC Machine CPU
_d__ _16_32 arm . winedbg LGPL2 WineDBG' s ARM d i s a s s e m b l e r
adAe _8_16 avr GPL AVR Atmel
adAe _16_32_64 bf LGPL3 Brainfuck
_dA_ _32 chip8 LGPL3 Chip8 d i s a s s e m b l e r
_dA_ _16 cr16 LGPL3 cr16 disassembly p l u g i n
_dA_ _32 cris GPL3 Axis Communications 32− b i t
embedded p r o c e s s o r
adA_ _32_64 dalvik LGPL3 AndroidVM Dalvik
ad__ _16 dcpu16 PD Mojang ' s DCPU−16
_dA_ _32_64 ebc LGPL3 EFI Bytecode
adAe _16 gb LGPL3 GameBoy(TM) ( z80−l i k e )
_dAe _16 h8300 LGPL3 H8/300 disassembly p l u g i n
_dAe _32 hexagon LGPL3 Qualcomm Hexagon (QDSP6) V6
_d__ _32 hppa GPL3 HP PA−RISC
_dAe _0 i4004 LGPL3 I n t e l 4004 m i c r o p r o c e s s o r
_dA_ _8 i8080 BSD I n t e l 8080 CPU
adA_ _32 java Apache Java bytecode
_d__ _32 lanai GPL3 LANAI
...
Currently there are 136 asm. configuration variables so we do not list them all.
135
Disassembly Syntax
The asm.syntax variable is used to change the flavor of the assembly syntax used
by a disassembler engine. To switch between Intel and AT&T representations:
e asm . syntax = i n t e l
e asm . syntax = a t t
Flags
Flags are conceptually similar to bookmarks. They associate a name with a
given offset in a file. Flags can be grouped into ‘flag spaces’. A flag space is a
namespace for flags, grouping together flags of similar characteristics or type.
Examples for flag spaces: sections, registers, symbols.
To create a flag:
[ 0 x4A13B8C0]> f flag_name @ o f f s e t
136
0 439 ∗ s t r i n g s
1 17 ∗ symbols
2 54 ∗ s e c t i o n s
3 20 ∗ segments
4 115 ∗ r e l o c s
5 109 ∗ imports
[ 0 x00005310]>
Local flags
Every flag name should be unique for addressing reasons. But it is quite a
common need to have the flags, for example inside the functions, with simple
and ubiquitous names like loop or return. For this purpose you can use so called
“local” flags, which are tied to the function where they reside. It is possible
to add them using f . command:
[ 0 x00003a04]> pd 10
| 0x00003a04 48 c705c9cc21 . mov qword [ 0 x002206d8 ] ,
0xffffffffffffffff ;
[ 0 x2206d8 :8]=0
| 0 x00003a0f c60522cc2100 . mov byte [ 0 x00220638 ] , 0 ;
[ 0 x220638 :1]=0
| 0x00003a16 83 f802 cmp eax , 2
| .−< 0x00003a19 0 f84880d0000 j e 0x47a7
| | 0 x00003a1f 83 f803 cmp eax , 3
| .−−< 0x00003a22 740 e j e 0x3a32
| || 0x00003a24 83 e801 sub eax , 1
|.−−−< 0x00003a27 0 f84ed080000 j e 0x431a
|||| 0x00003a2d e8fef8ffff c a l l sym . imp . abort ;
void abort ( void )
|||| ; CODE XREF from main (0 x3a22 )
||`−−> 0x00003a32 be07000000 mov e s i , 7
[ 0 x00003a04]> f . l o c a l f l a g @ 0x3a32
[ 0 x00003a04]> f .
0x00003a32 l o c a l f l a g [ main + 2 1 0 ]
[ 0 x00003a04]> pd 10
| 0x00003a04 48 c705c9cc21 . mov qword [ 0 x002206d8 ] ,
0xffffffffffffffff ;
[ 0 x2206d8 :8]=0
| 0 x00003a0f c60522cc2100 . mov byte [ 0 x00220638 ] , 0 ;
[ 0 x220638 :1]=0
| 0x00003a16 83 f802 cmp eax , 2
137
| .−< 0x00003a19 0 f84880d0000 j e 0x47a7
| | 0 x00003a1f 83 f803 cmp eax , 3
| .−−< 0x00003a22 740 e j e 0x3a32 ;
main . l o c a l f l a g
| || 0x00003a24 83 e801 sub eax , 1
|.−−−< 0x00003a27 0 f84ed080000 j e 0x431a
|||| 0x00003a2d e8fef8ffff c a l l sym . imp . abort ;
void abort ( void )
|||| ; CODE XREF from main (0 x3a22 )
||`−−> . l o c a l f l a g :
|||| ; CODE XREF from main (0 x3a22 )
||`−−> 0x00003a32 be07000000 mov e s i , 7
[ 0 x00003a04]>
Flag Zones
radare2 offers flag zones, which lets you label different offsets on the scrollbar,
for making it easier to navigate through large binaries. You can set a flag
zone on the current seek using:
[ 0 x00003a04]> f z f l a g −zone−name
Set scr. scrollbar=1 and go to the Visual mode, to see your flag zone appear on
the scrollbar on the right end of the window.
See fz? for more information.
Writing Data
Radare can manipulate a loaded binary file in many ways. You can resize the
file, move and copy/paste bytes, insert new bytes (shifting data to the end
of the block or file), or simply overwrite bytes. New data may be given as a
wide-string, assembler instructions, or the data may be read in from another
file.
Resize the file using the r command. It accepts a numeric argument. A
positive value sets a new size for the file. A negative one will truncate the file
to the current seek position minus N bytes.
r 1024 ; r e s i z e the f i l e to 1024 bytes
r −10 @ 33 ; s t r i p 10 bytes at o f f s e t 33
Write bytes using the w command. It accepts multiple input formats like
inline assembly, endian-friendly dwords, files, hexpair files, wide strings:
[ 0 x00404888]> w?
Usage : w[ x ] [ s t r ] [< f i l e ] [<<EOF] [ @addr ]
| w[ 1 2 4 8 ] [ + − ] [ n ] increment /decrement byte , word . .
| w foobar w r i t e s t r i n g ' foobar '
138
| w0 [ l e n ] w r i t e ' len ' bytes with value 0x00
| w6 [ de ] base64 /hex w r i t e base64 [ d ] ecoded or [ e ] ncoded s t r i n g
| wa [ ? ] push ebp w r i t e opcode , separated by ' ; ' ( use ' ” '
around the command)
| waf f . asm assemble f i l e and w r i t e bytes
| waF f . asm assemble f i l e and w r i t e bytes and show 'wx'
op with hexpair bytes o f assembled code
| wao [ ? ] op modify opcode ( change c o n d i t i o n a l o f jump .
nop , e t c )
| wA[ ? ] r 0 a l t e r /modify opcode at c u r r e n t seek ( s e e wA?)
| wb 010203 f i l l c u r r e n t block with c y c l i c h e x p a i r s
| wB[ −]0xVALUE s e t or unset b i t s with given value
| wc l i s t a l l w r i t e changes
| wc [ ? ] [ j i r +−∗?] w r i t e cache undo/commit/ r e s e t / l i s t ( i o . cache )
| wd [ o f f ] [ n ] d u p l i c a t e N bytes from o f f s e t at c u r r e n t seek
(memcpy) ( s e e y ?)
| we [ ? ] [ nNsxX ] [ arg ] extend w r i t e o p e r a t i o n s ( i n s e r t i n s t e a d o f
replace )
| wf [ f s ] −| f i l e w r i t e c o n te n t s o f f i l e at c u r r e n t o f f s e t
| wh r2 whereis /which s h e l l command
| wm f 0 f f s e t binary mask hexpair to be used as c y c l i c
w r i t e mask
| wo [ ? ] hex w r i t e i n block with o p e r a t i o n . 'wo? ' fmi
| wp [ ? ] −| f i l e apply radare patch f i l e . See wp? fmi
| wr 10 w r i t e 10 random bytes
| ws p s t r i n g w r i t e 1 byte f o r l e n g t h and then the s t r i n g
| wt [ f ] [ ? ] f i l e [ s z ] w r i t e to f i l e ( from c u r r e n t seek , b l o c k s i z e
or s z bytes )
| wts host : port [ s z ] send data to remote host : port v i a tcp : / /
| ww foobar w r i t e wide s t r i n g
' f \x00o\x00o\x00b\x00a\ x00r \x00 '
| wx [ ? ] [ f s ] 9090 w r i t e two i n t e l nops ( from w x f i l e or wxseek )
| wv [ ? ] e i p+34 w r i t e 32−64 b i t value honoring c f g . bigendian
| wz s t r i n g w r i t e z e r o terminated s t r i n g ( l i k e w + \x00 )
Some examples:
[ 0 x00000000]> wx 123456 @ 0x8048300
[ 0 x00000000]> wv 0x8048123 @ 0x8049100
[ 0 x00000000]> wa jmp 0x8048320
Write Over
The wo command (write over) has many subcommands, each combines the
existing data with the new data using an operator. The command is applied
to the current block. Supported operators include XOR, ADD, SUB…
[ 0 x4A13B8C0]> wo?
| Usage : wo [ asmdxoArl24 ] [ h e x p a i r s ] @ addr [ : b s i z e ]
| Example :
| wox 0x90 ; xor cur block with 0x90
| wox 90 ; xor cur block with 0x90
139
| wox 0x0203 ; xor cur block with 0203
| woa 02 03 ; add [ 0 2 0 3 ] [ 0 2 0 3 ] [ . . . ] to curblk
| woe 02 03 ; c r e a t e sequence from 2 to 255 with s t e p 3
| Supported o p e r a t i o n s :
| wow == w r i t e looped value ( a l i a s f o r 'wb' )
| woa += a d d i t i o n
| wos −= s u b t r a c t i o n
| wom ∗= multiply
| wod /= d i v i d e
| wox ^= xor
| woo |= or
| woA &= and
| woR random bytes ( a l i a s f o r ' wr $b ' )
| wor >>= s h i f t r i g h t
| wol <<= s h i f t l e f t
| wo2 2= 2 byte endian swap
| wo4 4= 4 byte endian swap
Rapatches
Human friendly text format to apply patches to binary files.
Patch format
Those patches must be written in files and the syntax looks like the following:
^# −> comments
140
. −> execute command
! −> execute command
OFFSET { code block }
OFFSET ” s t r i n g ”
OFFSET 01020304
OFFSET : assembly
+ { code } | ” s t r ” | 0 2 1 0 | : asm
Rapatch Example
This script will run the ?e .. command in r2 and then write the string ‘Hello’
at 0x200 offset
# rapatch example
: ? e h e l l o world
0x200 ” H e l l o ”
Applying rapatches
$ r2 −P rapatch . t x t t a r g e t−program . t x t
Zoom
The zoom is a print mode that allows you to get a global view of the whole
file or a memory map on a single screen. In this mode, each byte represents
file_size /block_size bytes of the file. Use the pz command, or just use Z in the
visual mode to toggle the zoom mode.
The cursor can be used to scroll faster through the zoom out view. Pressing
z again will zoom-in at the cursor position.
[ 0 x004048c5]> pz?
| Usage : pz [ l e n ] p r i n t zoomed b l o c k s ( f i l e s i z e /N)
| e zoom . maxsz max s i z e o f block
| e zoom . from s t a r t address
| e zoom . to end address
| e zoom . byte s p e c i f y how to c a l c u l a t e each byte
| pzp number o f p r i n t a b l e chars
| pzf count o f f l a g s i n block
| pzs s t r i n g s i n range
| pz0 number o f bytes with value ' 0 '
| pzF number o f bytes with value 0xFF
| pze c a l c u l a t e entropy and expand to 0−255 range
| pzh head ( f i r s t byte value ) ; This i s the d e f a u l t mode
141
Let’s see some examples:
[ 0 x08049790]> e zoom . byte=h
[ 0 x08049790]> pz // or d e f a u l t pzh
0x00000000 7 f 0 0 0000 e200 0000 146 e 6 f74 0300 0000
0x00000010 0000 0000 0068 2102 00 f f 2024 e8f0 007a
0x00000020 8 c00 18 c2 f f f f 0080 4421 41 c4 1500 5dff
0x00000030 f f 1 0 0018 0 f c 8 031a 000 c 8484 e970 8648
0x00000040 d68b 3148 348b 03a0 8 b0f c200 5d25 7074
0x00000050 7500 00 e1 f f e 8 58 f e 4dc4 00 e0 dbc8 b885
You can limit zooming to a range of bytes instead of the whole bytespace.
Change zoom.from and zoom.to eval variables:
[ 0 x00003a04]> e ? zoom .
zoom . byte : Zoom c a l l b a c k to c a l c u l a t e each byte ( See pz? f o r help )
zoom . from : Zoom s t a r t address
zoom . i n : S p e c i f y boundaries f o r zoom
zoom . maxsz : Zoom max s i z e o f block
zoom . to : Zoom end address
[ 0 x00003a04]> e zoom .
zoom . byte = h
zoom . from = 0
zoom . i n = i o . map
zoom . maxsz = 512
zoom . to = 0
142
Yank/Paste
Radare2 has an internal clipboard to save and write portions of memory loaded
from the current io layer.
This clipboard can be manipulated with the y command.
The two basic operations are
• copy (yank)
• paste
The yank operation will read N bytes (specified by the argument) into the
clipboard. We can later use the yy command to paste what we read before
into a file.
You can yank/paste bytes in visual mode selecting them with the cursor mode
(Vc) and then using the y and Y key bindings which are aliases for y and yy
commands of the command-line interface.
[ 0 x00000000]> y?
Usage : y [ ptxy ] [ l e n ] [ [@] addr ] # See wd? f o r memcpy, same as ' yf ' .
| y! open c f g . e d i t o r to e d i t the c l i p b o a r d
| y 16 0x200 copy 16 bytes i n t o c l i p b o a r d from 0x200
| y 16 @ 0x200 copy 16 bytes i n t o c l i p b o a r d from 0x200
| y 16 copy 16 bytes i n t o c l i p b o a r d
| y show yank b u f f e r i n f o r m a t i on ( s r c o f f l e n bytes )
| y∗ p r i n t i n r2 commands what ' s been yanked
| y f 64 0x200 copy f i l e 64 bytes from 0x200 from f i l e
| yfa f i l e copy copy a l l bytes from f i l e ( opens w/ i o )
| yfx 10203040 yank from h e x p a i r s ( same as ywx)
| yj p r i n t i n JSON commands what ' s been yanked
| yp p r i n t c o n te n ts o f c l i p b o a r d
| yq p r i n t c o n te n ts o f c l i p b o a r d i n h e x p a i r s
| ys p r i n t c o n te n ts o f c l i p b o a r d as s t r i n g
| yt 64 0x200 copy 64 bytes from c u r r e n t seek to 0x200
| ytf f i l e dump the c l i p b o a r d to given f i l e
| yw h e l l o world yank from s t r i n g
| ywx 10203040 yank from h e x p a i r s ( same as yfx )
| yx p r i n t c o n te n ts o f c l i p b o a r d i n hexadecimal
| yy 0x3344 paste c l i p b o a r d
| yz [ l e n ] copy nul−terminated s t r i n g ( up to b l o c k s i z e ) i n t o
clipboard
Sample session:
[ 0 x00000000]> s 0x100 ; seek at 0x100
[ 0 x00000100]> y 100 ; yanks 100 bytes from here
[ 0 x00000200]> s 0x200 ; seek 0x200
[ 0 x00000200]> yy ; p a s t e s 100 bytes
You can perform a yank and paste in a single line by just using the yt command
(yank-to). The syntax is as follows:
143
[ 0 x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B 0123456789AB
0x4A13B8C0 , 89 e0 e839 0700 0089 c7e8 e 2 f f . . . 9 . . . . . . . .
0x4A13B8CC, f f f f 81 c3 eea6 0100 8b83 08 f f . . . . . . . . . . . .
0x4A13B8D8 , f f f f 5a8d 2484 29 c2 . . Z. $ .) .
[ 0 x4A13B8C0]> x
offset 0 1 2 3 4 5 6 7 8 9 A B 0123456789AB
0x4A13B8C0 , 89 e0 e839 0700 0089 c7e8 e 2 f f . . . 9 . . . . . . . .
0x4A13B8CC, 89 e0 e839 0700 0089 8b83 08 f f . . . 9 . . . . . . . .
0x4A13B8D8 , f f f f 5a8d 2484 29 c2 . . Z. $ .) .
Comparing Bytes
For most generic reverse engineering tasks like finding the differences between
two binary files, which bytes has changed, find differences in the graphs of the
code analysis results, and other diffing operations you can just use radiff2:
$ r a d i f f 2 −h
Inside r2, the functionalities exposed by radiff2 are available with the c com-
mand.
c (short for “compare”) allows you to compare arrays of bytes from differ-
ent sources. The command accepts input in a number of formats and then
compares it against values found at current seek position.
[ 0 x00404888]> c ?
Usage : c [ ? dfx ] [ argument ] # Compare
| c [ string ] Compare a p l a i n with escaped chars s t r i n g
| c∗ [ s t r i n g ] Same as above , but p r i n t i n g r2 commands
instead
| c1 [ addr ] Compare 8 b i t s from c u r r e n t o f f s e t
| c2 [ value ] Compare a word from a math e x p r e s s i o n
| c4 [ value ] Compare a doubleword from a math
expression
| c8 [ value ] Compare a quadword from a math e x p r e s s i o n
| cat [ f i l e ] Show c o n t e n t s o f f i l e ( s e e pwd, l s )
| cc [ at ] Compares i n two hexdump columns o f block
size
| ccc [ at ] Same as above , but only showing d i f f e r e n t
lines
| ccd [ at ] Compares i n two disasm columns o f block
size
| ccdd [ at ] Compares decompiler output ( e
cmd . pdc=pdg | pdd )
| cf [ f i l e ] Compare c o n t e n t s o f f i l e at c u r r e n t seek
| cg [ ? ] [ o ] [ f i l e ] Graphdiff c u r r e n t f i l e and [ f i l e ]
| cu [ ? ] [ addr ] @at Compare memory hexdumps o f $$ and dst i n
unified d i f f
144
| cud [ addr ] @at U n i f i e d d i f f disasm from $$ and given
address
| cv [ 1 2 4 8 ] [ h e x p a i r s ] @at Compare 1 ,2 ,4 ,8 − byte ( s i l e n t r e t u r n i n $ ?)
| cV [ 1 2 4 8 ] [ addr ] @at Compare 1 ,2 ,4 ,8 − byte address co n t e n t s
( s i l e n t , r e t u r n i n $ ?)
| cw [ ? ] [ us ? ] [ . . . ] Compare memory watchers
| cx [ hexpair ] Compare hexpair s t r i n g ( use ' . ' as n i b b l e
wildcard )
| cx∗ [ hexpair ] Compare hexpair s t r i n g ( output r2
commands)
| cX [ addr ] Like ' cc ' but using h e x d i f f output
| cd [ d i r ] chdir
| cl | cls | clear Clear screen , ( c l e a r 0 to goto 0 , 0 only )
[ 0 x08048000]> cx 7 f 45 90 46
Compare 3/4 equal bytes
0x00000002 ( byte=03) 90 ' ' −> 4c 'L '
[ 0 x08048000]>
c8 compares a quadword from the current seek (in the example below,
0x00000000) against a math expression:
[ 0 x00000000]> c8 4
The number parameter can, of course, be math expressions which use flag
names and anything allowed in an expression:
[ 0 x00000000]> cx 7 f469046
145
You can use the compare command to find differences between a current block
and a file previously dumped to a disk:
$ r2 / bin / t r u e
[ 0 x08049A80]> s 0
[ 0 x08048000]> c f / bin / t r u e
Compare 512/512 equal bytes
Comparison Watchers
Watchers are used to record memory at 2 different points in time, then report
if and how it changed.
[ 0 x00000000]> cw?
Usage : cw [ a r g s ] Manage compare watchers ; See i f and how memory
changes
| cw?? Show more i n f o about watchers
| cw addr s z cmd Add a compare watcher
| cw [ ∗ q j ] [ addr ] Show compare watchers (∗=r2 commands , q=q u i e t )
| cwd [ addr ] Delete watcher
| cwr [ addr ] Revert watcher
| cwu [ addr ] Update watcher
To record the second state, use cwu. Now, when you run cw, the watcher will
report if the bytes changed and run the command given at creation with the
size and address. When an address is an optional argument, the command
will apply to all watchers if you don’t pass one.
# Introduce a change to the block o f data we ' r e watching
[ 0 x00000000]> wx 11223344
# Update a l l watchers
[ 0 x00000000]> cwu
# Show changes
[ 0 x00000000]> cw
0x00000000 modified
11223344
You may overwrite any watcher by creating another at the same address. This
will discard the existing watcher completely.
# Overwrite our e x i s t i n g watcher to d i s p l a y a bistream i n s t e a d o f
# hexpairs , and make the watched area l a r g e r
146
[ 0 x00000000]> cw 0 8 pB
# Check that i t ' s no l o n g e r ” modified ” as t h i s i s a new watcher
[ 0 x00000000]> cw
0x00000000
0001000100100010001100110100010000000000000000000000000000000000
Reverting State
When you create a watcher, the data read from memory is marked as “new”.
Updating the watcher with cwu will mark this data as “old”, and then read
the “new” data.
cwr will mark the current “old” state as being “new”, letting you reuse it as
your new base state when updating with cwu. Any existing “new” state from
running cwu previously is lost in this process. Showing a watcher without
updating will still run the command, but it will not report changes.
# Create a b a s i c watcher
[ 0 x00000000]> cw 0 4 p8
[ 0 x00000000]> cw
0x00000000
00000000
# Modify the memory and update the watcher
[ 0 x00000000]> wx 11223344
[ 0 x00000000]> cwu
# Watcher r e p o r t s m o d i f i c a t i o n
# The ”new” s t a t e i s 11223344 , and the ” old ” s t a t e i s 00000000
[ 0 x00000000]> cw
0x00000000 modified
11223344
# Revert the watcher
[ 0 x00000000]> cwr
# The ”new” s t a t e i s 00000000 again , and t h e r e i s no ” old ” s t a t e
# The watcher r e p o r t s no change s i n c e i t i s no l o n g e r up−to−date
[ 0 x00000000]> cw
0x00000000
11223344
Overlapping areas
Watched memory areas may overlap with no ill effects, but may have unex-
pected results if you update some but not others.
# Create a watcher that watches 512 bytes s t a r t i n g at 0
[ 0 x00000000]> cw 0 0x200 p8
# Create a watcher that watches 16 bytes s t a r t i n g at 0x100
[ 0 x00000000]> cw 0x100 0x10 p8
# Modify memory watched by both watchers
[ 0 x00000000]> wx 11223344 @ 0x100
# Watchers aren ' t updated , so they don ' t r e p o r t a change
147
[ 0 x00000000]> cw∗
cw 0x00000000 512 p8
cw 0x00000100 16 p8
# Update only the watcher at 0x100
[ 0 x00000000]> cwu 0x100
# Since only one watcher was updated , the other can ' t
# r e p o r t the change
[ 0 x00000000]> cw∗
cw 0x00000000 512 p8
cw 0x00000100 16 p8 # d i f f e r s
SDB
SDB stands for String DataBase. It’s a simple key-value database that only
operates with strings created by pancake. It is used in many parts of r2 to
have a disk and in-memory database which is small and fast to manage using
it as a hashtable on steroids.
SDB is a simple string key/value database based on djb’s cdb disk storage
and supports JSON and arrays introspection.
There’s also the sdbtypes: a vala library that implements several data struc-
tures on top of an sdb or a memcache instance.
148
SDB supports:
• namespaces (multiple sdb paths)
• atomic database sync (never corrupted)
• bindings for vala, luvit, newlisp and nodejs
• commandline frontend for sdb databases
• memcache client and server with sdb backend
• arrays support (syntax sugar)
• json parser/getter
Usage example
Let’s create a database!
$ sdb d h e l l o=world
$ sdb d h e l l o
world
Using arrays:
$ sdb − ' [ ] l i s t =1 ,2 ' ' [ 0 ] l i s t ' ' [ 0 ] l i s t=foo ' ' [ ] l i s t ' ' [ + 1 ] l i s t=bar '
1
foo
2
foo
bar
2
$ sdb −
f o o=bar
foo
bar
a=3
+a
4
−a
3
149
Remove the database
$ rm −f d
So what ?
So, you can now do this inside your radare2 sessions!
Let’s take a simple binary, and check what is already sdbized.
$ cat t e s t . c
i n t main ( ) {
puts (” H e l l o world \n ”) ;
}
$ gcc t e s t . c −o t e s t
$ r2 −A . / t e s t
[ 0 x08048320]> k ∗∗
bin
anal
syscall
debug
More Examples
List namespaces
k ∗∗
List sub-namespaces
k anal /∗∗
List keys
150
k ∗
k anal /∗
Set a key
k f o o=bar
Visual Mode
The visual mode is a more user-friendly interface alternative to radare2’s
command-line prompt. It allows easy navigation, has a cursor mode for se-
lecting bytes, and offers numerous key bindings to simplify debugger use. To
enter visual mode, use V command. To exit from it back to command line,
press q.
Navigation
Navigation can be done using HJKL or arrow keys and PgUp/PgDown keys.
It also understands usual Home/End keys. Like in Vim the movements can
be repeated by preceding the navigation key with the number, for example 5j
will move down for 5 lines, or 2l will move 2 characters right.
151
Figure 9: Visual Mode
Notice that the top of the panel contains the command which is used, for
example for the disassembly panel:
[ 0 x00404890 16% 120 / bin / l s ]> pd $r @ entry0
Getting Help
To see help on all key bindings defined for visual mode, press ?:
Visual mode help :
? show t h i s help
?? show the user−f r i e n d l y hud
% i n c u r s o r mode f i n d s matching pair , or t o g g l e a u to bl o ck sz
@ redraw s c r e e n every 1 s ( multi−u s e r view )
^ seek to the beginning o f the f u n c t i o n
! e n t e r i n t o the v i s u a l p a n e l s mode
_ e n t e r the f l a g /comment/ f u n c t i o n s / . . hud ( same as VF_)
= s e t cmd . vprompt ( top row )
| s e t cmd . cprompt ( r i g h t column )
. seek to program counter
\ t o g g l e v i s u a l s p l i t mode
” t o g g l e the column mode ( u s e s pC . . )
/ i n c u r s o r mode s e a rc h i n c u r r e n t block
: cmd run radare command
152
; [ − ] cmt add/remove comment
0 seek to beginning o f c u r r e n t f u n c t i o n
[1 −9] f o l l o w jmp/ c a l l i d e n t i f i e d by s h o r t c u t ( l i k e ; [ 1 ] )
, file add a l i n k to the t e x t f i l e
/∗+−[] change block s i z e , [ ] = r e s i z e hex . c o l s
</> seek a l i g n e d to block s i z e ( seek c u r s o r i n c u r s o r mode)
a/A ( a ) ssemble code , v i s u a l (A) ssembler
b browse symbols , f l a g s , c o n f i g u r a t i o n s , c l a s s e s , . . .
B t o g g l e breakpoint
c/C t o g g l e ( c ) u r s o r and (C) o l o r s
d[ f ?] d e f i n e fu nc tio n , data , code , . .
D e n t e r v i s u a l d i f f mode ( s e t d i f f . from/ to
e edit eval configuration variables
f /F s e t / unset or browse f l a g s . f− to unset , F to browse , . .
gG go seek to begin and end o f f i l e (0−$s )
hjkl move around ( or HJKL) ( l e f t −down−up−r i g h t )
i i n s e r t hex or s t r i n g ( i n hexdump) use tab to t o g g l e
mK/ 'K mark/go to Key ( any key )
M walk the mounted f i l e s y s t e m s
n/N seek next / prev f u n c t i o n / f l a g / h i t ( s c r . nkey )
g go/ seek to given o f f s e t
O t o g g l e asm . pseudo and asm . e s i l
p/P r o t a t e p r i n t modes ( hex , disasm , debug , words , buf )
q back to radare s h e l l
r r e f r e s h s c r e e n / i n c u r s o r mode browse comments
R randomize c o l o r p a l e t t e ( e c r )
sS s t e p / s t e p over
t browse types
T e n t e r t e x t l o g chat c o n s o l e (TT)
uU undo/ redo seek
v v i s u a l f u n c t i o n / vars code a n a l y s i s menu
V (V) iew graph using cmd . graph ( agv ?)
wW seek c u r s o r to next / prev word
xX show x r e f s / r e f s o f c u r r e n t f u n c t i o n from/ to data / code
yY copy and paste s e l e c t i o n
z f o l d / unfold comments i n disassembly
Z t o g g l e zoom mode
Enter f o l l o w address o f jump/ c a l l
Function Keys : ( See ' e key . ' ) , d e f a u l t s to :
F2 t o g g l e breakpoint
F4 run to c u r s o r
F7 s i n g l e step
F8 s t e p over
F9 continue
Visual Disassembly
The visual disassembler mode in radare2 is accessed by pressing ‘p’ after en-
tering the V command. This mode displays the disassembled code in a struc-
tured format, making it easier to read and navigate through the program’s
instructions.
153
In this view, users can scroll through the code, examine function calls, and
identify control flow structures. The layout includes address information, ma-
chine code, and human-readable assembly instructions. This presentation
helps in understanding the program’s logic and behavior.
The visual disassembler mode also offers various keybindings for quick actions
such as jumping to specific addresses, adding comments, or setting break-
points.
In other words, it’s like using the pd command from the shell but in an inter-
active way.
For example, you can press the spacebar key to toggle between the control-flow-
graph and linear disassembly listing. Or press the numeric comments ;[1] in
the jump/reference hints next to the instructions to quickly jump there.
Navigation
Move within the Disassembly using arrow keys or hjkl. Use g to seek directly
to a flag or an offset, type it when requested by the prompt: [ offset ]>.
Follow a jump or a call using the number of your keyboard [0−9] and the
number on the right in disassembly to follow a call or a jump. In this example
typing 1 on the keyboard would follow the call to sym.imp.__libc_start_main
and therefore, seek at the offset of this symbol.
0x00404894 e857dcffff c a l l sym . imp . __libc_start_main ; [ 1 ]
Seek back to the previous location using u, U will allow you to redo the seek.
Cursor mode
Remember that, to be able to actually edit files loaded in radare2, you have
to start it with the −w option. Otherwise a file is opened in read-only mode.
Pressing lowercase c toggles the cursor mode. When this mode is active, the
currently selected byte (or byte range) is highlighted.
The cursor is used to select a range of bytes or simply to point to a byte. You
can use the cursor to create a named flag at specific location. To do so, seek
to the required position, then press f and enter a name for a flag. If the file
was opened in write mode using the −w flag or the o+ command, you can also
use the cursor to overwrite a selected range with new values. To do so, select
a range of bytes (with HJKL and SHIFT key pressed), then press i and enter
the hexpair values for the new data. The data will be repeated as needed to
fill the range selected. For example:
154
Figure 10: Cursor at 0x00404896
XREF
When radare2 has discovered a XREF during the analysis, it will show you
the information in the Visual Disassembly using XREF tag:
; DATA XREF from 0 x00402e0e ( unk )
s t r . David_MacKenzie :
To see where this string is called, press x, if you want to jump to the location
where the data is used then press the corresponding number [0-9] on your
keyboard. (This functionality is similar to axt)
X corresponds to the reverse operation aka axf.
Add a comment
To add a comment press ; .
155
Figure 11: funcarg
156
Type other commands
Quickly type commands using : .
Search
/:allows highlighting of strings in the current display. :cmd allows you to use
one of the “/?” commands that perform more specialized searches.
The HUDS
The “UserFriendly HUD”
The “UserFriendly HUD” can be accessed using the ?? key-combination. This
HUD acts as an interactive Cheat Sheet that one can use to more easily find
and execute commands. This HUD is particularly useful for new-comers. For
experienced users, the other HUDS which are more activity-specific may be
more useful.
157
Figure 12: First Select asm
158
Figure 13: Pseudo disassembly disabled
159
Figure 14: Pseudo disassembly enabled
160
Examples
asm.arch: Change Architecture && asm.bits: Word size in bits at
assembler You can view the list of all arch using e asm.arch=?
> e asm . arch = d a l v i k
0x00404870 31 ed4989 cmp−long v237 , v73 , v137
0x00404874 d15e4889 rsub−i n t v14 , v5 , 0x8948
0x00404878 e24883e4 ushr−i n t / l i t 8 v72 , v131 , 0xe4
0x0040487c f0505449c7c0 +invoke−ob j ec t−i n i t −range {} ,
method+18772 ; [ 0 ]
0x00404882 90244100 add−i n t v36 , v65 , v0
> e asm . b i t s = 16
0000:4870 31ed xor bp , bp
0000:4872 49 dec cx
0000:4873 89d1 mov cx , dx
0000:4875 5e pop si
0000:4876 48 dec ax
0000:4877 89 e2 mov dx , sp
This latest operation can also be done using & in Visual mode.
> e asm . d e s c r i b e = t r u e
0x00404870 xor ebp , ebp ; l o g i c a l e x c l u s i v e or
0x00404872 mov r9 , rdx ; moves data from s r c to dst
0x00404875 pop r s i ; pops l a s t element o f s t a c k and s t o r e s
the r e s u l t i n argument
0x00404876 mov rdx , rsp ; moves data from s r c to dst
0x00404879 and rsp , −0x f ; binary and o p e r a t i o n between s r c and
dst , s t o r e s r e s u l t on dst
161
Visual Assembler
You can use Visual Mode to assemble code pressing the A key inside the Visual
mode (or just type VA from the shell). Note that the cursor mode also plays
well with the visual assembler, use it to point to the instruction that you want
to patch insted of just scrolling up and down changing the seek.
For example let’s replace the push by a jmp:
162
Figure 16: After
163
Visual Configuration Editor
Ve or e in visual mode allows you to edit radare2 configuration visually. For
example, if you want to change the assembly display just select asm in the list
and choose your assembly display flavor.
Example switch to pseudo disassembly:
Visual Menus
There are a couple of keystrokes in Visual Mode that will lead to some menus
with useful actions in a very accessible way. These are some of them:
Vv visual analysis
This visual mode can be used to navigate through the program like in the
visual disassembly view, but having some extra visual modes to follow refer-
ences, etc
[ 0 x00000000]> Vv
.−− f u n c t i o n s −−−−− pdr −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−.
| ( a ) nalyze (−) d e l e t e ( x ) x r e f s (X) r e f s ( j /k ) next / prev |
| ( r ) ename (c) alls (d) e f i n e (Tab) disasm (_) hud |
| (d) e f i n e (v) ars ( ? ) help ( : ) s h e l l (q) quit |
| ( s ) ignature |
'−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
Note that all those actions can be done through the Vd menu, as well as the
commandline, and it is probably that most of these actions will end up being
moved into the Vd for simplicity reasons and compatibility with Visual Mode
and Visual Panels.
164
Figure 17: First Select asm
165
Figure 18: Pseudo disassembly disabled
166
Figure 19: Pseudo disassembly enabled
167
Ve visual config
The e command is used to change any configuration option inside radare2,
the visual mode have a visual version so you can use it to change settings
interactively.
Note that you can also press the R key to quickly rotate between different the
available color themes.
Vd as in define
The Vd menu can be used to redefine information in the current function or
instruction quickly.
This is the list of actions:
[ 0 x00000000]> Vd
[Vd]− Define c u r r e n t block as :
$ define flag size
1 edit bits
> small i n t e g e r ( s h i f t r i g h t by 1)
a assembly
b as byte (1 byte )
B d e f i n e h a l f word (16 b i t , 2 byte s i z e )
c as code ( unset any data / s t r i n g / format ) i n here
C define flag color ( fc )
d s e t as data
e end o f f u n c t i o n
E e s i l debugger ( aev )
f analyze f u n c t i o n
F format
h d e f i n e h i n t ( f o r h a l f −word , s e e 'B' )
i ( ahi ) immediate base (b( i n ) , o ( c t ) , d( ec ) , h( ex ) , s ( t r ) )
I ( ahi1 ) immediate base (b( i n ) , o ( c t ) , d( ec ) , h( ex ) , s ( t r ) )
j merge down ( j o i n t h i s and next f u n c t i o n s )
k merge up ( j o i n t h i s and p r e v i o u s f u n c t i o n )
h d e f i n e anal h i n t
m manpage f o r c u r r e n t c a l l
n rename f l a g or v a r i a b l e r e f e r e n c e d by the i n s t r u c t i o n i n c u r s o r
N edit function signature ( afs ! )
o opcode s t r i n g
r rename f u n c t i o n
s set string
S s e t s t r i n g s i n c u r r e n t block
t s e t opcode type v i a aht h i n t s ( c a l l , nop , jump , . . . )
u undefine metadata here
v rename v a r i a b l e at o f f s e t that matches some hex d i g i t s
x f i n d x r e f s to c u r r e n t address ( . / r )
X find cross references /r
w s e t as 32 b i t word
W s e t as 64 b i t word
168
q q u i t menu
z zone f l a g
d can be used to change the type of data of the current block, several basic
types/structures are available as well as more advanced one using pf template:
d → ...
0 x004048f7 48 c 1 e 8 3 f shr rax , 0 x3f
d → b
0 x004048f7 . byte 0x48
d → B
0 x004048f7 . word 0xc148
d → d
0 x004048f7 hex l e n g t h=165 d e l t a=0
0 x004048f7 48 c1 e 8 3 f 4801 c648 d1fe 7415 b800 0000
...
To improve code readability you can change how radare2 presents numerical
values in disassembly, by default most of disassembly display numerical value
as hexadecimal. Sometimes you would like to view it as a decimal, binary or
even custom defined constant. To change value format you can use d following
by i then choose what base to work in, this is the equivalent to ahi:
d → i → ...
0 x004048f7 48 c 1 e 8 3 f shr rax , 0 x3f
d → i → 10
0 x004048f7 48 c 1 e 8 3 f shr rax , 63
d → i → 2
0 x004048f7 48 c 1 e 8 3 f shr rax , ' ? '
Panels
Concept
Visual Panels is characterized by the following core functionalities:
1. Split Screen
2. Display multiple screens such as Symbols, Registers, Stack, as well as
custom panels
3. Menu will cover all those commonly used commands for you so that you
don’t have to memorize any of them
CUI met some useful GUI as the menu, that is Visual Panels.
Panels can be accessed by using v or by using ! from the visual mode.
169
Overview
Commands
| Visual A s c i i Art Panels :
| | s p l i t the c u r r e n t panel v e r t i c a l l y
| − s p l i t the c u r r e n t panel h o r i z o n t a l l y
| : run r2 command i n prompt
| ; add/remove comment
| _ s t a r t the hud input mode
| \ show the user−f r i e n d l y hud
| ? show t h i s help
| ! run r2048 game
| . seek to PC or e n t r y p o i n t
| ∗ show decompiler i n the c u r r e n t panel
| ” c r e a t e a panel from the l i s t and r e p l a c e the c u r r e n t one
| / h i g h l i g h t the keyword
| ( t o g g l e snow
| & t o g g l e cache
| [1 −9] f o l l o w jmp/ c a l l i d e n t i f i e d by s h o r t c u t ( l i k e ; [ 1 ] )
| ' ' ( space ) t o g g l e graph / p a n e l s
| tab go to the next panel
| Enter s t a r t Zoom mode
| a t o g g l e auto update f o r decompiler
| b browse symbols , f l a g s , c o n f i g u r a t i o n s , c l a s s e s , . . .
170
| c toggle cursor
| C toggle color
| d d e f i n e i n the c u r r e n t address . Same as Vd
| D show disassembly i n the c u r r e n t panel
| e change t i t l e and command o f c u r r e n t panel
| f s e t /add f i l t e r keywords
| F remove a l l the f i l t e r s
| g go/ seek to given o f f s e t
| G go/ seek to h i g h l i g h t
| i i n s e r t hex
| hjkl move around ( l e f t −down−up−r i g h t )
| HJKL move around ( l e f t −down−up−r i g h t ) by page
| m s e l e c t the menu panel
| M open new custom frame
| n/N seek next / prev f u n c t i o n / f l a g / h i t ( s c r . nkey )
| p/P r o t a t e panel layout
| q quit , or c l o s e a tab
| Q c l o s e a l l the tabs and q u i t
| r t o g g l e c a l l h i n t s / jmphints / l e a h i n t s
| R randomize c o l o r p a l e t t e ( e c r )
| s /S s t e p i n / s t e p over
| t /T tab prompt / c l o s e a tab
| u/U undo / redo seek
| w s t a r t Window mode
| V go to the graph mode
| xX show x r e f s / r e f s o f c u r r e n t f u n c t i o n from/ to data / code
| z swap c u r r e n t panel with the f i r s t one
Basic Usage
Use tab to move around the panels until you get to the targeted panel. Then,
use hjkl, just like in vim, to scroll the panel you are currently on. Use S and
s to step over/in, and all the panels should be updated dynamically while
you are debugging. Either in the Registers or Stack panels, you can edit the
values by inserting hex. This will be explained later. While hitting tab can
help you moving between panels, it is highly recommended to use m to open
the menu. As usual, you can use hjkl to move around the menu and will find
tons of useful stuff there. You can also press ” to quickly browse through the
different options View offers and change the contents of the selected panel.
Split Screen
| is for the vertical and − is for the horizontal split. You can delete any panel
by pressing X.
Split panels can be resized from Window Mode, which is accessed with w.
171
Window Mode Commands
| Panels Window mode help :
| ? show t h i s help
| ?? show the user−f r i e n d l y hud
| Enter s t a r t Zoom mode
| c toggle cursor
| hjkl move around ( l e f t −down−up−r i g h t )
| JK r e s i z e panels v e r t i c a l l y
| HL r e s i z e panels h ori zo nta lly
| q q u i t Window mode
Edit Values
Either in the Register or Stack panel, you can edit the values. Use c to activate
cursor mode and you can move the cursor by pressing hjkl, as usual. Then,
hit i , just like the insert mode of vim, to insert a value.
Tabs
Visual Panels also offer tabs to quickly access multiple forms of information
easily. Press t to enter Tab Mode. All the tabs numbers will be visible in the
top right corner.
By default you will have one tab and you can press t to create a new tab with
the same panels and T to create a new panel from scratch.
For traversing through the tabs, you can type in the tab number while in Tab
Mode.
And pressing − deletes the tab you are in.
Saving layouts
You can save your custom layout of your visual panels either by picking the
option ‘Save Layout’ from the File menu of the menu bar or by running:
v= t e s t
Where test is the name with which you’d like to save it.
You can open a saved layout by passing the name as the parameter to v:
172
v test
Searching
The radare2 search engine is based on work done by esteve, plus multiple fea-
tures implemented on top of it. It supports multiple keyword searches, binary
masks, and hexadecimal values. It automatically creates flags for search hit
locations to ease future referencing.
Searching is accessed with / command.
[ 0 x00000000]> /?
| Usage : / [ ! bf ] [ arg ] Search s t u f f ( s e e ' e ?? search ' f o r o p t i o n s )
| Use i o . va f o r s e a r c h i n g i n non v i r t u a l a d d r e s s i n g s pace s
| / f o o \x00 s e a r c h f o r s t r i n g ' f o o \0 '
| / j f o o \x00 s e a r c h f o r s t r i n g ' f o o \0 ' ( j s o n output )
| /! f f s e a r c h f o r f i r s t o cc u r r e n ce not matching ,
command m o d i f i e r
| / ! x 00 i n v e r s e hexa s e a r c h ( f i n d f i r s t byte !=
0x00 )
| /+ / bin /sh c o n s t r u c t the s t r i n g with chunks
| // repeat l a s t search
| /a jmp eax assemble opcode and s ea r c h i t s bytes
| /A jmp f i n d analyzed i n s t r u c t i o n s o f t h i s type
(/A? f o r help )
| /b s e a r c h backwards , command mod ifier ,
f o l l o w e d by other command
| /B s e a r c h r e c o g n i z e d RBin headers
| /c jmp [ esp ] s e a r c h f o r asm code matching the given
string
| / ce rsp , rbp s e a r c h f o r e s i l e x p r e s s i o n s matching
| /C[ ar ] s e a r c h f o r crypto m a t e r i a l s
| /d 101112 s e a r c h f o r a d e l t i f i e d sequence o f bytes
| /e /E. F/ i match r e g u l a r e x p r e s s i o n
| /E e s i l −expr o f f s e t matching given e s i l e x p r e s s i o n s %%=
here
| /f s e a r c h forwards , command mod ifi er ,
f o l l o w e d by other command
| /F f i l e [ o f f ] [ s z ] s e a r c h c o n t e n t s o f f i l e with o f f s e t and
size
| /g [ g ] [ from ] f i n d a l l graph paths A to B (/ gg f o l l o w
jumps , s e e se a r c h . count and
anal . depth )
| /h [ t ] [ hash ] [ l e n ] f i n d block matching t h i s hash . See ph
| / i foo s e a r c h f o r s t r i n g ' foo ' i g n o r i n g c a s e
| /m m a g i c f i l e s e a r c h f o r matching magic f i l e ( use
blocksize )
173
| /M s e a r c h f o r known f i l e s y s t e m s and mount
them a u t o m a t i c a l l y
| /o [ n ] show o f f s e t o f n i n s t r u c t i o n s backward
| /O [ n ] same as /o , but with a d i f f e r e n t f a l l b a c k
i f anal cannot be used
| /p p a t t e r n s i z e s e a r c h f o r pattern o f given s i z e
| /P p a t t e r n s i z e search s i m i l a r blocks
| / r [ erwx ] [ ? ] sym . p r i n t f analyze opcode r e f e r e n c e an o f f s e t (/ r e
for e s i l )
| /R [ grepopcode ] s e a r c h f o r matching ROP gadgets ,
semicolon−separated
| /s search f o r a l l s y s c a l l s in a region
(EXPERIMENTAL)
| /v [ 1 2 4 8 ] value look f o r an ` c f g . bigendian ` 32 b i t value
| /V[ 1 2 4 8 ] min max look f o r an ` c f g . bigendian ` 32 b i t value i n
range
| /w f o o s e a r c h f o r wide s t r i n g ' f \0o\0o \0 '
| /wi f o o s e a r c h f o r wide s t r i n g i g n o r i n g c a s e
' f \0o\0o \0 '
| /x f f . . 3 3 s e a r c h f o r hex s t r i n g i g n o r i n g some n i b b l e s
| /x f f 0 0 3 3 s e a r c h f o r hex s t r i n g
| /x f f 4 3 : f f d 0 s e a r c h f o r hexpair with mask
| /z min max s e a r c h f o r s t r i n g s o f given s i z e
Search Options
Options are controlled by the search. variables.
[ 0 x00000000]> e ?? s e a rc h
s e a r c h . a l i g n : only catch a l i g n e d s e a r c h h i t s
s e a r c h . chunk : chunk s i z e f o r /+ ( d e f a u l t s i z e i s asm . b i t s /8
s e a r c h . contiguous : accept contiguous / adjacent s e a r ch h i t s
se a r c h . d i s t a n c e : s e ar c h s t r i n g d i s t a n c e
se a r c h . esilcombo : stop s e a r c h a f t e r N c o n s e c u t i v e h i t s
s e a r c h . f l a g s : a l l s e a r c h r e s u l t s are f l a g g e d , o t h e r w i s e only
printed
se a r c h . from : se a r c h s t a r t address
s ea r c h . i n : s p e c i f y s e a r c h boundaries
s e a r c h . kwidx : s t o r e l a s t s e a r c h index count
s ea r c h . maxhits : maximum number o f h i t s ( 0 : no l i m i t )
s ea r c h . o v e r l a p : look f o r overlapped s e a r c h h i t s
s e a r c h . p r e f i x : p r e f i x name i n s e a r c h h i t s l a b e l
se a r c h . show : show s e a r c h r e s u l t s
s ea r c h . to : s e a rc h end address
174
s ea r c h . verbose : make the output o f s e a r c h commands verbose
Perhaps the most important search variable is search.in - it controls where your
search is occurring. If you aren’t finding hits you expect, check this variable
first. Note the difference between map and maps - map will only search the
map that you are currently in, while maps will search all memory maps, with
options to narrow the search by permissions.
[ 0 x00000000]> e s ea rc h . i n=?
raw
block
bin . s e c t i o n
bin . s e c t i o n s
bin . s e c t i o n s . rwx
bin . s e c t i o n s . r
bin . s e c t i o n s . rw
bin . s e c t i o n s . rx
bin . s e c t i o n s . wx
bin . s e c t i o n s . x
i o . map
i o . maps
i o . maps . rwx
i o . maps . r
i o . maps . rw
i o . maps . rx
i o . maps . wx
i o . maps . x
dbg . s t a c k
dbg . heap
dbg . map
dbg . maps
dbg . maps . rwx
dbg . maps . r
dbg . maps . rw
dbg . maps . rx
dbg . maps . wx
dbg . maps . x
anal . f c n
anal . bb
Basic Search
A basic search for a plain text string in a file would be something like:
$ r2 −q −c ”/ l i b ” / bin / l s
Searching 3 bytes from 0x00400000 to 0x0041ae08 : 6c 69 62
hits : 9
0x00400239 hit0_0 ” l i b 6 4 / ld−linux−x86 −64. so . 2 ”
0 x00400f19 hit0_1 ” l i b s e l i n u x . so . 1 ”
175
0 x00400fae hit0_2 ” l i b r t . so . 1 ”
0 x00400fc7 hit0_3 ” l i b a c l . so . 1 ”
0x00401004 hit0_4 ” l i b c . so . 6 ”
0 x004013ce hit0_5 ” libc_start_main ”
0x00416542 hit0_6 ” l i b s /”
0x00417160 hit0_7 ” l i b / xstrtol . c”
0x00417578 hit0_8 ” lib ”
As can be seen from the output above, radare2 generates a “hit” flag for every
entry found. You can then use the ps command to see the strings stored at
the offsets marked by the flags in this group, and they will have names of the
form hit0_<index>:
[ 0 x00404888]> / l s
...
[ 0 x00404888]> ps @ hit0_0
lseek
You can search for wide-char strings (e.g., unicode letters) using the /w com-
mand:
[ 0 x00000000]> /w H e l l o
0 r e s u l t s found .
if, instead, you are searching for a string of hexadecimal values, you’re prob-
ably better of using the /x command:
[ 0 x00000000]> /x 7F454C46
If you want to mask some nibble during the search you can use the symbol .
to allow any nibble value to match:
[ 0 x00407354]> /x 8 0 . . 8 0
0x0040d4b6 hit3_0 800080
0x0040d4c8 hit3_1 808080
0x004058a6 hit3_2 80 fb80
You may not know some bit values of your hexadecimal pattern. Thus you
may use a bit mask on your pattern. Each bit set to one in the mask indicates
176
to search the bit value in the pattern. A bit set to zero in the mask indicates
that the value of a matching value can be 0 or 1:
[ 0 x00407354]> /x 808080: f f 8 0 f f
0x0040d4c8 hit4_0 808080
0x0040d7b0 hit4_1 808080
0x004058a6 hit4_2 80 fb80
You can notice that the command /x 808080:ff00ff is equivalent to the command
/x 80..80.
Once the search is done, the results are stored in the searches flag space.
[ 0 x00000000]> f s
0 0 . strings
1 0 . symbols
2 6 . searches
[ 0 x00000000]> f
0x00000135 512 hit0_0
0x00000b71 512 hit0_1
0x00000bad 512 hit0_2
0x00000bdd 512 hit0_3
0 x00000bfb 512 hit0_4
0 x00000f2a 512 hit0_5
To remove “hit” flags after you do not need them anymore, use the f− hit∗
command.
Often, during long search sessions, you will need to launch the latest search
more than once. You can use the // command to repeat the last search.
[ 0 x00000f2a ]> // ; repeat l a s t search
177
The search.align variable is used to limit valid search hits to certain alignment.
For example, with e search.align=4 you will see only hits found at 4-bytes aligned
offsets.
The search.flags boolean variable instructs the search engine to flag hits so that
they can be referenced later. If a currently running search is interrupted with
Ctrl−C keyboard sequence, current search position is flagged with search_stop.
This command output will show different patterns found and how many times
each of them is encountered.
It is possible to search patterns with a known difference between consecutive
bytes with /d command. For example, the command to search all the patterns
with the first and second bytes having the first bit which differs and the second
and third bytes with the second bit which differs is:
[ 0 x00000000]> /d 0102
Searching 2 bytes i n [ 0 x0−0x400 ]
hits : 2
0x00000118 hit2_0 9a9b9d
0x00000202 hit2_1 a4a5a7
Search Automation
The cmd.hit configuration variable is used to define a radare2 command to be
executed when a matching entry is found by the search engine. If you want to
run several commands, separate them with ; . Alternatively, you can arrange
them in a separate script, and then invoke it as a whole with . script−file−name
command. For example:
[ 0 x00404888]> e cmd . h i t = p8 8
[ 0 x00404888]> / l i b
178
Searching 3 bytes from 0x00400000 to 0x0041ae08 : 6c 69 62
hits : 9
0x00400239 hit4_0 ” l i b 6 4 / ld−linux−x86 −64. so . 2 ”
31 ed4989d15e4889
0 x00400f19 hit4_1 ” l i b s e l i n u x . so . 1 ”
31 ed4989d15e4889
0 x00400fae hit4_2 ” l i b r t . so . 1 ”
31 ed4989d15e4889
0 x00400fc7 hit4_3 ” l i b a c l . so . 1 ”
31 ed4989d15e4889
0x00401004 hit4_4 ” l i b c . so . 6 ”
31 ed4989d15e4889
0 x004013ce hit4_5 ” libc_start_main ”
31 ed4989d15e4889
0x00416542 hit4_6 ” l i b s /”
31 ed4989d15e4889
0x00417160 hit4_7 ” l i b / xstrtol . c”
31 ed4989d15e4889
0x00417578 hit4_8 ” lib ”
31 ed4989d15e4889
Searching Backwards
Sometimes you want to find a keyword backwards. This is, before the cur-
rent offset, to do this you can seek back and search forward by adding some
search.from/to restrictions, or use the /b command.
[ 0 x100001200]> / nop
0x100004b15 hit0_0 . STUWabcdefghiklmnopqrstuvwxbin/ l s .
0 x100004f50 hit0_1 . STUWabcdefghiklmnopqrstuwx1 ] [ f i l e .
[ 0 x100001200]> /b nop
[ 0 x100001200]> s 0 x100004f50p
[ 0 x100004f50]> /b nop
0x100004b15 hit2_0 . STUWabcdefghiklmnopqrstuvwxbin/ l s .
[ 0 x100004f50]>
Note that /b is doing the same as /, but backward, so what if we want to use /x
backward? We can use /bx, and the same goes for other search subcommands:
[ 0 x100001200]> /x 90
0x100001a23 hit1_0 90
0 x10000248f hit1_1 90
0x1000027b2 hit1_2 90
0x100002b2e hit1_3 90
0x1000032b8 hit1_4 90
0x100003454 hit1_5 90
0x100003468 hit1_6 90
0x10000355b hit1_7 90
0x100003647 hit1_8 90
0x1000037ac hit1_9 90
179
0x10000389c hit1_10 90
0 x100003c5c hit1_11 90
[ 0 x100001200]> /bx 90
[ 0 x100001200]> s 0x10000355b
[ 0 x10000355b]> /bx 90
0x100003468 hit3_0 90
0x100003454 hit3_1 90
0x1000032b8 hit3_2 90
0x100002b2e hit3_3 90
0x1000027b2 hit3_4 90
0 x10000248f hit3_5 90
0x100001a23 hit3_6 90
[ 0 x10000355b]>
Assembler Search
If you want to search for a certain assembler opcodes, you can use /a com-
mands.
The command /ad/ jmp [esp] searches for the specified category of assembly
mnemonic:
[ 0 x00404888]> /ad/ jmp qword [ rdx ]
f hit_0 @ 0x0040e50d # 2 : jmp qword [ rdx ]
f hit_1 @ 0x00418dbb # 2 : jmp qword [ rdx ]
f hit_2 @ 0 x00418fcb # 3 : jmp qword [ rdx ]
f hit_3 @ 0x004196ab # 6 : jmp qword [ rdx ]
f hit_4 @ 0 x00419bf3 # 3 : jmp qword [ rdx ]
f hit_5 @ 0x00419c1b # 3 : jmp qword [ rdx ]
f hit_6 @ 0x00419c43 # 3 : jmp qword [ rdx ]
The command /a jmp eax assembles a string to machine code, and then searches
for the resulting bytes:
[ 0 x00404888]> /a jmp eax
hits : 1
0x004048e7 hit3_0 f f e 0 0 f 1 f 8 0 0 0 0 0 0 0 0 0 b 8
180
search.distance limit, or until end of file is reached. You can interrupt current
search by pressing Ctrl−C. For example, to look for AES keys in a memory
dump:
[ 0 x00000000]> / ca aes
Searching 40 bytes i n [ 0 x0−0x1ab ]
hits : 1
0 x000000fb hit0_0 6920 e299a5202a6d656e636869746f2a
For AES, the output length gives you the size of the AES key used: 128, 192
or 256 bits. If you are simply looking for plaintext AES keys in your binary,
/ca will not find them they must have been expanded by the key expansion
algorithm.
Entropy analysis
p=e might give some hints if high entropy sections are found trying to cover
up a hardcoded secret.
There is the possibility to delimit entropy sections for later use with \s com-
mand:
[ 0 x00000000]> b
0x100
[ 0 x00000000]> b 4096
[ 0 x00000000]> / s
0x00100000 − 0x00101000 ~ 5.556094
0 x014e2c88 − 0 x014e3c88 ~ 0.000000
0x01434374 − 0x01435374 ~ 6.332087
0x01435374 − 0x0144c374 ~ 3.664636
0x0144c374 − 0x0144d374 ~ 1.664368
0x0144d374 − 0 x0144f374 ~ 4.229199
0 x0144f374 − 0x01451374 ~ 2.000000
(...)
[ 0 x00000000]> / s ∗
181
f entropy_section_0 0x00001000 0x00100000
f entropy_section_1 0x00001000 0 x014e2c88
f entropy_section_2 0x00001000 0x01434374
f entropy_section_3 0x00017000 0x01435374
f entropy_section_4 0x00001000 0x0144c374
f entropy_section_5 0x00002000 0x0144d374
f entropy_section_6 0x00002000 0 x0144f374
The blocksize is increased to 4096 bytes from the default 100 bytes so that the
entropy search /s can work on reasonably sized chunks for entropy analysis.
The sections flags can be applied with the dot operator, ./s∗ and then looped
through px 32 @@ entropy∗.
Disassembling
Disassembling in radare is just a way to represent an array of bytes. It is
handled as a special print mode within p command.
In the old times, when the radare core was smaller, the disassembler was
handled by an external rsc file. That is, radare first dumped current block
into a file, and then simply called objdump configured to disassemble for Intel,
ARM or other supported architectures.
182
It was a working and unix friendly solution, but it was inefficient as it repeated
the same expensive actions over and over, because there were no caches. As
a result, scrolling was terribly slow.
So there was a need to create a generic disassembler library to support multiple
plugins for different architectures. We can list the current loaded plugins with
$ rasm2 −L
This was many years before capstone appeared. So r2 was using udis86 and
olly disassemblers, many gnu (from binutils).
Nowadays, the disassembler support is one of the basic features of radare. It
now has many options, endianness, including target architecture flavor and
disassembler variants, among other things.
To see the disassembly, use the pd command. It accepts a numeric argument
to specify how many opcodes of current block you want to see. Most of the
commands in radare consider the current block size as the default limit for
data input. If you want to disassemble more bytes, set a new block size using
the b command.
[ 0 x00000000]> b 100 ; s e t block s i z e to 100
[ 0 x00000000]> pd ; d i s a s s e m b l e 100 bytes
[ 0 x00000000]> pd 3 ; d i s a s s e m b l e 3 opcodes
[ 0 x00000000]> pD 30 ; d i s a s s e m b l e 30 bytes
The pD command works like pd but accepts the number of input bytes as its
argument, instead of the number of opcodes.
The “pseudo” syntax may be somewhat easier for a human to understand
than the default assembler notations. But it can become annoying if you read
lots of code. To play with it:
[ 0 x00405e1c]> e asm . pseudo = t r u e
[ 0 x00405e1c]> pd 3
; JMP XREF from 0 x00405dfa ( f c n .00404531)
0 x00405e1c 488 b9424a80 . rdx = [ rsp+0x2a8 ]
0x00405e24 64483314252. rdx ^= [ f s : 0 x28 ]
0x00405e2d 4889d8 rax = rbx
183
[ 0 x00405e1c]> e asm . syntax=a t t
[ 0 x00405e1c]> pd 3
; JMP XREF from 0 x00405dfa ( f c n .00404531)
0 x00405e1c 488 b9424a80 . mov 0x2a8(%rsp ) , %rdx
0x00405e24 64483314252. xor %f s : 0 x28 , %rdx
0x00405e2d 4889d8 mov %rbx , %rax
Decompilation
Radare2, as a tool that focus on extensibility and flexibility provides support
for many decompilers.
For historical reasons the decompilers in r2 has been allocated as pd subcom-
mands.
• pdd - r2dec
• pdg - r2ghidra
• …
By default only the pdc pseudodecompiler is shipped within radare2, but you
can install any other via r2pm, the standard package manager for radare2.
Most decompilers implement all the common subcommands that modify the
output:
PseudoDecompiler
By combining ESIL emulation, asm.pseudo disassembly and some extra ref-
erence processing and function signature, comments and metadata; the pdc
command provides a quick way to read a function in a higher level representa-
tion. It is not really implementing any control flow improvement (like switch,
if/else, for/while). Also, no code optimizations or garbage logic is removed.
You may find it’s output quite verbose and noisy, but handy and fast, and
that serves like a good source to feed language models.
184
Another benefit of pdc is that it is available for ALL architectures supported
by r2.
[ 0 x100003a48]> pdc
i n t sym . func .100003 a48 ( i n t x0 , i n t x1 ) {
x8 = [ x0 + 0x60 ] // arg1
x8 = [ x8 + 0x60 ]
x9 = [ x1 + 0x60 ] // arg2
x9 = [ x9 + 0x60 ]
( a , b) = compare ( x8 , x9 )
i f ( a <= b) goto loc_0x100003a68 // l i k e l y
goto loc_0x100003a60 ;
loc_0x100003a68 :
i f ( a >= b) goto loc_0x100003a74 // l i k e l y
goto loc_0x100003a6c ;
loc_0x100003a74 :
x8 = x1 + 0x68 // arg2
x1 = x0 + 0x68 // arg1
x0 = x8
r e t u r n sym . imp . s t r c o l l ( ” ” , ””)
loc_0x100003a60 :
w0 = 1
r e t u r n x0 ;
}
[ 0 x100003a48]>
r2dec
This decompiler is available via r2pm and is sits after the pdd command. It
provides control flow analysis and some code cleanup which makes it easier
for the reader to understand what is going on.
This plugin can be configured with the e r2dec. variables:
[ 0 x00000000]> e ?? r2dec .
r2dec . asm : i f true , shows pseudo next to the assembly .
r2dec . b l o c k s : i f true , shows only sc op es b l o c k s .
r2dec . c a s t s : i f f a l s e , h i d e s a l l c a s t s i n the pseudo code .
r2dec . debug : do not catch e x c e p t i o n s i n r2dec .
r2dec . h i g h l i g h t : h i g h l i g h t s the c u r r e n t address .
r2dec . paddr : i f true , a l l x r e f s u s e s p h y s i c a l a d d r e s s e s compare .
r2dec . slow : load a l l the data b e f o r e to avoid m u l t i r e q u e s t s to
r2 .
r2dec . x r e f s : i f true , shows a l l x r e f s i n the pseudo code .
[ 0 x00000000]>
In this example we show how pdda works, displaying the two columns:
[ 0 x100003a48]> pdda
; assembly | /∗ r2dec pseudo code output ∗/
185
| /∗ / bin / l s @ 0x100003a48 ∗/
| #i n c l u d e <s t d i n t . h>
|
; ( f c n ) sym . func .100003 a48 ( ) | uint32_t func_100003a48 ( int64_t
arg1 , int64_t arg2 ) {
| x0 = arg1 ;
| x1 = arg2 ;
0x100003a48 ldr x8 , [ x0 , 0x60 ] | x8 = ∗ ( ( x0 + 0x60 ) ) ;
0x100003a4c ldr x8 , [ x8 , 0x60 ] | x8 = ∗ ( ( x8 + 0x60 ) ) ;
0x100003a50 ldr x9 , [ x1 , 0x60 ] | x9 = ∗ ( ( x1 + 0x60 ) ) ;
0x100003a54 ldr x9 , [ x9 , 0x60 ] | x9 = ∗ ( ( x9 + 0x60 ) ) ;
0x100003a58 cmp x8 , x9 |
| i f ( x8 > x9 ) {
0x100003a5c b . l e 0x100003a68 |
0x100003a60 mov w0 , 1 | w0 = 1 ;
0x100003a64 r e t | r e t u r n w0 ;
| }
| i f ( x8 < x9 ) {
0x100003a68 b . ge 0x100003a74 |
0x100003a6c mov w0 , −1 | w0 = −1;
0x100003a70 r e t | r e t u r n w0 ;
| }
0x100003a74 add x8 , x1 , 0x68 | x8 = x1 + 0x68 ;
0x100003a78 add x1 , x0 , 0x68 | x1 = x0 + 0x68 ;
0x100003a7c mov x0 , x8 | x0 = x8 ;
0x100003a80 b 0x1000077c8 | r e t u r n void (∗0 x1000077c8 ) ( ) ( ) ;
| }
[ 0 x100003a48]>
R2Ghidra
The Ghidra tool ships a decompiler as a separate program (written in C++
instead of Java), for r2 purposes the logic from this tool has been massaged
to work as a native plugin so it doesn’t require the java runtime to work.
Note that the quality of the decompilation of r2ghidra compared to ghidra
is not the same, because r2ghidra is not providing the same analysis results
that Ghidra would provide, and some other metadata differs, which causes
the engine to behave different and probably miss quite a lot of details when
handling structures and other complex features.
The plugin can be configured with the e r2ghidra. variables:
[ 0 x00000000]> e ?? r 2 g h i d r a .
r2 g h i d r a . c a s t s : Show type c a s t s where needed
r 2 g h i d r a . cmt . cpp : C++ comment s t y l e
r2 g h i d r a . cmt . indent : Comment indent
r 2 g h i d r a . indent : Indent increment
r2 g h i d r a . lang : Custom S l e i g h ID to o v e r r i d e auto−d e t e c t i o n
( e . g . x86 :LE: 3 2 : d e f a u l t )
186
r 2 g h i d r a . l i n e l e n : Max l i n e l e n g t h
r2 g h i d r a . maximplref : Maximum number o f r e f e r e n c e s to an e x p r e s s i o n
b e f o r e showing an e x p l i c i t v a r i a b l e .
r 2 g h i d r a . rawptr : Show unknown g l o b a l s as raw a d d r e s s e s i n s t e a d
of variables
r 2 g h i d r a . roprop : Propagate read−only c o n s t a n t s ( 0 , 1 , 2 , 3 , 4 )
r2 g h i d r a . sleighhome : SLEIGHHOME
r 2 g h i d r a . timeout : Run decompilation i n a s e p a r a t e p r o c e s s and
k i l l i t a f t e r a s p e c i f i c time
r2 g h i d r a . vars : Honor l o c a l v a r i a b l e / argument a n a l y s i s from
r2 (may cause s e g f a u l t s i f enabled )
r 2 g h i d r a . verbose : Show verbose warning messages while decompiling
[ 0 x00000000]>
Other
There’s support for many other decompilers in radare2, but those are not
documented in this book yet, feel free to submit your details, here’s the list:
187
• radeco -> experimental and abandoned esil based decompiler written in
Rust
• r2snow -> snowman’s decompiler only for intel architectures
• pdq -> r2papi-based decompiler on top of esil and the r2js runtime
Please keep in mind that importing IDA Pro metadata from IDC dump is
deprecated mechanism and might not work in the future. The recommended
way to do it - use python-idb-based ida2r2.py which opens IDB files directly
without IDA Pro installed.
The C command is used to manage comments and data conversions. You
can define a range of program’s bytes to be interpreted as either code, binary
data or string. It is also possible to execute external code at every specified
flag location in order to fetch some metadata, such as a comment, from an
external file or database.
There are many different metadata manipulation commands, here is the
glimpse of all of them:
[ 0 x00404cc0]> C?
| Usage : C[−LCvsdfm ∗ ? ] [ ∗ ? ] [...] # Metadata management
| C l i s t meta i n f o i n
human f r i e n d l y form
188
| C∗ l i s t meta i n f o i n
r2 commands
| C∗ . l i s t meta i n f o o f
c u r r e n t o f f s e t i n r2 commands
| C− [ l e n ] [ [@] addr ] d e l e t e metadata at
given address range
| C. l i s t meta i n f o o f
c u r r e n t o f f s e t i n human f r i e n d l y form
| CC! [ @addr ] e d i t comment with
$EDITOR
| CC[ ? ] [ −] [ comment−t e x t ] [ @addr ] add/remove comment
| CC. [ addr ] show comment i n
c u r r e n t address
| CCa[− at ] | [ at ] [ t e x t ] [ @addr ] add/remove comment
at given address
| CCu [ comment−t e x t ] [ @addr ] add unique comment
| CF[ s z ] [ fcn−s i g n . . ] [ @addr ] function signature
| CL[ − ] [ ∗ ] [ f i l e : l i n e ] [ addr ] show or add ' code
l i n e ' i n f o r m a ti o n ( b i n i n f o )
| CS[ − ] [ space ] manage meta−sp ac es
to f i l t e r comments , e t c . .
| C[ Cthsdmf ] list
comments/ types / hidden / s t r i n g s / data /magic/ formatted i n human
f r i e n d l y form
| C[ Cthsdmf ] ∗ list
comments/ types / hidden / s t r i n g s / data /magic/ formatted i n r2 commands
| Cd[ −] [ s i z e ] [ r e p e a t ] [ @addr ] hexdump data array
(Cd 4 10 == dword [ 1 0 ] )
| Cd . [ @addr ] show s i z e o f data
at c u r r e n t address
| Cf [ ? ] [ − ] [ s z ] [ 0 | cnt ] [ fmt ] [ a0 a1 . . . ] [ @addr ] format memory ( s e e
pf ?)
| Ch[ −] [ s i z e ] [ @addr ] hide data
| Cm[ −] [ s z ] [ fmt . . ] [ @addr ] magic parse ( s e e
pm?)
| Cs [ ? ] [ −] [ s i z e ] [ @addr ] add s t r i n g
| Ct [ ? ] [ −] [ comment−t e x t ] [ @addr ] add/remove type
a n a l y s i s comment
| Ct . [ @addr ] show comment at
c u r r e n t or s p e c i f i e d address
| Cv [ bsr ] [ ? ] add comments to a r g s
| Cz [ @addr ] add s t r i n g ( s e e Cs?)
Simply to add the comment to a particular line/address you can use Ca com-
mand:
[ 0 x00000000]> CCa 0x0000002 t h i s guy seems l e g i t
[ 0 x00000000]> pd 2
0x00000000 0000 add [ rax ] , a l
; t h i s guy seems l e g i t
0x00000002 0000 add [ rax ] , a l
The C? family of commands lets you mark a range as one of several kinds of
189
types. Three basic types are: code (disassembly is done using asm.arch), data
(an array of data elements) or string. Use the Cs command to define a string,
use the Cd command for defining an array of data elements, and use the Cf
command to define more complex data structures like structs.
Annotating data types is most easily done in visual mode, using the “d” key,
short for “data type change”. First, use the cursor to select a range of bytes
(press c key to toggle cursor mode and use HJKL keys to expand selection),
then press ‘d’ to get a menu of possible actions/types. For example, to mark
the range as a string, use the ‘s’ option from the menu. You can achieve the
same result from the shell using the Cs command:
[ 0 x00000000]> f s t r i n g _ f o o @ 0x800
[ 0 x00000000]> Cs 10 @ s t r i n g _ f o o
The Cf command is used to define a memory format string (the same syntax
used by the pf command). Here’s an example:
[ 0 x7fd9f13ae630 ]> Cf 16 2 x i f o o bar
[ 0 x7fd9f13ae630 ]> pd
;−− r i p :
0 x7fd9f13ae630 format 2 x i f o o bar {
0 x7fd9f13ae630 [ 0 ] {
f o o : 0 x7fd9f13ae630 = 0 xe8e78948
bar : 0 x7fd9f13ae634 = 14696
}
0 x7fd9f13ae638 [ 1 ] {
f o o : 0 x7fd9f13ae638 = 0x8bc48949
bar : 0 x7fd9f13ae63c = 571928325
}
} 16
0 x7fd9f13ae633 e868390000 c a l l 0 x7fd9f13b1fa0
0 x7fd9f13ae638 4989 c4 mov r12 , rax
The [sz] argument to Cf is used to define how many bytes the struct should
take up in the disassembly, and is completely independent from the size of the
data structure defined by the format string. This may seem confusing, but
has several uses. For example, you may want to see the formatted structure
displayed in the disassembly, but still have those locations be visible as offsets
and with raw bytes. Sometimes, you find large structures, but only identified
a few fields, or only interested in specific fields. Then, you can tell r2 to
display only those fields, using the format string and using ‘skip’ fields, and
also have the disassembly continue after the entire structure, by giving it full
size using the sz argument.
Using Cf, it’s easy to define complex structures with simple oneliners. See
pf?for more information. Remember that all these C commands can also be
accessed from the visual mode by pressing the d (data conversion) key. Note
190
that unlike t commands Cf doesn’t change analysis results. It is only a visual
boon.
Sometimes just adding a single line of comments is not enough, in this case
radare2 allows you to create a link for a particular text file. You can use it
with CC, command or by pressing , key in the visual mode. This will open an
$EDITOR to create a new file, or if filename does exist, just will create a link.
It will be shown in the disassembly comments:
[ 0 x00003af7 11% 290 / bin / l s ]> pd $r @ main+55 # 0 x3af7
| 0 x00003af7 c a l l sym . imp . s e t l o c a l e ; [ 1 ] ; , ( l o c a l e −help . t x t )
; char ∗ s e t l o c a l e ( i n t category , const char ∗ l o c a l e )
| 0 x00003afc l e a r s i , s t r . usr_share_locale ; 0 x179cc ;
”/ usr / share / l o c a l e ”
| 0 x00003b03 l e a r d i , [ 0 x000179b2 ] ; ” coreutils ”
| 0 x00003b0a c a l l sym . imp . bindtextdomain ; [ 2 ] ; char
∗ bindtextdomain ( char ∗domainname , char ∗dirname )
Disassembling
Disassembling in radare is just a way to represent an array of bytes. It is
handled as a special print mode within p command.
In the old times, when the radare core was smaller, the disassembler was
handled by an external rsc file. That is, radare first dumped current block
into a file, and then simply called objdump configured to disassemble for Intel,
ARM or other supported architectures.
It was a working and unix friendly solution, but it was inefficient as it repeated
the same expensive actions over and over, because there were no caches. As
a result, scrolling was terribly slow.
So there was a need to create a generic disassembler library to support multiple
plugins for different architectures. We can list the current loaded plugins with
$ rasm2 −L
191
This was many years before capstone appeared. So r2 was using udis86 and
olly disassemblers, many gnu (from binutils).
Nowadays, the disassembler support is one of the basic features of radare. It
now has many options, endianness, including target architecture flavor and
disassembler variants, among other things.
To see the disassembly, use the pd command. It accepts a numeric argument
to specify how many opcodes of current block you want to see. Most of the
commands in radare consider the current block size as the default limit for
data input. If you want to disassemble more bytes, set a new block size using
the b command.
[ 0 x00000000]> b 100 ; s e t block s i z e to 100
[ 0 x00000000]> pd ; d i s a s s e m b l e 100 bytes
[ 0 x00000000]> pd 3 ; d i s a s s e m b l e 3 opcodes
[ 0 x00000000]> pD 30 ; d i s a s s e m b l e 30 bytes
The pD command works like pd but accepts the number of input bytes as its
argument, instead of the number of opcodes.
The “pseudo” syntax may be somewhat easier for a human to understand
than the default assembler notations. But it can become annoying if you read
lots of code. To play with it:
[ 0 x00405e1c]> e asm . pseudo = t r u e
[ 0 x00405e1c]> pd 3
; JMP XREF from 0 x00405dfa ( f c n .00404531)
0 x00405e1c 488 b9424a80 . rdx = [ rsp+0x2a8 ]
0x00405e24 64483314252. rdx ^= [ f s : 0 x28 ]
0x00405e2d 4889d8 rax = rbx
192
⊠ Disassembler
⊠ Assembler
⊠ Emulation (esil)
⊠ Basic address space mapping
Untested
□ Debugger
Missing
r2 configuration
Set architecture to 8051:
$ r2 −a 8051
After changing the cpu model, run ‘aei’ to initialize/reset the registers and
mapped memory. For example:
e asm . cpu = 8051− g e n e r i c
aei
193
register address space comment
_code CODE Program memory.
Typically located at 0.
_idata IDATA 256 bytes of internal
RAM.
_sfr SFR 128 bytes for special
function registers. _sfr
is the base address.
Registers start
at_sfr+0x80.
_xdata XDATA 64K of external RAM.
_pdata PDATA, XREG MSB of address of
256-byte page in
XDATA accessed with
‘movx @Ri’ op codes.
The registers are initialized based on the selected CPU. See command ‘e
asm.cpu=?’.
The registers can be viewed and modified with the ‘ar’ command. When modi-
fying the pseudo-registers or updating ‘asm.cpu’, memory will be (re)allocated
automatically when the analyzer is invoked the next time (e.g. during ‘aei’).
Use the ‘om’ command to see the list of allocated memory blocks.
[ 0 x00000000]> e asm . cpu=8051. g e n e r i c
[ 0 x00000000]> a e i
[ 0 x00000000]> om
4 fd : 6 +0x00000000 0x00000000 − 0 x 0 0 0 0 f f f f −rwx
3 fd : 5 +0x00000000 0x20000000 − 0 x 2 0 0 0 f f f f −rw− xdata
2 fd : 4 +0x00000000 0x10000180 − 0 x 1 0 0 0 0 1 f f −rw− s f r
1 fd : 3 +0x00000000 0x10000000 − 0 x 1 0 0 0 0 0 f f −rw− i d a t a
Analysis and emulation rely on the address mapping. Setup the pseudo-
registers before running analysis, or rerun analysis after updating pseudo-
registers.
Address spaces can overlap in r2 memory. This allows emulating 8051 variants
that mirror IDATA and SFR into XDATA, or have shared XDATA and CODE
address spaces.
For example, the CC2430 from Texas Instruments maps SFR to 0xDF80 and
IDATA to 0xFF00 in XDATA memory space. In r2 this can be setup with:
ar _sfr = _xdata + 0 xdf00
ar _idata = _xdata + 0 x f f 0 0
194
For overlapping areas, r2 will prioritize smaller memory blocks over larger
ones. For example, if IDATA is mapped into XDATA, all r2 operations will
use IDATA in the overlapping addresses. If you want to use XDATA instead,
you can delete the offending map with the command ‘om-’. See ’om?’for more
information.
For using emulation with overlapping code and RAM spaces, the r2 memory
holding the firmware must allow write access. This is best achieved with the
command ‘omf 4 rwx’, with 4 being the id of the firmware file’s IO map entry.
See ‘om?’ for more information.
Some 8051 variants use memory banking to address memory spaces larger
than 64K. Currently, memory banking is not supported by r2.
195
Analysis
Radare2 has a very rich set of commands and configuration options to per-
form data and code analysis, to extract useful information from a binary,
like pointers, string references, basic blocks, opcode data, jump targets, cross
references and much more. These operations are handled by the a (analyze)
command family:
| Usage : a [ abdefFghoprxstc ] [ . . . ]
| aa [ ? ] analyze a l l ( f c n s + bbs ) ( aa0 to avoid sub
renaming )
| a8 [ h e x p a i r s ] analyze bytes
| ab [ b ] [ addr ] analyze block at given address
| abb [ l e n ] analyze N b a s i c b l o c k s i n [ l e n ] ( s e c t i o n . s i z e
by d e f a u l t )
| abt [ addr ] f i n d paths i n the bb f u n c t i o n graph from
c u r r e n t o f f s e t to given address
| ac [ c y c l e s ] analyze which op could be executed i n [ c y c l e s ]
| ad [ ? ] analyze data trampoline ( wip )
| ad [ from ] [ to ] analyze data p o i n t e r s to ( from−to )
| ae [ ? ] [ expr ] analyze opcode e v a l e x p r e s s i o n ( s e e ao )
| af [ ? ] analyze Functions
| aF same as above , but using anal . depth=1
| ag [ ? ] [ o p t i o n s ] draw graphs i n v a r i o u s formats
| ah [ ? ] a n a l y s i s h i n t s ( f o r c e opcode s i z e , . . . )
| a i [ addr ] address i n f o r m a t i o n ( show perms , stack , heap ,
...)
| an [ name ] [ @addr ] show/rename/ c r e a t e whatever f l a g / f u n c t i o n i s
used at addr
| ao [ ? ] [ l e n ] analyze Opcodes ( or emulate i t )
| aO [ ? ] [ l e n ] Analyze N i n s t r u c t i o n s i n M bytes
| ap f i n d prelude f o r c u r r e n t o f f s e t
| ar [ ? ] l i k e ' dr ' but f o r the e s i l vm. ( r e g i s t e r s )
| as [ ? ] [num] analyze s y s c a l l using dbg . reg
| av [ ? ] [ . ] show v t a b l e s
| ax [ ? ] manage r e f s / x r e f s ( s e e a l s o afx ?)
In fact, a namespace is one of the biggest in radare2 tool and allows to control
very different parts of the analysis:
196
• Objects information, like virtual tables
Code Analysis
Code analysis is the process of finding patterns, combining information from
different sources and process the disassembly of the program in multiple ways
in order to understand and extract more details of the logic behind the code.
Radare2 has many different code analysis techniques implemented under dif-
ferent commands and configuration options, and it’s important to understand
what they do and how that affects in the final results before going for the
default-standard aaaaa way because on some cases this can be too slow or just
produce false positive results.
As long as the whole functionalities of r2 are available with the API as well as
using commands. This gives you the ability to implement your own analysis
loops using any programming language, even with r2 oneliners, shellscripts,
or analysis or core native plugins.
The analysis will show up the internal data structures to identify basic blocks,
function trees and to extract opcode-level information.
The most common radare2 analysis command sequence is aa, which stands
for “analyze all”. That all is referring to all symbols and entry-points. If your
binary is stripped you will need to use other commands like aaa, aab, aar, aac
or so.
Take some time to understand what each command does and the results after
running them to find the best one for your needs.
[ 0 x08048440]> aa
[ 0 x08048440]> pdf @ main
; DATA XREF from 0x08048457 ( entry0 )
/ ( f c n ) f c n .08048648 141
| ;−− main :
| 0x08048648 8d4c2404 l e a ecx , [ esp+0x4 ]
| 0x0804864c 83 e 4 f 0 and esp , 0 x f f f f f f f 0
| 0 x0804864f ff71fc push dword [ ecx−0x4 ]
| 0x08048652 55 push ebp
| ; CODE (CALL) XREF from 0x08048734 ( f c n .080486 e5 )
| 0x08048653 89 e5 mov ebp , esp
| 0x08048655 83 ec28 sub esp , 0x28
| 0x08048658 894 df4 mov [ ebp−0xc ] , ecx
| 0x0804865b 895 df8 mov [ ebp−0x8 ] , ebx
| 0x0804865e 8975 f c mov [ ebp−0x4 ] , e s i
| 0x08048661 8b19 mov ebx , [ ecx ]
| 0x08048663 8b7104 mov e s i , [ ecx+0x4 ]
| 0x08048666 c744240c000 . mov dword [ esp+0xc ] , 0x0
197
| 0x0804866e c7442408010 . mov dword [ esp+0x8 ] , 0x1 ;
0x00000001
| 0x08048676 c7442404000 . mov dword [ esp+0x4 ] , 0x0
| 0x0804867e c7042400000 . mov dword [ esp ] , 0x0
| 0x08048685 e852fdffff c a l l sym . . imp . p t r a c e
| sym . . imp . p t r a c e ( unk , unk )
| 0x0804868a 85 c0 t e s t eax , eax
| ,=< 0x0804868c 7911 j n s 0 x804869f
| | 0x0804868e c70424cf870 . mov dword [ esp ] ,
s t r . Don_tuseadebuguer_ ; 0 x080487cf
| | 0x08048695 e882fdffff c a l l sym . . imp . puts
| | sym . . imp . puts ( )
| | 0x0804869a e80dfdffff c a l l sym . . imp . abort
| | sym . . imp . abort ( )
| `−> 0 x0804869f 83 fb02 cmp ebx , 0x2
|,==< 0x080486a2 7411 j e 0x80486b5
|| 0x080486a4 c704240c880 . mov dword [ esp ] ,
s t r . Youmustgiveapasswordforusethisprogram_ ; 0x0804880c
|| 0x080486ab e86cfdffff c a l l sym . . imp . puts
|| sym . . imp . puts ( )
|| 0x080486b0 e8f7fcffff c a l l sym . . imp . abort
|| sym . . imp . abort ( )
|`−−> 0x080486b5 8b4604 mov eax , [ e s i +0x4 ]
| 0x080486b8 890424 mov [ esp ] , eax
| 0x080486bb e8e5feffff c a l l f c n .080485 a5
| f c n .080485 a5 ( ) ; f c n .080484 c6+223
| 0x080486c0 b800000000 mov eax , 0x0
| 0x080486c5 8 b4df4 mov ecx , [ ebp−0xc ]
| 0x080486c8 8 b5df8 mov ebx , [ ebp−0x8 ]
| 0x080486cb 8 b75fc mov e s i , [ ebp−0x4 ]
| 0 x080486ce 89 ec mov esp , ebp
| 0x080486d0 5d pop ebp
| 0x080486d1 8 d61fc l e a esp , [ ecx−0x4 ]
\ 0x080486d4 c3 ret
In this example, we analyze the whole file (aa) and then print disassembly
of the main() function (pdf). The aa command belongs to the family of auto
analysis commands and performs only the most basic auto analysis steps. In
radare2 there are many different types of the auto analysis commands with
a different analysis depth, including partial emulation: aa, aaa, aab, aaaa, …
There is also a mapping of those commands to the r2 CLI options: r2 −A,
r2 −AA, and so on.
198
Analyze functions
One of the most important “basic” analysis commands is the set of af subcom-
mands. af means “analyze function”. Using this command you can either allow
automatic analysis of the particular function or perform completely manual
one.
[ 0 x00000000]> a f ?
Usage : a f
| a f ( [ name ] ) ( [ addr ] ) analyze f u n c t i o n s ( s t a r t at
addr or $$ )
| a f r ( [ name ] ) ( [ addr ] ) analyze f u n c t i o n s r e c u r s i v e l y
| a f+ addr name [ type ] [ d i f f ] hand c r a f t a f u n c t i o n
( r e q u i r e s afb+)
| af− [ addr ] clean a l l function analysis
data ( or f u n c t i o n at addr )
| afa analyze f u n c t i o n arguments
i n a c a l l ( a f a l honors dbg . funcarg )
| afb+ fcnA bbA s z [ j ] [ f ] ( [ t ] ( [ d ] ) ) add bb to f u n c t i o n @ fcnaddr
| afb [ ? ] [ addr ] L i s t b a s i c b l o c k s o f given
function
| afbF ( [ 0 | 1 ] ) Toggle the basic−block
' fo l ded ' a t t r i b u t e
| afB 16 s e t c u r r e n t f u n c t i o n as
thumb ( change asm . b i t s )
| afC [ l c ] ( [ addr ] )@[ addr ] c a l c u l a t e the Cycles ( afC )
or Cyclomatic Complexity ( afCc )
| a f c [ ? ] type @[ addr ] s e t c a l l i n g convention f o r
function
| afd [ addr ] show f u n c t i o n + d e l t a f o r
given o f f s e t
| afF [ 1 | 0 | ] f o l d / unfold / t o g g l e
| a f i [ addr | f c n . name ] show f u n c t i o n ( s ) i n f o r m a t i o n
( verbose a f l )
| a f j [ tableaddr ] [ count ] analyze f u n c t i o n jumptable
| a f l [ ? ] [ l s ∗ ] [ f c n name ] l i s t f u n c t i o n s ( addr , s i z e ,
bbs , name) ( s e e a f l l )
| afm name merge two f u n c t i o n s
| afM name p r i n t f u n c t i o n s map
| afn [ ? ] name [ addr ] rename name f o r f u n c t i o n at
address ( change f l a g too )
| afna s u g g e s t automatic name f o r
current o f f s e t
| a f o [ ? j ] [ f c n . name ] show address f o r the
f u n c t i o n name or c u r r e n t o f f s e t
| afs [ ! ] ( [ fcnsign ] ) get / s e t f u n c t i o n s i g n a t u r e
at c u r r e n t address ( a f s ! u s e s c f g . e d i t o r )
| afS [ s t a c k _ s i z e ] s e t s t a c k frame s i z e f o r
f u n c t i o n at c u r r e n t address
| a f s r [ function_name ] [ new_type ] change type f o r given
function
199
| aft [ ? ] type matching , type
propagation
| afu addr r e s i z e and analyze f u n c t i o n
from c u r r e n t address u n t i l addr
| afv [ absrx ] ? manipulate args , r e g i s t e r s
and v a r i a b l e s i n f u n c t i o n
| afx l i s t function references
You can use afl to list the functions found by the analysis.
There are a lot of useful commands under afl such as aflj , which lists the
function in JSON format and aflm, which lists the functions in the syntax
found in makefiles.
There’s also afl =, which displays ASCII-art bars with function ranges.
You can find the rest of them under afl ?.
Some of the most challenging tasks while performing a function analysis are
merge, crop and resize. As with other analysis commands you have two
modes: semi-automatic and manual. For the semi-automatic, you can use
afm <function name> to merge the current function with the one specified by
name as an argument, aff to readjust the function after analysis changes or
function edits, afu <address> to do the resize and analysis of the current func-
tion until the specified address.
Apart from those semi-automatic ways to edit/analyze the function, you can
hand craft it in the manual mode with af+ command and edit basic blocks of
it using afb commands. Before changing the basic blocks of the function it is
recommended to check the already presented ones:
[ 0 x00003ac0]> afb
0x00003ac0 0 x00003b7f 01:001A 191 f 0 x00003b7f
0 x00003b7f 0x00003b84 00:0000 5 j 0x00003b92 f 0x00003b84
0x00003b84 0x00003b8d 00:0000 9 f 0x00003b8d
0x00003b8d 0x00003b92 00:0000 5
0x00003b92 0x00003ba8 01:0030 22 j 0x00003ba8
0x00003ba8 0 x00003bf9 00:0000 81
200
r e s u l t += 1 ;
return r e s u l t ;
}
then compile with gcc −c example.c −m32 −O0 −fno−pie, and open the object file
with radare2.
example.o
Since we haven’t analyzed it yet, the pdf command will not print out the
disassembly here:
$ r2 example . o
[ 0 x08000034]> pdf
p : Cannot f i n d f u n c t i o n at 0x08000034
[ 0 x08000034]> pd
;−− s e c t i o n . . t e x t :
;−− . t e x t :
;−− code_block :
;−− e i p :
0x08000034 55 push ebp
; [ 0 1 ] −r−x s e c t i o n s i z e 41 named . t e x t
0x08000035 89 e5 mov ebp , esp
0x08000037 83 ec10 sub esp , 0x10
0x0800003a c745f8000000 . mov dword [ ebp − 8] , 0
0x08000041 c745fc000000 . mov dword [ ebp − 4] , 0
,=< 0x08000048 eb08 jmp 0x8000052
.−−> 0x0800004a 8345 f801 add dword [ ebp − 8] , 1
:| 0x0800004e 8345 f c 0 1 add dword [ ebp − 4] , 1
:`−> 0x08000052 837 dfc09 cmp dword [ ebp − 4] , 9
`==< 0x08000056 7ef2 j l e 0x800004a
0x08000058 8 b45f8 mov eax , dword [ ebp − 8 ]
0x0800005b c9 leave
0x0800005c c3 ret
201
Figure 21: analyze_one
202
the next block (0x08000052 ~ 0x08000056) is more likeyly an if conditional
statement which has two branches. It will jump to 0x800004a if jle −less or
equal, otherwise (the fail condition) jump to next instruction – 0x08000058.:
[ 0 x08000034]> afb+ code_block 0x8000052 0x8000058−0x8000052
0x800004a 0x8000058
follow the control flow and create the remaining two blocks (two branches) :
[ 0 x08000034]> afb+ code_block 0x800004a 0x8000052−0x800004a 0x8000052
[ 0 x08000034]> afb+ code_block 0x8000058 0x800005d−0x8000058
There are two very important commands for this: afc and afB. The latter is
a must-know command for some platforms like ARM. It provides a way to
change the “bitness” of the particular function. Basically, allowing to select
between ARM and Thumb modes.
afc on the other side, allows to manually specify function calling convention.
You can find more information on its usage in calling_conventions.
Recursive analysis
There are 5 important program wide half-automated analysis commands:
203
Figure 22: handcraft_one
204
| ax addr [ at ] add code r e f p o i n t i n g to addr ( from c u r s e e k )
| ax− [ at ] c l e a n a l l r e f s / r e f s from addr
| ax−∗ clean a l l r e f s / r e f s
| axc addr [ at ] add g e n e r i c code r e f
| axC addr [ at ] add code c a l l r e f
| axg [ addr ] show x r e f s graph to reach c u r r e n t f u n c t i o n
| axg∗ [ addr ] show x r e f s graph to given address , use . axg ∗ ; aggv
| axgj [ addr ] show x r e f s graph to reach c u r r e n t f u n c t i o n i n j s o n
format
| axd addr [ at ] add data r e f
| axq l i s t r e f s i n q u i e t /human−re ad a b l e format
| axj l i s t r e f s i n j s o n format
| axF [ f l g −glob ] f i n d data / code r e f e r e n c e s o f f l a g s
| axm addr [ at ] copy data / code r e f e r e n c e s p o i n t i n g to addr to a l s o
point to c u rs e e k ( or at )
| axt [ addr ] f i n d data / code r e f e r e n c e s to t h i s address
| axf [ addr ] f i n d data / code r e f e r e n c e s from t h i s address
| axv [ addr ] l i s t l o c a l v a r i a b l e s read−write−exec r e f e r e n c e s
| ax . [ addr ] f i n d data / code r e f e r e n c e s from and to t h i s address
| a x f f [ j ] [ addr ] f i n d data / code r e f e r e n c e s from t h i s f u n c t i o n
| axs addr [ at ] add s t r i n g r e f
The most commonly used ax commands are axt and axf, especially as a part of
various r2pipe scripts. Lets say we see the string in the data or a code section
and want to find all places it was referenced from, we should use axt:
[ 0 x0001783a]> pd 2
;−− s t r . 0 2 x :
; STRING XREF from 0x00005de0 ( sub . strlen_d50 )
; CODE XREF from 0x00017838 ( s t r . . _s_s_s + 7)
0x0001783a . s t r i n g ”%%%02x” ; l e n=7
;−− s t r . s r c _ l s . c :
; STRING XREF from 0x0000541b ( sub . free_b04 )
; STRING XREF from 0x0000543a ( sub . __assert_fail_41f + 27)
; STRING XREF from 0x00005459 ( sub . __assert_fail_41f + 58)
; STRING XREF from 0 x00005f9e ( sub . _setjmp_e30 )
; CODE XREF from 0 x0001783f ( s t r . 0 2 x + 5)
0x00017841 . s t r i n g ” s r c / l s . c ” ; l e n=9
[ 0 x0001783a]> axt
sub . strlen_d50 0x5de0 [STRING] l e a rcx , s t r . 0 2 x
( nofunc ) 0x17838 [CODE] j a e s t r . 0 2 x
There are also some useful commands under axt. Use axtg to generate radare2
commands which will help you to create graphs according to the XREFs.
[ 0 x08048320]> s main
[ 0 x080483e0]> axtg
agn 0x8048337 ” entry0 + 23”
agn 0x80483e0 ”main”
age 0x8048337 0x80483e0
Use axt∗ to split the radare2 commands and set flags on those corresponding
XREFs.
205
Also under ax is axg, which finds the path between two points in the file by
showing an XREFs graph to reach the location or function. For example:
:> axg sym . imp . p r i n t f
− 0x08048a5c f c n 0x08048a5c sym . imp . p r i n t f
− 0x080483e5 f c n 0x080483e0 main
− 0x080483e0 f c n 0x080483e0 main
− 0x08048337 f c n 0x08048320 entry0
− 0x08048425 f c n 0x080483e0 main
Use axg∗ to generate radare2 commands which will help you to create graphs
using agn and age commands, according to the XREFs.
Apart from predefined algorithms to identify functions there is a way to specify
a function prelude with a configuration option anal.prelude. For example, like
e anal.prelude = 0x554889e5 which means
push rbp
mov rbp , rsp
Configuration
Radare2 allows to change the behavior of almost any analysis stages or com-
mands. There are different kinds of the configuration options:
• Flow control
• Basic blocks control
• References control
• IO/Ranges
• Jump tables analysis control
• Platform/target specific options
206
In addition to those we can also set anal.jmp.indir to follow the indirect jumps,
continuing analysis; anal.pushret to analyze push ...; ret sequence as a jump;
anal.nopskip to skip the NOP sequences at a function beginning.
For now, radare2 also allows you to change the maximum basic block size
with anal.bb.maxsize option . The default value just works in most use cases,
but it’s useful to increase that for example when dealing with obfuscated code.
Beware that some of basic blocks control options may disappear in the future
in favor of more automated ways to set those.
For some unusual binaries or targets, there is an option anal.noncode. Radare2
doesn’t try to analyze data sections as a code by default. But in some cases
- malware, packed binaries, binaries for embedded systems, it is often a case.
Thus - this option.
Reference control The most crucial options that change the analysis re-
sults drastically. Sometimes some can be disabled to save the time and mem-
ory when analyzing big binaries.
• anal.jmp.ref - to allow references creation for unconditional jumps
• anal.jmp.cref - same, but for conditional jumps
• anal.datarefs - to follow the data references in code
• anal. refstr - search for strings in data references
• anal.strings - search for strings and creating references
207
– To analyze in the current function or basic block, you can specify
anal.in=anal.fcn or anal.in=anal.bb.
Jump tables Jump tables are one of the trickiest targets in binary reverse
engineering. There are hundreds of different types, the end result depending
on the compiler/linker and LTO stages of optimization. Thus radare2 allows
enabling some experimental jump tables detection algorithms using anal.jmp.tbl
option. Eventually, algorithms moved into the default analysis loops once they
start to work on every supported platform/target/testcase. Two more options
can affect the jump tables analysis results too:
• anal.jmp.indir - follow the indirect jumps, some jump tables rely on them
• anal.datarefs - follow the data references, some jump tables use those
Platform specific controls There are two common problems when ana-
lyzing embedded targets: ARM/Thumb detection and MIPS GP value. In
case of ARM binaries radare2 supports some auto-detection of ARM/Thumb
mode switches, but beware that it uses partial ESIL emulation, thus slowing
the analysis process. If you will not like the results, particular functions’ mode
can be overridden with afB command.
The MIPS GP problem is even trickier. It is a basic knowledge that GP value
can be different not only for the whole program, but also for some functions.
To partially solve that there are options anal.gp and anal.gpfixed. The first one
sets the GP value for the whole program or particular function. The latter
allows to “constantify” the GP value if some code is willing to change its value,
always resetting it if the case. Those are heavily experimental and might be
changed in the future in favor of more automated analysis.
Visuals
One of the easiest way to see and check the changes of the analysis commands
and variables is to perform a scrolling in a Vv special visual mode, allowing
functions preview:
When we want to check how analysis changes affect the result in the case of
big functions, we can use minimap instead, allowing to see a bigger flow graph
on the same screen size. To get into the minimap mode type VV then press p
twice:
This mode allows you to see the disassembly of each node separately, just
navigate between them using Tab key.
208
Figure 23: vv
209
Analysis hints
It is not an uncommon case that analysis results are not perfect even after
you tried every single configuration option. This is where the “analysis hints”
radare2 mechanism comes in. It allows to override some basic opcode or meta-
information properties, or even to rewrite the whole opcode string. These
commands are located under ah namespace:
Usage : ah [ lba −] An al ysi s Hints
| ah? show t h i s help
| ah? o f f s e t show h i n t o f given o f f s e t
| ah l i s t h i n t s i n human−re a d ab l e format
| ah . l i s t h i n t s i n human−re a d ab l e format from
current o f f s e t
| ah− remove a l l h i n t s
| ah− o f f s e t [ s i z e ] remove h i n t s at given o f f s e t
| ah∗ o f f s e t l i s t h i n t s i n radare commands format
| aha ppc @ 0x42 f o r c e arch ppc f o r a l l addrs >= 0x42 or u n t i l
the next h i n t
| aha 0 @ 0x84 d i s a b l e the e f f e c t o f arch h i n t s f o r a l l addrs
>= 0x84 or u n t i l the next h i n t
| ahb 16 @ 0x42 f o r c e 16 b i t f o r a l l addrs >= 0x42 or u n t i l the
next h i n t
| ahb 0 @ 0x84 d i s a b l e the e f f e c t o f b i t s h i n t s f o r a l l addrs
>= 0x84 or u n t i l the next h i n t
| ahc 0x804804 o v e r r i d e c a l l /jump address
| ahd f o o a0 , 3 3 r e p l a c e opcode s t r i n g
| ahe 3 , eax,+= s e t vm a n a l y s i s s t r i n g
| ahf 0x804840 o v e r r i d e f a l l b a c k address f o r c a l l
| ahF 0x10 s e t stackframe s i z e at c u r r e n t o f f s e t
| ahh 0x804840 h i g h l i g h t t h i s address o f f s e t i n disasm
| ahi [ ? ] 10 d e f i n e numeric base f o r immediates ( 2 , 8 , 10 ,
10u , 16 , i , p , S , s )
| ahj l i s t h i n t s i n JSON
| aho c a l l change opcode type ( s e e aho ?) ( deprecated ,
moved to ”ahd ”)
| ahp addr set pointer hint
| ahr v a l s e t h i n t f o r r e t u r n value o f a f u n c t i o n
| ahs 4 s e t opcode s i z e=4
| ahS j z s e t asm . syntax=j z f o r t h i s opcode
| aht [ ? ] <type> Mark immediate as a type o f f s e t ( deprecated ,
moved to ”aho ”)
| ahv v a l change opcode ' s v a l f i e l d ( u s e f u l to s e t jmptbl
s i z e s i n jmp rax )
One of the most common cases is to set a particular numeric base for imme-
diates:
[ 0 x00003d54]> ahi ?
Usage : ahi [ 2 | 8 | 1 0 | 1 0 u | 1 6 | bodhipSs ] [@ o f f s e t ] Define numeric base
| ahi <base> s e t numeric base ( 2 , 8 , 10 , 16)
| ahi 1 0 | d s e t base to s i g n e d decimal ( 1 0 ) , s i g n b i t should
depend on r e c e i v e r s i z e
210
| ahi 10u | du set base to unsigned decimal ( 1 1 )
| ahi b set base to binary ( 2 )
| ahi o set base to octal (8)
| ahi h set base to hexadecimal ( 1 6 )
| ahi i set base to IP address ( 3 2 )
| ahi p set base to htons ( port ) ( 3 )
| ahi S set base to s y s c a l l (80)
| ahi s set base to string (1)
[ 0 x00003d54]> pd 2
0x00003d54 0583000000 add eax , 0x83
0x00003d59 3d13010000 cmp eax , 0x113
[ 0 x00003d54]> ahi d
[ 0 x00003d54]> pd 2
0x00003d54 0583000000 add eax , 131
0x00003d59 3d13010000 cmp eax , 0x113
[ 0 x00003d54]> ahi b
[ 0 x00003d54]> pd 2
0x00003d54 0583000000 add eax , 10000011b
0x00003d59 3d13010000 cmp eax , 0x113
It is notable that some analysis stages or commands add the internal analysis
hints, which can be checked with ah command:
[ 0 x00003d54]> ah
0x00003d54 − 0x00003d54 => immbase=2
[ 0 x00003d54]> ah∗
ahi 2 @ 0x3d54
211
d i r e c t i o n : exec
f a i l : 0 x00003cf3
st a ck : n u l l
f a m i l y : cpu
stackop : n u l l
[ 0 x00003cee]> ahc 0x5382
[ 0 x00003cee]> pd 2
0 x00003cee e83d080100 c a l l sub . __errno_location_530
0 x00003cf3 85 c0 t e s t eax , eax
[ 0 x00003cee]> ao
address : 0 x3cee
opcode : c a l l 0x14530
mnemonic : c a l l
prefix : 0
i d : 56
bytes : e83d080100
refptr : 0
size : 5
sign : f a l s e
type : c a l l
cycles : 3
e s i l : 83248 , ri p , 8 , rsp ,−=,rsp , = [ ] , r i p ,=
jump : 0x00005382
d i r e c t i o n : exec
f a i l : 0 x00003cf3
st a ck : n u l l
f a m i l y : cpu
stackop : n u l l
[ 0 x00003cee]> ah
0 x00003cee − 0 x00003cee => jump : 0x5382
As you can see, despite the unchanged disassembly view the jump address in
opcode was changed (jump option).
If anything of the previously described didn’t help, you can simply override
shown disassembly with anything you like:
[ 0 x00003d54]> pd 2
0x00003d54 0583000000 add eax , 10000011b
0x00003d59 3d13010000 cmp eax , 0x113
[ 0 x00003d54]> ”ahd myopcode bla , f o o ”
[ 0 x00003d54]> pd 2
0x00003d54 myopcode bla , f o o
0x00003d55 830000 add dword [ rax ] , 0
Managing variables
Radare2 allows managing local variables, no matter their location, stack or
registers. The variables’ auto analysis is enabled by default but can be dis-
abled with anal.vars configuration option.
The main variables commands are located in afv namespace:
212
Usage : afv [ rbs ]
| afv ∗ output r2 command to add a r g s / l o c a l s
to f l a g s p a c e
| afv −([name ] ) remove a l l or given var
| afv= l i s t f u n c t i o n v a r i a b l e s and
arguments with disasm r e f s
| afva analyze f u n c t i o n arguments/ l o c a l s
| afvb [ ? ] manipulate bp based arguments/ l o c a l s
| afvd name output r2 command f o r d i s p l a y i n g the
value o f a r g s / l o c a l s i n the debugger
| afvf show BP r e l a t i v e stackframe v a r i a b l e s
| afvn [ new_name ] ( [ old_name ] ) rename argument/ l o c a l
| afvr [ ? ] manipulate r e g i s t e r based arguments
| afvR [ varname ] l i s t a d d r e s s e s where vars are
a c c e s s e d (READ)
| afvs [ ? ] manipulate sp based arguments/ l o c a l s
| a f v t [ name ] [ new_type ] change type f o r given argument/ l o c a l
| afvW [ varname ] l i s t a d d r e s s e s where vars are
a c c e s s e d (WRITE)
| afvx show f u n c t i o n v a r i a b l e x r e f s ( same
as afvR+afvW)
afvr, afvband afvs commands are uniform but allow manipulation of register-
based arguments and variables, BP/FP-based arguments and variables, and
SP-based arguments and variables respectively. If we check the help for afvr
we will get the way two others commands works too:
| Usage : a f v r [ reg ] [ type ] [ name ]
| afvr l i s t r e g i s t e r based arguments
| afvr ∗ same as a f v r but i n r2 commands
| a f v r [ reg ] [ name ] ( [ type ] ) d e f i n e r e g i s t e r arguments
| afvrj r e t u r n l i s t o f r e g i s t e r arguments i n
JSON format
| afvr− [ name ] d e l e t e r e g i s t e r arguments at the given
index
| a f v r g [ reg ] [ addr ] d e f i n e argument get r e f e r e n c e
| a f v r s [ reg ] [ addr ] d e f i n e argument s e t r e f e r e n c e
213
As mentioned before the analysis loop relies heavily on types information
while performing variables analysis stages. Thus comes next very important
command - afvt, which allows you to change the type of variable:
[ 0 x00003b92]> a f v s
var i n t local_8h @ rsp+0x8
var i n t local_10h @ rsp+0x10
var i n t local_28h @ rsp+0x28
var i n t local_30h @ rsp+0x30
var i n t local_32h @ rsp+0x32
var i n t local_38h @ rsp+0x38
var i n t local_45h @ rsp+0x45
var i n t local_46h @ rsp+0x46
var i n t local_47h @ rsp+0x47
var i n t local_48h @ rsp+0x48
[ 0 x00003b92]> a f v t local_10h char ∗
[ 0 x00003b92]> a f v s
var i n t local_8h @ rsp+0x8
var char ∗ local_10h @ rsp+0x10
var i n t local_28h @ rsp+0x28
var i n t local_30h @ rsp+0x30
var i n t local_32h @ rsp+0x32
var i n t local_38h @ rsp+0x38
var i n t local_45h @ rsp+0x45
var i n t local_46h @ rsp+0x46
var i n t local_47h @ rsp+0x47
var i n t local_48h @ rsp+0x48
Less commonly used feature, which is still under heavy development - dis-
tinction between variables being read and written. You can list those being
read with afvR command and those being written with afvW command. Both
commands provide a list of the places those operations are performed:
[ 0 x00003b92]> afvR
local_48h 0 x48ee
local_30h 0x3c93 , 0 x520b , 0 x52ea , 0 x532c , 0 x5400 , 0 x3cfb
local_10h 0x4b53 , 0 x5225 , 0 x53bd , 0 x50cc
local_8h 0x4d40 , 0 x4d99 , 0 x5221 , 0 x53b9 , 0 x50c8 , 0 x4620
local_28h 0x503a , 0 x51d8 , 0 x51fa , 0 x52d3 , 0 x531b
local_38h
local_45h 0x50a1
local_47h
local_46h
local_32h 0x3cb1
[ 0 x00003b92]> afvW
local_48h 0 x3adf
local_30h 0x3d3e , 0 x4868 , 0 x5030
local_10h 0x3d0e , 0 x5035
local_8h 0x3d13 , 0 x4d39 , 0 x5025
local_28h 0x4d00 , 0 x52dc , 0 x53af , 0 x5060 , 0 x507a , 0 x508b
local_38h 0x486d
local_45h 0x5014 , 0 x5068
local_47h 0x501b
214
local_46h 0x5083
local_32h
[ 0 x00003b92]>
Type inference
The type inference for local variables and arguments is well integrated with
the command afta.
Let’s see an example of this with a simple hello_world binary
[ 0 x000007aa]> pdf
| ;−− main :
/ ( f c n ) sym . main 157
| sym . main ( ) ;
| ; var i n t local_20h @ rbp−0x20
| ; var i n t local_1ch @ rbp−0x1c
| ; var i n t local_18h @ rbp−0x18
| ; var i n t local_10h @ rbp−0x10
| ; var i n t local_8h @ rbp−0x8
| ; DATA XREF from entry0 (0 x6bd )
| 0x000007aa push rbp
| 0x000007ab mov rbp , rsp
| 0x000007ae sub rsp , 0x20
| 0x000007b2 l e a rax , s t r . H e l l o ; 0x8d4 ; ” H e l l o ”
| 0x000007b9 mov qword [ local_18h ] , rax
| 0x000007bd l e a rax , s t r . r 2 _ f o l k s ; 0x8da ; ” r2−f o l k s ”
| 0x000007c4 mov qword [ local_10h ] , rax
| 0x000007c8 mov rax , qword [ local_18h ]
| 0 x000007cc mov r d i , rax
| 0 x000007cf c a l l sym . imp . s t r l e n ; s i z e _ t s t r l e n ( const char
∗s )
215
| 0x000007bd l e a rax , s t r . r 2 _ f o l k s ; 0x8da ; ” r2−f o l k s ”
| 0x000007c4 mov qword [ s2 ] , rax
| 0x000007c8 mov rax , qword [ s r c ]
| 0 x000007cc mov r d i , rax ; const char ∗ s
| 0 x000007cf c a l l sym . imp . s t r l e n ; s i z e _ t s t r l e n ( const char
∗s )
It also extracts type information from format strings like printf (”fmt : %s , %u
, %d”, ...), the format specifications are extracted from anal/d/spec.sdb
You could create a new profile for specifying a set of format chars depending
on different libraries/operating systems/programming languages like this :
win=spec
spec . win . u32=unsigned i n t
Then change your default specification to newly created one using this config
variable e anal.spec = win
For more information about primitive and user-defined types support in
radare2 refer to types chapter.
Types
Radare2 supports the C-syntax data types description. Those types are parsed
by a C11-compatible parser and stored in the internal SDB, thus are intro-
spectable with k command.
Most of the related commands are located in t namespace:
[ 0 x00000000]> t ?
| Usage : t # c p a r s e types commands
| t L i s t a l l loaded types
| tj L i s t a l l loaded types as j s o n
| t <type> Show type i n ' pf ' syntax
| t∗ L i s t types i n f o i n r2 commands
| t− <name> Delete types by i t s name
| t−∗ Remove a l l types
| t a i l [ filename ] Output the l a s t part o f f i l e s
| t c [ type . name ] L i s t a l l / given types i n C output format
| te [ ? ] L i s t a l l loaded enums
| td [ ? ] <s t r i n g > Load types from s t r i n g
| tf L i s t a l l loaded f u n c t i o n s s i g n a t u r e s
| tk <sdb−query> Perform sdb query
| tl [?] Show/Link type to an address
| tn [ ? ] [ − ] [ addr ] manage noreturn f u n c t i o n a t t r i b u t e s and
marks
| to − Open c f g . e d i t o r to load types
| to <path> Load types from C header f i l e
| toe [ type . name ] Open c f g . e d i t o r to e d i t types
| t o s <path> Load types from parsed Sdb database
216
| tp <type> [ addr | varname ] c a s t data at <address> to <type> and
print i t (XXX: type can contain s pa ce s )
| tpv <type> @ [ value ] Show o f f s e t formatted f o r given type
| tpx <type> <hexpairs> Show value f o r type with s p e c i f i e d byte
sequence (XXX: type can contain sp a ce s )
| ts [ ? ] Print loaded s t r u c t types
| tu [ ? ] Print loaded union types
| tx [ f ? ] Type x r e f s
| tt [ ? ] L i s t a l l loaded t y p e d e f s
Note that the basic (atomic) types are not those from C standard - not char,
_Bool, or short. Because those types can be different from one platform to
another, radare2 uses definite types like as int8_t or uint64_t and will convert int
to int32_t or int64_t depending on the binary or debuggee platform/compiler.
Basic types can be listed using t command. For the structured types you need
to use ts, for unions use tu and for enums — te.
[ 0 x00000000]> t
char
char ∗
double
float
gid_t
int
int16_t
int32_t
int64_t
int8_t
long
long long
pid_t
short
size_t
uid_t
uint16_t
uint32_t
uint64_t
uint8_t
unsigned char
unsigned i n t
unsigned s h o r t
void ∗
Loading types
There are three easy ways to define a new type:
• Directly from the string using td command
• From the file using to <filename> command
• Open an $EDITOR to type the definitions in place using to −
217
[ 0 x00000000]> ” td s t r u c t f o o { char ∗ a ; i n t b ; } ”
[ 0 x00000000]> cat ~/ radare2−r e g r e s s i o n s / b i n s / headers / s3 . h
s t r u c t S1 {
int x [ 3 ] ;
int y [ 4 ] ;
int z ;
};
[ 0 x00000000]> to ~/ radare2−r e g r e s s i o n s / b i n s / headers / s3 . h
[ 0 x00000000]> ts
foo
S1
Also note there is a config option to specify include directories for types parsing
[ 0 x00000000]> e ? d i r . types
d i r . types : Default path to look f o r c p a r s e type f i l e s
[ 0 x00000000]> e d i r . types
/ usr / i n c l u d e
Printing types
Notice below we have used ts command, which basically converts the C type
description (or to be precise it’s SDB representation) into the sequence of pf
commands. See more about print format.
The tp command uses the pf string to print all the members of type at the
current offset/given address:
[ 0 x00000000]> ” td s t r u c t f o o { char ∗ a ; i n t b ; } ”
[ 0 x00000000]> wx 68656 c6c6f000c000000
[ 0 x00000000]> wz world @ 0x00000010 ; wx 17 @ 0x00000016
[ 0 x00000000]> px
[ 0 x00000000]> t s f o o
pf zd a b
[ 0 x00000000]> tp f o o
a : 0x00000000 = ” h e l l o ”
b : 0x00000006 = 12
[ 0 x00000000]> tp f o o @ 0x00000010
a : 0x00000010 = ” world ”
b : 0x00000016 = 23
Also, you could fill your own data into the struct and print it using tpx com-
mand
[ 0 x00000000]> tpx f o o 414243440010000000
a : 0x00000000 = ”ABCD”
b : 0x00000005 = 16
218
Linking Types
The tp command just performs a temporary cast. But if we want to link some
address or variable with the chosen type, we can use tl command to store the
relationship in SDB.
[ 0 x000051c0]> t l S1 = 0 x51cf
[ 0 x000051c0]> t l l
( S1 )
x : 0 x000051cf = [ 2315619660 , 1207959810 , 34803085 ]
y : 0x000051db = [ 2370306049 , 4293315645 , 3860201471 , 4093649307 ]
z : 0x000051eb = 4464399
Moreover, the link will be shown in the disassembly output or visual mode:
[ 0 x000051c0 15% 300 / bin / l s ]> pd $r @ entry0
;−− entry0 :
0x000051c0 xor ebp , ebp
0x000051c2 mov r9 , rdx
0x000051c5 pop r s i
0x000051c6 mov rdx , rsp
0x000051c9 and rsp , 0 x f f f f f f f f f f f f f f f 0
0x000051cd push rax
0 x000051ce push rsp
( S1 )
x : 0 x000051cf = [ 2315619660 , 1207959810 , 34803085 ]
y : 0x000051db = [ 2370306049 , 4293315645 , 3860201471 , 4093649307 ]
z : 0x000051eb = 4464399
0 x000051f0 l e a r d i , l o c . _edata ; 0 x21f248
0 x000051f7 push rbp
0 x000051f8 l e a rax , l o c . _edata ; 0 x21f248
0 x 00 0 0 5 1 f f cmp rax , r d i
0x00005202 mov rbp , rsp
Once the struct is linked, radare2 tries to propagate structure offset in the
function at current offset, to run this analysis on whole program or at any
targeted functions after all structs are linked you have aat command:
[ 0 x00000000]> aa?
| aat [ f c n ] Analyze a l l / given f u n c t i o n to convert
immediate to l i n k e d s t r u c t u r e o f f s e t s ( s e e t l ?)
Note sometimes the emulation may not be accurate, for example as below :
| 0 x000006da push rbp
| 0 x000006db mov rbp , rsp
| 0 x000006de sub rsp , 0x10
| 0 x000006e2 mov edi , 0x20 ; ”@”
| 0 x000006e7 c a l l sym . imp . malloc ; void ∗ malloc ( s i z e _ t s i z e )
| 0 x000006ec mov qword [ local_8h ] , rax
| 0 x000006f0 mov rax , qword [ local_8h ]
219
The return value of malloc may differ between two emulations, so you have to
set the hint for return value manually using ahr command, so run tl or aat
command after setting up the return value hint.
[ 0 x000006da]> ah?
| ahr v a l s e t h i n t f o r r e t u r n value o f a f u n c t i o n
Structure Immediates
There is one more important aspect of using types in radare2 - using aht you
can change the immediate in the opcode to the structure offset. Lets see a
simple example of [R]SI-relative addressing
[ 0 x000052f0 ]> pd 1
0 x000052f0 mov rax , qword [ r s i + 8 ] ; [ 0 x8 :8]=0
Here 8 - is some offset in the memory, where rsi probably holds some structure
pointer. Imagine that we have the following structures
[ 0 x000052f0 ]> ” td s t r u c t ms { char b [ 8 ] ; i n t member1 ; i n t member2 ;
};”
[ 0 x000052f0 ]> ” td s t r u c t ms1 { uint64_t a ; i n t member1 ; } ; ”
[ 0 x000052f0 ]> ” td s t r u c t ms2 { uint16_t a ; int64_t b ; i n t member1 ;
};”
Now we need to set the proper structure member offset instead of 8 in this
instruction. At first, we need to list available types matching this offset:
[ 0 x000052f0 ]> ahts 8
ms . member1
ms1 . member1
Note, that ms2 is not listed, because it has no members with offset 8. After
listing available options we can link it to the chosen offset at the current
address:
[ 0 x000052f0 ]> aht ms1 . member1
[ 0 x000052f0 ]> pd 1
0 x000052f0 488b4608 mov rax , qword [ r s i + ms1 . member1 ]
; [ 0 x8 :8]=0
Managing enums
• Printing all fields in enum using te command
[ 0 x00000000]> ” td enum Foo {COW=1,BAR=2};”
[ 0 x00000000]> t e Foo
COW = 0x1
BAR = 0x2
220
• Finding matching enum member for given bitfield and vice-versa
[ 0 x00000000]> t e Foo 0x1
COW
[ 0 x00000000]> teb Foo COW
0x1
Internal representation
To see the internal representation of the types you can use tk command:
[ 0 x000051c0]> tk~S1
S1=s t r u c t
s t r u c t . S1=x , y , z
s t r u c t . S1 . x=int32_t , 0 , 3
s t r u c t . S1 . x . meta=4
s t r u c t . S1 . y=int32_t , 1 2 , 4
s t r u c t . S1 . y . meta=4
s t r u c t . S1 . z=int32_t , 2 8 , 0
s t r u c t . S1 . z . meta=0
[ 0 x000051c0]>
there are basically 3 mandatory keys for defining basic data types: X=type
type.X=format_specifier type.X.size=size_in_bits For example, let’s define UNIT,
according to Microsoft documentation UINT is just equivalent of standard C
unsigned int (or uint32_t in terms of TCC engine). It will be defined as:
221
UINT=type
type .UINT=d
type .UINT. s i z e =32
This one may only be used in case of pointer type.X=p, one good example is
LPFILETIME definition, it is a pointer to _FILETIME which happens to be
a structure. Assuming that we are targeting only 32-bit windows machine, it
will be defined as the following:
LPFILETIME=type
type .LPFILETIME=p
type .LPFILETIME. s i z e =32
type .LPFILETIME. p o i n t t o=_FILETIME
This last field is not mandatory because sometimes the data structure internals
will be proprietary, and we will not have a clean representation for it.
There is also one more optional entry:
type .UINT. meta=4
This entry is for integration with C parser and carries the type class informa-
tion: integer size, signed/unsigned, etc.
Structures
Those are the basic keys for structs (with just two elements):
X=s t r u c t
s t r u c t .X=a , b
s t r u c t .X. a=a_type , a_offset , a_number_of_elements
s t r u c t .X. b=b_type , b_offset , b_number_of_elements
The first line is used to define a structure called X, the second line defines
the elements of X as comma separated values. After that, we just define each
element info.
For example. we can have a struct like this one:
struct _FILETIME {
DWORD dwLowDateTime ;
DWORD dwHighDateTime ;
}
assuming we have DWORD defined, the struct will look like this
222
_FILETIME=s t r u c t
s t r u c t ._FILETIME=dwLowDateTime , dwHighDateTime
s t r u c t ._FILETIME. dwLowDateTime=DWORD, 0 , 0
s t r u c t ._FILETIME. dwHighDateTime=DWORD, 4 , 0
Note that the number of elements field is used in case of arrays only to identify
how many elements are in arrays, other than that it is zero by default.
Unions
Unions are defined exactly like structs the only difference is that you will
replace the word struct with the word union.
Function prototypes
Function prototypes representation is the most detail oriented and the most
important one of them all. Actually, this is the one used directly for type
matching
X=func
func .X. a r g s=NumberOfArgs
func . x . arg0=Arg_type , arg_name
.
.
.
func .X. r e t=Return_type
func .X. cc=c a l l i n g _ c o n v e n t i o n
When converting it into its sdb representation it will look like the following:
strcasecmp=func
func . strcasecmp . a r g s=3
func . strcasecmp . arg0=char ∗ , s1
func . strcasecmp . arg1=char ∗ , s2
func . strcasecmp . arg2=size_t , n
func . strcasecmp . r e t=i n t
func . strcasecmp . cc=c d e c l
Note that the .cc part is optional and if it didn’t exist the default calling-
convention for your target architecture will be used instead. There is one
extra optional key
func . x . noreturn=t r u e / f a l s e
223
This key is used to mark functions that will not return once called, such as
exit and _exit.
Calling Conventions
Radare2 uses calling conventions to help in identifying function formal argu-
ments and return types. It is used also as a guide for basic function prototype
and type propagation.
[ 0 x00000000]> a f c ?
| Usage : a f c [ a g l ? ]
| a f c convention Manually s e t c a l l i n g convention f o r c u r r e n t
function
| afc Show C a l l i n g convention f o r the Current f u n c t i o n
| a f c =([ cctype ] ) S e l e c t or show d e f a u l t c a l l i n g convention
| afcr [ j ] Show r e g i s t e r usage f o r the c u r r e n t f u n c t i o n
| afca Analyse f u n c t i o n f o r f i n d i n g the c u r r e n t c a l l i n g
convention
| a f c f [ j ] [ name ] P r i n t s r e t u r n type f u n c t i o n ( arg1 , arg2 . . . ) , s e e
afij
| afck L i s t SDB d e t a i l s o f c a l l loaded c a l l i n g conventions
| afcl L i s t a l l a v a i l a b l e c a l l i n g conventions
| a f c o path Open C a l l i n g Convention sdb p r o f i l e from given path
| afcR R e g i s t e r t e l e s c o p i n g using the c a l l i n g conventions
order
[ 0 x00000000]>
• To list all available calling conventions for current architecture using afcl
command
[ 0 x00000000]> a f c l
amd64
ms
ms=cc
cc . ms . name=ms
cc . ms . arg1=rcx
cc . ms . arg2=rdx
cc . ms . arg3=r8
224
cc . ms . arg3=r9
cc . ms . argn=s t a c k
cc . ms . r e t=rax
cc.x.argi=rax is used to set the ith argument of this calling convention to register
name rax
cc.x.argn=stack means that all the arguments (or the rest of them in case there
was argi for any i as counting number) will be stored in stack from left to
right
cc.x.argn=stack_rev same as cc.x.argn=stack except for it means argument are
passed right to left
Virtual Tables
There is a basic support of virtual tables parsing (RTTI and others). The
most important thing before you start to perform such kind of analysis is to
check if the anal.cpp.abi option is set correctly, and change if needed.
All commands to work with virtual tables are located in the av namespace.
Currently, the support is very basic, allowing you only to inspect parsed tables.
| Usage : av [ ? j r ∗ ] C++ v t a b l e s and RTTI
| av se a r c h f o r v t a b l e s i n data s e c t i o n s and show r e s u l t s
| avj l i k e av , but as j s o n
| av∗ l i k e av , but as r2 commands
| avr [ j@addr ] t r y to parse RTTI at v t a b l e addr ( s e e anal . cpp . abi )
| avra [ j ] se a r c h f o r v t a b l e s and t r y to parse RTTI at each o f
them
The main commands here are av and avr. av lists all virtual tables found when
r2 opened the file. If you are not happy with the result you may want to try
to parse virtual table at a particular address with avr command. avra performs
the search and parsing of all virtual tables in the binary, like r2 does during
the file opening.
Syscalls
Radare2 allows manual search for assembly code looking like a syscall opera-
tion. For example on ARM platform usually they are represented by the svc
instruction, on the others can be a different instructions, e.g. syscall on x86
PC.
[ 0 x0001ece0]> /ad/ svc
...
0x000187c2 # 2 : svc 0x76
0x000189ea # 2 : svc 0xa9
225
0x00018a0e # 2 : svc 0x82
...
If you setup ESIL stack with aei or aeim, you can use /as command to search
the addresses where particular syscalls were found and list them.
[ 0 x0001ece0]> a e i
[ 0 x0001ece0]> / as
0x000187c2 sd_ble_gap_disconnect
0x000189ea sd_ble_gatts_sys_attr_set
0x00018a0e sd_ble_gap_sec_info_reply
...
To reduce searching time it is possible to restrict the searching range for only
executable segments or sections with /as @e:search.in=io.maps.x
Using the ESIL emulation radare2 can print syscall arguments in the disas-
sembly output. To enable the linear (but very rough) emulation use asm.emu
configuration variable:
[ 0 x0001ece0]> e asm . emu=t r u e
[ 0 x0001ece0]> s 0x000187c2
[ 0 x000187c2]> pdf~ svc
0x000187c2 svc 0x76 ; 118 = sd_ble_gap_disconnect
[ 0 x000187c2]>
In case of executing aae (or aaaa which calls aae) command radare2 will push
found syscalls to a special syscall . flagspace, which can be useful for automation
purpose:
[ 0 x000187c2]> f s
0 0 ∗ imports
1 0 ∗ symbols
2 1523 ∗ f u n c t i o n s
3 420 ∗ s t r i n g s
4 183 ∗ s y s c a l l s
[ 0 x000187c2]> f ~ s y s c a l l
...
0x000187c2 1 s y s c a l l . sd_ble_gap_disconnect . 0
226
0x000189ea 1 s y s c a l l . sd_ble_gatts_sys_attr_set
0x00018a0e 1 s y s c a l l . sd_ble_gap_sec_info_reply
...
When debugging in radare2, you can use dcs to continue execution until the
next syscall. You can also run dcs∗ to trace all syscalls.
[ 0 xf7fb9120 ]> dcs ∗
Running c h i l d u n t i l s y s c a l l s :−1
c h i l d stopped with s i g n a l 133
−−> SN 0 xf7fd3d5b s y s c a l l 45 brk (0 x f f f f f f d a )
c h i l d stopped with s i g n a l 133
−−> SN 0 x f 7 f d 2 8 f 3 s y s c a l l 384 arch_prctl (0 x f f f f f f d a 0x3001 )
c h i l d stopped with s i g n a l 133
−−> SN 0 x f 7 f c 8 1 b 2 s y s c a l l 33 a c c e s s (0 x f f f f f f d a 0 x f 7 f d 8 b f 1 )
c h i l d stopped with s i g n a l 133
radare2 also has a syscall name to syscall number utility. You can return the
syscall name of a given syscall number or vice versa, without leaving the shell.
[ 0 x08048436]> a s l 1
exit
[ 0 x08048436]> a s l w r i t e
4
[ 0 x08048436]> ask w r i t e
0x80 , 4 , 3 , i Z i
Signatures
Radare2 has its own format of the signatures, allowing to both load/apply and
create them on the fly. They are available under the z command namespace:
[ 0 x00000000]> z ?
Usage : z [ ∗ j−a o f / c s ] [ a r g s ] # Manage z i g n a t u r e s
| z show z i g n a t u r e s
| z. f i n d matching z i g n a t u r e s i n c u r r e n t o f f s e t
| zb [ ? ] [ n=5] s e a r c h f o r b e s t match
| z∗ show z i g n a t u r e s i n radare format
| zq show z i g n a t u r e s i n q u i e t mode
| zj show z i g n a t u r e s i n j s o n format
227
| zk show z i g n a t u r e s i n sdb format
| z−z i g n a t u r e delete zignature
| z−∗ delete a l l zignatures
| za [ ? ] add z i g n a t u r e
| zg g e n e r a te z i g n a t u r e s ( a l i a s f o r zaF )
| zo [ ? ] manage z i g n a t u r e f i l e s
| zf [ ? ] manage FLIRT s i g n a t u r e s
| z /[?] se a r c h z i g n a t u r e s
| zc [ ? ] compare c u r r e n t z i g n s p a c e z i g n a t u r e s with another one
| zs [ ? ] manage z i g n s p a c e s
| zi show z i g n a t u r e s matching i n f o r m at i on
To load the created signature file you need to load it from SDB file using zo
command or from the compressed SDB file using zoz command.
To create signature you need to make function first, then you can create it
from the function:
$ r2 / bin / l s
[ 0 x000051c0]> aaa # t h i s c r e a t e s f u n c t i o n s , i n c l u d i n g ' entry0 '
[ 0 x000051c0]> z a f entry0 entry
[ 0 x000051c0]> z
entry :
bytes :
31 ed4989d15e4889e24883e4f050544c . . . . . . . . . . . . 4 8 . . . . . . . . . . . . 4 8 . . . . . . . . . . . . f f .
graph : cc=1 nbbs=1 edges=0 ebbs=1
o f f s e t : 0x000051c0
[ 0 x000051c0]>
As you can see it made a new signature with a name entry from a function
entry0. You can show it in JSON format too, which can be useful for scripting:
[ 0 x000051c0]> z j ~{}
[
{
”name ” : ” entry ” ,
” bytes ” :
”31 ed4989d15e4889e24883e4f050544c . . . . . . . . . . . . 4 8 . . . . . . . . . . . . 4 8 . . . . . . . . . . . . f f
” graph ” : {
” cc ” : ”1” ,
”nbbs ” : ”1” ,
” edges ” : ”0” ,
” ebbs ” : ”1”
},
” o f f s e t ” : 20928 ,
” refs ”: [
]
}
]
[ 0 x000051c0]>
228
If you want, instead, to save all created signatures, you need to save it into
the SDB file using command zos myentry.
Then we can apply them. Lets open a file again:
$ r2 / bin / l s
−− Log On. Hack In . Go Anywhere . Get Everything .
[ 0 x000051c0]> zo myentry
[ 0 x000051c0]> z
entry :
bytes :
31 ed4989d15e4889e24883e4f050544c . . . . . . . . . . . . 4 8 . . . . . . . . . . . . 4 8 . . . . . . . . . . . . f f .
graph : cc=1 nbbs=1 edges=0 ebbs=1
o f f s e t : 0x000051c0
[ 0 x000051c0]>
This means that the signatures were successfully loaded from the file myentry
and now we can search matching functions:
[ 0 x000051c0]> z .
[+] s e a r c h i n g 0 x000051c0 − 0 x000052c0
[+] s e a r c h i n g f u n c t i o n m e t r i c s
hits : 1
[ 0 x000051c0]>
Note that z. command just checks the signatures against the current address.
To search signatures across the all file we need to do a bit different thing.
There is an important moment though, if we just run it “as is” - it wont find
anything:
[ 0 x000051c0]> z/
[+] s e a r c h i n g 0 x0021dfd0 − 0x002203e8
[+] s e a r c h i n g f u n c t i o n m e t r i c s
hits : 0
[ 0 x000051c0]>
Note the searching address - this is because we need to adjust the searching
range first:
[ 0 x000051c0]> e s ea r c h . i n=i o . s e c t i o n
[ 0 x000051c0]> z/
[+] s e a r c h i n g 0x000038b0 − 0x00015898
[+] s e a r c h i n g function metrics
hits : 1
[ 0 x000051c0]>
We are setting the search mode to io .section (it was file by default) to search in
the current section (assuming we are currently in the .text section of course).
Now we can check, what radare2 found for us:
[ 0 x000051c0]> pd 5
;−− entry0 :
229
;−− s i g n . bytes . entry_0 :
0x000051c0 31ed xor ebp , ebp
0x000051c2 4989d1 mov r9 , rdx
0x000051c5 5e pop rsi
0x000051c6 4889 e2 mov rdx , rsp
0x000051c9 4883 e 4 f 0 and rsp , 0 x f f f f f f f f f f f f f f f 0
[ 0 x000051c0]>
Here we can see the comment of entry0, which is taken from the ELF parsing,
but also the sign.bytes.entry_0, which is exactly the result of matching signature.
Signatures configuration stored in the zign. config vars’ namespace:
[ 0 x000051c0]> e ? z i g n .
z i g n . autoload : Autoload a l l z i g n a t u r e s l o c a t e d i n
~ / . l o c a l / share / radare2 / z i g n s
z i g n . bytes : Use bytes p a t t e r n s f o r matching
z i g n . d i f f . bthresh : Threshold f o r d i f f i n g z i g n bytes [ 0 , 1 ] ( s e e
zc ?)
z i g n . d i f f . gthresh : Threshold f o r d i f f i n g z i g n graphs [ 0 , 1 ] ( s e e
zc ?)
z i g n . graph : Use graph m e t r i c s f o r matching
z i g n . hash : Use Hash f o r matching
z i g n . maxsz : Maximum z i g n a t u r e l e n g t h
z i g n . mincc : Minimum cyclomatic complexity f o r matching
z i g n . minsz : Minimum z i g n a t u r e l e n g t h f o r matching
z i g n . o f f s e t : Use o r i g i n a l o f f s e t f o r matching
z i g n . p r e f i x : Default p r e f i x f o r z i g n a t u r e s matches
z i g n . r e f s : Use r e f e r e n c e s f o r matching
z i g n . t h r e s h o l d : Minimum s i m i l a r i t y r e q u i r e d f o r i n c l u s i o n i n
zb output
z i g n . types : Use types f o r matching
[ 0 x000051c0]>
The zb (zign best) command will show the top 5 closest signatures to a function.
Each will contain a score between 1.0 and 0.0.
230
[ 0 x0041e390]> s sym . f c l o s e
[ 0 x0040fc10 ]> zb
0.96032 0.92400 B 0.99664 G sym . f c l o s e
0.65971 0.35600 B 0.96342 G sym . _nl_expand_alias
0.65770 0.37800 B 0.93740 G sym . fdopen
0.65112 0.35000 B 0.95225 G sym . __run_exit_handlers
0.62532 0.34800 B 0.90264 G sym . __cxa_finalize
Graph
Uunderstanding the structure and flow of a program is crucial. While linear
disassembly and text-based analysis have their place, graphs provide a pow-
erful visual representation that can significantly enhance your understanding
of complex code.
Radare2’s graph capabilities offer a multifaceted approach to visualizing var-
ious aspects of a program code structures:
• Control Flow Graphs (CFG): Visualize the logical flow between
basic blocks within a function, making it easier to identify loops, condi-
tional branches, and execution paths.
• Call Graphs: Map out the relationships between functions, showing
which functions call others and how data potentially flows between them.
231
• String Reference Graphs: Illustrate where and how strings are used
throughout the program, often providing valuable insights into the pro-
gram’s functionality.
These graphical representations serve multiple purposes:
• Quickly identify complex structures and patterns that might be missed
in text-based analysis.
• Facilitate easier navigation through large codebases.
• Aid in understanding the overall architecture and design of the program.
• Assist in locating potential vulnerabilities or points of interest for further
investigation.
In the following sections, we’ll explore the various graph commands available
in radare2, demonstrating how to generate, navigate, and interpret these vi-
sual aids to supercharge your reverse engineering workflow.
Let’s dive into the world of radare2 graphs and unlock new dimensions in your
analysis!
Commands
Radare2 supports various types of graph available through commands starting
with ag:
[ 0 x00005000]> ag?
Usage : ag<graphtype><format> [ addr ]
Graph commands :
| aga [ format ] data r e f e r e n c e s graph
| agA [ format ] g l o b a l data r e f e r e n c e s graph
| agc [ format ] function callgraph
| agC [ format ] global callgraph
| agd [ format ] [ f c n addr ] d i f f graph
| a g f [ format ] b a s i c b l o c k s f u n c t i o n graph
| a g i [ format ] imports graph
| agr [ format ] r e f e r e n c e s graph
| agR [ format ] g l o b a l r e f e r e n c e s graph
| agx [ format ] c r o s s r e f e r e n c e s graph
| agg [ format ] custom graph
| agt [ format ] t r e e map graph
| ag− c l e a r the custom graph
| agn [ ? ] t i t l e body add a node to the custom graph
| age [ ? ] t i t l e 1 t i t l e 2 add an edge to the custom graph
Output formats :
| <blank> a s c i i art
| ∗ r2 commands
| b b r a i l e a r t r e n d e r i n g ( agfb )
| d graphviz dot
| g graph Modelling Language ( gml )
| j j s o n ( ' J ' f o r formatted disassembly )
232
| k sdb key−value
| m mermaid
| t tiny a s c i i art
| v interactive a s c i i art
| w [ path ] w r i t e to path or d i s p l a y graph image ( s e e
graph . gv . format )
Ascii Art
Command: agf
Displays the graph directly to stdout using ASCII art to represent blocks and
edges.
Warning: displaying large graphs directly to stdout might prove to be compu-
tationally expensive and will make r2 not responsive for some time. In case
of a doubt, prefer using the interactive view (explained below).
Graphviz dot
Command: agfd
Prints the dot source code representing the graph, which can be interpreted
by programs such as graphviz or online viewers like this
233
JSON
Command: agfj
Prints a JSON string representing the graph.
• In case of the f format (basic blocks of function), it will have detailed
information about the function and will also contain the disassembly of
the function (use J format for the formatted disassembly).
• In all other cases, it will only have basic information about the nodes
of the graph (id, title, body, and edges).
SDB key-value
Command: agfk
Prints key-value strings representing the graph that was stored by sdb
(radare2’s string database).
234
`−−−−−−−−−−−−−−−−−−−−'
t f
| |
.−−−−−−−−−−−−−−' |
| '−−−−−−−−.
| |
.−−−−−−−−−−−−−−−−−−−−. .−−−−−−−−−−−−−−−−−−−−.
| bar | | cow |
`−−−−−−−−−−−−−−−−−−−−' `−−−−−−−−−−−−−−−−−−−−'
[ 0 x00000000]>
Web / image
Command: agfw
Radare2 will convert the graph to dot format, use the dot program to convert
it to a . gif image and then try to find an already installed viewer on your
system (xdg−open, open, …) and display the graph there.
The extension of the output image can be set with the graph.extension config
variable. Available extensions are png, jpg, gif , pdf, ps.
Note: for particularly large graphs, the most recommended extension is svg as
it will produce images of much smaller size
If graph.web config variable is enabled, radare2 will try to display the graph
using the browser (this feature is experimental and unfinished, and disabled
by default.)
Emulation
Understanding the distinction between static analysis and dynamic analysis
is crucial in reverse engineering. radare2 uses two different kind of instruction
information to perform static analysis:
• OpType, Instruction Family plus other static details
• ESIL expression associated
Radare2 employs its own intermediate language and virtual machine, known
as ESIL, for partial emulation (or imprecise full emulation).
Radare2’s ESIL supports partial emulation across all platforms by evaluating
those expressions.
Use Cases
There are many use cases for ESIL in radare2, not just bare code emulation:
235
• Resolve indirect branches
• Determine the likelity of a branch
• Search memory addresses matching complex nested conditionals
• Find out computed pointer references (aae or /re)
• Execution of a function portion
• Simulate behaviour of syscalls and imports
• r2wars (let’s play!)
To view the ESIL representation of your program, use the ao~esil command
or enable the asm.esil configuration variable. This will let you verify how the
code is uplifted from assembly to ESIL and understand better how that works
internally.
[ 0 x00001660]> pdf
. ( f c n ) f c n .00001660 40
| f c n .00001660 ( ) ;
| ; CALL XREF from 0x00001713 ( entry2 . f i n i )
| 0x00001660 l e a r d i , obj . __progname ; 0x207220
| 0x00001667 push rbp
| 0x00001668 l e a rax , obj . __progname ; 0x207220
| 0 x0000166f cmp rax , r d i
| 0x00001672 mov rbp , rsp
| .−< 0x00001675 j e 0x1690
| | 0x00001677 mov rax , qword [ r e l o c . _ITM_deregisterTMCloneTable ]
; [ 0 x206fd8 :8]=0
| | 0x0000167e t e s t rax , rax
|.−−< 0x00001681 j e 0x1690
||| 0x00001683 pop rbp
||| 0x00001684 jmp rax
|``−> 0x00001690 pop rbp
` 0x00001691 r e t
[ 0 x00001660]> e asm . e s i l=t r u e
[ 0 x00001660]> pdf
. ( f c n ) f c n .00001660 40
| f c n .00001660 ( ) ;
| ; CALL XREF from 0x00001713 ( entry2 . f i n i )
| 0x00001660 0x205bb9 , r i p ,+ , r d i ,=
| 0x00001667 rbp , 8 , rsp ,−=,rsp , = [ 8 ]
| 0x00001668 0x205bb1 , r i p ,+ , rax ,=
| 0 x0000166f
r d i , rax ,==,$z , z f ,= , $b64 , c f ,= ,$p , pf ,= , $s , s f ,= , $o , of ,=
| 0x00001672 rsp , rbp ,=
| .−< 0x00001675 z f , ? { , 5 7 7 6 , r i p ,= ,}
| | 0x00001677 0x20595a , r i p , + , [ 8 ] , rax ,=
| | 0x0000167e
0 , rax , rax ,&,==,$z , z f ,= ,$p , pf ,= , $s , s f ,= , $0 , c f ,= , $0 , of ,=
|.−−< 0x00001681 z f , ? { , 5 7 7 6 , r i p ,= ,}
||| 0x00001683 rsp , [ 8 ] , rbp ,= ,8 , rsp ,+=
||| 0x00001684 rax , r i p ,=
|``−> 0x00001690 rsp , [ 8 ] , rbp ,= ,8 , rsp ,+=
` 0x00001691 rsp , [ 8 ] , r i p ,= ,8 , rsp ,+=
236
Commands
To manually set up imprecise ESIL emulation, run the following sequence of
commands:
• aei to initialize the ESIL VM
• aeim to initialize ESIL VM memory (stack)
• aeipto set the initial ESIL VM IP (instruction pointer)
• a sequence of aer commands to set the initial register values.
While performing emulation, please remember that the ESIL VM cannot em-
ulate external calls system calls, nor SIMD instructions. Thus, the most
common scenario is to emulate only a small chunk of code like encryption,
decryption, unpacking, or a calculation.
After successfully setting up the ESIL VM, we can interact with it like a
normal debugging session. The command interface for the ESIL VM is almost
identical to the debugging interface:
• aes to step (or s key in visual mode)
• aesi to step over function calls
• aesu <address> to step until some specified address
• aesue <ESIL expression> to step until some specified ESIL expression is
met
• aec to continue until break (Ctrl-C). This one is rarely used due to the
omnipresence of external calls
In visual mode, all of the debugging hotkeys will also work in ESIL emulation
mode.
In addition to normal emulation, it’s also possible to record and replay ses-
sions:
• aets to list all current ESIL R&R sessions
• aets+ to create a new one
• aesb to step back in the current ESIL R&R session
You can read more about this operation mode in the Reverse Debugging
chapter.
Options
The emulation can be triggered at analysis, runtime or at will with full manual
control, in other words, the user can decide what and how to use ESIL.
To change some of the behaviours of the emulation engine in radare2 you can
use the following options:
237
[0x00000000]> e??esil.
Problems
There are several situations where emulation will not work as expected or
solve your problems. It is important to understand those situations to avoid
undesired surprises and know how to workaround them.
• Path explossion (too many execution or unknown paths to follow)
• Incorrect stack size or contents (aeim)
• Thread local storage (custom segments or memory layouts) not defined
• Unimplemented instructions (Use ahe to set analysis hints)
• Undefined behaviour (analy
• Custom Ops (requires esil plugins)
• Don’t go into Syscall / Imports implementations
238
Introduction to ESIL
ESIL stands for ‘Evaluable Strings Intermediate Language’. It aims to describe
a Forth-like representation for every target CPU opcode semantics. ESIL
representations can be evaluated (interpreted) in order to emulate individual
instructions. Each command of an ESIL expression is separated by a comma.
Its virtual machine can be described as this:
while ( ( word=haveCommand( ) ) ) {
i f ( word . is Op erat o r ( ) ) {
e s i l O p e r a t o r s [ word ] ( e s i l ) ;
} else {
e s i l . push ( word ) ;
}
nextCommand ( ) ;
}
Can you guess what this is? If we take this post-fix notation and transform
it back to in-fix we get
esp −= 4
4 bytes ( dword ) [ esp ] = ebp
We can see that this corresponds to the x86 instruction push ebp! Isn’t that
cool? The aim is to be able to express most of the common operations per-
formed by CPUs, like binary arithmetic operations, memory loads and stores,
processing syscalls. This way if we can transform the instructions to ESIL
we can see what a program does while it is running even for the most cryptic
architectures you definitely don’t have a device to debug on for.
Using ESIL
r2’s visual mode is great to inspect the ESIL evaluations.
There are 3 environment variables that are important for watching what a
program does:
[ 0 x00000000]> e emu . s t r = t r u e
239
asm.emu tells r2 if you want ESIL information to be displayed. If it is set to
true, you will see comments appear to the right of your disassembly that tell
you how the contents of registers and memory addresses are changed by the
current instruction. For example, if you have an instruction that subtracts
a value from a register it tells you what the value was before and what it
becomes after. This is super useful so you don’t have to sit there yourself and
track which value goes where.
One problem with this is that it is a lot of information to take in at once
and sometimes you simply don’t need it. r2 has a nice compromise for this.
That is what the emu.str variable is for (asm.emustr on <= 2.2). Instead of this
super verbose output with every register value, this only adds really useful
information to the output, e.g., strings that are found at addresses a program
uses or whether a jump is likely to be taken or not.
The third important variable is asm.esil. This switches your disassembly to no
longer show you the actual disassembled instructions, but instead now shows
you corresponding ESIL expressions that describe what the instruction does.
So if you want to take a look at how instructions are expressed in ESIL simply
set “asm.esil” to true.
[ 0 x00000000]> e asm . e s i l = t r u e
ESIL Commands
• “ae” : Evaluate ESIL expression.
[ 0 x00000000]> ” ae 1 ,1 ,+”
0x2
[ 0 x00000000]>
240
• “ar” : Show/modify ESIL registry.
[ 0 x00001ec7]> ar r_00 = 0x1035
[ 0 x00001ec7]> ar r_00
0x00001035
[ 0 x00001019]>
ESIL
Op-
code Operands
Name Operation
example
TRAPsrc Trap Trap
sig-
nal
**∗∗
|𝑠𝑟𝑐|𝐼𝑛𝑡𝑒𝑟𝑟𝑢𝑝𝑡|𝑖𝑛𝑡𝑒𝑟𝑟𝑢𝑝𝑡|0𝑥80,
() src Syscallsyscallrax,()
$$ src Instruction
Get
ad- ad-
dress dress
of
cur-
rent
in-
struc-
tion
stack=instruction
address
== src,dstCompare stack
=
(dst
==
src)
;
update_eflags(dst
-
src)
241
ESIL
Op-
code Operands
Name Operation
example
< stack [0x0000000]> “ae 1,5,<”
src,dstSmaller
(signed= 0x0
com- (dst > “ae 5,5”
par- < 0x0”
i- src)
son) ;
update_eflags(dst
-
src)
<= src,dstSmaller
stack [0x0000000]> “ae 1,5,<”
or = 0x0
Equal(dst > “ae 5,5”
(signed<= 0x1”
com- src)
par- ;
i- update_eflags(dst
son) -
src)
> src,dstBiggerstack > “ae 1,5,>”
(signed= 0x1
com- (dst > “ae 5,5,>”
par- > 0x0
i- src)
son) ;
update_eflags(dst
-
src)
>= src,dstBiggerstack > “ae 1,5,>=”
or = 0x1
Equal(dst > “ae 5,5,>=”
(signed>= 0x1
com- src)
par- ;
i- update_eflags(dst
son) -
src)
242
ESIL
Op-
code Operands
Name Operation
example
« src,dstShift stack > “ae 1,1,«”
Left = 0x2
dst > “ae 2,1,«”
« 0x4
src
» src,dstShift stack > “ae 1,4,»”
Right = 0x2
dst > “ae 2,4,»”
» 0x1
src
«< src,dstRotatestack=dst
> “ae 31,1,«<”
Left ROL 0x80000000
src > “ae 32,1,«<”
0x1
»> src,dstRotatestack=dst
> “ae 1,1,»>”
Right ROR 0x80000000
src > “ae 32,1,»>”
0x1
& src,dstAND stack > “ae 1,1,&”
= 0x1
dst > “ae 1,0,&”
& 0x0
src > “ae 0,1,&”
0x0
> “ae 0,0,&”
0x0
| src,dstOR stack > “ae 1,1,|”
= 0x1
dst > “ae 1,0,|”
| 0x1
src > “ae 0,1,|”
0x1
> “ae 0,0,|”
0x0
243
ESIL
Op-
code Operands
Name Operation
example
^ src,dstXOR stack > “ae 1,1,^”
= 0x0
dst > “ae 1,0,^”
^src 0x1
> “ae 0,1,^”
0x1
> “ae 0,0,^”
0x0
+ src,dstADD stack > “ae 3,4,+”
= 0x7
dst > “ae 5,5,+”
+ 0xa
src
- src,dstSUB stack > “ae 3,4,-”
= 0x1
dst > “ae 5,5,-”
- 0x0
src > “ae 4,3,-”
0xffffffffffffffff
* src,dstMUL stack > “ae 3,4,*”
= 0xc
dst > “ae 5,5,*”
* 0x19
src
/ src,dstDIV stack > “ae 2,4,/”
= 0x2
dst > “ae 5,5,/”
/ 0x1
src > “ae 5,9,/”
0x1
% src,dstMOD stack > “ae 2,4,%”
= 0x0
dst > “ae 5,5,%”
% 0x0
src > “ae 5,9,%”
0x4
244
ESIL
Op-
code Operands
Name Operation
example
~ stack > “ae 8,0x80,~”
bits,srcSIGNEXT
= 0xffffffffffffff80
src
sign
ex-
tended
~/ src,dstSIGNED
stack > “ae 2,-4,~/”
DIV = 0xfffffffffffffffe
dst
/
src
(signed)
~% src,dstSIGNED
stack > “ae 2,-5,~%”
MOD = 0xffffffffffffffff
dst
%
src
(signed)
! src NEG stack > “ae 1,!”
= 0x0
!!!src > “ae 4,!”
0x0
> “ae 0,!”
0x1
245
ESIL
Op-
code Operands
Name Operation
example
– src DEC stack > ar r_00=5;ar r_00
= 0x00000005
src– > “ae r_00,–”
0x4
> ar r_00
0x00000005
> “ae 5,–”
0x4
= src,regEQU reg > “ae 3,r_00,=”
= > aer r_00
src 0x00000003
> “ae r_00,r_01,=”
> aer r_01
0x00000003
:= src,regweak reg > “ae 3,r_00,:=”
EQU = > aer r_00
src 0x00000003
with- > “ae r_00,r_01,:=”
out > aer r_01
side 0x00000003
ef-
fects
+= src,regADD reg > ar r_01=5;ar r_00=0;ar r_00
eq = 0x00000000
reg > “ae r_01,r_00,+=”
+ > ar r_00
src 0x00000005
> “ae 5,r_00,+=”
> ar r_00
0x0000000a
-= src,regSUB reg > “ae r_01,r_00,-=”
eq = > ar r_00
reg 0x00000004
- > “ae 3,r_00,-=”
src > ar r_00
0x00000001
246
ESIL
Op-
code Operands
Name Operation
example
*= src,regMUL reg > ar r_01=3;ar r_00=5;ar r_00
eq = 0x00000005
reg > “ae r_01,r_00,*=”
* > ar r_00
src 0x0000000f
> “ae 2,r_00,*=”
> ar r_00
0x0000001e
/= src,regDIV reg > ar r_01=3;ar r_00=6;ar r_00
eq = 0x00000006
reg > “ae r_01,r_00,/=”
/ > ar r_00
src 0x00000002
> “ae 1,r_00,/=”
> ar r_00
0x00000002
%= src,regMOD reg > ar r_01=3;ar r_00=7;ar r_00
eq = 0x00000007
reg > “ae r_01,r_00,%=”
% > ar r_00
src 0x00000001
> ar r_00=9;ar r_00
0x00000009
> “ae 5,r_00,%=”
> ar r_00
0x00000004
«= src,regShift reg > ar r_00=1;ar r_01=1;ar r_01
Left = 0x00000001
eq reg > “ae r_00,r_01,«=”
« > ar r_01
src 0x00000002
> “ae 2,r_01,«=”
> ar r_01
0x00000008
247
ESIL
Op-
code Operands
Name Operation
example
»= src,regShift reg > ar r_00=1;ar r_01=8;ar r_01
Right = 0x00000008
eq reg > “ae r_00,r_01,»=”
« > ar r_01
src 0x00000004
> “ae 2,r_01,»=”
> ar r_01
0x00000001
&= src,regAND reg > ar r_00=2;ar r_01=6;ar r_01
eq = 0x00000006
reg > “ae r_00,r_01,&=”
& > ar r_01
src 0x00000002
> “ae 2,r_01,&=”
> ar r_01
0x00000002
> “ae 1,r_01,&=”
> ar r_01
0x00000000
|= src,regOR reg > ar r_00=2;ar r_01=1;ar r_01
eq = 0x00000001
reg > “ae r_00,r_01,|=”
| > ar r_01
src 0x00000003
> “ae 4,r_01,|=”
> ar r_01
0x00000007
^= src,regXOR reg > ar r_00=2;ar r_01=0xab;ar r_01
eq = 0x000000ab
reg > “ae r_00,r_01,^=”
^ > ar r_01
src 0x000000a9
> “ae 2,r_01,^=”
> ar r_01
0x000000ab
248
ESIL
Op-
code Operands
Name Operation
example
++=reg INC reg > ar r_00=4;ar r_00
eq = 0x00000004
reg > “ae r_00,++=”
+1 > ar r_00
0x00000005
–= reg DEC reg > ar r_00=4;ar r_00
eq = 0x00000004
reg > “ae r_00,–=”
-1 > ar r_00
0x00000003
!= reg NOT reg > ar r_00=4;ar r_00
eq = 0x00000004
!reg > “ae r_00,!=”
> ar r_00
0x00000000
> “ae r_00,!=”
> ar r_00
0x00000001
— — — — ———————————————-
=[] src,dstpoke *dst=src
=[*] > “ae 0xdeadbeef,0x10000,=[4],”
=[1]
=[2] > pxw 4@0x10000
=[4] 0x00010000 0xdeadbeef ….
=[8]
> “ae 0x0,0x10000,=[4],”
249
ESIL
Op-
code Operands
Name Operation
example
|=[] reg name code >
|=[1] >
|=[2]
|=[4]
|=[8]
SWAP Swap Swap SWAP
two
top
ele-
ments
DUP Duplicate
Duplicate
DUP
top
ele-
ment
in
stack
NUM Numeric
If NUM
top
ele-
ment
is a
ref-
er-
ence
(register
name,
la-
bel,
etc),
dereference
it
and
push
its
real
value
CLEAR Clear Clear CLEAR
stack
250
ESIL
Op-
code Operands
Name Operation
example
BREAK Break Stops BREAK
ESIL
em-
u-
la-
tion
GOTOn Goto JumpsGOTO 5
to
Nth
ESIL
word
TODO To Stops TODO
Do ex-
e-
cu-
tion
(reason:
ESIL
ex-
pres-
sion
not
completed)
ESIL Flags
ESIL VM provides by default a set of helper operations for calculating flags.
They fulfill their purpose by comparing the old and the new value of the dst
operand of the last performed eq-operation. On every eq-operation (e.g. =)
ESIL saves the old and new value of the dst operand. Note, that there also
exist weak eq operations (e.g. :=), which do not affect flag operations. The
== operation affects flag operations, despite not being an eq operation. Flag
operations are prefixed with $ character.
z − z e r o f l a g , only s e t i f the r e s u l t o f an o p e r a t i o n i s 0
b − borrow , t h i s r e q u i r e s to s p e c i f y from which b i t ( example :
4 , $b − checks i f borrow from b i t 4)
c − carry , same l i k e above ( example : 7 , $c − checks i f c a r r y
from b i t 7)
o − overflow
p − parity
251
r − r e g s i z e ( asm . b i t s /8 )
s − sign
ds − delay s l o t s t a t e
jt − jump t a r g e t
js − jump t a r g e t s e t
The ? operator uses the value of its argument to decide whether to evaluate
the expression in curly braces.
1. Is the value zero? -> Skip it.
2. Is the value non-zero? -> Evaluate it.
cmp eax , 123 −> 123 , eax ,==,$z , z f ,=
j z eax −> z f , ? { , eax , eip ,= ,}
If you want to run several expressions under a conditional, put them in curly
braces:
z f , ? { , eip , esp , = [ ] , eax , eip ,= , $r , esp ,−=,}
Whitespaces, newlines and other chars are ignored. So the first thing when
processing a ESIL program is to remove spaces:
e s i l = r_str_replace ( e s i l , ” ” , ”” , R_TRUE) ;
Syscalls need special treatment. They are indicated by ‘$’ at the beginning of
an expression. You can pass an optional numeric value to specify a number
of syscall. An ESIL emulator must handle syscalls. See (r_esil_syscall).
252
Special Instructions
NOPs are represented as empty strings. As it was said previously, interrupts
are marked by ‘′ 𝑐𝑜𝑚𝑚𝑎𝑛𝑑.𝐹 𝑜𝑟𝑒𝑥𝑎𝑚𝑝𝑙𝑒,′ 0𝑥80,’. It delegates emulation from
the ESIL machine to a callback which implements interrupt handler for a
specific OS/kernel/platform.
Traps are implemented with the TRAP command. They are used to throw
exceptions for invalid instructions, division by zero, memory read error, or
any other needed by specific architectures.
Quick Analysis
Here is a list of some quick checks to retrieve information from an ESIL string.
Relevant information will be probably found in the first expression of the list.
indexOf ( ' [ ' ) −> have memory r e f e r e n c e s
indexOf (”=[”) −> w r i t e i n memory
indexOf (” pc ,=”) −> m o d i f i e s program counter ( branch , jump , c a l l )
indexOf (” sp ,=”) −> m o d i f i e s the s t a c k ( what i f we found sp+= or
sp−=?)
indexOf (”=”) −> r e t r i e v e s r c and dst
indexOf ( ” : ” ) −> unknown e s i l , raw opcode ahead
indexOf (” $ ”) −> a c c e s s e s i n t e r n a l e s i l vm f l a g s ex : $z
indexOf (” $ ”) −> s y s c a l l ex : 1 , $
indexOf (”TRAP”) −> can trap
indexOf ( '++ ') −> has i t e r a t o r
indexOf ('−−') −> count to z e r o
indexOf ( ” ? { ” ) −> conditional
equalsTo ( ” ” ) −> empty s t r i n g , aka nop ( wrong , i f we append pc+=x )
Common operations:
• Check dstreg
• Check srcreg
• Get destinaion
• Is jump
• Is conditional
• Evaluate
• Is syscall
CPU Flags
CPU flags are usually defined as single bit registers in the RReg profile. They
are sometimes found under the ‘flg’ register type.
Variables
Properties of the VM variables:
253
1. They have no predefined bit width. This way it should be easy to extend
them to 128, 256 and 512 bits later, e.g. for MMX, SSE, AVX, Neon
SIMD.
2. There can be unbound number of variables. It is done for SSA-form
compatibility.
3. Register names have no specific syntax. They are just strings.
4. Numbers can be specified in any base supported by RNum (dec, hex,
oct, binary …).
5. Each ESIL backend should have an associated RReg profile to describe
the ESIL register specs.
Bit Arrays
What to do with them? What about bit arithmetics if use variables instead
of registers?
Arithmetics
1. ADD (“+”)
2. MUL (“*”)
3. SUB (“-”)
4. DIV (“/”)
5. MOD (“%”)
Bit Arithmetics
1. AND “&”
2. OR “|”
3. XOR “^”
4. SHL “«”
5. SHR “»”
6. ROL “«<”
7. ROR “»>”
8. NEG “!”
254
Handling x86 REP Prefix in ESIL
ESIL specifies that the parsing control-flow commands must be uppercase.
Bear in mind that some architectures have uppercase register names. The
corresponding register profile should take care not to reuse any of the follow-
ing:
3 ,SKIP − s k i p N i n s t r u c t i o n s . used to make r e l a t i v e forward GOTOs
3 ,GOTO − goto i n s t r u c t i o n 3
LOOP − a l i a s f o r 0 ,GOTO
BREAK − stop e v a l u a t i n g the e x p r e s s i o n
STACK − dump s t a c k c o n t e n t s to s c r e e n
CLEAR − c l e a r stack
Unimplemented/Unhandled Instructions
Those are expressed with the ‘TODO’ command. They act as a ‘BREAK’, but
displays a warning message describing that an instruction is not implemented
and will not be emulated. For example:
fmulp ST( 1 ) , ST( 0 ) => TODO, fmulp ST( 1 ) ,ST( 0 )
255
0x100001138 7 f1a s f , of , ! , ^ , z f , ! , & , ? { , 0 x1154 , r ip ,= ,} ; [ 2 ]
0x10000113a 7d07 of , ! , s f , ^ , ? { , 0 x1143 , r i p , } ; [ 3 ]
0x10000113c b8ffffffff 0 x f f f f f f f f , eax ,= ; 0 x f f f f f f f f
0x100001141 eb11 0x1154 , r i p ,= ; [ 2 ]
0x100001143 488 b4938 rcx , 5 6 , + , [ 8 ] , rcx ,=
0x100001147 48394 a38 rdx , 5 6 , + , [ 8 ] , rcx ,==,cz ,?=
Introspection
To ease ESIL parsing we should have a way to express introspection expres-
sions to extract the data that we want. For example, we may want to get the
target address of a jump. The parser for ESIL expressions should offer an
API to make it possible to extract information by analyzing the expressions
easily.
> ao~ e s i l , opcode
opcode : jmp 0x10000465a
e s i l : 0x10000465a , r i p ,=
We need a way to retrieve the numeric value of ‘rip’. This is a very simple
example, but there are more complex, like conditional ones. We need expres-
sions to be able to get:
• opcode type
• destination of a jump
• condition depends on
• all regs modified (write)
• all regs accessed (read)
API HOOKS
It is important for emulation to be able to setup hooks in the parser, so we
can extend it to implement analysis without having to change it again and
again. That is, every time an operation is about to be executed, a user hook
is called. It can be used for example to determine if RIP is going to change,
or if the instruction updates the stack. Later, we can split that callback into
several ones to have an event-based analysis API that may be extended in
JavaScript like this:
e s i l . on ( ' r e g s e t ' , f u n c t i o n ( ) { . .
e s i l . on ( ' s y s c a l l ' , f u n c t i o n ( ) { e s i l . r e g s e t ( ' r i p '
256
Other operations require bindings to external functionalities to work. In this
case, r_ref and r_io. This must be defined when initializing the ESIL VM.
• Io Get/Set
Out ax , 44
44 , ax , : ou
• Selectors (cs,ds,gs…)
Mov eax , ds : [ ebp+8]
Ebp, 8 , + , : ds , eax ,=
257
|``−> 0x00001690 pop rbp ; rbp=0x10102464c457f ;
rsp=0x8 −> 0 x464c457f
` 0x00001691 r e t ; r i p=0x0 ; rsp=0x10 −>
0x3e0003
Note the comments containing likely , which indicate conditional jumps likely
to be taken by ESIL emulation.
Apart from the basic ESIL VM setup, you can change its behavior with other
options located in the emu. and esil . configuration namespaces.
After this command, you can use any of the d sub-commands to change register
values, step or skip instructions, set breakpoints, etc. but using the internal
emulation logic of ESIL.
Scripting
Scripting is a big part of using radare2. It’s really important to get good at
using radare2 commands. The better you know these commands, the more
you can do with the tool. You’ll be able to work faster and figure out tougher
problems.
Spending time to learn the commands will pay off in the long run. But com-
mands are just a portion of the capabilities of the shell, these can be modifier,
combined or processed when used with some special characters similar to the
posix shell, like pipes, filters, redirections, etc
258
r2pipe is the main way to use radare2 from other programming languages. It
lets you control radare2 from languages like Python, Javascript or even Rust.
This is great for making your own tools that work with radare2. You can
write scripts to do things automatically, which saves a lot of time. r2pipe
opens up a lot of possibilities for using radare2 in new ways.
radare2 also has some built-in ways to run scripts. There’s r2js, which lets
you run JavaScript right inside radare2. This is useful for quick scripts (and
plugins) when you don’t want to use external dependencies.
There’s also rlang, which lets you use radare2’s inner workings from different
programming languages. These features help you customize radare2 and make
it do exactly what you need. You can extend radare2’s abilities and create
your own add-ons.
Shell
As mentioned before many commands can be executed in sequence by using
; the semicolon operator.
[ 0 x00404800]> pd 1 ; ao 1
0x00404800 b827e66100 mov eax , 0x61e627 ; ” tab ”
address : 0x404800
opcode : mov eax , 0x61e627
prefix : 0
bytes : b827e66100
ptr : 0 x0061e627
refptr : 0
size : 5
type : mov
e s i l : 6415911 , rax ,=
st a ck : n u l l
f a m i l y : cpu
[ 0 x00404800]>
It simply runs the second command after finishing the first one, like in a posix
shell.
The second important way to sequence the commands is with a simple pipe
|:
ao | grep address
Note, the | pipe only can pipe output of r2 commands to external (shell)
commands, like system programs or builtin shell commands.
There is a similar way to sequence r2 commands, using the backtick operator
`command`. The quoted part will undergo command substitution and the
output will be used as an argument of the command line.
259
For example, we want to see a few bytes of the memory at the address referred
to by the ‘mov eax, addr’ instruction. We can do that without jumping to it,
using a sequence of commands:
[ 0 x00404800]> pd 1
0x00404800 b827e66100 mov eax , 0x61e627 ; ” tab ”
[ 0 x00404800]> ao
address : 0x404800
opcode : mov eax , 0x61e627
prefix : 0
bytes : b827e66100
ptr : 0 x0061e627
refptr : 0
size : 5
type : mov
e s i l : 6415911 , rax ,=
st a ck : n u l l
f a m i l y : cpu
[ 0 x00404800]> ao~ ptr [ 1 ]
0x0061e627
0
[ 0 x00404800]> px 10 @ `ao~ ptr [ 1 ] `
− offset − 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x0061e627 7461 6200 2 e69 6 e74 6572 tab . . i n t e r
[ 0 x00404800]>
And of course it’s possible to redirect the output of an r2 command into a file,
using the > and >> commands
[ 0 x00404800]> px 10 @ `ao~ ptr [ 1 ] ` > example . t x t
[ 0 x00404800]> px 10 @ `ao~ ptr [ 1 ] ` >> example . t x t
Radare2 also provides quite a few Unix type file processing commands like
head, tail, cat, grep and many more. One such command is Uniq, which can
be used to filter a file to display only non-duplicate content. So to make a
new file with only unique strings, you can do:
[ 0 x00404800]> uniq f i l e > u n i q _ f i l e
Other than stdout, you can specify other file descriptors to be redirected like
in the posix shell:
[ 0 x00404800]> aaa 2> /dev/ n u l l
The head command can be used to see the first N number of lines in the file,
similarly tail command allows the last N number of lines to be seen.
[ 0 x00404800]> head 3 foodtypes . t x t
Proteins
Fats
Carbohydrates
260
[ 0 x00404800]> t a i l 2 foodtypes . t x t
Probiotics
Water
Similarly, sorting the content is also possible with the sort command. A
typical example could be:
[ 0 x00404800]> cat f o o d s . t x t
Lentils
Avocado
Brown r i c e
Chia s e e d s
Spinach
Almonds
Blueberries
Broccoli
Sauerkraut
Cucumber
[ 0 x00404800]> s o r t f o o d s . t x t
Almonds
Avocado
Blueberries
Broccoli
Brown r i c e
Chia s e e d s
Cucumber
Lentils
Sauerkraut
Spinach
The ?$? command describes several helpful variables you can use to do similar
actions even more easily, like the $v “immediate value” variable, or the $m
opcode memory reference variable.
r2js
Radare2 ships the QuickJS ES6/javascript runtime by default starting on
versions 5.8.x, having a complete and standard programming language brings
a lot of possibilities and ease
As long as javascript is a also a common target language for transpilation from
many other languages it is possible to use this runtime for other programming
languages, not just Javascript.
TypeScript is probably the primary choice because it is very well integrated
with Visual Studio Code (or Vim, Helix, ..) offering autocompletion and other
facilities for developing your scripts.
But it is also possible to use Nim, C (via Emscripten), Vlang, and many other
languages.
261
Scripts
You can run r2js scripts like you do with any other script:
• Using the −i flag on the system shell when launching r2.
• With the . command inside the radare2 shell.
The rlang plugin will be selected depending on the file extension. In this case
the qjs rlang plugin handles the .r2. js extension.
For example:
$ r2 −i f o o . r2 . j s / bin / l s
If you want to go back to the shell after running the script use the −q flag:
$ r2 −q i f o o . r2 . j s / bin / l s
The REPL
To enter the r2js repl you can use the −j command or flag.
0$ r2 −j
QuickJS − Type ”\h” f o r help
[ r 2 j s ]>
In this repl (read-eval-print-loop) shell you can run javascript statements, like
the ones you would use in NodeJS.
The <tab> key can be used to autocomplete expressions.
R2Pipe.r2js
The rlang plugin exposes the classic r2.cmd interface to interact with radare2.
This means that you can run a command and get the output in response.
R2Papi.r2js
The R2Papi apis are also embedded inside the r2, this means that you can
use the high level / idiomatic APIs too.
If the global r2pipe instance is available through the r2 object. The R2Papi
one is available as R.
This is an example:
262
var r2 = new R2Pipe ( ) ;
var R = new R2Papi ( r2 ) ;
R2FridaCompile
Frida-tools ship a TypeScript compiler that targets ESM and generates a
single file containing all the js compiled files from a TypeScript project.
Radare2 supports the same esm-blob file format used by Frida, and if you
don’t want to depend on Python you can also use the native one distributed
with the r2frida plugin named r2frida−compile.
For example:
$ r 2 f r i d a −compile −o f o o . r2 . j s f o o . t s
$ r2 −q i f o o . r2 . j s −
TypeScript
The easiest way to run typescript programs inside radare2 is by using
r2frida−compile, but you can also use the standard tsc.
Loops
One of the most common task in automation is looping through something,
there are multiple ways to do this in radare2.
We can loop over flags:
@@ flagname−regex
263
data−x r e f s :
locals :0
ar g s : 0
d i f f : type : new
[ 0 x004047d6]>
Now let’s say, for example, that we’d like see a particular field from this
output for all functions found by analysis. We can do that with a loop over
all function flags (whose names begin with fcn. ):
[ 0 x004047d6]> f s f u n c t i o n s
[ 0 x004047d6]> a f i @@ f c n . ∗ ~name
This command will extract the name field from the afi output of every flag with
a name matching the regexp fcn.∗. There are also a predefined loop called @@f,
which runs your command on every functions found by r2:
[ 0 x004047d6]> a f i @@f ~name
We can also loop over a list of offsets, using the following syntax:
@@=1 2 3 . . . N
For example, say we want to see the opcode information for 2 offsets: the
current one, and at current + 2:
[ 0 x004047d6]> ao @@=$$ $$+2
address : 0x4047d6
opcode : mov rdx , rsp
prefix : 0
bytes : 4889 e2
refptr : 0
size : 3
type : mov
e s i l : rsp , rdx ,=
st a ck : n u l l
f a m i l y : cpu
address : 0x4047d8
opcode : loop 0x404822
prefix : 0
bytes : e248
refptr : 0
size : 2
type : cjmp
e s i l : 1 , rcx ,−=,rcx , ? { , 4 2 1 2 7 7 0 , r i p ,= ,}
jump : 0x00404822
f a i l : 0x004047da
st a ck : n u l l
cond : a l
f a m i l y : cpu
[ 0 x004047d6]>
264
Note we’re using the $$ variable which evaluates to the current offset. Also
note that $$+2 is evaluated before looping, so we can use the simple arithmetic
expressions.
A third way to loop is by having the offsets be loaded from a file. This file
should contain one offset per line.
[ 0 x004047d0]> ?v $$ > o f f s e t s . t x t
[ 0 x004047d0]> ?v $$+2 >> o f f s e t s . t x t
[ 0 x004047d0]> ! cat o f f s e t s . t x t
4047d0
4047d2
[ 0 x004047d0]> p i 1 @@. o f f s e t s . t x t
xor ebp , ebp
mov r9 , rdx
radare2 also offers various foreach constructs for looping. One of the most
useful is for looping through all the instructions of a function:
[ 0 x004047d0]> pdf
/ ( f c n ) entry0 42
| ; UNKNOWN XREF from 0x00400018 ( unk )
| ; DATA XREF from 0 x004064bf ( sub . strlen_460 )
| ; DATA XREF from 0x00406511 ( sub . strlen_460 )
| ; DATA XREF from 0x0040b080 ( unk )
| ; DATA XREF from 0 x0040b0ef ( unk )
| 0 x004047d0 xor ebp , ebp
| 0 x004047d2 mov r9 , rdx
| 0 x004047d5 pop r s i
| 0 x004047d6 mov rdx , rsp
| 0 x004047d9 and rsp , 0 x f f f f f f f f f f f f f f f 0
| 0 x004047dd push rax
| 0 x004047de push rsp
| 0 x004047df mov r8 , 0x4136c0
| 0 x004047e6 mov rcx , 0x413660 ; ”AWA. . AVI . . AUI . .ATL. % . . ”
0A . . AVI . . AUI .
| 0 x004047ed mov r d i , main ; ”AWAVAUATUH. . S . . H . . . . ” @
0
| 0 x004047f4 c a l l sym . imp . __libc_start_main
\0 x004047f9 h l t
[ 0 x004047d0]> p i 1 @@i
mov r9 , rdx
pop r s i
mov rdx , rsp
and rsp , 0 x f f f f f f f f f f f f f f f 0
push rax
push rsp
mov r8 , 0x4136c0
mov rcx , 0x413660
mov r d i , main
c a l l sym . imp . __libc_start_main
hlt
265
In this example the command pi 1 runs over all the instructions in the current
function (entry0). There are other options too (not complete list, check @@?
for more information):
• @@k sdbquery - iterate over all offsets returned by that sdbquery
• @@t- iterate over on all threads (see dp)
• @@b - iterate over all basic blocks of current function (see afb)
• @@f - iterate over all functions (see aflq)
The last kind of looping lets you loop through predefined iterator types:
• symbols
• imports
• registers
• threads
• comments
• functions
• flags
This is done using the @@@ command. The previous example of listing infor-
mation about functions can also be done using the @@@ command:
[ 0 x004047d6]> a f i @@@ f u n c t i o n s ~name
This will extract name field from afi output and will output a huge list of func-
tion names. We can choose only the second column, to remove the redundant
name: on every line:
[ 0 x004047d6]> a f i @@@ f u n c t i o n s ~name [ 1 ]
Macros
Apart from simple sequencing and looping, radare2 allows to write simple
macros, using this construction:
[ 0 x00404800]> (qwe ; pd 4 ; ao )
This will define a macro called ‘qwe’ which runs sequentially first ‘pd 4’ then
‘ao’. Calling the macro using syntax .(macro) is simple:
[ 0 x00404800]> (qwe ; pd 4 ; ao )
[ 0 x00404800]> . ( qwe)
0x00404800 mov eax , 0x61e627 ; ” tab ”
0x00404805 push rbp
0x00404806 sub rax , section_end .LOAD1
0x0040480c mov rbp , rsp
266
address : 0x404800
opcode : mov eax , 0x61e627
prefix : 0
bytes : b827e66100
ptr : 0 x0061e627
refptr : 0
size : 5
type : mov
e s i l : 6415911 , rax ,=
st a ck : n u l l
f a m i l y : cpu
[ 0 x00404800]>
And if want to remove some macro, just add ‘-’ before the name:
[ 0 x00404800]> (−qwe)
Macro ' qwe ' removed .
[ 0 x00404800]>
Moreover, it’s possible to create a macro that takes arguments, which comes
in handy in some simple scripting situations. To create a macro that takes
arguments you simply add them to macro definition.
[ 0 x00404800 ]
[ 0 x004047d0]> ( f o o x y ; pd $0 ; s +$1 )
[ 0 x004047d0]> . ( f o o 5 6)
;−− entry0 :
0x004047d0 xor ebp , ebp
0x004047d2 mov r9 , rdx
0x004047d5 pop r s i
0x004047d6 mov rdx , rsp
0x004047d9 and rsp , 0 x f f f f f f f f f f f f f f f 0
[ 0 x004047d6]>
As you can see, the arguments are named by index, starting from 0: $0, $1, …
Aliases
The command to create, manage and run command aliases is the $. This is
also the prefix used for aliases files, this chapter will dig
• Variable (like flags)
• Commands (simplest macros)
• Files (in-memory virtual files)
267
You can find some interesting details and examples by checking the help mes-
sage:
[ 0 x100003a84]> $?
Usage : $ a l i a s [=cmd ] [ a r g s . . . ] A l i a s commands and data ( See ?$? f o r
help on $ v a r i a b l e s )
| $ l i s t a l l defined a l i a s e s
| $∗ l i s t a l l d e f i n e d a l i a s e s and t h e i r
values , with u n p r i n t a b l e c h a r a c t e r s escaped
| $∗∗ same as above , but i f an a l i a s c o n t a i n s
u n p r i n t a b l e c h a r a c t e r s , b64 encode i t
| $foo :=123 a l i a s f o r ' f f o o =123'
| $foo−=4 a l i a s f o r ' f foo −=4'
| $foo+=4 a l i a s f o r ' f f o o+=4'
| $foo a l i a s f o r ' s foo ' ( note that command
a l i a s e s can o v e r r i d e f l a g r e s o l u t i o n )
| $ d i s=base64 :AAA= a l i a s $ d i s to the raw bytes from decoding
t h i s base64 s t r i n g
| $ d i s=$ h e l l o world a l i a s $ d i s to the s t r i n g a f t e r ' $ '
| $ d i s=$ h e l l o \\ nworld \\0a s t r i n g a l i a s e s accept double−backslash
and hex es ca p i n g
| $ d i s=− e d i t $ d i s i n c f g . e d i t o r ( use
s i n g l e −b a c k s l a s h e s f o r e s c a p in g )
| $ d i s=a f a l i a s $ d i s to the a f command
| ” $ d i s=a f ; pdf ” a l i a s $ d i s to run af , then pdf . you must
quote the whole command .
| $ t e s t =. /tmp/ t e s t . j s c r e a t e command − r l a n g p i p e s c r i p t
| $ d i s= undefine a l i a s
| $dis execute a d e f i n e d command a l i a s , or p r i n t
a data a l i a s with u n p r i n t a b l e c h a r a c t e r s escaped
| $dis ? show commands a l i a s e d by $ d i s
[ 0 x100003a84]>
The above command will create an alias disas for pdf. The following command
prints the disassembly of the main function.
[ 0 x00404800]> $ d i s a s @ main
Apart from commands, you can also alias a text to be printed, when called.
[ 0 x00404800]> $my_alias=$ t e s t input
[ 0 x00404800]> $my_alias
t e s t input
268
$pmore
[ 0 x00404800]> $pmore=
[ 0 x00404800]> $
A single $ in the above will list all defined aliases. It’s also possible check the
aliased command of an alias:
[ 0 x00404800]> $pmore?
b 2 0 0 ; px
File Aliases If a file accessed from the repl starts with the dollar sign it will
be treated as a virtual one that lives in memory only for the current session
of radare2. They are handy when you don’t want to depend on the filesystem
to create or read files. For example in webassembly environments or other
sandboxed executions.
[ 0 x00000000]> echo h e l l o > $world
[ 0 x00000000]> cat $world
hello
[ 0 x00000000]>
[ 0 x00000000]> $
$world
[ 0 x00000000]> $world
hello
[ 0 x00000000]> rm $world
[ 0 x00000000]> $
[ 0 x00000000]>
Variable Aliases This is a short syntax for accessing and modifying flags,
use them as numeric variables.
269
[ 0 x00000000]> $foo :=4
[ 0 x00000000]> s foo
[ 0 x00000004]> $foo+=4
[ 0 x00000004]> s foo
[ 0 x00000008]>
R2pipe
The r2pipe api was initially designed for NodeJS in order to support reusing
the web’s r2.js API from the commandline. The r2pipe module permits inter-
acting with r2 instances in different methods:
• spawn pipes (r2 -0)
• http queries (cloud friendly)
• tcp socket (r2 -c)
pipe spawn async http tcp rap j s o n
nodejs x x x x x − x
python x x − x x x x
swift x x x x − − x
dotnet x x x x − − −
haskell x x − x − − x
java − x − x − − −
golang x x − − − − x
ruby x x − − − − x
rust x x − − − − x
vala − x x − − − −
erlang x x − − − − −
newlisp x − − − − − −
dlang x − − − − − x
perl x − − − − − −
Examples
Here there are some examples about scripting with r2pipe in different lan-
guages
Python
$ pip i n s t a l l r 2 p i p e
import r 2 p i p e
r2 = r 2 p i p e . open( ”/ bin / l s ” )
r2 . cmd( ' aa ' )
print ( r2 . cmd( ” a f l ” ) )
print ( r2 . cmdj ( ” a f l j ” ) ) # e v a l u a t e s JSONs and r e t u r n s an o b j e c t
270
NodeJS
Use this command to install the r2pipe bindings
$ npm i n s t a l l r 2 p i p e
Go
$ r2pm −i r2pipe−go
https://github.com/radare/r2pipe-go
package main
import (
”fmt”
” github . com/ radare / r2pipe−go”
)
func main ( ) {
r2p , e r r := r 2 p i p e . NewPipe ( ”/ bin / l s ” )
i f e r r != n i l {
panic ( e r r )
}
defer r2p . Close ( )
buf1 , e r r := r2p .Cmd( ”?E H e l l o World” )
i f e r r != n i l {
panic ( e r r )
}
fmt . P r i n t l n ( buf1 )
}
271
Rust
$ cat Cargo . toml
...
[ dependencies ]
r 2 p i p e = ”∗”
#[macro_use ]
extern c r a t e r 2 p i p e ;
use r 2 p i p e : : R2Pipe ;
fn main ( ) {
l e t mut r2p = open_pipe ! ( Some(”/ bin / l s ”) ) . unwrap ( ) ;
p r i n t l n ! ( ” { : ? } ” , r2p . cmd(”? e H e l l o World ”) ) ;
l e t j s o n = r2p . cmdj (” i j ”) . unwrap ( ) ;
p r i n t l n ! ( ” { } ” , serde_json : : to_string_pretty(&j s o n ) . unwrap ( ) ) ;
p r i n t l n ! ( ”ARCH {}” , j s o n [ ” bin ” ] [ ” arch ” ] ) ;
r2p . c l o s e ( ) ;
}
Ruby
$ gem i n s t a l l r 2 p i p e
Perl
#! / usr / bin / p e r l
use R2 : : Pipe ;
use s t r i c t ;
my $r = R2 : : Pipe−>new ( ”/ bin / l s ” ) ;
print $r−>cmd ( ”pd 5” ) . ”\n” ;
print $r−>cmd ( ”px 64” ) . ”\n” ;
$r−>q u i t ( ) ;
Erlang
#! / usr / bin /env e s c r i p t
%% −∗− e r l a n g −∗−
%%! −smp enable
272
%% −sname hr
−mode( compile ) .
−export ( [ main/1 ] ) .
%% i n i t i a l i z i n g t h e l i n k with r2
H = r2pipe : i n i t ( lpipe ) ,
Haskell
import R2pipe
import qualified Data . ByteString . Lazy as L
showMainFunction ctx = do
cmd ctx ” s main”
L . putStr =<< cmd ctx ”pD ` f l $$ `”
main = do
−− Run r2 l o c a l l y
open ”/ bin / l s ” >>= showMainFunction
−− Connect to r2 v i a HTTP ( e . g . i f ” r2 −qc=h / bin / l s ” i s running )
open ” http : / / 1 2 7 . 0 . 0 . 1 : 9 0 9 0 ” >>= showMainFunction
Dotnet
using System ;
using System . C o l l e c t i o n s . Generic ;
using System . D i a g n o s t i c s ;
using System . Linq ;
using System . Text ;
using System . Threading . Tasks ;
using r2pipe ;
namespace LocalExample {
c l a s s Program {
s t a t i c void Main( s t r i n g [ ] a r g s ) {
#i f __MonoCS__
using ( IR2Pipe pipe = new R2Pipe (”/ bin / l s ”) ) {
#e l s e
using ( IR2Pipe pipe = new R2Pipe (@”C: \ Windows\notepad . exe ” ,
@”C: \ radare2 \ radare2 . exe ”) ) {
#e n d i f
273
Console . WriteLine (” H e l l o r2 ! ” + pipe .RunCommand(”?V”) ) ;
Task<s t r i n g > async = pipe . RunCommandAsync(”?V”) ;
Console . WriteLine (” H e l l o async r2 ! ” + async . Result ) ;
QueuedR2Pipe qr2 = new QueuedR2Pipe ( pipe ) ;
qr2 . Enqueue (new R2Command(” x ” , ( s t r i n g r e s u l t ) => {
Console . WriteLine (” Result o f x : \ n {0}” , r e s u l t ) ; }) ) ;
qr2 . Enqueue (new R2Command(” p i 10” , ( s t r i n g r e s u l t ) => {
Console . WriteLine (” Result o f p i 1 0 : \ n {0}” , r e s u l t ) ;
}) ) ;
qr2 . ExecuteCommands ( ) ;
}
}
}
}
Java
import org . radare . r 2 p i p e . R2Pipe ;
Swift
i f l e t r2p = R2Pipe ( u r l : n i l ) {
r2p . cmd ( ”?V” , c l o s u r e : {
( s t r : S t r i n g ?) in
i f let s = s t r {
p r i n t ( ” Version : \( s ) ” ) ;
exit (0) ;
} else {
debugPrint ( ”R2PIPE . Error ” ) ;
exit (1) ;
}
}) ;
NSRunLoop . currentRunLoop ( ) . run ( ) ;
} else {
p r i n t ( ”Needs to run from r2 ” )
}
274
Vala
p u b l i c s t a t i c i n t main ( s t r i n g [ ] a r g s ) {
MainLoop loop = new MainLoop ( ) ;
var r2p = new R2Pipe (”/ bin / l s ”) ;
r2p . cmd (” p i 4” , ( x ) => {
stdout . p r i n t f (” Disassembly : \ n%s \n ” , x ) ;
r2p . cmd (” i e ” , ( x ) => {
stdout . p r i n t f (” Entrypoint : \ n%s \n ” , x ) ;
r2p . cmd (” q ”) ;
}) ;
}) ;
ChildWatch . add ( r2p . child_pid , ( pid , s t a t u s ) => {
Process . close_pid ( pid ) ;
loop . q u i t ( ) ;
}) ;
loop . run ( ) ;
return 0;
}
NewLisp
( load ” r 2 p i p e . l s p ” )
( p r i n t l n ”pd 3 : \ n” ( r 2 p i p e : cmd ”pd 3” ) )
( exit )
Dlang
import std . s t d i o ;
import r 2 p i p e ;
void main ( ) {
auto r2 = r 2 p i p e . open ( ) ;
w r i t e l n (” H e l l o ”~ r2 . cmd(”? e World ”) ) ;
w r i t e l n (” H e l l o ”~ r2 . cmd(”? e Works”) ) ;
s t r i n g u r i = r2 . cmdj (” i j ”) [ ” c o r e ” ] [ ” u r i ” ] . s t r ;
w r i t e l n (” Uri : ” , u r i ) ;
}
R2Pipe2
The original r2pipe protocol is very simple, this have some advantages, but
also some inconvieniences and limitations.
The 2nd version aims to address these problems by extending the r2 shell with
a new command: {.
Sounds funny? Probably yes, but it works and keeps the things simple and
powerful.
275
The new { command (introduced in r2-5.9.x) permits to enter a JSON object
right into the r2 shell, the output of the command will be another json con-
taining not just the output of the command executed, but also some extra
information that was missing in the previous version.
• Command output
• Return value
• Return code
• Error reason
• Log messages
As long as the JSON object can be easily extended in the future more
R2pipe2 Example
The { object takes the mandatory “cmd” parameter, but can also handle two
more fields:
• json: output of the command inlined as json in the resulting object
• trim: remove trailing spaces in the output of the command
Let’s check the help:
[ 0 x00000000]> {?
Usage : {”cmd ” : ” . . . ” , ” j s o n ” : f a l s e , ” trim ” : t r u e } # `cmd` i s r e q u i r e d
[ 0 x00000000]>
For example:
[ 0 x00000000]> '{”cmd” : ” ? e h e l l o ”}
{” r e s ” : ” h e l l o \n ” , ” e r r o r ” : f a l s e , ” value ” : 2 5 6 , ” code ” : 0 , ” code ” : 0 }
[ 0 x00000000]>
R2pipe2 APIs
As you can imagine, the new { command can be used directly from an r2. callj
command. But r2pipe2 Python, TypeScript and R2JS implementations ex-
pose the r2.cmd2 and r2.cmd2j functions to abstract this.
Debugger
Debuggers are implemented as IO plugins. Therefore, radare can handle dif-
ferent URI types for spawning, attaching and controlling processes. The com-
plete list of IO plugins can be viewed with r2 −L. Those that have “d” in the
first column (“rwd”) support debugging. For example:
276
r_d debug Debug a program or pid . dbg : / / / bin / l s , dbg ://1388
(LGPL3)
rwd gdb Attach to gdbserver , 'qemu −s ' ,
gdb : / / l o c a l h o s t :1234 (LGPL3)
There are different backends for many target architectures and operating sys-
tems, e.g., GNU/Linux, Windows, MacOS X, (Net,Free,Open)BSD and So-
laris.
Process memory is treated as a plain file. All mapped memory pages of a
debugged program and its libraries can be read and interpreted as code or
data structures.
Communication between radare and the debugger IO layer is wrapped into
system() calls, which accept a string as an argument, and executes it as a
command. An answer is then buffered in the output console, its contents can
be additionally processed by a script. Access to the IO system is achieved
with =!. Most IO plugins provide help with =!? or =!help. For example:
$ r2 −d / bin / l s
...
[ 0 x 7 f c 1 5 a f a 3 c c 0 ]> =! help
Usage : =!cmd a r g s
=! p t r a c e − use p t r a c e i o
=!mem − use / proc / pid /mem i o i f p o s s i b l e
=! pid − show t a r g e t e d pid
=! pid <#> − s e l e c t new pid
277
| dL [ ? ] L i s t or s e t debugger handler
| dm[ ? ] Show memory maps
| do [ ? ] Open p r o c e s s ( reload , a l i a s f o r ' oo ' )
| doo [ a r g s ] Reopen i n debug mode with a r g s ( a l i a s f o r
' ood ' )
| doof [ f i l e ] Reopen i n debug mode from f i l e ( a l i a s f o r
' oodf ' )
| doc Close debug s e s s i o n
| dp [ ? ] L i s t , attach to p r o c e s s or thread i d
| dr [ ? ] Cpu r e g i s t e r s
| ds [ ? ] Step , over , s o u r c e l i n e
| dt [ ? ] Display i n s t r u c t i o n t r a c e s
| dw <pid> Block prompt u n t i l pid d i e s
| dx [ ? ] I n j e c t and run code on t a r g e t p r o c e s s
( See gs )
Getting Started
Small session in radare2 debugger
• r2 −d /bin/ls: Opens radare2 with file /bin/ls in debugger mode using the
radare2 native debugger, but does not run the program. You’ll see a
prompt (radare2) - all examples are from this prompt.
• db flag: place a breakpoint at flag, where flag can be either an address
or a function name
• db − flag: remove the breakpoint at flag, where flag can be either an
address or a function name
• db: show list of breakpoint
• dc: run the program
• dr: Show registers state
• drr: Show registers references (telescoping) (like peda)
• ds: Step into instruction
• dso: Step over instruction
• dbt: Display backtrace
• dm: Show memory maps
278
• dk <signal>: Send KILL signal to child
• ood: reopen in debug mode
• ood arg1 arg2: reopen in debug mode with arg1 and arg2
279
How to list Source code as in gdb list ?
CL @ sym.main - though the feature is highly experimental
Reference Commands
r2 (visual
Command IDA Pro radare2 mode) GDB WinDbg
Analysis
Analysis of Automatically aaa or −A (aaaa N/A N/A N/A
everything launched or −AA for even
when experimental
opening a analysis)
binary
Navigation
xref to x axt x N/A N/A
xref from ctrl + j axf X N/A N/A
xref to ? agt [ offset ] ? N/A N/A
graph
xref from ? agf [ offset ] ? N/A N/A
graph
list alt + 1 afl ; is t N/A N/A
functions
listing alt + 2 pdf p N/A N/A
hex mode alt + 3 pxa P N/A N/A
imports alt + 6 ii : ii N/A N/A
exports alt + 7 is~FUNC ? N/A N/A
follow enter s offset enter or 0-9 N/A N/A
jmp/call
undo seek esc s− u N/A N/A
redo seek ctrl +enter s+ U N/A N/A
show space agv V N/A N/A
graph
Edit
rename n afn dr N/A N/A
graph view space agv V N/A N/A
define as d Cd [size] dd,db,dw,dW N/A N/A
data
define as c C− [size] d− or du N/A N/A
code
define as u C− [size] d− or du N/A N/A
undefined
280
r2 (visual
Command IDA Pro radare2 mode) GDB WinDbg
define as A Cs [size ] ds N/A N/A
string
define as Alt+Q Cf [ size ] dF N/A N/A
struct
Debugger
Start F9 dc F9 r and g
Process / c
Continue
execution
Terminate Ctrl+F2 dk 9 ? kill q
Process
Detach ? o− ? detach
step into F7 ds s n t
step into 4 ? ds 4 F7 n4 t 4
instruc-
tions
step over F8 dso S s p
step until ? dsu <addr> ? s g
a specific <addr>
address
Run until Ctrl+F7 dcr ? finish gu
return
Run until F4 #249 #249 N/A N/A
cursor
Show ? dbt ? bt
Backtrace
display On register dr all Shown in info r
Register Windows Visual mode registers
display eax On register dr?eax Shown in info r
Windows Visual mode registers rax
eax
display old ? dro ? ? ?
state of all
registers
display ? afi $$ - display ? ? ?
function function
addr + N information of
current offset
($$)
281
r2 (visual
Command IDA Pro radare2 mode) GDB WinDbg
display ? pxw rbp−rsp@rsp ? i f ?
frame state
How to ? dsi ? ? ?
step until
condition
is true
Update a ? dr rip=0x456 ? set r
register $rip=0x456
rip=456
value
Disassembly
disassembly N/A pd Vp disas uf,
forward u
disassembly N/A pd X Vp x/<N>i u
N instruc- <addr>
tions LX
disassembly N/A pd −X Vp disas ub
N <a−o>
(backward) <a>
Information
on the
bin
Sections/regions
Menu iS or S (append N/A maint !address
sections j for json) info
sec-
tions
Load
symbol
file
Sections/regions
pdb menu asm.dwarf.file, N/A add−symbol−file
r
pdb.XX
BackTrace
Stack N/A dbt N/A bt k
Trace
Stack N/A dbtj N/A
Trace in
Json
Partial N/A dbt (dbg.btdepth N/A bt k
Backtrace dbg.btalgo) <N> <N>
(inner-
most)
282
r2 (visual
Command IDA Pro radare2 mode) GDB WinDbg
Partial N/A dbt (dbg.btdepth N/A bt
Backtrace dbg.btalgo) −<N>
(outer-
most)
Stacktrace N/A dbt@t N/A thread ~∗ k
for all apply
threads all bt
Breakpoints
Breakpoint Ctrl+Alt+B db ? info bl
list breakpoints
add F2 db [ offset ] F2 break bp
breakpoint
Threads
Switch to Thread menu dp N/A thread ~<N>s
thread <N>
Frames
Frame N/A ? N/A any kn
Numbers bt
command
Select N/A ? N/A frame .frame
Frame
Parameters/Locals
Display N/A afv N/A info dv
parameters args /t
/i
/V
Display N/A afv N/A info dv
parameters locals /t
/i
/V
Display N/A afvj N/A info dv
parameter- locals /t
s/locals in /i
json /V
list N/A afvR/afvW N/A ? ?
addresses
where vars
are ac-
cessed(R/W)
283
r2 (visual
Command IDA Pro radare2 mode) GDB WinDbg
Project
Related
open Po [ file ] ?
project
save automatic Ps [ file ] ?
project
show Pi [ file ] ?
project in-
formations
Miscellaneous
Dump N/A pc?(json, C, Vpppp x/<N>bcdb
byte char char, etc.)
array
options option e? e
menu
search search /? Select the s
menu zone with the
cursor c then
/
Common features
• r2 accepts FLIRT signatures
• r2 can connect to GDB, LLVM and WinDbg
• r2 can write/patch in place
• r2 have fortunes and [s]easter eggs[/s]balls of steel
• r2 can do basic loading of ELF core files from the box and MDMP
(Windows minidumps)
Registers
The registers are part of a user area stored in the context structure used by
the scheduler. This structure can be manipulated to get and set the values
284
of those registers, and, for example, on Intel hosts, it is possible to directly
manipulate DR0-DR7 hardware registers to set hardware breakpoints.
There are different commands to get values of registers. For the General
Purpose ones use:
[ 0 x4A13B8C0]> dr
r15 = 0x00000000
r14 = 0x00000000
r13 = 0x00000000
r12 = 0x00000000
rbp = 0x00000000
rbx = 0x00000000
r11 = 0x00000000
r10 = 0x00000000
r9 = 0x00000000
r8 = 0x00000000
rax = 0x00000000
rcx = 0x00000000
rdx = 0x00000000
r s i = 0x00000000
r d i = 0x00000000
oeax = 0x0000003b
r i p = 0 x7f20bf5df630
rsp = 0 x 7 f f f 5 1 5 9 2 3 c 0
285
f r f l a g s 1 0x200
f rsp 1 0 x 7 f f f 7 3 5 5 7 9 4 0
An old copy of registers is stored all the time to keep track of the changes
done during execution of a program being analyzed. This old copy can be
accessed with oregs.
[ 0 x7f1fab84c630 ]> dro
r15 = 0x00000000
r14 = 0x00000000
r13 = 0x00000000
r12 = 0x00000000
rbp = 0x00000000
rbx = 0x00000000
r11 = 0x00000000
r10 = 0x00000000
r9 = 0x00000000
r8 = 0x00000000
rax = 0x00000000
rcx = 0x00000000
rdx = 0x00000000
r s i = 0x00000000
r d i = 0x00000000
oeax = 0x0000003b
r i p = 0 x7f1fab84c630
r f l a g s = 0x00000200
rsp = 0 x 7 f f f 3 8 6 b 5 0 8 0
286
Values stored in eax, oeax and eip have changed.
To store and restore register values you can just dump the output of ’dr*’
command to disk and then re-interpret it again:
[ 0 x4A13B8C0]> dr∗ > r e g s . saved ; save r e g i s t e r s
[ 0 x4A13B8C0]> drp r e g s . saved ; r e s t o r e
You can get a string which represents latest changes of registers using drd
command (diff registers):
[ 0 x4A13B8C0]> drd
oeax = 0x0000003b was 0x00000000 d e l t a 59
r i p = 0 x7f00e71282d0 was 0x00000000 d e l t a −418217264
r f l a g s = 0x00000200 was 0x00000000 d e l t a 512
rsp = 0 x 7 f f f e 8 5 a 0 9 c 0 was 0x00000000 d e l t a −396752448
Register Profiles
The way register values are transferred from kernel to userland (or via network
when using gdb or other debuggers) it’s usually done through a linear memory
buffer and an associated register profile which is in charge to describe the
name, location, size and other attributes to interpret that buffer.
Usually not all registers are transferred in the same buffer, this is because
there are register groups or families, like floating pointer, general purpose,
privileged ones..
In the case of GDB, XML format is choosen to describe all this information, in
radare2 we use our own space/tab separated document which can be dumped
or changed at any time with the drp and arp commands (note one is for de-
bugging sessions, and the other will be used for the static esil emulation).
Radare2 is able to parse the gdb xml register profile and generate one in
the radare2 syntax when connecting to unknown targets that support those
commands.
287
$ r2 −a x86 −b 16 −qc arp −−
=PC i p
=SP sp
=BP bp
=R0 ax
=A0 ax
=A1 bx
=A2 cx
=A3 dx
=A4 s i
=A5 d i
=SN ah
=TR f s
gpr i p . 1 6 48 0
gpr ax . 1 6 24 0
gpr ah . 8 25 0
gpr a l . 8 24 0
gpr bx . 1 6 0 0
gpr bh . 8 1 0
gpr b l . 8 0 0
gpr cx . 1 6 4 0
gpr ch . 8 5 0
gpr c l . 8 4 0
gpr dx . 1 6 8 0
gpr dh . 8 9 0
gpr d l . 8 8 0
gpr sp . 1 6 60 0
gpr bp . 1 6 20 0
gpr s i . 1 6 12 0
gpr d i . 1 6 16 0
seg c s . 1 6 52 0
seg s s . 1 6 54 0
seg ds . 1 6 56 0
seg e s . 1 6 58 0
gpr f l a g s . 1 6 56 0
flg cf .1 .448 0
f l g pf . 1 .449 0
f l g af .1 .450 0
flg zf .1 .451 0
flg sf .1 .452 0
flg tf .1 .453 0
flg if .1 .454 0
f l g df . 1 .455 0
f l g of .1 .456 0
flg rf .1 .457 0
288
registers, experiment with it, ..
These are the commands you must use to dump the current register profile to
a file, edit it and then load it again:
drp > p r o f i l e . t x t
vim p r o f i l e . t x t
drp p r o f i l e . t x t
This line means that everytime we try to pick the “PC” register, it will be
redirected to point to the one named ip. This way radare2 is able to work
across multiple architectures having a generic way to refer to each of them.
Alias Register
The register aliases are used for a variety of actions in radare2, so the code
analysis, calling conventions, syscall scanning and so on will be affected by
those.
• PC : Program Counter
• SP : Stack Pointer
• BP : Base Pointer (delta for the stack frame with SP)
• R0 : First Register used to return values
289
• R1 : Second Register (used for tuples or 64bit values on 32bit systems)
• A0 : First argument passed to a syscall
• A1 : Second argument..
• A2 : Third argument..
• A3 : Fourth argument..
• SN : Register used Syscall Number
• TR : Thread Local Storage Register
Register Groups
As mentioned earlier the registers can be grouped and classified depending on
the uses for proper displaying them as well as the debugger backend pulling
them back from the source.
These are the group names, as you will notice, all of them have 3 lowercase
letters:
• gpr : General Purpose Registers
• flg : Status Flags
• seg : Segment Registers
• fpu : Floating Pointer Registers
• vec : Vector Registers
• pri : Privileged Registers
Column Meanings
The following lines will look like this:
..
gpr r2 .32 8 0
gpr r3 .32 12 0
...
290
• Sizes or offsets starting with a dot . are represented in bits instead of
bytes
The Packing size is used to define the syllab size of each register word for
vector registers.
Endianness
Values can be stored and represented in different endianness when working in
local or remote instances with the debugger.
The way this information is represented in the reg profile is with a line starting
with ^. The next letter will tell the register profile the endianness to use which
can be big, little or middle.
You can find an usage example for this feature in the register profile for the
native debugger for s390x architecture.
Memory Maps
The ability to understand and manipulate the memory maps of a debugged
program is important for many different Reverse Engineering tasks. radare2
offers a rich set of commands to handle memory maps in the binary. This
includes listing the memory maps of the currently debugged binary, removing
memory maps, handling loaded libraries and more.
First, let’s see the help message for dm, the command which is responsible for
handling memory maps:
[ 0 x55f2104cf620 ]> dm?
Usage : dm # Memory maps commands
| dm L i s t memory maps o f t a r g e t p r o c e s s
| dm address s i z e A l l o c a t e <s i z e > bytes at
<address> ( anywhere i f address i s −1) i n c h i l d p r o c e s s
| dm= L i s t memory maps o f t a r g e t
p r o c e s s ( a s c i i −a r t bars )
| dm. Show map name o f c u r r e n t address
| dm∗ L i s t memmaps i n radare commands
| dm− address D e a l l o c a t e memory map o f <address>
| dmd[ a ] [ f i l e ] Dump c u r r e n t ( a l l ) debug map
r e g i o n to a f i l e ( from−to .dmp) ( s e e Sd )
| dmh [ ? ] Show map o f heap
| dmi [ addr | libname ] [ symname ] L i s t symbols o f t a r g e t l i b
| dmi∗ [ addr | libname ] [ symname ] L i s t symbols o f t a r g e t l i b i n
radare commands
| dmi . L i s t c l o s e s t symbol to the
c u r r e n t address
| dmiv Show address o f given symbol f o r
given l i b
| dmj L i s t memmaps i n JSON format
291
| dml <f i l e > Load c o n t e n t s o f f i l e i n t o the
c u r r e n t map r e g i o n
| dmm[ ? ] [ j ∗ ] L i s t modules ( l i b r a r i e s , b i n a r i e s
loaded i n memory)
| dmp [ ? ] <address> <s i z e > <perms> Change page at <address> with
<s i z e >, p r o t e c t i o n <perms> ( perm )
| dms [ ? ] <id> <mapaddr> Take memory snapshot
| dms− <id> <mapaddr> Restore memory snapshot
| dmS [ addr | libname ] [ sectname ] List sections of target l i b
| dmS∗ [ addr | libname ] [ sectname ] List sections of target l i b in
radare commands
| dmL address s i z e A l l o c a t e <s i z e > bytes at
<address> and promote to huge page
292
For those of you who prefer a more visual way, you can use dm= to see the
memory maps using an ASCII-art bars. This will be handy when you want
to see how these maps are located in the memory.
If you want to know the memory-map you are currently in, use dm.:
[ 0 x 7 f 1 3 3 f 0 2 2 f b 0 ]> dm.
0 x00007f947eed9000 # 0 x00007f947eefe000 ∗ usr 148K s r−x
/ usr / l i b / ld −2.27. so / usr / l i b / ld −2.27. so ;
map . usr_lib_ld_2 . 2 7 . so . r_x
Using dmm we can “List modules (libraries, binaries loaded in memory)”, this
is quite a handy command to see which modules were loaded.
[ 0 x7fa80a19dfb0 ]> dmm
0 x55ca23a4a000 /tmp/ h e l l o w o r l d
0 x7fa80a19d000 / usr / l i b / ld −2.27. so
293
Similar to the dm. command, with dmi. you can see the closest symbol to the
current address.
Another useful command is to list the sections of a specific library. In the
following example we’ll list the sections of ld−2.27.so:
[ 0 x55a7ebf09520]> dmS ld −2.27
[ Sections ]
00 0x00000000 0 0x00000000 0 −−−− ld −2.27. so .
01 0 x000001c8 36 0x4652d1c8 36 −r−−
ld −2.27. so . . note . gnu . build_id
02 0 x000001f0 352 0 x4652d1f0 352 −r−− ld −2.27. so . . hash
03 0x00000350 412 0x4652d350 412 −r−− ld −2.27. so . . gnu . hash
04 0 x000004f0 816 0 x4652d4f0 816 −r−− ld −2.27. so . . dynsym
05 0x00000820 548 0x4652d820 548 −r−− ld −2.27. so . . dynstr
06 0x00000a44 68 0x4652da44 68 −r−− ld −2.27. so . . gnu . v e r s i o n
07 0x00000a88 164 0x4652da88 164 −r−− ld −2.27. so . . gnu . version_d
08 0x00000b30 1152 0x4652db30 1152 −r−− ld −2.27. so . . r e l a . dyn
09 0 x00000fb0 11497 0 x4652dfb0 11497 −r−x ld −2.27. so . . t e x t
10 0x0001d0e0 17760 0 x4654a0e0 17760 −r−− ld −2.27. so . . rodata
11 0x00021640 1716 0 x4654e640 1716 −r−− ld −2.27. so . . eh_frame_hdr
12 0 x00021cf8 9876 0 x4654ecf8 9876 −r−− ld −2.27. so . . eh_frame
13 0x00024660 2020 0x46751660 2020 −rw− ld −2.27. so . . data . r e l . ro
14 0 x00024e48 336 0 x46751e48 336 −rw− ld −2.27. so . . dynamic
15 0 x00024f98 96 0 x46751f98 96 −rw− ld −2.27. so . . got
16 0x00025000 3960 0x46752000 3960 −rw− ld −2.27. so . . data
17 0 x00025f78 0 0 x46752f80 376 −rw− ld −2.27. so . . bss
18 0 x00025f78 17 0x00000000 17 −−−− ld −2.27. so . . comment
19 0 x00025fa0 63 0x00000000 63 −−−−
ld −2.27. so . . gnu . warning . l l s e e k
20 0 x00025fe0 13272 0x00000000 13272 −−−− ld −2.27. so . . symtab
21 0x000293b8 7101 0x00000000 7101 −−−− ld −2.27. so . . s t r t a b
22 0 x0002af75 215 0x00000000 215 −−−− ld −2.27. so . . s h s t r t a b
Heap
radare2’s dm subcommands can also display a map of the heap which is useful
for those who are interested in inspecting the heap and its content. Simply
execute dmh to show a map of the heap:
[ 0 x7fae46236ca6 ]> dmh
Malloc chunk @ 0 x55a7ecbce250 [ s i z e : 0x411 ] [ a l l o c a t e d ]
Top chunk @ 0 x55a7ecbce660 − [ brk_start : 0 x55a7ecbce000 , brk_end :
0 x55a7ecbef000 ]
294
| fd : 0x0 , bk : 0x0 |
`−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
|
.−−−'
|
|
.−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−.
| Malloc chunk @ 0 x55a7ecbce250 |
| s i z e : 0x411 |
| fd : 0 x57202c6f6c6c6548 , bk : 0 xa21646c726f |
`−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
|
.−−−'
|
|
.−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−.
| Top chunk @ 0 x55a7ecbce660 |
| [ brk_start : 0 x55a7ecbce000 , brk_end : 0 x55a7ecbef000 ] |
`−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
Another heap commands can be found under dmh, check dmh? for the full list.
[ 0 x00000000]> dmh?
| Usage : dmh # Memory map heap
| dmh L i s t chunks i n heap segment
| dmh [ malloc_state ] L i s t heap chunks o f a p a r t i c u l a r arena
| dmha L i s t a l l malloc_state i n s t a n c e s i n a p p l i c a t i o n
| dmhb Display a l l parsed Double l i n k e d l i s t o f
main_arena ' s b i n s i n s t a n c e
| dmhb [ bin_num | bin_num : malloc_state ] Display parsed double
l i n k e d l i s t o f b i n s i n s t a n c e from a p a r t i c u l a r arena
| dmhbg [ bin_num ] Display double l i n k e d l i s t graph o f
main_arena ' s bin [ Under developemnt ]
| dmhc @[ chunk_addr ] Display malloc_chunk s t r u c t f o r a given malloc
chunk
| dmhf Display a l l parsed f a s t b i n s o f main_arena ' s
fastbinY i n s t a n c e
| dmhf [ fastbin_num | fastbin_num : malloc_state ] Display parsed s i n g l e
l i n k e d l i s t i n fastbinY i n s t a n c e from a p a r t i c u l a r arena
| dmhg Display heap graph o f heap segment
| dmhg [ malloc_state ] Display heap graph o f a p a r t i c u l a r arena
| dmhi @[ malloc_state ] Display heap_info s t r u c t u r e / s t r u c t u r e s f o r a
given arena
| dmhm L i s t a l l elements o f s t r u c t malloc_state o f
main thread ( main_arena )
| dmhm [ malloc_state ] L i s t a l l malloc_state i n s t a n c e o f a p a r t i c u l a r
arena
| dmht Display a l l parsed thead cache b i n s o f
main_arena ' s tcache i n s t a n c e
| dmh? Show map heap help
To print safe-linked lists (glibc >= 2.32) with demangled pointers, the variable
dbg.glibc.demangle must be true.
295
Signals
You can send signals to the target process, or change the behaviour of the the
debugger and signal handler associated with the dk command.
[ 0 x00000000]> dk?
Usage : dk S i g n a l commands
| dk l i s t a l l s i g n a l h a n d le r s o f c h i l d
process
| dk <s i g n a l > send KILL s i g n a l to c h i l d
| dk <s i g n a l >=1 s e t s i g n a l handler f o r <s i g n a l > i n c h i l d
| dk?<s i g n a l > name/signum r e s o l v e r
| dko [ ? ] <s i g n a l > r e s e t s k i p or cont o p t i o n s f o r given
signal
| dko <s i g n a l > [ | s k i p | cont ] on s i g n a l SKIP handler or CONT i n t o
| dkj l i s t a l l s i g n a l h a n d le r s i n JSON
[ 0 x00000000]>
To change the behaviour of the r2 debugger when the target process receives
a specific signal use the dko command. Note that radare2 handles signals in
a portable way, so the Windows exceptions will be used instead of the signal
unix syscalls.
These are the list of signals with their associated numbers:
[ 0 x00000000]> dk
32 SIGRTMIN 30 SIGPWR 14 SIGALRM 31 SIGSYS 15 SIGTERM 16 SIGSTKFLT
17 SIGCHLD 10 SIGUSR1 11 SIGSEGV 12 SIGUSR2 13 SIGPIPE 18 SIGCONT
19 SIGSTOP 27 SIGPROF 26 SIGVTALRM 25 SIGXFSZ 24 SIGXCPU 23 SIGURG
22 SIGTTOU 5 SIGTRAP 21 SIGTTIN 4 SIGILL 20 SIGTSTP 7 SIGBUS 6
SIGABRT
1 SIGHUP 3 SIGQUIT 2 SIGINT 29 SIGLOST 28 SIGWINCH 9 SIGKILL 8 SIGFPE
Files
The radare2 debugger allows the user to list and manipulate the file descriptors
from the target process.
This is a useful feature, which is not found in other debuggers, the functional-
ity is similar to the lsof command line tool, but have extra subcommands to
change the seek, close or duplicate them.
So, at any time in the debugging session you can replace the stdio file de-
scriptors to use network sockets created by r2, or replace a network socket
connection to hijack it.
This functionality is also available in r2frida by using the dd command prefixed
with a backslash. In r2 you may want to see the output of dd? for proper
details.
296
[ 0 x00000000]> dd?
Usage : dd Manage f i l e d e s c r i p t o r s f o r c h i l d p r o c e s s (∗ to show r2
commands)
| dd [ ∗ ] l i s t f i l e descriptors
| dd [ ∗ ] < f i l e | addr> open f i l e as read−only ( r−−); addr =
use as char ∗ f o r path
| dd+[∗] < f i l e | addr> open/ c r e a t e f i l e as read−w r i t e (rw−) ;
addr = use as char ∗ f o r path
| dd −[∗] <fd> c l o s e fd
| ddt [ ∗ ] c l o s e t e r m i n a l fd ( a l i a s f o r `dd− 0 `)
| dds [ ∗ ] <fd> [ o f f s e t ] seek fd to o f f s e t ( no o f f s e t = seek to
beginning )
| ddd [ ∗ ] <oldfd> <newfd> copy o l d f d to newfd with dup2
| ddf [ ∗ ] <addr> c r e a t e pipe and w r i t e f d s to
( i n t [ 2 ] ) addr
| ddr [ ∗ ] <fd> <addr> <s i z e > read bytes from fd i n t o ( char ∗) addr
| ddw [ ∗ ] <fd> <addr> <s i z e > w r i t e bytes from ( const char ∗) addr to fd
[ 0 x00000000]>
Tweaking descriptors
The dd command will use ragg2 internally to compile a shellcode that is then
injected into the target process to manipulate the file descriptors.
For example if we want to open a file we can use this:
dd /bin/ls
Reverse Debugging
Radare2 has reverse debugger, that can seek the program counter backward.
(e.g. reverse-next, reverse-continue in gdb) Firstly you need to save program
state at the point that you want to start recording. The syntax for recording
is:
[ 0 x004028a0]> dts+
You can use dts commands for recording and managing program states. After
recording the states, you can seek pc back and forth to any points after saved
address. So after recording, you can try single step back:
[ 0 x004028a0]> 2dso
[ 0 x004028a0]> dr r i p
0x004028ae
[ 0 x004028a0]> dsb
continue u n t i l 0x004028a2
h i t breakpoint at : 4028 a2
[ 0 x004028a0]> dr r i p
0x004028a2
297
When you run dsb, reverse debugger restore previous recorded state and exe-
cute program from it until desired point.
Or you can also try continue back:
[ 0 x004028a0]> db 0x004028a2
[ 0 x004028a0]> 10 dso
[ 0 x004028a0]> dr r i p
0x004028b9
[ 0 x004028a0]> dcb
[ 0 x004028a0]> dr r i p
0x004028a2
dcb seeks program counter until hit the latest breakpoint. So once set a
breakpoint, you can back to it any time.
You can see current recorded program states using dts:
[ 0 x004028a0]> dts
session : 0 at : 0 x004028a0 ””
session : 1 at : 0 x004028c2 ””
NOTE: Program records can be saved at any moments. These are diff style
format that save only different memory area from previous. It saves memory
space rather than entire dump.
And also can add comment:
[ 0 x004028c2]> dtsC 0 program s t a r t
[ 0 x004028c2]> dtsC 1 decryption s t a r t
[ 0 x004028c2]> dts
session : 0 at : 0 x004028a0 ”program s t a r t ”
session : 1 at : 0 x004028c2 ” decryption s t a r t ”
You can leave notes for each records to keep in your mind. dsb and dcb
commands restore the program state from latest record if there are many
records.
Program records can exported to file and of course import it. Export/Import
records to/from file:
[ 0 x004028c2]> d t s t r e c o r d s _ f o r _ t e s t
S e s s i o n saved i n re c o r d s _ f o r _ t e s t . s e s s i o n and dump i n
r e c o r d s_ f o r _ t e s t . dump
[ 0 x004028c2]> d t s f r e c o r d s _ f o r _ t e s t
s e s s i o n : 0 , 0x4028a0 d i f f s : 0
s e s s i o n : 1 , 0x4028c2 d i f f s : 0
Moreover, you can do reverse debugging in ESIL mode. In ESIL mode, pro-
gram state can be managed by aets commands.
[ 0 x00404870]> a e t s+
298
And step back by aesb:
[ 0 x00404870]> aer r i p
0x00404870
[ 0 x00404870]> 5 aeso
[ 0 x00404870]> aer r i p
0x0040487d
[ 0 x00404870]> aesb
[ 0 x00404870]> aer r i p
0x00404879
Windows Messages
On Windows, you can use dbW while debugging to set a breakpoint for the
message handler of a specific window.
Get a list of the current process windows with dW :
[ 0 x7 f f e 88 5 c1 16 4 ]> dW
.−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−.
| Handle | PID | TID | Class Name |
)−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−(
| 0x0023038e | 9432 | 22432 | MSCTFIME UI |
| 0x0029049e | 9432 | 22432 | IME |
| 0x002c048a | 9432 | 22432 | Edit |
| 0x000d0474 | 9432 | 22432 | msctls_statusbar32 |
| 0x00070bd6 | 9432 | 22432 | Notepad |
`−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
Set the breakpoint with a message type, together with either the window class
name or its handle:
[ 0 x7 f f e 88 5 c1 16 4 ]> dbW WM_KEYDOWN Edit
Breakpoint s e t .
Or
[ 0 x7 f f e 88 5 c1 16 4 ]> dbW WM_KEYDOWN 0x002c048a
Breakpoint s e t .
If you aren’t sure which window you should put a breakpoint on, use dWi to
identify it with your mouse:
[ 0 x7 f f e 88 5 c1 16 4 ]> dWi
Move c u r s o r to the window to be i d e n t i f i e d . Ready? y
Try to get the c h i l d ? y
299
.−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−.
| Handle | PID | TID | Class Name |
)−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−(
| 0x002c048a | 9432 | 22432 | Edit |
`−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−'
remote commands :
| = l i s t a l l open c o n n e c t i o n s
| =<[fd ] cmd send output o f l o c a l command to
remote fd
| =[ fd ] cmd exec cmd at remote ' fd ' ( l a s t open
i s d e f a u l t one )
| =! cmd run command v i a r_io_system
| =+ [ proto : / / ] host : port connect to remote host : port
(∗ rap : / / , raps : / / , tcp : / / , udp : / / , http : / / )
| =−[fd ] remove a l l h o s t s or host ' fd '
| ==[fd ] open remote s e s s i o n with host ' fd ' ,
' q ' to q u i t
| =!= d i s a b l e remote cmd mode
| !=! enable remote cmd mode
servers :
| .:9000 start the tcp s e r v e r ( echo x | nc : : 1
9090 or c u r l : : 1 : 9 0 9 0 /cmd/x )
| =: port start the rap s e r v e r ( o rap : / / 9 9 9 9 )
| =g [ ? ] start the gdbserver
| =h [ ? ] start the http webserver
| =H[ ? ] start the http webserver ( and launch
the web browser )
other :
| =&:port s t a r t rap s e r v e r i n background ( same
as '&_=h ' )
| =: host : port cmd run 'cmd' command on remote s e r v e r
examples :
| =+tcp : / / l o c a l h o s t :9090/ connect to : r2 −c . : 9 0 9 0 . / bin
| =+rap : / / l o c a l h o s t :9090/ connect to : r2 rap : / / : 9 0 9 0
| =+http : / / l o c a l h o s t :9090/cmd/ connect to : r2 −c '=h 9090 ' bin
| o rap : / / : 9 0 9 0 / s t a r t the rap s e r v e r on tcp port 9090
300
You can learn radare2 remote capabilities by displaying the list of supported
IO plugins: radare2 −L.
A little example should make this clearer. A typical remote session might look
like this:
At the remote host1:
$ radare2 rap : / / : 1 2 3 4
At localhost:
$ radare2 −
Add hosts
[ 0 x004048c5]> =+ rap ://< host1 >:1234// bin / l s
Connected to : <host1> at port 1234
waiting . . . ok
[ 0 x004048c5]> =
0 − rap ://< host1 >:1234// bin / l s
You can open remote files in debug mode (or using any IO plugin) specifying
URI when adding hosts:
[ 0 x004048c5]> =+ =+ rap ://< host2 >:1234/dbg : / / / bin / l s
Connected to : <host2> at port 1234
waiting . . . ok
0 − rap ://< host1 >:1234// bin / l s
1 − rap ://< host2 >:1234/dbg : / / / bin / l s
301
You can also redirect radare output to a TCP or UDP server (such as nc −l).
First, Add the server with ‘=+ tcp://’ or ‘=+ udp://’, then you can redirect
the output of a command to be sent to the server:
[ 0 x004048c5]> =+ tcp ://< host >:<port>/
Connected to : <host> at port <port>
5 − tcp ://< host >:<port>/
[ 0 x004048c5]> =<5 cmd . . .
The =< command will send the output from the execution of cmd to the remote
connection number N (or the last one used if no id specified).
Note that the following command does the same, r2 will use the debug plugin
specified by the uri if found.
$ r2 −D gdb gdb://< host >:<port>
It is also possible to start debugging after analyzing a file using the doof
command which rebases the current session’s data after opening gdb
[ 0 x00404870]> doof gdb://< host >:<port>/<pid>
After connecting, you can use the standard r2 debug commands as normal.
radare2 does not yet load symbols from gdbserver, so it needs the binary to be
locally present to load symbols from it. In case symbols are not loaded even
if the binary is present, you can try specifying the path with e dbg.exe.path:
$ r2 −e dbg . exe . path=<path> −d gdb://< host >:<port>
If symbols are loaded at an incorrect base address, you can try specifying the
base address too with e bin.baddr:
$ r2 −e bin . baddr=<baddr> −e dbg . exe . path=<path> −d
gdb://< host >:<port>
302
Usually the gdbserver reports the maximum packet size it supports. Other-
wise, radare2 resorts to sensible defaults. But you can specify the maximum
packet size with the environment variable R2_GDB_PKTSZ. You can also
check and set the max packet size during a session with the IO system, : .
$ export R2_GDB_PKTSZ=512
$ r2 −d gdb://< host >:<port>
= attach <pid> <t i d>
Assuming f i l e p a t h <path/ to /exe>
[ 0 x 7 f f 6 5 9 d 9 f c c 0 ]> : pktsz
packet s i z e : 512 bytes
[ 0 x 7 f f 6 5 9 d 9 f c c 0 ]> : pktsz 64
[ 0 x 7 f f 6 5 9 d 9 f c c 0 ]> : pktsz
packet s i z e : 64 bytes
The gdb IO system provides useful commands which might not fit into any
standard radare2 commands. You can get a list of these commands with :? .
(Remember, : accesses the underlying IO plugin’s system()).
[ 0 x 7 f f 6 5 9 d 9 f c c 0 ]> : ?
Usage : : cmd a r g s
: pid − show t a r g e t e d pid
: pkt s − send packet ' s '
: monitor cmd − hex−encode monitor command and pass to t a r g e t
interpreter
: rd − show r e v e r s e debugging a v a i l a b i l i t y
: dsb − s t e p backwards
: dcb − continue backwards
: detach [ pid ] − detach from remote/ detach s p e c i f i c pid
: inv . reg − i n v a l i d a t e reg cache
: pktsz − get max packet s i z e used
: pktsz bytes − s e t max . packet s i z e as ' bytes ' bytes
: e x e c _ f i l e [ pid ] − get f i l e which was executed f o r
c u r r e n t / s p e c i f i e d pid
Note that :dsb and :dcb are only available in special gdbserver implementations
such as Mozilla’s rr, the default gdbserver doesn’t include remote reverse
debugging support.
Use :rd to print the currently available reverse debugging capabilities.
If you are interested in debugging radare2’s interaction with gdbserver you
can use :monitor set remote−debug 1 to turn on logging of gdb’s remote protocol
packets in gdbserver’s console and :monitor set debug 1 to show general debug
messages from gdbserver in it’s console. You can also increase log level using
e log. level=5 and monitor GDB client/server messages on radare2’s side.
303
| Usage : =[g ] [ . . . ] # gdb s e r v e r
| gdbserver :
| =g port f i l e [ a r g s ] l i s t e n on ' port ' debugging ' f i l e ' using
gdbserver
And then connect to it like you would to any gdbserver. For example, with
radare2:
$ r2 −d gdb : / / l o c a l h o s t :8000
Setting Up KD on Windows
For a complete walkthrough, refer to Microsoft’s documentation.
Serial Port Enable KD over a serial port on Windows Vista and higher
like this:
bcdedit /debug on
bcdedit / d b g s e t t i n g s s e r i a l debugport : 1 baudrate :115200
In case of VMWare
304
V i r t u a l Machine S e t t i n g s −> Add −> S e r i a l Port
Device Status :
[ v ] Connect at power on
Connection :
[ v ] Use s o c k e t (named pipe )
[_/tmp/winkd .pipe________]
From : Server To : V i r t u a l Machine
[ v ] Enable S e r i a l Port
Port Number : [_COM1_______[ v ] ]
Port Mode : [ _Host_Pipe__ [ v ] ]
[ v ] Create Pipe
Port/ F i l e Path : [_/tmp/winkd . pipe____ ]
Starting from Windows 8 there is no way to enforce debugging for every boot,
but it is possible to always show the advanced boot options, which allows to
enable kernel debugging:
b c e d i t / s e t { g l o b a l s e t t i n g s } advancedoptions t r u e
Connecting to KD interface on r2
Serial Port Radare2 will use the winkd io plugin to connect to a socket file
created by virtualbox or qemu. Also, the winkd debugger plugin and we should
specify the x86-32 too. (32 and 64 bit debugging is supported)
$ r2 −a x86 −b 32 −D winkd winkd : / / /tmp/winkd . pipe
305
$ r2 −a x86 −b 32 −d winkd://< hostip >:<port >:w. x . y . z
In order to skip that trap we will need to change eip and run ‘dc’ twice:
dr e i p=e i p+1
dc
dr e i p=e i p+1
dc
Now the Windows VM will be interactive again. We will need to kill r2 and
attach again to get back to control the kernel.
In addition, the dp command can be used to list all processes, and dpa or dp=
to attach to the process. This will display the base address of the process in
the physical memory layout.
306
Using the plugin To use the windbg plugin, pass the same command-line
options as you would for WinDBG or kd (see Microsoft’s documentation), quot-
ing/escaping when necessary:
> r2 −d ”windbg://−remote tcp : s e r v e r=Server , port=Socket ”
You can then debug normally (see d? command) or interact with the backend
shell directly with the =! command:
[ 0 x 7 f f c a c 9 f c e a 0 ]> dcu 0 x 0 0 0 7 f f c 9 8 f 4 2 1 9 0
Continue u n t i l 0 x 7 f f c 9 8 f 4 2 1 9 0 using 1 b p s i z e
ModLoad : 00007 f f c `ab6b0000 00007 f f c `ab6e0000
C: \WINDOWS\System32\IMM32.DLL
Breakpoint 1 h i t
h i t breakpoint at : 0 x 7 f f c 9 8 f 4 2 1 9 0
[ 0 x 7 f f f c f 2 3 2 1 9 0 ]> =!k4
Child−SP RetAddr Call Site
00000033 `73 b1f618 00007 f f 6 `c67a861d r_main ! r_main_radare2
00000033 `73 b1f620 00007 f f 6 `c67d0019 radare2 ! main+0x8d
00000033 `73 b1f720 00007 f f 6 ` c 6 7 c f e b e radare2 ! invoke_main+0x39
00000033 `73 b1f770 00007 f f 6 ` c67cfd7e
radare2 ! __scrt_common_main_seh+0x12e
Plugins
radare2 is implemented on top of a bunch of libraries, almost every of those li-
braries support plugins to extend the capabilities of the library or add support
for different targets.
This section aims to explain what are the plugins, how to write them and use
them
307
Skeletons
See r2skel
$ l s l i b r /∗/p | grep : | awk −F / '{ p r i n t $2 } '
anal # analysis plugins
asm # assembler / d i s a s s e m b l e r p l u g i n s
bin # binary format p a r s i n g p l u g i n s
bp # breakpoint p l u g i n s
core # c o r e p l u g i n s ( implement new commands)
crypto # encrypt / decrypt /hash / . . .
debug # debugger backends
egg # s h e l l c o d e encoders , e t c
fs # f i l e s y s t e m s and p a r t i t i o n t a b l e s
io # io plugins
lang # embedded s c r i p t i n g languages
parse # disassembler parsing plugins
reg # arch r e g i s t e r l o g i c
Listing plugins
Some r2 tools have the −L flag to list all the plugins associated to the func-
tionality.
rasm2 −L # list asm p l u g i n s
r2 −L # list io plugins
rabin2 −L # list bin p l u g i n s
rahash2 −L # list hash/ crypto / encoding p l u g i n s
There are more plugins in r2land, we can list them from inside r2, and this is
done by using the L suffix.
Those are some of the commands:
L # l i s t core plugins
iL # l i s t bin p l u g i n s
dL # l i s t debug p l u g i n s
mL # l i s t f s plugins
ph # p r i n t support hash al g or i th m s
You can use the ? as value to get the possible values in the associated eval
vars.
e asm . arch=? # l i s t assembler / d i s a s s e m b l e r p l u g i n s
e anal . arch=? # l i s t analysis plugins
Notes
Note there are some inconsistencies that most likely will be fixed in the future
radare2 versions.
308
IO plugins
All access to files, network, debugger and all input/output in general is
wrapped by an IO abstraction layer that allows radare to treat all data as
if it were just a file.
IO plugins are the ones used to wrap the open, read, write and ‘system’ on
virtual file systems. You can make radare understand anything as a plain file.
E.g. a socket connection, a remote radare session, a file, a process, a device,
a gdb session.
So, when radare reads a block of bytes, it is the task of an IO plugin to get
these bytes from any place and put them into internal buffer. An IO plugin
is chosen by a file’s URI to be opened. Some examples:
• Debugging URIs
$ r2 dbg : / / / bin / l s
$ r2 pid ://1927
• Remote sessions
$ r2 rap : / / : 1 2 3 4
$ r2 rap ://< host >:1234// bin / l s
• Virtual buffers
$ r2 malloc ://512
shortcut for
$ r2 −
You can get a list of the radare IO plugins by typing radare2 −L:
$ r2 −L
rw_ ar Open ar / l i b f i l e s [ ar | l i b ] : / / [ f i l e // path ] (LGPL3)
rw_ bfdbg BrainFuck Debugger ( bfdbg : / / path/ to / f i l e ) (LGPL3)
rwd bochs Attach to a BOCHS debugger (LGPL3)
r_d debug Native debugger ( dbg : / / / bin / l s dbg ://1388 p i d o f : / /
w a i t f o r : / / ) (LGPL3) v0 . 2 . 0 pancake
rw_ d e f a u l t open l o c a l f i l e s using def_mmap: / / (LGPL3)
rwd gdb Attach to gdbserver , 'qemu −s ' , gdb : / / l o c a l h o s t :1234
(LGPL3)
rw_ gprobe open gprobe connection using gprobe : / / (LGPL3)
rw_ gzip read / w r i t e gzipped f i l e s (LGPL3)
rw_ http http get ( http : / / rada . r e /) (LGPL3)
rw_ ihex I n t e l HEX f i l e ( ihex : / / eeproms . hex ) (LGPL)
r__ mach mach debug i o ( unsupported i n t h i s platform ) (LGPL)
rw_ malloc memory a l l o c a t i o n ( malloc ://1024 hex : / / cd8090 ) (LGPL3)
rw_ mmap open f i l e using mmap: / / (LGPL3)
rw_ null n u l l−p l u g i n ( n u l l : / / 2 3 ) (LGPL3)
rw_ procpid / proc / pid /mem i o (LGPL3)
rwd ptrace p t r a c e and / proc / pid /mem ( i f a v a i l a b l e ) i o (LGPL3)
309
rwd qnx Attach to QNX pdebug i n s t a n c e , qnx : / / host :1234 (LGPL3)
rw_ r2k k e r n e l a c c e s s API i o ( r2k : / / ) (LGPL3)
rw_ r2pipe r 2 p i p e i o p l u g i n (MIT)
rw_ r2web r2web i o c l i e n t ( r2web : / / cloud . rada . r e /cmd/) (LGPL3)
rw_ rap radare network p r o t o c o l ( rap : / / : port
rap : / / host : port / f i l e ) (LGPL3)
rw_ rbuf RBuffer IO p l u g i n : rbuf : / / (LGPL)
rw_ self read memory from myself using ' s e l f : / / ' (LGPL3)
rw_ shm shared memory r e s o u r c e s (shm: / / key ) (LGPL3)
rw_ sparse s p a r s e b u f f e r a l l o c a t i o n ( s p a r s e ://1024 s p a r s e : / / )
(LGPL3)
rw_ tcp load f i l e s v i a TCP ( l i s t e n or connect ) (LGPL3)
rwd windbg Attach to a KD debugger ( windbg : / / s o c k e t ) (LGPL3)
rwd winedbg Wine−dbg i o and debug . i o p l u g i n f o r r2 (MIT)
rw_ zip Open z i p f i l e s [ apk | ipa | z i p | z i p a l l ] : / / [ f i l e // path ]
(BSD)
STATIC_OBJ+=${OBJ_DAP}
TARGET_DAP=io_dap . ${EXT_SO}
ALL_TARGETS+=${TARGET_DAP}
i f e q ( ${WITHPIC} , 0 )
LINKFLAGS+ = . . / . . / u t i l / l i b r _ u t i l . a
LINKFLAGS+ = . . / . . / i o / l i b r _ i o . a
else
LINKFLAGS+=−L . . / . . / u t i l −l r _ u t i l
LINKFLAGS+=−L . . −l r _ i o
endif
${TARGET_DAP} : ${OBJ_DAP}
${CC} $ ( c a l l libname , io_dap ) ${OBJ_DAP} ${CFLAGS} \
${LINKFLAGS} ${LDFLAGS_LIB} $ (LDFLAGS)
#include ”io_dap . h”
310
#define URI_PREFIX ” f o o : / / ”
i f ( ! __plugin_open ( io , pathname , 0) )
return r e t ;
rio_foo = fd−>data ;
// d e s t r o y
return t r u e ;
}
i f ( ! fd | | ! fd−>data )
return −1;
switch ( whence ) {
case SEEK_SET:
io−>o f f = o f f s e t ;
break ;
case SEEK_CUR:
io−>o f f += ( int ) o f f s e t ;
break ;
case SEEK_END:
io−>o f f = UT64_MAX;
break ;
}
return io−>o f f ;
311
}
i f ( ! fd | | ! fd−>data )
return −1;
rio_foo = fd−>data ;
return 0 ;
}
return 0 ;
}
rio_foo = fd−>data ;
return 0 ;
}
RIOPlugin r_io_plugin_dap = {
. name = ”dap” ,
. desc = ”IO Foo p l u g i n ” ,
. l i c e n s e = ”LGPL” ,
. check = __plugin_open ,
. open = __open ,
. c l o s e = __close ,
. seek = __lseek ,
. read = __read ,
. w r i t e = __write ,
312
. g e t p i d = __getpid ,
. system = __system ,
. isdbg = true , // # −−d f l a g
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
. type = R_LIB_TYPE_IO,
. data = &r_io_plugin_dap ,
. v e r s i o n = R2_VERSION
};
#endif
At last but not least, for the Makefile (not for meson), in dist/plugins−cfg/plugins.def.cfg,
add io .dap after io .debug.
2)Write r2 plugin for radare2:
Edit radare2/libr/io/meson.build and in r_io_sources = [... add 'p/io_dap.c',. And
in radare2/libr/meson.build, add 'dap' in io_plugins += [.
3)Insert the plugin in radare2
Edit radare2/dist/plugins−cfg/plugins.def.cfg and add io .dap in the list.
4)Add dap.h
Now, if you need to use some data and structures, edit the file
radare2/libr/io/p/dap.h for:
#ifndef LIBR_IO_P_IO_DAP_H_
#define LIBR_IO_P_IO_DAP_H_
typedef struct {
int x ;
} RIOFoo ;
#endif /∗ LIBR_IO_P_IO_DAP_H_ ∗/
Arch Plugins
TODO: this is outdated after 5.9.0
Radare2 has modular architecture, thus adding support for a new architecture
is very easy, if you are fluent in C. For various reasons it might be easier to
313
implement it out of the tree. For this we will need to create single C file,
called asm_mycpu.c and makefile for it.
The key thing of RAsm plugin is a structure
RAsmPlugin r_asm_plugin_mycpu = {
. name = ”mycpu” ,
. l i c e n s e = ”LGPL3” ,
. desc = ”MYCPU disassembly p l u g i n ” ,
. arch = ”mycpu” ,
. b i t s = 32 ,
. endian = R_SYS_ENDIAN_LITTLE,
. d i s a s s e m b l e = &d i s a s s e m b l e
};
Makefile
NAME=asm_snes
R2_PLUGIN_PATH=$ ( s h e l l r2 −H R2_USER_PLUGINS)
LIBEXT=$ ( s h e l l r2 −H LIBEXT)
CFLAGS=−g −fPIC $ ( s h e l l pkg−c o n f i g −−c f l a g s r_anal )
LDFLAGS=−shared $ ( s h e l l pkg−c o n f i g −−l i b s r_anal )
OBJS=$ (NAME) . o
LIB=$ (NAME) . $ (LIBEXT)
a l l : $ (LIB)
clean :
rm −f $ (LIB) $ (OBJS)
$ (LIB) : $ (OBJS)
$ (CC) $ (CFLAGS) $ (LDFLAGS) $ (OBJS) −o $ (LIB)
install :
cp −f asm_mycpu . $ (SO_EXT) $ (R2_PLUGIN_PATH)
uninstall :
rm −f $ (R2_PLUGIN_PATH) /asm_mycpu . $ (SO_EXT)
asm_mycpu.c
/∗ radare − LGPL − Copyright 2018 − user ∗/
314
static int d i s a s s e m b l e (RAsm ∗a , RAsmOp ∗op , const ut8 ∗buf , int l e n )
{
struct op_cmd cmd = {
. i n s t r = ”” ,
. operands = ””
};
i f ( l e n < 2) return −1;
int r e t = decode_opcode ( buf , len , &cmd) ;
i f ( r e t > 0) {
s n p r i n t f ( op−>buf_asm , R_ASM_BUFSIZE, ”%s %s ” ,
cmd . i n s t r , cmd . operands ) ;
}
return op−>s i z e = r e t ;
}
RAsmPlugin r_asm_plugin_mycpu = {
. name = ”mycpu” ,
. l i c e n s e = ”LGPL3” ,
. desc = ”MYCPU disassembly p l u g i n ” ,
. arch = ”mycpu” ,
. b i t s = 32 ,
. endian = R_SYS_ENDIAN_LITTLE,
. d i s a s s e m b l e = &d i s a s s e m b l e
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
. type = R_LIB_TYPE_ASM,
. data = &r_asm_plugin_mycpu ,
. v e r s i o n = R2_VERSION
};
#endif
Check out how the NIOS II CPU disassembly plugin was implemented by
reading those commits:
315
Implement RAsm plugin: https://github.com/radareorg/radare2/commit/93
3dc0ef6ddfe44c88bbb261165bf8f8b531476b
Implement RAnal plugin: https://github.com/radareorg/radare2/commit/
ad430f0d52fbe933e0830c49ee607e9b0e4ac8f2
Analysis plugins
TODO: outdated section after 5.9.0
After implementing disassembly plugin, you might have noticed that output
is far from being good - no proper highlighting, no reference lines and so
on. This is because radare2 requires every architecture plugin to provide also
analysis information about every opcode. At the moment the implementation
of disassembly and opcodes analysis is separated between two modules - RAsm
and RAnal. Thus we need to write an analysis plugin too. The principle is
very similar - you just need to create a C file and corresponding Makefile.
They structure of RAnal plugin looks like
RAnalPlugin r_anal_plugin_v810 = {
. name = ”mycpu” ,
. desc = ”MYCPU code a n a l y s i s p l u g i n ” ,
. l i c e n s e = ”LGPL3” ,
. arch = ”mycpu” ,
. b i t s = 32 ,
. op = mycpu_op ,
. e s i l = true ,
. set_reg_profile = set_reg_profile ,
};
Like with disassembly plugin there is a key function - mycpu_op which scans
the opcode and builds RAnalOp structure. On the other hand, in this example
analysis plugins also performs uplifting to ESIL, which is enabled in . esil =
true statement. Thus, mycpu_op obliged to fill the corresponding RAnalOp
ESIL field for the opcodes. Second important thing for ESIL uplifting and
emulation - register profile, like in debugger, which is set within set_reg_profile
function.
Makefile
316
NAME=anal_snes
R2_PLUGIN_PATH=$ ( s h e l l r2 −H R2_USER_PLUGINS)
LIBEXT=$ ( s h e l l r2 −H LIBEXT)
CFLAGS=−g −fPIC $ ( s h e l l pkg−c o n f i g −−c f l a g s r_anal )
LDFLAGS=−shared $ ( s h e l l pkg−c o n f i g −−l i b s r_anal )
OBJS=$ (NAME) . o
LIB=$ (NAME) . $ (LIBEXT)
a l l : $ (LIB)
clean :
rm −f $ (LIB) $ (OBJS)
$ (LIB) : $ (OBJS)
$ (CC) $ (CFLAGS) $ (LDFLAGS) $ (OBJS) −o $ (LIB)
install :
cp −f anal_snes . $ (SO_EXT) $ (R2_PLUGIN_PATH)
uninstall :
rm −f $ (R2_PLUGIN_PATH) / anal_snes . $ (SO_EXT)
anal_snes.c:
/∗ radare − LGPL − Copyright 2015 − condret ∗/
static int snes_anop (RAnal ∗ anal , RAnalOp ∗op , ut64 addr , const ut8
∗data , int l e n ) {
memset ( op , ' \0 ' , sizeof (RAnalOp) ) ;
op−>s i z e = snes_op [ data [ 0 ] ] . l e n ;
op−>addr = addr ;
op−>type = R_ANAL_OP_TYPE_UNK;
switch ( data [ 0 ] ) {
case 0xea :
op−>type = R_ANAL_OP_TYPE_NOP;
break ;
}
return op−>s i z e ;
}
317
. f i n i = NULL,
. op = &snes_anop ,
. s e t _ r e g _ p r o f i l e = NULL,
. fi n ge rpri nt _ bb = NULL,
. f i n g e r p r i n t _ f c n = NULL,
. diff_bb = NULL,
. d i f f _ f c n = NULL,
. d i f f _ e v a l = NULL
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
. type = R_LIB_TYPE_ANAL,
. data = &r_anal_plugin_snes ,
. v e r s i o n = R2_VERSION
};
#endif
snes_op_table.h: https://github.com/radareorg/radare2/blob/master/lib
r/asm/arch/snes/snes_op_table.h
Example:
• 6502: https://github.com/radareorg/radare2/commit/64636e9505f9ca
8b408958d3c01ac8e3ce254a9b
• SNES: https://github.com/radareorg/radare2/commit/60d6e5a1b9d2
44c7085b22ae8985d00027624b49
RBin plugins
To enable virtual addressing
In info add et−>has_va = 1; and ptr−>srwx with the R_BIN_SCN_MAP; at-
tribute
318
a l l : $ (LIB)
clean :
rm −f $ (LIB) $ (OBJS)
$ (LIB) : $ (OBJS)
$ (CC) $ (CFLAGS) $ (LDFLAGS) $ (OBJS) −o $ (LIB)
install :
cp −f $ (NAME) . $ (SO_EXT) $ (R2_PLUGIN_PATH)
uninstall :
rm −f $ (R2_PLUGIN_PATH) /$ (NAME) . $ (SO_EXT)
bin_nes.c:
#include <r _ u t i l . h>
#include <r_bin . h>
i f ( ! arch | | ! arch−>buf ) {
free ( ret ) ;
return NULL;
}
re t−>f i l e = strdup ( arch−>f i l e ) ;
re t−>type = strdup ( ”ROM” ) ;
re t−>machine = strdup ( ” Nintendo NES” ) ;
re t−>os = strdup ( ” nes ” ) ;
re t−>arch = strdup ( ” 6502 ” ) ;
re t−>b i t s = 8 ;
return r e t ;
319
}
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
. type = R_LIB_TYPE_BIN,
. data = &r_bin_plugin_nes ,
. v e r s i o n = R2_VERSION
};
#endif
Some Examples
• XBE - https://github.com/radareorg/radare2/pull/972
• COFF - https://github.com/radareorg/radare2/pull/645
• TE - https://github.com/radareorg/radare2/pull/61
• Zimgz - https://github.com/radareorg/radare2/commit/d1351cf836df
3e2e63043a6dc728e880316f00eb
• OMF - https://github.com/radareorg/radare2/commit/44fd8b2555a0
446ea759901a94c06f20566bbc40
Charset Plugins
1. Create a file in radare2/libr/util/d/yourfile.sdb.txt. The extension .sdb.txt
is important.
2. Edit the file radare2/libr/util/charset.c. -add extern SdbGperf gperf_latin_1_ISO_8859_1_
-then add your variable &gperf_latin_1_ISO_8859_1_western_european, in
static const SdbGperf ∗gperfs[]
3. Update the Makefile: radare2/libr/util/Makefile: -Add OBJS+=d/latin_1_ISO_8859_1_
4. Update the Makefile radare2/libr/util/d/Makefile to add your file name with
not .sdb and not .txt in FILES=latin_1_ISO_8859_1_western_european
5. Update the unit tests of radare2/test/db/cmd/charset
Congratulation! You can now type the command:
320
e c f g . c h a r s e t=latin_1_ISO_8859_1_western_european ;
If you have any issue with this tutorial you can check out the example at
https://github.com/radareorg/radare2/pull/19627/files.
R2JS Plugins
The javascript runtime embedded in radare2 provides a way to implement
different types of plugins.
Check out the r2skel project for more examples, but we will cover the basics
now.
( function () {
r2 . unload (” c o r e ” , ”mycore ”) ;
r2 . p l u g i n (” c o r e ” , f u n c t i o n ( ) {
c o n s o l e . l o g(”==> The ' mycore ' p l u g i n has been i n s t a n t i a t e d . Type
' mycore ' to t e s t i t ”) ;
f u n c t i o n c o r e C a l l (cmd) {
i f (cmd . startsWith (” mycore ”) ) {
c o n s o l e . l o g (” H e l l o From My Core ! ” ) ;
return true ;
}
return f a l s e ;
}
return {
”name ” : ”mycore ” ,
” l i c e n s e ” : ”MIT” ,
” desc ” : ” simple c o r e p l u g i n i n t y p e s c r i p t f o r radare2 ” ,
” c a l l ” : coreCall ,
};
}) ;
}) ( ) ;
321
Plugins in Python
At first, to be able to write a plugins in Python for radare2 you need to install
r2lang plugin: r2pm −i lang−python. Note - in the following examples there are
missing functions of the actual decoding for the sake of readability!
For this you need to do this:
1. import r2lang and from r2lang import R (for constants)
2. Make a function with 2 subfunctions - assemble and disassemble and re-
turning plugin structure - for RAsm plugin
def mycpu( a ) :
def assemble ( s ) :
return [ 1 , 2 , 3 , 4 ]
322
” gpr sp . 3 2 24 0\n” + \
” gpr pc . 3 2 28 0\n”
return p r o f i l e
def op (memview , pc ) :
analop = {
” type ” : R.R_ANAL_OP_TYPE_NULL,
” cycles ” : 0 ,
” stackop ” : 0 ,
” stackptr ” : 0 ,
” ptr ” : −1,
”jump” : −1,
” addr ” : 0 ,
” eob ” : False ,
” e s i l ” : ”” ,
}
try :
opcode = get_opcode (memview) #
h t t p s :// docs . python . org /3/ l i b r a r y / s t d t y p e s . html#memoryview
e s i l s t r = optbl [ opcode ] [ 2 ]
i f optbl [ opcode ] [ 0 ] == ”J” : # i t ' s jump
analop [ ” type ” ] = R.R_ANAL_OP_TYPE_JMP
analop [ ”jump” ] = decode_jump ( opcode , j_mask )
e s i l s t r = jump_esil ( e s i l s t r , opcode , j_mask )
except :
r e s u l t = analop
# Don ' t f o r g e t to return proper i n s t r u c t i o n s i z e !
return [ 4 , r e s u l t ]
323
i f query == R.R_ANAL_ARCHINFO_MAX_OP_SIZE:
return 8
i f query == R.R_ANAL_ARCHINFO_INV_OP_SIZE: # invalid
op s i z e
return 2
return 0
def analop (memview , pc ) :
[...]
return {
”name” : ”mycpu” ,
” arch ” : ”mycpu” ,
” b i t s ” : 32 ,
” l i c e n s e ” : ”GPL” ,
” desc ” : ”MYCPU anal ” ,
”esil” : 1,
” set_reg_profile ” : set_reg_profile ,
” archinfo ” : archinfo ,
”op” : op ,
}
You can combine everything in one file and load it using −i option:
$ r2 −I mycpu . py some_file . bin
324
• load_bytes
• destroy
• check_bytes
• baddr
• entries
• sections
• imports
• relocs
• binsym
• info
and so on. Please be sure of the parameters for each function and format
of returns. Note, that functions entries , sections, imports, relocs returns a
list of special formed dictionaries - each with a different type. Other
functions return just a list of numerical values, even if single element
one. There is a special function, which returns information about the
file - info:
def i n f o ( b i n f ) :
return [ {
” type ” : ” l e ” ,
” bclass ” : ” le ” ,
” rclass ” : ” le ” ,
” os ” : ”OS/2” ,
” subsystem ” : ”CLI” ,
”machine” : ”IBM” ,
” arch ” : ”x86” ,
”has_va” : 0 ,
” b i t s ” : 32 ,
” big_endian ” : 0 ,
” dbg_info ” : 0 ,
}]
325
3. This structure should contain a pointers to the most important functions
like check_bytes, load and load_bytes, entries , relocs, imports.
return {
”name” : ” l e ” ,
” desc ” : ”OS/2 LE/LX format ” ,
” l i c e n s e ” : ”GPL” ,
” load ” : load ,
” load_bytes ” : load_bytes ,
” d e st r o y ” : destroy ,
” check_bytes ” : check_bytes ,
”baddr” : baddr ,
” entries ” : entries ,
” sections ” : sections ,
” imports ” : imports ,
” symbols ” : symbols ,
” relocs ” : relocs ,
”binsym” : binsym ,
” info ” : info ,
}
Debugger plugins
• Adding the debugger registers profile into the shlr/gdb/src/core.c
• Adding the registers profile and architecture support in the libr/de-
bug/p/debug_native.c and libr/debug/p/debug_gdb.c
• Add the code to apply the profiles into the function r_debug_gdb_attach(RDebug
∗dbg, int pid)
If you want to add support for the gdb, you can see the register profile in the
active gdb session using command maint print registers.
More to come
• Related article: https://radare.today/posts/extending-r2-with-new-
plugins/
Some commits related to “Implementing a new architecture”
• Extensa: https://github.com/radareorg/radare2/commit/6f1655c491
60fe9a287020537afe0fb8049085d7
• Malbolge: https://github.com/radareorg/radare2/pull/579
• 6502: https://github.com/radareorg/radare2/pull/656
• h8300: https://github.com/radareorg/radare2/pull/664
326
• GBA: https://github.com/radareorg/radare2/pull/702
• CR16: https://github.com/radareorg/radare2/pull/721/ && 726
• XCore: https://github.com/radareorg/radare2/commit/bb16d1737ca5
a471142f16ccfa7d444d2713a54d
• SharpLH5801: https://github.com/neuschaefer/radare2/commit/f499
3cca634161ce6f82a64596fce45fe6b818e7
• MSP430: https://github.com/radareorg/radare2/pull/1426
• HP-PA-RISC: https://github.com/radareorg/radare2/commit/f8384f
eb6ba019b91229adb8fd6e0314b0656f7b
• V810: https://github.com/radareorg/radare2/pull/2899
• TMS320: https://github.com/radareorg/radare2/pull/596
Troubleshooting
It is common to have an issues when you write a plugin, especially if you do
this for the first time.
This is why debugging them is very important. The first step for debugging
is to set an environment variable when running radare2 instance:
$ R2_DEBUG=yes r2 / bin / l s
Loading / usr / l o c a l / l i b / radare2 /2.2.0 − g i t // bin_xtr_dyldcache . so
Cannot f i n d symbol ' radare_plugin ' i n l i b r a r y
'/ usr / l o c a l / l i b / radare2 /2.2.0 − g i t // bin_xtr_dyldcache . so '
Cannot open / usr / l o c a l / l i b / radare2 /2.2.0 − g i t //2.2.0 − g i t
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /asm_mips_ks . so
PLUGIN OK 0x55b205ea6070 f c n 0 x7f298de08762
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /asm_sparc_ks . so
PLUGIN OK 0x55b205ea6070 f c n 0 x7f298de08762
Cannot open /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /pimp
Cannot open /home/ u s e r / . c o n f i g / radare2 / p l u g i n s / yara
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /asm_arm_ks . so
PLUGIN OK 0x55b205ea6070 f c n 0 x7f298de08762
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s / core_yara . so
Module v e r s i o n mismatch
/home/ u s e r / . c o n f i g / radare2 / p l u g i n s / core_yara . so ( 2 . 1 . 0 ) vs
(2.2.0 − g i t )
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /asm_ppc_ks . so
PLUGIN OK 0x55b205ea6070 f c n 0 x7f298de08762
Loading /home/ u s e r / . c o n f i g / radare2 / p l u g i n s /lang_python3 . so
PLUGIN OK 0x55b205ea5ed0 f c n 0 x7f298de08692
Loading / usr / l o c a l / l i b / radare2 /2.2.0 − g i t /bin_xtr_dyldcache . so
Cannot f i n d symbol ' radare_plugin ' i n l i b r a r y
'/ usr / l o c a l / l i b / radare2 /2.2.0 − g i t / bin_xtr_dyldcache . so '
Cannot open / usr / l o c a l / l i b / radare2 /2.2.0 − g i t /2.2.0 − g i t
Cannot open d i r e c t o r y '/ usr / l o c a l / l i b / radare2−e x t r a s /2.2.0 − g i t '
Cannot open d i r e c t o r y '/ usr / l o c a l / l i b / radare2−bi n d in g s /2.2.0 − g i t '
USER CONFIG loaded from /home/ u s e r / . c o n f i g / radare2 / r a d a r e 2 r c
−− In v i s u a l mode p r e s s ' c ' to t o g g l e the c u r s o r mode . Use tab to
navigate
327
[ 0 x00005520]>
Let’s open an empty file using the ‘mycpu’ arch and write some random code
there.
$ r2 −
−− I endians swap
[ 0 x00000000]> e asm . arch=mycpu
[ 0 x00000000]> woR
[ 0 x00000000]> pd 10
0x00000000 888 e mov r8 , 14
0x00000002 b2a5 i f n o t r10 , r5
0x00000004 3 f67 ret
0x00000006 7ef6 b l r15 , r6
0x00000008 2701 xor r0 , 1
0x0000000a 9826 mov r2 , 6
0x0000000c 478d xor r8 , 13
0x0000000e 6b6b s t o r e r6 , 11
0x00000010 1382 add r8 , r2
0x00000012 7 f15 ret
R2PM_INSTALL( ) {
${MAKE} c l e a n
${MAKE} a l l | | exit 1
328
${MAKE} i n s t a l l R2PM_PLUGDIR=”${R2PM_PLUGDIR}”
}
R2PM_UNINSTALL( ) {
rm −f ”${R2PM_PLUGDIR}/asm_mycpu . ”∗
rm −f ”${R2PM_PLUGDIR}/anal_mycpu . ”∗
}
R2PM_END
Add your package in the /db directory of radare2-pm repository and send a
pull request when it’s ready to be shared.
$ r2pm −H R2PM_DBDIR
/ Users /pancake / . l o c a l / share / radare2 /r2pm/ g i t / radare2−pm/db
$
r2frida
r2frida is a plugin that merges the capabilities of radare2 and Frida, allowing
you to inspect and manipulate running processes. It is useful for dynamic
analysis and debugging, leveraging radare2’s reverse engineering tools and
Frida’s dynamic instrumentation.
With r2frida you can use short mnemonic r2 commands instead of having to
type long javascript oneliners in the prompt, also those commands are exe-
cuted inside the target process and are well integrated with radare2, allowing
to import all the analysis information from dynamic instrumentation into your
static analysis environment.
Some of the most relevant features include:
• Running Frida scripts with :. command
• Executing snippets in C, JavaScript, or TypeScript
• Attaching, spawning, or launching processes locally or remotely
• Listing sections, symbols, classes, methods
• Searching memory, creating hooks, and manipulating file descriptors
• Supporting Dalvik, Java, ObjC, Swift, and C interfaces
Installation
Install r2frida via radare2 package manager:
$ r2pm −c i r 2 f r i d a
Now you should be able to test if the system session works by running the
following command:
329
$ r2 f r i d a : / / 0
If this is not working try with the R2_DEBUG=1 environment variable set and
see if there’s any relevant error. Maybe the plugin is not loaded or it was not
compiled for the specific version of radare2 that you are using.
The URI handler of r2frida can be quite complex as it allows you to specify dif-
ferent ways to start a process, attaching as well as the communication channel,
permitting it to connect though usb, tcp or working with local programs.
First Steps
If there’s nothing after the peekaboo (://) you will get introduced into the vi-
sual uri maker which let’s you select the target device, communication channel,
and application/process to attach or spawn to start tracing from it.
$ r2 f r i d a : / /
You can invoke the help menu via the following command:
$ r2 ' f r i d a : / / ? '
r2 f r i d a : / / [ a c t i o n ] / [ l i n k ] / [ d e v i c e ] / [ t a r g e t ]
∗ a c t i o n = l i s t | apps | attach | spawn | launch
∗ link = l o c a l | usb | remote host : port
∗ d e v i c e = ' ' | host : port | device−i d
∗ t a r g e t = pid | appname | process−name | program−in−path | abspath
Local :
∗ frida :// # v i s u a l mode to s e l e c t
a c t i o n+d e v i c e+program
∗ f ri d a ://? # show t h i s help
∗ f r i d a ://0 # attach to f r i d a −h e l p e r ( no
spawn needed )
∗ f r i d a : / / / usr / l o c a l / bin / rax2 # abspath to spawn
∗ f r i d a : / / rax2 # same as above , c o n s i d e r i n g
l o c a l / bin i s i n PATH
∗ f r i d a : / / spawn/$ ( program ) # spawn a new p r o c e s s i n the
c u r r e n t system
∗ f r i d a : / / attach /( t a r g e t ) # attach to t a r g e t PID i n c u r r e n t
host
USB:
∗ f r i d a : / / l i s t /usb// # l i s t p r o c e s s e s i n the f i r s t usb
device
∗ f r i d a : / / apps/usb// # l i s t apps i n the f i r s t usb
device
∗ f r i d a : / / attach /usb //12345 # attach to given pid i n the
f i r s t usb d e v i c e
∗ f r i d a : / / spawn/usb//appname # spawn an app i n the f i r s t
r e s o l v e d usb d e v i c e
∗ f r i d a : / / launch /usb//appname # spawn+resume an app i n the
f i r s t usb d e v i c e
Remote :
330
∗ f r i d a : / / attach /remote / 1 0 . 0 . 0 . 3 : 9 9 9 9 / 5 5 8 # attach to pid 558 on tcp
remote f r i d a −s e r v e r
Environment : ( Use the `%` command to change the environment at
runtime )
R2FRIDA_SCRIPTS_DIR=/usr / l o c a l / share / r 2 f r i d a / s c r i p t s
R2FRIDA_SCRIPTS_DIR=~/. l o c a l / share / radare2 / r 2 f r i d a / s c r i p t s
R2FRIDA_SAFE_IO=0|1 # Workaround a Frida bug on
Android/thumb
R2FRIDA_DEBUG=0|1 # Used to t r a c e i n t e r n a l r 2 f r i d a
C and JS c a l l s
R2FRIDA_RUNTIME=q j s | v8 # S e l e c t the j a v a s c r i p t engine to
use i n the agent s i d e ( v8 i s d e f a u l t )
R2FRIDA_DEBUG_URI=0|1 # Trace u r i p a r s i n g code and e x i t
b e f o r e doing any a c t i o n
R2FRIDA_COMPILER_DISABLE=0|1 # Disable the new f r i d a
t y p e s c r i p t compiler ( ` : . f o o . ts `)
R2FRIDA_AGENT_SCRIPT=[ f i l e ] # path to f i l e o f the r 2 f r i d a
agent
Process Info
Basic information about the app and environemnt
The : i commands are useful to check some basic information about the run-
time:
[ 0 x100610000]> : i
arch arm
bits 64
os darwin
pid 19347
uid 0
objc false
runtime QJS
swift false
java false
mainLoop false
pageSize 16384
pointerSize 8
modulename arm_hello_ios
modulebase 0x10060c000
codeSigningPolicy optional
isDebuggerAttached false
cwd / p r i v a t e / var / r o o t
[ 0 x100610000]>
Enumerating symbols
Here we can use : is to enumerate the symbols present in the process.
331
[ 0 x100610000]> : i s
0x10060c000 s _mh_execute_header
0x100610000 s main
0x0 u p r i n t f
0x0 u s l e e p
332
And we can get the full ranges using :dmm:
[ 0 x1021d8058]> :dmm
0x00000001021d4000 − 0 x00000001021e4000 r−x
/ p r i v a t e / var / r o o t / arm_hello_ios
0 x00000001021e4000 − 0x0000000102328000 rwx
/ usr / l i b / l i b s u b s t r a t e . d y l i b
0x0000000102328000 − 0x0000000102360000 rwx
/ usr / l i b / l i b s u b s t i t u t e . d y l i b
0x0000000102360000 − 0 x00000001024c0000 rwx / usr / l i b / dyld
0x0000000102520000 − 0x0000000102ed0000 rwx
/ usr / l i b / s u b s t i t u t e −l o a d e r . d y l i b
0x0000000107d00000 − 0 x000000018ae40000 rwx
/System/ Library /Caches/com . apple . dyld /dyld_shared_cache_arm64
Objective-C
iOS and macOS apps are usually made or containing some objc metadata that
is important for us to locate the methods of interest
Classes
We can list the ObjC classes in memory using the : icl command:
[ 0 x00000000]> : i c l
Obfuscator
Challenge3
Challenge2
Challenge1
AppDelegate
Crackmes
Reverse engineering is a crucial skill in today’s digital landscape, and one of
the best ways to hone this skill is by participating in crackme challenges. A
crackme (short for “crack me” challenge) is a piece of software or firmware
that has been intentionally obfuscated or encrypted, making it difficult to
reverse engineer without the correct key or password.
In this chapter, we will explore how to use radare2 to defeat various crackmes
and uncover their secrets. We will cover tutorials on how to analyze and
disassemble different types of crackmes, including those that use encryption,
compression, and other forms of obfuscation.
By following along with these tutorials, you will gain a deeper understanding
of the reverse engineering process and develop the skills needed to tackle even
the most challenging crackmes. Whether you’re a beginner or an experienced
333
reverser, this chapter is designed to provide you with the tools and knowledge
necessary to take on any crackme that comes your way.
So let’s get started!
IOLI CrackMes
The Ioli Crackmes are a series of reverse engineering exercises designed by
Pau Oliva Fora for users of Radare1, this revision is up to date with the latest
version of Radare2.
These exercises are intended to help you learn and practice reverse engineering
techniques using Radare2. Each crackme is a self-contained challenge that
requires you to analyze and understand executable files, gradually building
your skills as you progress.
Each crackme in the series is slightly more difficult than the previous one,
introducing new concepts and commands at a manageable pace. This incre-
mental difficulty helps ease the learning process, ensuring that you gain a
solid understanding of basic techniques before moving on to more complex
tasks. As you advance, you will become more proficient in using Radare2 and
develop a deeper understanding of reverse engineering principles.
Every crackme is presented in three sections:
• An introduction that explains the challenge to be solved,
• Hints that provide guidance on useful commands and steps to follow
• Solution section that offers a step-by-step guide to solving the challenge.
This structured approach ensures that you not only learn how to solve each
specific crackme but also understand the underlying concepts and methodolo-
gies, allowing you to apply these skills to other reverse engineering tasks in
the future.
Contents based on the dustri tutorials.
The binaries are available at mirror
IOLI 0x00
This first challenge is designed to introduce you to the basics of reverse engi-
neering with Radare2. The objective is to find the correct password to unlock
the program.
By executing the program you may see something like this:
$ . / crackme0x00
IOLI Crackme Level 0x00
334
Password : 1234
I n v a l i d Password !
Hints For this initial challenge, you won’t need to dive into complex dis-
assembly. Instead, focus on searching for plaintext strings within the binary
file.
There are multiple ways to find the strings embedded inside a binary, which
are equivalents to the GNU strings utility.
• Check the manpage and help message of rabin2
– Use man rabin2 and rabin2 −h in your terminal
• Load the binary with radare2
– Append the question mark to the i and iz commands to find rele-
vant
– Understand the difference between iz , izz and izzz
• Read the output of those commands and make a blind guess
Solution As explained in the hints, the first thing to check is if the pass-
word is just plaintext inside the file. In this case, we don’t need to do any
disassembly, and we can just use rabin2 with the -z flag to search for strings
in the binary.
$ rabin2 −z . / crackme0x00
[ Strings ]
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 0x00000568 0x08048568 24 25 . rodata a s c i i IOLI Crackme Level
0x00\n
1 0x00000581 0x08048581 10 11 . rodata a s c i i Password :
2 0 x0000058f 0 x0804858f 6 7 . rodata a s c i i 250382
3 0x00000596 0x08048596 18 19 . rodata a s c i i I n v a l i d Password ! \ n
4 0x000005a9 0x080485a9 15 16 . rodata a s c i i Password OK : ) \n
335
3 0x00000596 0x08048596 18 19 . rodata a s c i i I n v a l i d Password ! \ n
What about this string? It hasn’t appeared when running the application yet.
2 0 x0000058f 0 x0804858f 6 7 . rodata a s c i i 250382
Now we know that 250382 is the correct password, completing this crackme!
IOLI 0x01
This second challenge is designed to introduce you to more advanced reverse
engineering techniques using Radare2. The objective is to find the correct
password to unlock the program by examining the binary’s disassembly.
$ . / crackme0x01
IOLI Crackme Level 0x01
Password : t e s t
I n v a l i d Password !
Hints To solve this challenge, this time you will need to go beyond searching
for plaintext strings.
Learn how to load the binary with radare2, analise the code and disassemble
the main function.
• Load the binary with radare2 and use the −A or −AA flags to analyze
the program before showing the prompt.
These flags will run aa or aaa. The more a’s you append the deeper the analysis
will be, so it will perform more actions, which in some cases it’s useful, but
in other can result on invalid results, learn about the differences and find the
right balance for each target you face. For our needs aa should be probably
enough.
$ r2 −A crackme0x01
336
To disassemble the main function you can use the pdf command. You can
learn about other disassembly commands by typing pd?.
In the disassembled code, look for cmp (compare) instructions. These are
often used to compare user input against hardcoded values. Identifying these
values can help you find the correct password.
You can practice a little the | (pipe operator) or the ~ (internal grep) special
characters to grep directly the instructions you need:
> s main
> pdf~cmp
Now it’s probably a good time to make another blind guess trying the value
by running the crackme and typing the number.
Solution Let’s go step by step to solve the second IOLI crackme. We can
start by trying what we learned in the previous challenge by listing the strings
with rabin2:
$ rabin2 −z . / crackme0x01
[ Strings ]
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 0x00000528 0x08048528 24 25 . rodata a s c i i IOLI Crackme Level
0x01\n
1 0x00000541 0x08048541 10 11 . rodata a s c i i Password :
2 0 x0000054f 0 x0804854f 18 19 . rodata a s c i i I n v a l i d Password ! \ n
3 0x00000562 0x08048562 15 16 . rodata a s c i i Password OK : ) \n
This isn’t going to be as easy as 0x00. Let’s try disassembly with r2.
$ r2 . / crackme0x01
[ 0 x08048330]> aa
INFO: Analyze a l l f l a g s s t a r t i n g with sym . and entry0 ( aa )
INFO: Analyze imports (af@@@i)
INFO: Analyze e n t r y p o i n t ( af@ entry0 )
INFO: Analyze symbols (af@@@s)
INFO: Recovering v a r i a b l e s (afva@@@F)
INFO: Analyze a l l f u n c t i o n s arguments/ l o c a l s (afva@@@F)
[ 0 x08048330]> −e asm . bytes=f a l s e # dont show the bytes
[ 0 x08048330]> pdf@main
; DATA XREF from entry0 @ 0x8048347
/ 1 1 3 : i n t main ( i n t argc , char ∗∗ argv , char ∗∗envp ) ;
337
| ; var int32_t var_4h @ ebp−0x4
| ; var int32_t var_sp_4h @ esp+0x4
| 0x080483e4 push ebp
| 0x080483e5 mov ebp , esp
| 0x080483e7 sub esp , 0x18
| 0x080483ea and esp , 0 x f f f f f f f 0
| 0x080483ed mov eax , 0
| 0 x080483f2 add eax , 0 x f
| 0 x080483f5 add eax , 0 x f
| 0 x080483f8 shr eax , 4
| 0 x080483fb s h l eax , 4
| 0 x080483fe sub esp , eax
| 0x08048400 mov dword [ esp ] , s t r . IOLI_Crackme_Level_0x01
| 0x08048407 c a l l sym . imp . p r i n t f
| 0x0804840c mov dword [ esp ] , s t r . Password :
| 0x08048413 c a l l sym . imp . p r i n t f
| 0x08048418 l e a eax , [ var_4h ]
| 0x0804841b mov dword [ var_sp_4h ] , eax
| 0 x0804841f mov dword [ esp ] , 0x804854c
| 0x08048426 c a l l sym . imp . s c a n f
| 0x0804842b cmp dword [ var_4h ] , 0x149a
| ,=< 0x08048432 j e 0x8048442
| | 0x08048434 mov dword [ esp ] , s t r . Invalid_Password
| | 0x0804843b c a l l sym . imp . p r i n t f
| ,==< 0x08048440 jmp 0x804844e
| |`−> 0x08048442 mov dword [ esp ] , s t r . Password_OK_ :
| | 0x08048449 c a l l sym . imp . p r i n t f
| `−−> 0x0804844e mov eax , 0
| 0x08048453 leave
\ 0x08048454 ret
The aa command instructs r2 to analyze the whole binary, which gets you
symbol names, among things.
The pdf stands for “Print” “Disassembly” of the “Function”. The @ character
will perform a temporal seek to the given address or symbol name.
This will print the disassembly of the main function, or the main() that every-
one knows. You can see several things as well: weird names, arrows, etc.
• imp. stands for imports. (Functions imported from libraries, like printf
which is in the libc)
• str . stands for strings. (Usually those listed by the iz command)
If you look carefully, you’ll see a cmp instruction, with a constant, 0x149a.
cmp is an x86 compare instruction, and the 0x in front of it specifies it is in
base 16, or hex (hexadecimal).
[ 0 x08048330]> pdf@main~cmp
0x0804842b 817 dfc9a140 . cmp dword [ ebp + 0 x f f f f f f f c ] , 0x149a
You can use radare2’s ? command to display 0x149a in another numeric base.
338
[ 0 x08048330]> ? 0x149a
int32 5274
uint32 5274
hex 0x149a
octal 012232
unit 5 . 2K
segment 0000:049 a
s t r i n g ”\ x9a\x14”
f v a l u e : 5274.0
f l o a t : 0.000000 f
double : 0.000000
binary 0b0001010010011010
trits 0 t21020100
So now we know that 0x149a is 5274 in decimal. Let’s try this as a password.
$ . / crackme0x01
IOLI Crackme Level 0x01
Password : 5274
Password OK : )
Bingo, the password was 5274. In this case, the password function at
0x0804842b was comparing the input against the value, 0x149a in hex. Since
user input is usually decimal, it was a safe bet that the input was intended
to be in decimal, or 5274. Now, since we’re hackers, and curiosity drives us,
let’s see what happens when we input in hex.
$ . / crackme0x01
IOLI Crackme Level 0x01
Password : 0x149a
I n v a l i d Password !
It was worth a shot, but it doesn’t work. That’s because scanf() will take the
0 in 0x149a to be a zero, rather than accepting the input as actually being
the hex value.
And this concludes IOLI 0x01.
IOLI 0x02
This is the third one.
$ . / crackme0x02
IOLI Crackme Level 0x02
Password : h e l l o
I n v a l i d Password !
339
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 0x00000548 0x08048548 24 25 . rodata a s c i i IOLI Crackme Level
0x02\n
1 0x00000561 0x08048561 10 11 . rodata a s c i i Password :
2 0 x0000056f 0 x0804856f 15 16 . rodata a s c i i Password OK : ) \n
3 0 x0000057f 0 x0804857f 18 19 . rodata a s c i i I n v a l i d Password ! \ n
340
| 0 x0804843f 0110 add dword [ eax ] , edx
| 0x08048441 8 b45f8 mov eax , dword [ var_8h ]
| 0x08048444 0faf45f8 imul eax , dword [ var_8h ]
| 0x08048448 8945 f 4 mov dword [ var_ch ] , eax
| 0x0804844b 8 b45fc mov eax , dword [ var_4h ]
| 0x0804844e 3 b45f4 cmp eax , dword [ var_ch ]
| ,=< 0x08048451 750 e j n e 0x8048461
| | 0x08048453 c704246f8504 . mov dword [ esp ] ,
s t r . Password_OK_ : ; [ 0 x804856f :4]=0 x73736150 ; ”Password OK : ) \n”
| | 0x0804845a e8bdfeffff c a l l sym . imp . p r i n t f
; i n t p r i n t f ( const char ∗ format )
| ,==< 0 x0804845f eb0c jmp 0x804846d
| |`−> 0x08048461 c704247f8504 . mov dword [ esp ] ,
s t r . Invalid_Password ; [ 0 x804857f :4]=0 x61766e49 ; ” I n v a l i d
Password ! \ n”
| | 0x08048468 e8affeffff c a l l sym . imp . p r i n t f
; i n t p r i n t f ( const char ∗ format )
| | ; CODE XREF from main @ 0 x804845f
| `−−> 0x0804846d b800000000 mov eax , 0
| 0x08048472 c9 leave
\ 0x08048473 c3 ret
with the experience of solving crackme0x02, we first locate the position of cmp
instruction by using this simple oneliner:
[ 0 x08048330]> pdf@main | grep cmp
| 0x0804844e 3 b45f4 cmp eax , dword [ var_ch ]
341
loc_0x80483e4 :
i n t p r i n t f (” Password : ”)
eax = var_4h
dword [ var_sp_4h ] = eax
dword [ esp ] = 0x804856c / / [ 0 x804856c :4]=0 x50006425 ; const
char ∗ format
i n t s c a n f (”%d ”)
//sym . imp . s c a n f ( )
dword [ var_8h ] = 0x5a // 'Z ' ; 90
dword [ var_ch ] = 0 x1ec //492
edx = dword [ var_ch ]
eax = var_8h //”Z”
dword [ eax ] += edx
eax = dword [ var_8h ]
eax = eax ∗ dword [ var_8h ]
dword [ var_ch ] = eax
eax = dword [ var_4h ]
var = eax − dword [ var_ch ]
i f ( var ) goto 0x8048461 // l i k e l y
{
loc_0x8048461 :
i n t p r i n t f (” I n v a l i d ”)
do
{
loc_0x804846d :
342
//CODE XREF from main @ 0 x804845f
eax = 0
leave //( p s t r 0 x0804857f ) ” I n v a l i d
Password ! \ n” ebp ; s t r . Invalid_Password
return
} while ( ? ) ;
} while ( ? ) ;
}
return ;
The pdc command is unreliable especially in processing loops (while, for, etc.).
So I prefer to use the r2dec plugin in r2 repo to generate the pseudo C code.
you can install it easily:
r2pm i n s t a l l r2dec
343
}
eax = 0 ;
return eax ;
}
it’s exactly the format string of scanf(). But r2dec does not recognize the
second argument (eax) which is a pointer. it points to var_4h and means our
input will store in var_4h.
we can easily write out pseudo code here.
var_ch = ( var_8h + var_ch ) ^ 2 ;
i f ( var_ch == our_input )
p r i n t f ( ”Password OK : ) \n” ) ;
given the initial status that var_8h is 0x5a, var_ch is 0x1ec, we have var_ch
= 338724 (0x52b24):
$ rax2 '=10 ' ' ( 0 x5a+0x1ec ) ∗(0 x5a+0x1ec ) '
338724
$ . / crackme0x02
IOLI Crackme Level 0x02
Password : 338724
Password OK : )
IOLI 0x03
crackme 0x03, let’s skip the string check part and analyze it directly.
[ 0 x08048360]> aaa
[ 0 x08048360]> pdd@sym . main
/∗ r2dec pseudo code output ∗/
/∗ . / crackme0x03 @ 0x8048498 ∗/
#include <s t d i n t . h>
344
eax = 0 ;
eax += 0 x f ;
eax += 0 x f ;
eax >>= 4 ;
eax <<= 4 ;
p r i n t f ( ”IOLI Crackme Level 0x03\n” ) ;
p r i n t f ( ”Password : ” ) ;
eax = &var_4h ;
s c a n f (0 x8048634 , eax ) ;
var_8h = 0x5a ;
var_ch = 0 x1ec ;
edx = 0 x1ec ;
eax = &var_8h ;
∗( eax ) += edx ;
eax = var_8h ;
eax ∗= var_8h ;
var_ch = eax ;
eax = var_4h ;
t e s t ( eax , eax ) ;
eax = 0 ;
return eax ;
}
Here comes thesym.test, called with two parameters. One is var_4h (our input
from scanf()). The other is var_ch. The value of var_ch (as the parameter of
test() ) can be calculated like it did in crackme_0x02. It’s 0x52b24. Try it!
$ . / crackme0x03
IOLI Crackme Level 0x03
Password : 338724
Password OK! ! ! : )
Take a look at sym.test. It’s a two path conditional jump which compares
two parameters and then do shift. We can guess that shift is most likely the
decryption part (shift cipher, e.g. Caesar cipher).
345
/∗ r2dec pseudo code output ∗/
/∗ . / crackme0x03 @ 0x804846e ∗/
#include <s t d i n t . h>
346
| 0x0804845c 89442404 mov [ esp+0x4 ] , eax
| 0x08048460 c70424e8850408 mov dword [ esp ] , 0x80485e8
| 0x08048467 e8e4feffff c a l l dword imp . p r i n t f
| ; imp . p r i n t f ( )
| 0x0804846c c9 leave
\ 0x0804846d c3 ret
; −−−−−−−−−−−−
you can read the assembly code and find the decryption is actually a “sub al,
0x3”. we can write a python script for it:
print ( ' ' . j o i n ( [ chr (ord( i )−0x3 ) for i in ' SdvvzrugRN$$$ ' ] ) )
print ( ' ' . j o i n ( [ chr (ord( i )−0x3 ) for i in ' LqydolgSdvvzrug$ ' ] ) )
the easier way is to run the decryption code, that means debug it or emulate
it. I used radare2 ESIL emulator but it got stuck when executed call dword
imp.strlen. And I can’t find the usage of hooking function / skip instruction in
radare2. The following is an example to show u how to emulate ESIL.
[ 0 x08048414]> s 0x08048445 # the ' sub al , 0x03 '
[ 0 x08048445]> a e i # i n i t VM
[ 0 x08048445]> aeim # i n i t memory
[ 0 x08048445]> a e i p # i n i t ip
[ 0 x08048445]> aer eax=0x41 # s e t eax=0x41 −− 'A'
[ 0 x08048445]> aer # show c u r r e n t value o f r e g s
oeax = 0x00000000
eax = 0x00000041
ebx = 0x00000000
ecx = 0x00000000
edx = 0x00000000
e s i = 0x00000000
e d i = 0x00000000
esp = 0x00178000
ebp = 0x00178000
e i p = 0x08048445
e f l a g s = 0x00000000
[ 0 x08048445]> V # e n t e r Visual mode
# ' p ' or 'P' to change v i s u a l mode
# I p r e f e r the [ xaDvc ] mode
# use ' s ' to s t e p i n and ' S ' to s t e p over
[ 0 x08048442 [ xaDvc ] 0 0% 265 . / crackme0x03]> diq ; ? 0 ; f t . . @
sym . s h i f t +46 # 0x8048442
dead at 0x00000000
− offset − 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x00178000 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00178010 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00178020 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x00178030 0000 0000 0000 0000 0000 0000 0000 0000 ................
oeax 0x00000000 eax 0x00000041 ebx 0x00000000 ecx
0x00000000
edx 0x00000000 e s i 0x00000000 e d i 0x00000000 esp
0x00178000
347
ebp 0x00178000 e i p 0x08048445 e f l a g s 0x00000000
: 0x08048442 0 fb600 movzx eax , byte [ eax ]
: ;−− e i p :
: 0x08048445 2 c03 sub al , 3
: 0x08048447 8802 mov byte [ edx ] , a l
: 0x08048449 8d4584 l e a eax , [ var_7ch ]
: 0x0804844c ff00 i n c dword [ eax ]
:=< 0 x0804844e ebd4 jmp 0x8048424
; CODE XREF from sym . s h i f t @ 0x8048432
0x08048450 8d4588 l e a eax , [ var_78h ]
By the way, u can also open the file and use write data command to decrypt
data.
$ r2 −w . / crackme0x03
[ 0 x08048360]> aaa
[ 0 x08048360]> f s s t r i n g s
[ 0 x08048360]> f
0 x080485ec 18 s t r . Lqydolg_Sdvvzrug
0 x080485fe 18 s t r . Sdvvzrug_RN
0x08048610 25 s t r . IOLI_Crackme_Level_0x03
0x08048629 11 s t r . Password :
[ 0 x08048360]> s s t r . Lqydolg_Sdvvzrug
[ 0 x080485ec]> wos 0x03 @ s t r . Lqydolg_Sdvvzrug ! 0 x11
[ 0 x080485ec]> px
− offset − 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0 x080485ec 496 e 7661 6 c69 6420 5061 7373 776 f 7264 I n v a l i d Password
0 x080485fc 2100 5364 7676 7a72 7567 2352 4 e24 2424 ! . Sdvvzrug#RN$$$
0x0804860c 233d 2 c00 494 f 4 c49 2043 7261 636b 6d65 #=,.IOLI Crackme
0x0804861c 204 c 6576 656 c 2030 7830 330a 0050 6173 Level 0x03 . . Pas
0x0804862c 7377 6 f 7 2 643a 2000 2564 0000 0000 0000 sword : .%d . . . . . .
[ 0 x080485ec]> wos 0x03 @ s t r . Sdvvzrug_RN ! 1 7
[ 0 x080485ec]> px
− offset − 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0 x080485ec 496 e 7661 6 c69 6420 5061 7373 776 f 7264 I n v a l i d Password
0 x080485fc 2100 5061 7373 776 f 7264 204 f 4b21 2121 ! . Password OK! ! !
0x0804860c 203a 2900 494 f 4 c49 2043 7261 636b 6d65 : ) . IOLI Crackme
0x0804861c 204 c 6576 656 c 2030 7830 330a 0050 6173 Level 0x03 . . Pas
0x0804862c 7377 6 f 7 2 643a 2000 2564 0000 0000 0000 sword : .%d . . . . . .
[ 0 x080485ec]>
IOLI 0x04
[ 0 x080483d0]> pdd@main
/∗ r2dec pseudo code output ∗/
/∗ . / crackme0x04 @ 0x8048509 ∗/
#include <s t d i n t . h>
348
eax += 0 x f ;
eax += 0 x f ;
eax >>= 4 ;
eax <<= 4 ;
p r i n t f ( ”IOLI Crackme Level 0x04\n” ) ;
p r i n t f ( ”Password : ” ) ;
eax = &var_78h ;
s c a n f (0 x8048682 , eax ) ;
eax = &var_78h ;
check ( eax ) ;
eax = 0 ;
return eax ;
}
349
manually analyze with both the assembly and pseudo code we can simply
write down the C-like code to describe this function:
#include <s t d i n t . h>
int32_t check ( char ∗ s )
{
var_ch = 0 ;
var_8h = 0 ;
for ( var_ch = 0 ; var_ch < s t r l e n ( s ) ; ++var_ch )
{
var_dh = s [ var_ch ] ;
s s c a n f (&var_dh , %d , &var_4h ) ; // read from
s t r i n g [ var_ch ] , s t o r e to var_4h
var_8h += var_4h ;
i f ( var_8h == 0 x f )
p r i n t f ( ”Password OK\n” ) ;
}
p r i n t f ( ”Password I n c o r r e c t ! \ n” ) ;
return 0 ;
}
In short, it calculates the Digit Sum of a number (add a number digit by digit.
for example, 96 => 9 + 6 = 15) :
$ . / crackme0x04
IOLI Crackme Level 0x04
Password : 12345
Password OK!
$ . / crackme0x04
IOLI Crackme Level 0x04
Password : 96
Password OK!
IOLI 0x05
check again, it uses scanf() to get our input and pass it to check() as parameter.
[ 0 x080483d0]> pdd@main
/∗ r2dec pseudo code output ∗/
/∗ . / crackme0x05 @ 0x8048540 ∗/
#include <s t d i n t . h>
350
eax = &var_78h ;
s c a n f (0 x80486b2 , eax ) ; // 0x80486b2 i s %s
eax = &var_78h ;
check ( eax ) ;
eax = 0 ;
return eax ;
}
351
#include <s t d i n t . h>
int32_t check ( char ∗ s )
{
var_ch = 0 ;
var_8h = 0 ;
for ( var_ch = 0 ; var_ch < s t r l e n ( s ) ; ++var_ch )
{
var_dh = s [ var_ch ] ;
s s c a n f (&var_dh , %d , &var_4h ) ; // read from
s t r i n g [ var_ch ] , s t o r e to var_4h
var_8h += var_4h ;
i f ( var_8h == 0x10 )
parell (s) ;
}
p r i n t f ( ”Password I n c o r r e c t ! \ n” ) ;
return 0 ;
}
uint32_t p a r e l l ( char ∗ s ) {
int32_t var_4h ;
char ∗ format ;
int32_t var_8h ;
eax = &var_4h ;
eax = s ;
s s c a n f ( eax , eax , 0x8048668 ) ;
eax = var_4h ;
eax &= 1 ;
i f ( eax == 0) {
p r i n t f ( ”Password OK! \ n” ) ;
exit (0) ;
}
return eax ;
}
the decompiled code looks well except the sscanf() function. It can be easily
corrected by checking the assembly code.
/ 6 8 : sym . p a r e l l ( int32_t arg_8h ) ;
| ; var int32_t var_4h @ ebp−0x4
| ; arg int32_t arg_8h @ ebp+0x8
| ; var int32_t var_sp_4h @ esp+0x4
| ; var int32_t var_8h @ esp+0x8
| 0x08048484 55 push ebp
352
| 0x08048485 89 e5 mov ebp , esp
| 0x08048487 83 ec18 sub esp , 0x18
| 0x0804848a 8 d45fc l e a eax , [ var_4h ]
| 0x0804848d 89442408 mov dword [ var_8h ] , eax
| 0x08048491 c74424046886 . mov dword [ var_sp_4h ] ,
0x8048668 ; [ 0 x8048668 :4]=0 x50006425 %d
| 0x08048499 8b4508 mov eax , dword [ arg_8h ]
| 0x0804849c 890424 mov dword [ esp ] , eax
| 0 x0804849f e800ffffff c a l l sym . imp . s s c a n f
; i n t s s c a n f ( const char ∗s , const char ∗format , ...)
....
The mov dword [esp], eax is the nearest instruction to sscanf (and it’s equivalent
to a push instruction). It stores the string ‘s’ to the stack top (arg1). mov
dword [var_sp_4h], 0x8048668 push ‘%d’ as arg2 into stack. var_8h (esp + 0x8)
which keeps the address of var_4h is the arg3.
Finally we have the corrected pseudo code:
uint32_t p a r e l l ( char ∗ s ) {
s s c a n f ( s , %d , &var_4h ) ;
i f ( ( var_4h & 1) == 0) {
p r i n t f ( ”Password OK! \ n” ) ;
exit (0) ;
}
return 0 ;
}
$ . / crackme0x05
IOLI Crackme Level 0x05
Password : 12346
Password OK!
we can also use angr to solve it since we have two constraints to the password.
IOLI 0x06
nearly a routine to check this binary (not complete output in the following):
353
$ rabin2 −z . / crackme0x06
[ Strings ]
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 0x00000738 0x08048738 4 5 . rodata a s c i i LOLO
1 0x00000740 0x08048740 13 14 . rodata a s c i i Password OK! \ n
2 0 x0000074e 0x0804874e 20 21 . rodata a s c i i Password
Incorrect !\n
3 0x00000763 0x08048763 24 25 . rodata a s c i i IOLI Crackme Level
0x06\n
4 0 x0000077c 0x0804877c 10 11 . rodata a s c i i Password :
$ rabin2 −I . / crackme0x06
arch x86
baddr 0x8048000
bintype e l f
bits 32
compiler GCC: (GNU) 3 . 4 . 6 ( Gentoo 3.4.6 − r2 , ssp −3.4.6 −1.0 ,
pie −8.7.10)
crypto false
endian little
havecode t r u e
lang c
machine I n t e l 80386
maxopsz 16
minopsz 1
os linux
static false
va true
// main l o g i c
p r i n t f ( ”IOLI Crackme Level 0x06\n” ) ;
p r i n t f ( ”Password : ” ) ;
eax = &var_78h ;
s c a n f (0 x8048787 , eax ) ;
eax = arg_10h ;
eax = &var_78h ;
354
check ( eax , arg_10h ) ;
eax = 0 ;
return eax ;
}
main has 3 arguments argc, argv, envp, and this program is compiled with GCC,
so the stack should be like this :
[ esp + 0x10 ] − envp
[ esp + 0x0c ] − argv
[ esp + 0x08 ] − argc
[ esp + 0x04 ] − r e t u r n address
enter the check() and decompile it. this function is different from 0x05 now.
but they still have similar code structure.
int32_t check ( char ∗ s , int32_t arg_ch ) {
char ∗ var_dh ;
uint32_t var_ch ;
uint32_t var_8h ;
int32_t var_4h ;
char ∗ format ;
int32_t var_sp_8h ;
var_8h = 0 ;
var_ch = 0 ;
do {
eax = s ;
eax = s t r l e n ( eax ) ;
i f ( var_ch >= eax ) {
goto label_0 ;
}
eax = var_ch ;
eax += s ;
eax = ∗( eax ) ;
var_dh = a l ;
eax = &var_4h ;
eax = &var_dh ;
s s c a n f ( eax , eax , 0x804873d ) ;
edx = var_4h ;
eax = &var_8h ;
∗( eax ) += edx ;
i f ( var_8h == 0x10 ) {
eax = arg_ch ;
eax = s ;
p a r e l l ( eax , arg_ch ) ;
}
eax = &var_ch ;
∗( eax )++;
} while ( 1 ) ;
label_0 :
p r i n t f ( ”Password I n c o r r e c t ! \ n” ) ;
return eax ;
}
355
Correct the sscanf part and parell part, both of them were generated incorrectly:
int32_t check ( char ∗ s , void∗ envp )
{
var_ch = 0 ;
var_8h = 0 ;
for ( var_ch = 0 ; var_ch < s t r l e n ( s ) ; ++var_ch )
{
var_dh = s [ var_ch ] ;
s s c a n f (&var_dh , %d , &var_4h ) ; // read from
s t r i n g [ var_ch ] , s t o r e to var_4h
var_8h += var_4h ;
i f ( var_8h == 0x10 )
p a r e l l ( s , envp ) ;
}
p r i n t f ( ”Password I n c o r r e c t ! \ n” ) ;
return 0 ;
}
return 0 ;
}
356
eax = 0 ;
edx = eax ∗ 4 ;
eax = s1 ;
i f ( ∗ ( ( edx + eax ) ) == 0) {
goto label_0 ;
}
eax = var_4h ;
ecx = eax ∗ 4 ;
edx = s1 ;
eax = &var_4h ;
∗( eax )++;
eax = ∗ ( ( ecx + edx ) ) ;
eax = strncmp ( eax , 3 , ”LOLO” ) ;
} while ( eax != 0) ;
var_8h = 1 ;
goto label_1 ;
label_0 :
var_8h = 0 ;
label_1 :
eax = 0 ;
return eax ;
}
357
IOLI 0x07
a weird “wtf?” string.
$ rabin2 −z . / crackme0x07
[ Strings ]
nth paddr vaddr l e n s i z e s e c t i o n type s t r i n g
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 0x000007a8 0x080487a8 4 5 . rodata a s c i i LOLO
1 0x000007ad 0x080487ad 20 21 . rodata a s c i i Password
Incorrect !\n
2 0 x000007c5 0x080487c5 13 14 . rodata a s c i i Password OK! \ n
3 0x000007d3 0x080487d3 5 6 . rodata a s c i i wtf ?\n
4 0x000007d9 0x080487d9 24 25 . rodata a s c i i IOLI Crackme Level
0x07\n
5 0 x000007f2 0 x080487f2 10 11 . rodata a s c i i Password :
due to the symbol info lost, neither aa nor aaa show the name of functions.
we can double check this in “flagspace”. Radare2 use fcn_080485b9 as the
function name. It’s a common case in reverse engineering that we don’t have
any symbol info of the binary.
[ 0 x080487fd]> f s symbols
[ 0 x080487fd]> f
0x08048400 33 entry0
0x0804867d 92 main
0x080487a4 4 obj . _IO_stdin_used
358
| 0x080485b9 55 push ebp
| 0x080485ba 89 e5 mov ebp , esp
| 0x080485bc 83 ec28 sub esp , 0x28
| 0 x080485bf c745f8000000 . mov dword [ var_8h ] , 0
| 0x080485c6 c745f4000000 . mov dword [ var_ch ] , 0
| ; CODE XREF from f c n .080485 b9 @ 0x8048628
| .−> 0x080485cd 8b4508 mov eax , dword [ s ]
| : 0x080485d0 890424 mov dword [ esp ] , eax
; const char ∗ s
| : 0x080485d3 e8d0fdffff c a l l sym . imp . s t r l e n
; s i z e _ t s t r l e n ( const char ∗ s )
| : 0x080485d8 3945 f 4 cmp dword [ var_ch ] , eax
| ,==< 0x080485db 734d j a e 0x804862a
| |: 0x080485dd 8 b45f4 mov eax , dword [ var_ch ]
| |: 0x080485e0 034508 add eax , dword [ s ]
| |: 0x080485e3 0 fb600 movzx eax , byte [ eax ]
| |: 0x080485e6 8845 f 3 mov byte [ var_dh ] , a l
| |: 0x080485e9 8 d45fc l e a eax , [ var_bp_4h ]
| |: 0 x080485ec 89442408 mov dword [ var_sp_8h ] ,
eax ; ...
| |: 0 x080485f0 c7442404c287 . mov dword [ format ] ,
0x80487c2 ; [ 0 x80487c2 :4]=0 x50006425 ; const char ∗ format
| |: ;−− e i p :
| |: 0 x080485f8 8 d45f3 l e a eax , [ var_dh ]
| |: 0 x080485fb 890424 mov dword [ esp ] , eax
; const char ∗ s
| |: 0 x080485fe e8c5fdffff c a l l sym . imp . s s c a n f
; int s s c a n f ( const char ∗s , const char ∗format , ...)
| |: 0x08048603 8 b55fc mov edx , dword [ var_bp_4h ]
| |: 0x08048606 8 d45f8 l e a eax , [ var_8h ]
| |: 0x08048609 0110 add dword [ eax ] , edx
| |: 0x0804860b 837 df810 cmp dword [ var_8h ] , 0x10
| ,===< 0 x0804860f 7512 j n e 0x8048623
| ||: 0x08048611 8b450c mov eax , dword [ arg_ch ]
| ||: 0x08048614 89442404 mov dword [ format ] , eax
; char ∗arg_ch
| ||: 0x08048618 8b4508 mov eax , dword [ s ]
| ||: 0x0804861b 890424 mov dword [ esp ] , eax
; char ∗ s
| ||: 0 x0804861e e81fffffff c a l l f c n .08048542
| ||: ; CODE XREF from f c n .080485 b9 @ 0 x804860f
| `−−−> 0x08048623 8 d45f4 l e a eax , [ var_ch ]
| |: 0x08048626 ff00 i n c dword [ eax ]
| |`=< 0x08048628 eba3 jmp 0x80485cd
| | ; CODE XREF from f c n .080485 b9 @ 0x80485db
\ `−−> 0x0804862a e8f5feffff c a l l f c n .08048524
we got familiar with this code structure in the previous challenges (the check
function). It’s not difficult for us even we don’t have the symbol info. you
can also use afn command to rename the function name if you like.
int32_t fcn_080485b9 ( char ∗ s , void∗ envp )
{
359
var_ch = 0 ;
var_8h = 0 ;
for ( var_ch = 0 ; var_ch < s t r l e n ( s ) ; ++var_ch )
{
var_dh = s [ var_ch ] ;
s s c a n f (&var_dh , %d , &var_4h ) ; // read from
s t r i n g [ var_ch ] , s t o r e to var_4h
var_8h += var_4h ;
i f ( var_8h == 0x10 )
fcn_08048542 ( s , envp ) ;
}
return fcn_08048524 ( ) ;
}
most part of crackme 0x07 is the same with 0x06. and it can be solved by the
same password & environment:
$ export LOLAA=help
$ . / cracke0x07
IOLI Crackme Level 0x07
Password : 12346
Password OK!
wait … where is the ‘wtf?’. Often, we would like to find the cross reference
(xref) to strings (or data, functions, etc.) in reverse engineering. The related
commands in Radare2 are under “ax” namespace:
[ 0 x08048400]> f
0x080487a8 5 s t r .LOLO
0x080487ad 21 s t r . Password_Incorrect
0x080487c5 14 s t r . Password_OK
0x080487d3 6 s t r . wtf
0x080487d9 25 s t r . IOLI_Crackme_Level_0x07
0 x080487f2 11 s t r . Password :
[ 0 x08048400]> axt 0x80487d3
( nofunc ) 0x804865c [DATA] mov dword [ esp ] , s t r . wtf
[ 0 x08048400]> axF s t r . wtf
Finding r e f e r e n c e s o f f l a g s matching ' s t r . wtf ' . . .
[ 0 x001eff28 −0x001f0000 ] ( nofunc ) 0x804865c [DATA] mov dword [ esp ] ,
s t r . wtf
Macro ' f i n d s t r e f ' removed .
360
0x08048632 89442404 mov dword [ esp + 4 ] , eax
0x08048636 8 b45fc mov eax , dword [ ebp − 4 ]
0x08048639 890424 mov dword [ esp ] , eax
; char ∗∗ s1
0x0804863c e873feffff c a l l f c n .080484 b4
0x08048641 85 c0 t e s t eax , eax
,=< 0x08048643 7436 j e 0x804867b
| 0x08048645 c745f4000000 . mov dword [ ebp − 0xc ] , 0
| ; CODE XREF from f c n .080485 b9 @ +0xc0
.−−> 0x0804864c 837 df409 cmp dword [ ebp − 0xc ] , 9
,===< 0x08048650 7 f29 j g 0x804867b
|:| 0x08048652 8 b45fc mov eax , dword [ ebp − 4 ]
|:| 0x08048655 83 e001 and eax , 1
|:| 0x08048658 85 c0 t e s t eax , eax
,====< 0x0804865a 7518 j n e 0x8048674
||:| 0 x0804865c c70424d38704 . mov dword [ esp ] , s t r . wtf
; [ 0 x80487d3 :4]=0 x3f667477 ; ” wtf ?\n” ; const char ∗ format
||:| 0x08048663 e850fdffff c a l l sym . imp . p r i n t f
; i n t p r i n t f ( const char ∗ format )
||:| 0x08048668 c70424000000 . mov dword [ esp ] , 0
; int status
||:| 0 x0804866f e874fdffff c a l l sym . imp . e x i t
; void e x i t ( i n t s t a t u s )
||:| ; CODE XREF from f c n .080485 b9 @ +0xa1
`−−−−> 0x08048674 8 d45f4 l e a eax , [ ebp − 0xc ]
|:| 0x08048677 ff00 i n c dword [ eax ]
|`==< 0x08048679 ebd1 jmp 0x804864c
| | ; CODE XREFS from f c n .080485 b9 @ +0x8a , +0x97
`−`−> 0x0804867b c9 leave
0x0804867c c3 ret
test eax, ea;je 0x804867b will jump to leave; ret, which forever skips the str.wtf
part. only use aa to analyze this binary can display the whole function.
IOLI 0x08
we can reverse it and find it’s similar to 0x07, and use the same password to
solve it:
$ export LOLAA=help
$ . / cracke0x08
IOLI Crackme Level 0x08
Password : 12346
Password OK!
361
sym . imp . __libc_start_main 6 0x8048388 | MATCH (1.000000) |
0x8048388 6 sym . imp . __libc_start_main
sym . imp . s c a n f 6 0x8048398 | MATCH (1.000000) |
0x8048398 6 sym . imp . s c a n f
sym . imp . s t r l e n 6 0x80483a8 | MATCH (1.000000) |
0x80483a8 6 sym . imp . s t r l e n
sym . imp . p r i n t f 6 0x80483b8 | MATCH (1.000000) |
0x80483b8 6 sym . imp . p r i n t f
sym . imp . s s c a n f 6 0x80483c8 | MATCH (1.000000) |
0x80483c8 6 sym . imp . s s c a n f
sym . imp . strncmp 6 0x80483d8 | MATCH (1.000000) |
0x80483d8 6 sym . imp . strncmp
sym . imp . e x i t 6 0x80483e8 | MATCH (1.000000) |
0x80483e8 6 sym . imp . e x i t
entry0 33 0x8048400 | MATCH (1.000000) |
0x8048400 33 entry0
f c n .08048424 33 0x8048424 | MATCH (1.000000) |
0x8048424 33 f c n .08048424
f c n .08048450 47 0x8048450 | MATCH (1.000000) |
0x8048450 47 sym . __do_global_dtors_aux
f c n .08048480 50 0x8048480 | MATCH (1.000000) |
0x8048480 50 sym . frame_dummy
f c n .080484 b4 112 0x80484b4 | MATCH (1.000000) |
0x80484b4 112 sym .dummy
f c n .08048524 30 0x8048524 | MATCH (1.000000) |
0x8048524 30 sym . che
f c n .08048542 119 0x8048542 | MATCH (1.000000) |
0x8048542 119 sym . p a r e l l
f c n .080485 b9 118 0x80485b9 | MATCH (1.000000) |
0x80485b9 118 sym . check
main 92 0x804867d | MATCH (1.000000) |
0x804867d 92 main
f c n .08048755 4 0x8048755 | MATCH (1.000000) |
0x8048755 4 sym . __i686 . get_pc_thunk . bx
f c n .08048760 35 0x8048760 | MATCH (1.000000) |
0x8048760 35 sym . __do_global_ctors_aux
f c n .0804878d 17 0x804878d | NEW (0.000000)
sym . __libc_csu_init 99 0 x80486e0 | NEW (0.000000)
sym . __libc_csu_fini 5 0x8048750 | NEW (0.000000)
sym . _ f i n i 26 0x8048784 | NEW (0.000000)
IOLI 0x09
Hints: crackme0x09 hides the format string (%d and %s), and nothing more
than 0x08.
$ export LOLA=help
$ . / crackme0x09
IOLI Crackme Level 0x09
Password : 12346
Password OK!
362
Avatao R3v3rs3 4
After a few years of missing out on wargames at Hacktivity, this year I’ve
finally found the time to begin, and almost finish (yeah, I’m quite embarrassed
about that unfinished webhack :) ) one of them. There were 3 different
games at the conf, and I’ve chosen the one that was provided by avatao. It
consisted of 8 challenges, most of them being basic web hacking stuff, one
sandbox escape, one simple buffer overflow exploitation, and there were two
reverse engineering exercises too. You can find these challenges on https:
//platform.avatao.com.
.radare2
I’ve decided to solve the reversing challenges using radare2, a free and open
source reverse engineering framework. I have first learned about r2 back in
2011. during a huge project, where I had to reverse a massive, 11MB statically
linked ELF. I simply needed something that I could easily patch Linux ELFs
with. Granted, back then I’ve used r2 alongside IDA, and only for smaller
tasks, but I loved the whole concept at first sight. Since then, radare2 evolved
a lot, and I was planning for some time now to solve some crackmes with the
framework, and write writeups about them. Well, this CTF gave me the
perfect opportunity :)
Because this writeup aims to show some of r2’s features besides how the
crackmes can be solved, I will explain every r2 command I use in blockquote
paragraphs like this one:
r2 tip: Always use ? or -h to get more information!
If you know r2, and just interested in the crackme, feel free to skip those parts!
Also keep in mind please, that because of this tutorial style I’m going to do a
lot of stuff that you just don’t do during a CTF, because there is no time for
proper bookkeeping (e.g. flag every memory area according to its purpose),
and with such small executables you can succeed without doing these stuff.
A few advice if you are interested in learning radare2 (and frankly, if you are
into RE, you should be interested in learning r2 :) ):
The framework has a lot of supplementary executables and a vast amount
of functionality - and they are very well documented. I encourage you to
read the available docs, and use the built-in help (by appending a ? to any
command) extensively! E.g.:
[ 0 x00000000]> ?
Usage : [ . ] [ times ] [ cmd ] [ ~ grep ] [@[ @iter ] addr ! s i z e ] [ | > pipe ] ; . . .
Append ' ? ' to any char command to get d e t a i l e d help
P r e f i x with number to r e p e a t command N times ( f . ex : 3x )
363
|%var =v a l u e A l i a s f o r ' env ' command
| ∗ o f f [=[0 x ] value ] Pointer read / w r i t e data / v a l u e s ( s e e ?v , wx,
wv)
| ( macro arg0 arg1 ) Manage s c r i p t i n g macros
| . [ − | (m) | f | ! sh | cmd ] Define macro or load r2 , cp a r s e or r l a n g f i l e
| = [ cmd ] Run t h i s command v i a rap : / /
| / Search f o r bytes , regexps , patterns , . .
| ! [ cmd ] Run given command as i n system ( 3 )
| # [ algo ] [ len ] C a l c u l a t e hash checksum o f c u r r e n t block
| #!lang [ . . ] Hashbang to run an r l a n g s c r i p t
| a Perform a n a l y s i s o f code
| b Get or change block s i z e
...
[ 0 x00000000]> a?
| Usage : a [ abdefFghoprxstc ] [...]
| ab [ h e x p a i r s ] analyze bytes
| aa analyze a l l ( f c n s + bbs ) ( aa0 to avoid sub
renaming )
| ac [ c y c l e s ] analyze which op could be executed i n [ c y c l e s ]
| ad analyze data trampoline ( wip )
| ad [ from ] [ to ] analyze data p o i n t e r s to ( from−to )
| ae [ expr ] analyze opcode e v a l e x p r e s s i o n ( s e e ao )
| a f [ r n b c s l ?+−∗] analyze Functions
| aF same as above , but using anal . depth=1
...
Also, the project is under heavy development, there is no day without commits
to the GitHub repo. So, as the readme says, you should always use the git
version!
Some highly recommended reading materials:
• Cheatsheet by pwntester
• Radare2 Book
• Radare2 Blog
• Radare2 Wiki
.first_steps
OK, enough of praising r2, lets start reversing this stuff. First, you have to
know your enemy:
[ 0 x00 avatao ] $ rabin2 −I r e v e r s e 4
pic false
canary true
nx true
crypto false
va true
364
intrp / l i b 6 4 / ld−linux−x86 −64. so . 2
bintype elf
class ELF64
lang c
arch x86
bits 64
machine AMD x86−64 a r c h i t e c t u r e
os linux
subsys linux
endian little
stripped true
static false
linenum false
lsyms false
relocs false
rpath NONE
binsz 8620
r2 tip: rabin2 is one of the handy tools that comes with radare2.
It can be used to extract information (imports, symbols, libraries,
etc.) about binary executables. As always, check the help (rabin2
-h)!
So, its a dynamically linked, stripped, 64bit Linux executable - nothing fancy
here. Let’s try to run it:
[ 0 x00 avatao ] $ . / r e v e r s e 4
?
S i z e o f data : 2623
pamparam
Wrong !
OK, so it reads a number as a size from the standard input first, than reads
further, probably “size” bytes/characters, processes this input, and outputs
either “Wrong!”, nothing or something else, presumably our flag. But do not
waste any more time monkeyfuzzing the executable, let’s fire up r2, because
in asm we trust!
[ 0 x00 avatao ] $ r2 −A r e v e r s e 4
−− Heisenbug : A bug that d i s a p p e a r s or a l t e r s i t s behavior when one
attempts to probe or i s o l a t e i t .
[ 0 x00400720]>
365
It is a good practice to create a project, so we can save our progress, and we
can come back at a later time:
[ 0 x00400720]> Ps avatao_reverse4
avatao_reverse4
[ 0 x00400720]>
r2 tip: You can save a project using Ps file, and load one using
Po file. With the -p option, you can load a project when starting
r2.
We can list all the strings r2 found:
[ 0 x00400720]> f s s t r i n g s
[ 0 x00400720]> f
0x00400e98 7 s t r . Wrong_
0 x00400e9f 27 s t r . We_are_in_the_outer_space_
0 x00400f80 18 s t r . Size_of_data :__u_n
0 x00400f92 23 s t r .Such_VM__MuCH_reV3rse_
0 x00400fa9 16 s t r . Use_everything_
0 x00400fbb 9 s t r . f l a g . t x t
0 x00400fc7 26 s t r . You_won__The_flag_is :__s_n
0 x00400fe1 21 s t r . Your_getting_closer_
[ 0 x00400720]>
366
r2 tip: We can list cross-references to addresses using the axt
[addr] command (similarly, we can use axf to list references from
the address). The _@@_ is an iterator, it just runs the command
once for every arguments listed.
The argument list in this case comes from the command
f[0]. It lists the strings from the executable with f, and uses the internal grep command
to select only the first column ([0]) that contains the strings’
addresses.
.main
As I was saying, I usually take a look at the entry point, so let’s just do that:
[ 0 x00400720]> s main
[ 0 x00400c63]>
367
Figure 25: main functions’s minimap
368
select the next or the previous block using the *<TAB>* and the
*<SHIFT><TAB>* keys respectively. You can also select the
true or the false branches using the t and the f keys.
It is possible to bring up the prompt in visual mode using the :
key, and you can use o to seek.
Lets read main node-by-node! The first block looks like this:
We can see that the program reads a word (2 bytes) into the local variable
named local_10_6, and than compares it to 0xbb8. That’s 3000 in decimal:
[ 0 x00400c63]> ? 0xbb8
3000 0xbb8 05670 2 . 9K 0000:0 bb8 3000 10111000 3000.0 0.000000 f
0.000000
369
Figure 27: main bb-0ca6
370
data - so lets name it accordingly (remember, you can open the r2 shell from
visual mode using the : key!):
:> afvn local_10_6 input_size
We’ve almost finished with this block, there are only two things remained.
First, an 512 (0x200) bytes memory chunk is zeroed out at offset 0x00602120.
A quick glance at XREFS to this address reveals that this memory is indeed
used somewhere in the application:
:> axt 0x00602120
d 0 x400cfe mov edi , 0x602120
d 0x400d22 mov edi , 0x602120
d 0x400dde mov edi , 0x602120
d 0x400a51 mov qword [ rbp − 8 ] , 0x602120
371
The only remaining thing in this block is a function call to 0x400a45 with the
input data as an argument. The function’s return value is compared to “*“,
and a conditional jump is executed depending on the result.
Earlier I told you that this crackme is probably based on a virtual machine.
Well, with that information in mind, one can guess that this function will
be the VM’s main loop, and the input data is the instructions the VM will
execute. Based on this hunch, I’ve named this function vmloop, and renamed
input_data to bytecode and input_size to bytecode_length. This is not really
necessary in a small project like this, but it’s a good practice to name stuff
according to their purpose (just like when you are writing programs).
:> a f vmloop 0x400a45
:> afvn input_size bytecode_length
:> afvn input_data bytecode
So, back to that conditional jump. If vmloop returns anything else than “*“,
372
the program just exits without giving us our flag. Obviously we don’t want
that, so we follow the false branch.
Now we see that a string in that 512 bytes memory area (sym.memory) gets
compared to “Such VM! MuCH reV3rse!”. If they are not equal, the program
prints the bytecode, and exits:
OK, so now we know that we have to supply a bytecode that will generate
that string when executed. As we can see on the minimap, there are still a few
more branches ahead, which probably means more conditions to meet. Lets
investigate them before we delve into vmloop!
If you take a look at the minimap of the whole function, you can probably
recognize that there is some kind of loop starting at block [ 0d34], and it
involves the following nodes:
• [0d34]
• [0d65]
• [0d3d]
• [0d61]
Here are the assembly listings for those blocks. The first one puts 0 into local
variable local_10_4:
And this one compares local_10_4 to 8, and executing a conditional jump
373
Figure 32: main bb-0d34
It’s pretty obvious that local_10_4 is the loop counter, so lets name it ac-
cordingly:
:> afvn local_10_4 i
374
Figure 34: main bb-0d3d
375
Figure 36: main bb-0d4d
Assuming we don’t break out and the loop completes, we are moving on to
some more checks:
This piece of code may look a bit strange if you are not familiar with x86_64
specific stuff. In particular, we are talking about RIP-relative addressing,
where offsets are described as displacements from the current instruction
pointer, which makes implementing PIE easier. Anyways, r2 is nice enough
to display the actual address (0x602104). Got the address, flag it!
:> f sym . good_if_ne_zero 4 0x602104
376
Figure 38: main bb-0d6b_meta
Well, it seems that we have fully reversed the main function. To summarize
it: the program reads a bytecode from the standard input, and feeds it to
a virtual machine. After VM execution, the program’s state have to satisfy
these conditions in order to reach the goodboy code:
• vmloop’s return value has to be “*”
• sym.memory has to contain the string “Such VM! MuCH reV3rse!”
• all 9 elements of sym.instr_dirty array should not be zero (probably
means that all instructions had to be used at least once)
• sym.good_if_ne_zero should not be zero
• sym.good_if_le_9 has to be lesser or equal to 9
This concludes our analysis of the main function, we can now move on to the
VM itself.
377
Figure 40: main bb-0d80
.vmloop
[ o f f s e t ]> f c n . vmloop
Next, sym.memory is put into another local variable at rbp-8 that r2 did not
recognize. So let’s define it!
378
Figure 41: vmloop bb-0a45
379
:> afv 8 memory qword
If that byte is not zero, the program subtracts 0x41 from it, and compares
the result to 0x17. If it is above 0x17, we get the dreaded “Wrong!” message,
and the function returns with 0. This basically means that valid bytecodes
are ASCII characters in the range of “A” (0x41) through “X” (0x41 + 0x17).
If the bytecode is valid, we arrive at the code piece that uses the jump table:
The jump table’s base is at 0x400ec0, so lets define that memory area as a
series of qwords:
[ 0 x00400a74]> s 0 x00400ec0
[ 0 x00400ec0]> Cd 8 @@=`?s $$ $$+8∗0x17 8`
r2 tip: Except for the ?s, all parts of this command should be
familiar now, but lets recap it! Cd defines a memory area as data,
380
and 8 is the size of that memory area. @@_ is an iterator that
make the preceding command run for every element that @@_
holds. In this example it holds a series generated using the ?s
command. ?s simply generates a series from the current seek (
∗)𝑡𝑜𝑐𝑢𝑟𝑟𝑒𝑛𝑡𝑠𝑒𝑒𝑘 + 8 ∗ 0𝑥17(∗
As we can see, the address 0x400c04 is used a lot, and besides that there are
9 different addresses. Lets see that 0x400c04 first!
We get the message “Wrong!”, and the function just returns 0. This means
381
that those are not valid instructions (they are valid bytecode though, they
can be e.g. parameters!) We should flag 0x400c04 accordingly:
[ 0 x00400ec0]> f not_instr @ 0 x0000000000400c04
As for the other offsets, they all seem to be doing something meaningful, so
we can assume they belong to valid instructions. I’m going to flag them using
the instructions’ ASCII values:
[ 0 x00400ec0]> f instr_A @ 0x0000000000400a80
[ 0 x00400ec0]> f instr_C @ 0x0000000000400b6d
[ 0 x00400ec0]> f instr_D @ 0x0000000000400b17
[ 0 x00400ec0]> f instr_I @ 0 x0000000000400aec
[ 0 x00400ec0]> f instr_J @ 0x0000000000400bc1
[ 0 x00400ec0]> f instr_P @ 0x0000000000400b42
[ 0 x00400ec0]> f instr_R @ 0x0000000000400be5
[ 0 x00400ec0]> f instr_S @ 0x0000000000400ab6
[ 0 x00400ec0]> f instr_X @ 0x0000000000400b99
Ok, so these offsets were not on the graph, so it is time to define basic blocks
for them!
r2 tip: You can define basic blocks using the afb+ command. You
have to supply what function the block belongs to, where does it
start, and what is its size. If the block ends in a jump, you have to
specify where does it jump too. If the jump is a conditional jump,
the false branch’s destination address should be specified too.
We can get the start and end addresses of these basic blocks from the full
disasm of vmloop.
As I’ve mentioned previously, the function itself is pretty short, and easy to
read, especially with our annotations. But a promise is a promise, so here is
how we can create the missing basic blocks for the instructions:
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400a80 0x00400ab6−0x00400a80
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400ab6 0x00400aec−0x00400ab6
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0 x00400aec 0x00400b17−0x00400aec
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400b17 0x00400b42−0x00400b17
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400b42 0x00400b6d−0x00400b42
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400b6d 0x00400b99−0x00400b6d
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400b99 0x00400bc1−0x00400b99
0x400c15
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400bc1 0x00400be5−0x00400bc1
0x400c15
382
Figure 46: vmloop full
383
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400be5 0x00400c04−0x00400be5
0x400c15
It is also apparent from the disassembly that besides the instructions there
are three more basic blocks. Lets create them too!
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400c15 0x00400c2d−0x00400c15
0 x400c3c 0x00400c2d
[ 0 x00400ec0]> afb+ 0x00400a45 0x00400c2d 0x00400c3c−0x00400c2d
0x400c4d 0 x00400c3c
[ 0 x00400ec0]> afb+ 0x00400a45 0 x00400c3c 0x00400c4d−0x00400c3c
0x400c61
Note that the basic blocks starting at 0x00400c15 and 0x00400c2d ending in
a conditional jump, so we had to set the false branch’s destination too!
And here is the graph in its full glory after a bit of manual restructuring:
I think it worth it, don’t you? :) (Well, the restructuring did not really worth
it, because it is apparently not stored when you save the project.)
r2 tip: You can move the selected node around in graph view
using the HJKL keys.
By the way, here is how IDA’s graph of this same function looks like for
comparison:
As we browse through the disassembly of the instr_LETTER basic blocks,
we should realize a few things. The first: all of the instructions starts with a
sequence like these:
It became clear now that the 9 dwords at sym.instr_dirty are not simply
indicators that an instruction got executed, but they are used to count
how many times an instruction got called. Also I should have realized
earlier that sym.good_if_le_9 (0x6020f0) is part of this 9 dword array, but
yeah, well, I didn’t, I have to live with it… Anyways, what the condition
“sym.good_if_le_9 have to be lesser or equal 9” really means is that instr_P
can not be executed more than 9 times:
Another similarity of the instructions is that 7 of them calls a function with
either one or two parameters, where the parameters are the next, or the next
two bytecodes. One parameter example:
And a two parameters example:
We should also realize that these blocks put the number of bytes they eat
up of the bytecode (1 byte instruction + 1 or 2 bytes arguments = 2 or 3)
into a local variable at 0xc. r2 did not recognize this local var, so lets do it
manually!
384
Figure 47: vmloop graph
385
Figure 48: IDA graph
386
Figure 53: vmloop bb-0a80_full
If we look at instr_J we can see that this is an exception to the above rule,
since it puts the return value of the called function into instr_ptr_step instead
of a constant 2 or 3:
And speaking of exceptions, here are the two instructions that do not call
functions:
This one simply puts the next bytecode (the first the argument) into eax, and
jumps to the end of vmloop. So this is the VM’s ret instruction, and we know
that vmloop has to return “*”, so “R*” should be the last two bytes of our
bytecode.
387
The next one that does not call a function:
Oh, and by the way, I do have a hunch that instr_C also had a function call
in the original code, but it got inlined by the compiler. Anyways, so far we
have these two instructions:
• instr_R(a1): returns with a1
• instr_C(a1): writes a1 to sym.written_by_instr_C
And we also know that these accept one argument,
• instr_I
• instr_D
• instr_P
• instr_X
• instr_J
and these accept two:
• instr_A
• instr_S
What remains is the reversing of the seven functions that are called by the
instructions, and finally the construction of a valid bytecode that gives us the
flag.
instr_A
The function this instruction calls is at offset 0x40080d, so lets seek there!
[ o f f s e t ]> 0x40080d
388
r2 tip: In visual mode you can just hit <Enter> when the current
line is a jump or a call, and r2 will seek to the destination address.
If we seek to that address from the graph mode, we are presented with a
message that says “Not in a function. Type ‘df’ to define it here. This is
because the function is called from a basic block r2 did not recognize, so r2
could not find the function either. Lets obey, and type df ! A function is
indeed created, but we want some meaningful name for it. So press dr while
still in visual mode, and name this function instr_A!
r2 tip: You should realize that these commands are all part of
the same menu system in visual mode I was talking about when
we first used Cd to declare sym.memory as data.
Ok, now we have our shiny new fcn.instr_A, lets reverse it! We can see from
the shape of the minimap that probably there is some kind cascading if-then-
elif, or a switch-case statement involved in this function. This is one of the
reasons the minimap is so useful: you can recognize some patterns at a glance,
which can help you in your analysis (remember the easily recognizable for loop
from a few paragraphs before?) So, the minimap is cool and useful, but I’ve
just realized that I did not yet show you the full graph mode, so I’m going to
do this using full graph. The first basic blocks:
389
Figure 58: instr_A bb-080d
The two function arguments (rdi and rsi) are stored in local variables, and
the first is compared to 0. If it is, the function returns (you can see it on
the minimap), otherwise the same check is executed on the second argument.
The function returns from here too, if the argument is zero. Although this
function is really tiny, I am going to stick with my methodology, and rename
the local vars:
:> afvn local_1 arg1
:> afvn local_2 arg2
And we have arrived to the predicted switch-case statement, and we can see
that arg1’s value is checked against “M”, “P”, and “C”.
This is the “M” branch:
It basically loads an address from offset 0x602088 and adds arg2 to the byte
at that address. As r2 kindly shows us in a comment, 0x602088 initially holds
the address of sym.memory, the area where we have to construct the “Such
VM! MuCH reV3rse!” string. It is safe to assume that somehow we will be
able to modify the value stored at 0x602088, so this “M” branch will be able to
modify bytes other than the first. Based on this assumption, I’ll flag 0x602088
as sym.current_memory_ptr:
390
Figure 59: instr_A switch values
391
:> f sym . current_memory_ptr 8 @ 0x602088
Well, it turned out that instr_C is not the only instruction that modifies
sym.written_by_instr_C: this piece of code adds arg2 to it.
And that was instr_A, lets summarize it! Depending on the first argument,
this instruction does the following:
• arg1 == “M”: adds arg2 to the byte at sym.current_memory_ptr.
• arg1 == “P”: steps sym.current_memory_ptr by arg2 bytes.
• arg1 == “C”: adds arg2 to the value at sym.written_by_instr_C.
instr_S
This function is not recognized either, so we have to manually define it like we
did with instr_A. After we do, and take a look at the minimap, scroll through
392
the basic blocks, it is pretty obvious that these two functions are very-very
similar. We can use radiff2 to see the difference.
r2 tip: radiff2 is used to compare binary files. There’s a few
options we can control the type of binary diffing the tool does,
and to what kind of output format we want. One of the cool
features is that it can generate DarumGrim-style bindiff graphs
using the -g option.
Since now we want to diff two functions from the same binary, we specify the
offsets with -g, and use reverse4 for both binaries. Also, we create the graphs
for comparing instr_A to instr_S and for comparing instr_S to instr_A.
[ 0 x00 ~ ] $ r a d i f f 2 −g 0x40080d , 0 x40089f r e v e r s e 4 r e v e r s e 4 | xdot −
A sad truth reveals itself after a quick glance at these graphs: radiff2 is a
liar! In theory, grey boxes should be identical, yellow ones should differ only
393
Figure 64: instr_S graph2
394
at some offsets, and red ones should differ seriously. Well this is obviously
not the case here - e.g. the larger grey boxes are clearly not identical. This is
something I’m definitely going to take a deeper look at after I’ve finished this
writeup.
Anyways, after we get over the shock of being lied to, we can easily recognize
that instr_S is basically a reverse-instr_A: where the latter does addition,
the former does subtraction. To summarize this:
• arg1 == “M”: subtracts arg2 from the byte at sym.current_memory_ptr.
• arg1 == “P”: steps sym.current_memory_ptr backwards by arg2 bytes.
• arg1 == “C”: subtracts arg2 from the value at sym.written_by_instr_C.
instr_I
This one is simple, it just calls instr_A(arg1, 1). As you may have noticed
the function call looks like call fcn.0040080d instead of call fcn.instr_A. This is
because when you save and open a project, function names get lost - another
thing to examine and patch in r2!
instr_D
Again, simple: it calls instr_S(arg1, 1).
instr_P
It’s local var rename time again!
:> afvn local_0_1 const_M
:> afvn local_0_2 const_P
:> afvn local_3 arg1
395
Figure 66: instr_D
396
This function is pretty straightforward also, but there is one oddity: const_M
is never used. I don’t know why it is there - maybe it is supposed to
be some kind of distraction? Anyways, this function simply writes arg1 to
sym.current_memory_ptr, and than calls instr_I(“P”). This basically means
that instr_P is used to write one byte, and put the pointer to the next byte.
So far this would seem the ideal instruction to construct most of the “Such
VM! MuCH reV3rse!” string, but remember, this is also the one that can be
used only 9 times!
instr_X
Another simple one, rename local vars anyways!
:> afvn local_1 arg1
instr_J
This one is not as simple as the previous ones, but it’s not that complicated
either. Since I’m obviously obsessed with variable renaming:
:> afvn local_3 arg1
:> afvn local_0_4 arg1_and_0x3f
After the result of arg1 & 0x3f is put into a local variable, arg1 & 0x40 is
checked against 0. If it isn’t zero, arg1_and_0x3f is negated:
The next branching: if arg1 >= 0, then the function returns arg1_and_0x3f,
else the function branches again, based on the value of sym.written_by_instr_C:
397
Figure 69: instr_J
398
Figure 72: instr_J bb-0a1a
399
If it is zero, the function returns 2,
else it is checked if arg1_and_0x3f is a negative number,
.instructionset
We’ve now reversed all the VM instructions, and have a full understanding
about how it works. Here is the VM’s instruction set:
400
Instruction 1st arg 2nd arg What does it do?
“P” arg2 sym.current_memory_ptr
+= arg2
“C” arg2 sym.written_by_instr_C
+= arg2
“S” “M” arg2 *sym.current_memory_ptr
-= arg2
“P” arg2 sym.current_memory_ptr
-= arg2
“C” arg2 sym.written_by_instr_C
-= arg2
“I” arg1 n/a instr_A(arg1, 1)
“D” arg1 n/a instr_S(arg1, 1)
“P” arg1 n/a *sym.current_memory_ptr
= arg1; instr_I(“P”)
“X” arg1 n/a *sym.current_memory_ptr
^= arg1
“J” arg1 n/a arg1_and_0x3f = arg1 &
0x3f;
if (arg1 & 0x40 != 0)
arg1_and_0x3f *= -1
if (arg1 >= 0) return
arg1_and_0x3f;
else if
(*sym.written_by_instr_C
!= 0) {
if (arg1_and_0x3f < 0)
++*sym.good_if_ne_zero;
return arg1_and_0x3f;
} else return 2;
“C” arg1 n/a *sym.written_by_instr_C
= arg1
“R” arg1 n/a return(arg1)
.bytecode
Well, we did the reverse engineering part, now we have to write a program for
the VM with the instruction set described in the previous paragraph. Here is
the program’s functional specification:
• the program must return “*”
• sym.memory has to contain the string “Such VM! MuCH reV3rse!” after
401
execution
• all 9 instructions have to be used at least once
• sym.good_if_ne_zero should not be zero
• instr_P is not allowed to be used more than 9 times
Since this document is about reversing, I’ll leave the programming part to
the fellow reader :) But I’m not going to leave you empty-handed, I’ll give
you one advice: Except for “J”, all of the instructions are simple, easy to use,
and it should not be a problem to construct the “Such VM! MuCH reV3rse!”
using them. “J” however is a bit complicated compared to the others. One
should realize that its sole purpose is to make sym.good_if_ne_zero bigger
than zero, which is a requirement to access the flag. In order to increment
sym.good_if_ne_zero, three conditions should be met:
• arg1 should be a negative number, otherwise we would return early
• sym.written_by_instr_C should not be 0 when “J” is called. This
means that “C”, “AC”, or “SC” instructions should be used before call-
ing “J”.
• arg1_and_0x3f should be negative when checked. Since 0x3f’s sign bit
is zero, no matter what arg1 is, the result of arg1 & 0x3f will always be
non-negative. But remember that “J” negates arg1_and_0x3f if arg1
& 0x40 is not zero. This basically means that arg1’s 6th bit should be 1
(0x40 = 01000000b). Also, because arg1_and_0x3f can’t be 0 either, at
least one of arg1’s 0th, 1st, 2nd, 3rd, 4th or 5th bits should be 1 (0x3f
= 00111111b).
I think this is enough information, you can go now and write that program.
Or, you could just reverse engineer the quick’n’dirty one I’ve used during the
CTF:
\x90\x00PSAMuAP\x01AMcAP\x01AMhAP\x01AM
AP\x01AMVAP\x01AMMAP\x01AM!AP\x01AM
AP\x01AMMAP\x01AMuAP\x01AMCAP\x01AMHAP\x01AM
AP\x01AMrAP\x01AMeAP\x01AMVAP\x01AM3AP\x01AMrAP\x01AMsAP\x01AMeIPAM!X\x00CA
Keep in mind though, that it was written on-the-fly, parallel to the reversing
phase - for example there are parts that was written without the knowledge
of all possible instructions. This means that the code is ugly and inefficient.
.outro
Well, what can I say? Such VM, much reverse! :)
What started out as a simple writeup for a simple crackme, became a rather
lengthy writeup/r2 tutorial, so kudos if you’ve read through it. I hope you
enjoyed it (I know I did), and maybe even learnt something from it. I’ve surely
402
learnt a lot about r2 during the process, and I’ve even contributed some small
patches, and got a few ideas of more possible improvements.
R2Wars
R2wars is an exciting and unique way to use radare2, allow users to engage in
programming duels using real assembly languages in this game-like environ-
ment confronting two programs against each other in a virtual memory space,
where they compete to overwrite each other’s code to make the opponent
crash.
Players must get familiar with the radare2 toolchain, assembly language and
the rules of the game.
Implementations
The intial implementation of the r2wars game was done in a Python r2pipe
script. But this served as a proof-of-concept for another more performant
implementation written in C# and available on this repository. This imple-
mentation is the one used in the official competitions at r2con.
• https://github.com/radareorg/r2wars
Supported Architectures
R2wars supports various architectures, and it used as an excuse to improve the
state of the assembler, disassemblers and emulation capabilities of radare2.
The most relevant are: x86, 8051, ARM32, ARM64, MIPS and RISC-V.
Players can choose their preferred architecture or agree on a specific one for
each battle, as specified by the competition rules if inter-arch bots are permit-
ted.
Writing Warriors
To create a warrior for r2wars, participants write assembly code tailored to
their chosen architecture.
Note that the assembly code should be optimized for size and efficiency, as
space in the virtual memory is limited. Other strategies are:
• Creating small, fast-moving code that’s hard to target
• Exploiting the use of memory scanning and copying data
• Note that turns depend on the instruction cost not the instruction count
• Developing efficient scanning techniques to locate the opponent quickly
403
• Drawing images and text in the r2wars panel GUI for fun
• Use instructions with low cycle count costs
Battle Mechanics
When a battle begins, both programs are loaded into the shared memory
space. Execution alternates between the two programs, with each getting a
turn to execute a single instruction. This continues until one program crashes
or a predefined number of cycles is reached.
The r2wars interface provides real-time visualization of the memory space,
allowing spectators to observe the battle as it unfolds. This includes tracking
changes in memory, register values, and the current execution point of each
program.
Examples
These are some of the bots used in real r2wars competitions.
jordi.x86-32.asm
call label
label :
pop eax
loop :
sub eax , 10
cmp dword ptr [ eax ] , 0
j e loop
mov dword ptr [ eax ] , 0
jmp loop
pancake.mips-64.asm
bal 0 + getpc
getpc :
move v0 , ra
l u i v1 , 1
loop :
sw v0 , 0( v1 )
addiu v1 , v1 , v0
b loop
nop
ricardoapl.x86-32.asm
mov edi , 0 x 0 f 6 0 f c 8 3
mov e s i , 0 x6060e04c
mov ebp , 0 x f f e 4 f f 6 0
404
mov ebx , 0xffffffff
mov edx , 0xffffffff
mov ecx , 0xffffffff
mov eax , 0x00000400
pushal
jmp esp
zeta.arm-32.asm
_start :
ldr r0 , [ pc , #48]
ldr r1 , [ pc , #48]
ldr r2 , [ pc , #48]
ldr r3 , [ pc , #44]
ldr r4 , [ pc , #40]
ldr r5 , [ pc , #36]
ldr r6 , [ pc , #36]
movt r7 , #0 x f f f f
movt r8 , #0 x f f f f
movt r9 , #0 x f f f f
movw r10 , #256
movw sp , #0x0400
push {r0 , r1 , r2 , r3 , r4 , r5 , r6 , r7 , r8 , sb , s l , fp , ip , sp ,
l r , pc}
bx sp
_data :
cmp sp , r10
movlt sp , 0x400
push {r0 , r1 , r2 , r3 , r4 , r5 , r6 , r7 , r8 , sb , s l , fp , ip , sp ,
l r , pc}
bx sp
Reference Card
This chapter is based on the Radare 2 reference card by Thanat0s, which is
written under the GNU/GPL licence.
This card may be f r e e l y d i s t r i b u t e d under the terms o f the GNU
g e n e r a l p u b l i c l i c e n c e — Copyright by Thanat0s − v0 . 1 −
Cheatsheets
If you are looking for updated and ready to be printed cheatsheets please
check the radare2-cheatsheets repository.
405
Survival Guide
Those are the basic commands you will want to know and use for moving
around a binary and getting information about it.
Command Description
s (tab) Seek to a different place
x [nbytes] Hexdump of nbytes, $b by default
aa Auto analyze
pdf@ [funcname](Tab) Disassemble function (main, fcn, etc.)
f fcn(Tab) List functions
f str(Tab) List strings
fr [flagname] [newname] Rename flag
psz [offset]~grep Print strings and grep for one
axF [flag] Find cross reference for a flag
Flags
Flags are like bookmarks, but they carry some extra information like size,
tags or associated flagspace. Use the f command to list, set, get them.
Command Description
f List flags
fd $$ Describe an offset
fj Display flags in JSON
fl Show flag length
fx [flagname] Show hexdump of flag
fC [name] [comment] Set flag comment
Flagspaces
Flags are created into a flagspace, by default none is selected, and listing flags
will list them all. To display a subset of flags you can use the fs command to
restrict it.
Command Description
fs Display flagspaces
fs * Select all flagspaces
fs [space] Select one flagspace
406
Information
Binary files have information stored inside the headers. The i command uses
the RBin api and allows us to the same things rabin2 do. Those are the most
common ones.
Command Description
ii Information on imports
iI Info on binary
ie Display entrypoint
iS Display sections
ir Display relocations
iz List strings (izz, izzz)
Print string
There are different ways to represent a string in memory. The ps command
allows us to print it in utf-16, pascal, zero terminated, .. formats.
Command Description
psz [offset] Print zero terminated string
psb [offset] Print strings in current block
psx [offset] Show string with scaped chars
psp [offset] Print pascal string
psw [offset] Print wide string
Visual mode
The visual mode is the standard interactive interface of radare2.
To enter in visual mode use the v or V command, and then you’ll only have
to press keys to get the actions happen instead of commands.
Command Description
V Enter visual mode
p/P Rotate modes (hex, disasm, debug, words, buf)
c Toggle (c)ursor
q Back to Radare shell
hjkl Move around (or HJKL) (left-down-up-right)
Enter Follow address of jump/call
407
Command Description
sS Step/step over
o Toggle asm.pseudo and asm.esil
. Seek to program counter
/ In cursor mode, search in current block
:cmd Run radare command
;[-]cmt Add/remove comment
/*+-[] Change block size, [] = resize hex.cols
<,> Seek aligned to block size
i/a/A (i)nsert hex, (a)ssemble code, visual (A)ssembler
b Toggle breakpoint
B Browse evals, symbols, flags, classes, …
d[f?] Define function, data, code, ..
D Enter visual diff mode (set diff.from/to)
e Edit eval configuration variables
f/F Set/unset flag
gG Go seek to begin and end of file (0-$s)
mK/’K Mark/go to Key (any key)
M Walk the mounted filesystems
n/N Seek next/prev function/flag/hit (scr.nkey)
C Toggle (C)olors
R Randomize color palette (ecr)
tT Tab related. see also tab
v Visual code analysis menu
V (V)iew graph (agv?)
wW Seek cursor to next/prev word
uU Undo/redo seek
x Show xrefs of current func from/to data/code
yY Copy and paste selection
z fold/unfold comments in diassembly
Searching
There are many situations where we need to find a value inside a binary or
in some specific regions. Use the e search.in=? command to choose where the
/ command may search for the given value.
Command Description
/ foo\00 Search for string ’foo\0’
/b Search backwards
408
Command Description
// Repeat last search
/w foo Search for wide string ’f\0o\0o\0’
/wi foo Search for wide string ignoring case
/! ff Search for first occurrence not matching
/i foo Search for string ’foo’ ignoring case
/e /E.F/i Match regular expression
/x a1b2c3 Search for bytes; spaces and uppercase nibbles are
allowed, same as /x A1 B2 C3
/x a1..c3 Search for bytes ignoring some nibbles (auto-generates
mask, in this example: ff00ff)
/x a1b2:fff3 Search for bytes with mask (specify individual bits)
/d 101112 Search for a deltified sequence of bytes
/!x 00 Inverse hexa search (find first byte != 0x00)
/c jmp [esp] Search for asm code (see search.asmstr)
/a jmp eax Assemble opcode and search its bytes
/A Search for AES expanded keys
/r sym.printf Analyze opcode reference an offset
/R Search for ROP gadgets
/P Show offset of previous instruction
/m magicfile Search for matching magic file
/p patternsize Search for pattern of given size
/z min max Search for strings of given size
/v[?248] num Look for a asm.bigendian 32bit value
Saving (Broken)
This feature has broken and not been resolved at the time of writing these
words (Nov.16th 2020). check #Issue 6945: META - Project files and #Issue
17034 for more details.
To save your analysis for now, write your own script which records the function
name, variable name, etc. for example:
$ vim sample_A . r2
e scr . utf8 = f a l s e
s 0 x000403ce0
aaa
s f c n .00403130
afn return_delta_to_heapaddr
afvn i t e r var_04h
...
409
Usable variables in expression
The ?$? command will display the variables that can be used in any math
operation inside the r2 shell. For example, using the ? $$ command to evaluate
a number or ?v to just the value in one format.
All commands in r2 that accept a number supports the use of those variables.
Command Description
|ℎ𝑒𝑟𝑒(𝑐𝑢𝑟𝑟𝑒𝑛𝑡𝑣𝑖𝑟𝑡𝑢𝑎𝑙𝑠𝑒𝑒𝑘)||$
current non-temporary virtual seek
$? last comparison value
$alias=value alias commands (simple macros)
$b block size
$B base address (aligned lowest map address)
$f jump fail address (e.g. jz 0x10 => next instruction)
$fl flag length (size) at current address (fla; pD $l @ entry0)
$F current function size
$FB begin of function
$Fb address of the current basic block
$Fs size of the current basic block
$FE end of function
$FS function size
$Fj function jump destination
$Ff function false destination
$FI function instructions
𝑐,r get width and height of terminal
$Cn get nth call of function
$Dn get nth data reference in function
$D current debug map base address ?v $D @ rsp
$DD current debug map size
$e 1 if end of block, else 0
$j jump address (e.g. jmp 0x10, jz 0x10 => 0x10)
$Ja get nth jump of function
$Xn get nth xref of function
$l opcode length
$m opcode memory reference (e.g. mov eax,[0x10] => 0x10)
$M map address (lowest map address)
$o here (current disk io offset)
$p getpid()
$P pid of children (only in debug)
$s file size
$S section offset
$SS section size
410
Command Description
$v opcode immediate value (e.g. lui a0,0x8010 => 0x8010)
$w get word size, 4 if asm.bits=32, 8 if 64, …
${ev} get value of eval config variable
$r{reg} get value of named register
$k{kv} get value of an sdb query value
$s{flag} get size of flag
RNum $variables usable in math expressions
• 7flying
• Adrian Studer
• Agustín Dall’Alba
• Ahmed Mohamed Abd El-MAwgood
• Akshay Krishnan R
• Ali Raheem
• Andrew Hoog
• Anton Kochkov
• Antonio Sánchez
• Apkunpacker
• Aswin
• Aswin C
• Austin Hartzheim
• Bob131
• Braiden Kindt
• Connor Armand Du Plooy
411
• Cyrill Leutwiler
• DZ_ruyk
• David Tomaschik
• Deepak Chethan
• Dennis Goodlett
• Dennis van der Schagt
• Dāvis
• Enshin Andrey
• Eric
• Evgeny Cherkashin
• Fangrui Song
• Francesco Tamagni
• FreeArtMan
• Gerardo García Peña
• Giovanni
• Giovanni Dante Grazioli
• Giuseppe
• Grigory Rechistov
• GustavoLCR
• Heersin
• Hui Peng
• ITAYC0HEN
• Itay Cohen
• Jacob Rosenthal
• Jeffrey Crowell
• John
• Judge Dredd (key 6E23685A)
• Jupiter
• Jürgen Hötzel
• Kali Kaneko
• Kevin Grandemange
• Kevin Laeufer
• LGTM Migrator
• Lazula
• Lev Aronsky
• Liumeo
• Luca Di Bartolomeo
• Lukas Dresel
• Maijin
• Martin Brunner
• Michael Scherer
• Michele
412
• Mike
• Nikita Abdullin
• Nikolaos Chatzikonstantinou
• Pau RE
• Paul
• Paweł Łukasik
• Peter C
• Rafael Rivera
• RandomLive
• Ren Kimura
• Reto Schneider
• Riccardo Schirone
• Roman Valls Guimera
• Ryan Geary
• SchumBlubBlub
• SkUaTeR
• Solomon
• Sophie Chen
• Srimanta Barua
• Sushant Dinesh
• Sylvain Pelissier
• TDKPS
• Thanat0s
• Tomasz Różański
• Vanellope
• Vasilij Schneidermann
• Vex Woo
• Vitaly Bogdanov
• Vorlent
• XYlearn
• Yuri Slobodyanyuk
• Zelalem Mekonnen
• Zi Fan
• adwait1-g
• aemmitt-ns
• ali
• aoighost
• ayedaemon
• ckanibal
• condret
• dependabot[bot]
• dodococo
413
• dreamist
• gogo
• gogo2464
• grepharder
• h0pp
• hdznrrd
• hmht
• ivan tkachenko
• izhuer
• jvoisin
• karliss
• kij
• krmpotic
• leongross
• lowsec
• madblobfish
• meowmeowxw
• mrmacete
• ms111ds
• muzlightbeer
• officialcjunior
• pancake
• pickDefault
• polym (Tim)
• puddl3glum
• ratijas
• sghctoma
• shakreiner
• sivaramaaa
• taiyu
• tick
• vane11ope
• xarkes
• xunoaib
• yep
• yossizap
• yurayake
• Óscar Carrasco
• Florian Best
414