Introduction / Overview
This article is for education and authorized security testing only. Only analyze binaries you own, samples provided in a legal training environment, or files you are explicitly authorized to assess. Reversing licensed software may violate its EULA or local law, and detonating live malware outside an isolated lab is dangerous. You are responsible for your own actions.
radare2 (often shortened to r2) is a free, open-source reverse engineering framework that runs on Linux, macOS, Windows, and even constrained embedded systems. rizin is a fork of radare2 that prioritizes a cleaner internal API, stable command syntax, and a friendlier contributor experience. The two share most of their command language, so the muscle memory you build in one transfers almost entirely to the other. In this post I will use r2 syntax; nearly every command works identically under rizin.
If you have previously used a GUI-first tool, you may want to read my notes on Ghidra for beginners before diving into r2's terminal-centric workflow.
How it works / Background
radare2 is a collection of small command-line utilities glued together by a scriptable core. The pieces you will touch most often are:
r2/rizin— the interactive analysis shell.rabin2/rz-bin— parses headers, imports, exports, strings, and sections.rasm2/rz-asm— assembles and disassembles instructions.radiff2/rz-diff— binary and function-level diffing (great for patch analysis).
The command language is terse but composable. Commands are read left to right, and suffixes change behavior: p prints, pd prints disassembly, pdf prints the disassembly of a function, and a trailing j or q switches almost any command to JSON or quiet output. That orthogonality is what makes r2 scriptable: you can pipe pdfj into jq and feed the result to your own tooling.
Prerequisites / Lab setup
Work inside an isolated VM with no network bridge to anything you care about. Install from source to get the newest analysis engine.
# radare2 (from source)
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
# rizin (Debian/Ubuntu package)
sudo apt install rizin
# verify
r2 -v
rizin -vBashCreate a tiny target so the output is predictable:
cat > target.c <<'EOF'
#include <stdio.h>
#include <string.h>
int check(const char *p){ return strcmp(p, "s3cr3t") == 0; }
int main(int argc, char **argv){
if (argc > 1 && check(argv[1])) puts("OK");
else puts("NO");
return 0;
}
EOF
gcc -no-pie -fno-stack-protector -o target target.cBashWalkthrough / PoC
Triage before opening the shell
Start with rabin2 to understand the file without running any analysis:
rabin2 -I target # binary info: arch, bits, NX, PIE, canary
rabin2 -z target # strings in data sections
rabin2 -i target # imported symbols (strcmp, puts, ...)
rabin2 -s target # exported symbolsBashThe -I output tells you whether mitigations like canary, nx, and pic are present — exactly the fields you care about before writing an exploit.
Loading and analyzing
Open the binary. Use -A to run analysis on load, or run it manually from the prompt:
r2 -A targetBashInside the shell, the single most important command is aaa ("analyze all, all"). It performs function discovery, names flags, identifies references, and propagates types. There are escalating variants:
aa # basic analysis (functions from symbols/entry)
aaa # aa + auto-name functions, find references, emulate where useful
aaaa # experimental, more aggressive (slower, noisier)PlaintextRun aaa, then list what r2 found:
[0x00401050]> aaa
[0x00401050]> afl # list all functions with addresses and sizes
[0x00401050]> afl~main # grep the list for "main" (~ is r2's internal grep)PlaintextDisassembling a function with pdf
Seek to main and print the disassembly of the function. pdf = "print disassembly of function":
[0x00401050]> s main
[0x00401146]> pdfPlaintextYou will see the prologue, the argc comparison, and a call sym.check. Jump straight to that function instead of scrolling:
[0x00401146]> s sym.check
[0x00401136]> pdfPlaintextUseful printing variants while you read:
pdf # full function disassembly
pdf # same, alias
pd 20 # disassemble 20 instructions from the current seek
pdc # pseudo-C-like decompilation (built-in, lightweight)
pdr # disassemble respecting control flow (recursive)
axt sym.check # show all cross-references TO check (who calls it)Plaintextaxt (analyze xrefs to) is how you build a call graph in your head: it tells you every site that references a function or string. Pair it with axf (xrefs from) to see what the current function reaches.
Visual mode
Typing commands is fast for triage, but for reading flow you want visual mode. Press V to enter it, then cycle print modes with p / P:
[0x00401136]> V # enter visual mode (hex/disasm panels)PlaintextKey bindings inside visual mode:
p/P— cycle the panel type (disassembly, hexdump, debug, etc.).V(again) — enter the graph view, an interactive control-flow graph.hjkl— navigate; arrow keys also work.Enterover a jump/call — follow it;u— go back (undo seek).:— drop into a command line without leaving visual mode.q— exit one level.
The graph view (VV from the prompt, or V then V) renders basic blocks as boxes with true/false edges — the closest r2 gets to the box-and-arrow experience of a GUI disassembler, entirely in the terminal.
Patching and scripting
r2 can write back to the binary. Open with -w for write mode and assemble a new instruction over an address:
r2 -w targetBash[0x00401050]> s sym.check
[0x00401136]> "wa mov eax, 1; ret" # always-true check
[0x00401136]> wao nop # NOP the current instructionPlaintextFor repeatable analysis, save commands to a script and replay them:
echo -e "aaa\ns main\npdf" > analyze.r2
r2 -q -i analyze.r2 targetBashCutter — the GUI front end
When you want a visual experience without leaving the ecosystem, use Cutter. Cutter is the official GUI built on rizin (earlier versions used radare2), bundling a graph view, hex editor, strings panel, and optional decompilers such as rz-ghidra (the Ghidra decompiler exposed through rizin). It is ideal for sharing findings or for newcomers who think better in panels, while still letting you drop into the rizin command bar for the precision of pdf, aaa, and axt.
Mermaid diagram

