Cheat sheet — Disassembly Basics¶
Companion to Module 07 — Disassembly Basics · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
Only handle live malware in an isolated, disposable analysis VM. Disassembly is static — the sample never runs — but the bytes still live on disk.
objdump — flat disassembly for the overview¶
objdump -d sample # disassemble executable sections (Intel or AT&T)
objdump -d -M intel sample # force Intel syntax (mov dst, src) — easier to read
objdump -d -j .text sample # just the .text section
objdump -t sample # symbol table — find function names
objdump -s -j .rodata sample # raw hex dump of a section (the encrypted blob lives here)
radare2 — analyse and read a function¶
r2 sample # open (add -w to write/patch, -d to debug)
r2 -q -c 'aaa; afl' sample # -q: batch, run commands, quit
aaa # analyse all — build functions, xrefs, strings
afl # list all discovered functions (find sym.decode, main)
s sym.decode # seek to a function by name
pdf # print disassembly of the current function
pdf @ sym.decode # print disassembly of a named function directly
iz # strings in the data sections
izz # strings in the whole binary
axt @ sym.decode # cross-references TO this function (who calls the decoder)
V # visual mode; VV = graph view of the current function
The XOR-decode loop — the pattern that matters most¶
loop:
movzx eax, byte [rbx + rcx] ; load buf[i] (rcx = index i)
xor al, dl ; XOR with key byte (dl often holds the key)
mov byte [rbx + rcx], al ; store decoded byte
inc rcx ; i++
cmp rcx, rsi ; compare i with length
jne loop ; not done → repeat
- Shape to spot: load byte →
xor→ store →incindex →cmpwith length →jneback. Recognise it without knowing in advance what it does; then read out the key and the length, and reverse it.
x86-64 reading kit¶
Registers rax rbx rcx rdx rsi rdi rsp rbp r8–r15
Arg order rdi rsi rdx rcx r8 r9 (System V AMD64 ABI, first six args)
Prologue push rbp / mov rbp, rsp Epilogue pop rbp / ret
Locals [rbp - N] Loop cmp + jne/jl + index inc
Families mov lea push pop | add sub imul xor | cmp test | je jne jg jl | call ret
Recover the string, then prove it¶
# read key + blob out of the disassembly, reverse in Python:
python3 -c 'b=bytes.fromhex("..."); print(bytes(x^0x5a for x in b))'
rule xor_decode_stub {
strings:
$stub = { 0F B6 04 0B 30 D0 88 04 0B 48 FF C1 } // the decode-loop bytes
condition:
$stub // prove on sample, quiet on benign
}
Gotchas worth remembering¶
- radare2 keeps you on the raw assembly on purpose — no decompiler abstraction at this stage. Reading instructions yourself is what separates understanding from guessing; Ghidra/Binary Ninja come on top of this skill, not instead of it.
- Watch the XOR key width (byte vs. word) and the loop bound — those are exactly the load-bearing details a decompiler's pseudocode (and an AI summary) quietly gets wrong, and they change the recovered string.
aaabeforepdf— radare2 shows almost nothing useful until it has analysed the binary and named functions.- AT&T vs. Intel syntax flips operand order (
mov src, dstvsmov dst, src); pick one (-M intel) and stay consistent or you'll misread everymov. - The AI explanation of a function is a hypothesis; trace the key and bounds by hand before you trust the recovered string as an IOC.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).