The diagram shows the analyst path from acquiring a sample to documenting indicators, branching on whether a graph view or a binary patch is needed.
Detection & Defense (Blue Team)
Reversing is a capability defenders need too — and the same tools attackers use to study your software help you study theirs. Equal weight to defense:
- Treat r2/rizin/Cutter as triage tooling, not just attacker tooling. Use
rabin2 -I,-z, and-ito extract IOCs (suspicious imports likeVirtualAllocEx,WinExec, embedded URLs, mutex names) from quarantined samples. Map observed behaviors to MITRE ATT&CK, e.g. T1027 (Obfuscated Files or Information), T1140 (Deobfuscate/Decode), and T1620 (Reflective Code Loading). - Raise the cost of static analysis. Ship release builds with stripped symbols and enable hardening: ASLR/PIE (
-fPIE -pie), stack canaries (-fstack-protector-strong), full RELRO (-Wl,-z,relro,-z,now), and NX. None of these stop a determined analyst, but they remove easy wins and break naive patching. - Make tampering detectable, not just hard. Code signing (Authenticode, codesign, GPG) plus integrity checks let you detect the kind of in-place patching shown above (
wa,wao nop). Verify signatures at load time and alert on mismatches. - Detect dynamic analysis at the endpoint. Debugger attachment and ptrace are observable. EDR rules can flag
ptrace(PTRACE_ATTACH), processes spawned underr2 -d, or unexpected memory protection changes (mprotectto RWX), aligning with T1622 (Debugger Evasion) detection. - Protect intellectual property pragmatically. For high-value logic, move secrets server-side, use attestation, or apply commercial obfuscation/packing — but assume a skilled reverser with r2 will eventually reach the logic. Defense in depth beats security-by-obscurity. See my notes on anti-debugging techniques for the cat-and-mouse details.
The takeaway: you cannot prevent reversing, but you can make it expensive, make tampering detectable, and use the very same tooling to accelerate your incident response.
Conclusion
radare2 and rizin reward a small amount of memorization with enormous leverage. Master a handful of commands — aaa to analyze, afl to list functions, pdf to read one, axt/axf to follow references, and V/VV for visual and graph modes — and you can triage most binaries entirely from the terminal. When you need pictures, Cutter gives you the rizin engine behind a GUI with optional Ghidra decompilation. For defenders, the same kit is a fast path to extracting IOCs and validating your hardening. Build the lab, reverse the toy binary above, and the workflow will quickly become second nature.
References
- Rizin project and documentation — https://rizin.re/
- radare2 GitHub repository — https://github.com/radareorg/radare2
- Cutter GUI — https://cutter.re/
- "r2 book" (radare2 official manual) — https://book.rada.re/
- HackTricks: Reversing Tools & Basic Methods — https://book.hacktricks.xyz/reversing/reversing-tools-basic-methods
- MITRE ATT&CK: T1027 Obfuscated Files or Information — https://attack.mitre.org/techniques/T1027/
- MITRE ATT&CK: T1622 Debugger Evasion — https://attack.mitre.org/techniques/T1622/



Comments