Every malware sample, every patched vulnerability diff, every mysterious binary that lands in a SOC queue eventually asks the same question: what does this program actually do? Reverse engineering is how analysts answer it without source code.
This introduction builds the mental model from the ground up — what compilation does to your code, the CPU concepts you genuinely need, and how modern tools like Ghidra turn raw bytes back into readable logic.
What Happens When Code Compiles?
When high-level code is compiled, human-readable logic is converted into machine opcodes. Disassemblers read these bytes and map them back to assembly instructions:
push rbp
mov rbp, rsp
sub rsp, 0x20
mov DWORD PTR [rbp-0x4], edi
cmp DWORD PTR [rbp-0x4], 0x1337
jne 0x401124
call grant_admin_access
Key Concepts Every Reverse Engineer Must Know
- Registers: High-speed memory storage inside the CPU (
RAX,RBX,RCX,RDX,RSPstack pointer,RBPbase pointer). - The Stack: Last-In-First-Out (LIFO) memory structure used for local variables and function return addresses.
- Decompilation: Modern tools like Ghidra reconstruct readable C pseudo-code from binary assembly graphs, turning weeks of manual reversing into hours.
The Analyst's Workflow in Ghidra
A typical first session with an unknown binary follows a rhythm. Load the file and let auto-analysis map functions and strings. Read the string table — error messages, URLs, and file paths are a table of contents written by the author. Find the entry point and follow cross-references from the interesting strings back into the code that uses them. Rename functions and variables as you understand them (check_license, decrypt_config), because the decompiler gets clearer every time you teach it something. Within an hour, a disciplined analyst usually knows what a small binary does and where its secrets live.
Static vs. Dynamic: Two Eyes Are Better
Static analysis reads the code; dynamic analysis watches it run. Running a sample in an isolated VM with tools like ProcMon, Wireshark, and a debugger shows you the files it touches, the domains it calls, and the registry it edits — behavior no amount of reading reveals as quickly. Professionals alternate: static to form hypotheses, dynamic to test them, static again to understand the mechanism. Malware fights back with anti-VM and anti-debug tricks, which is why the lab environment — snapshots, fake networks, no route to production — matters as much as the tools.
How to Start Practicing
Download Ghidra (it is free), then work through beginner crackmes — tiny programs designed to be reversed — before touching real malware. Pair the practice with one assembly concept at a time: calling conventions this week, the stack next week. Our own malware-analysis courses follow exactly this ladder, from first disassembly to full sample reports.
Reading Your First Function, Line by Line
Return to the assembly snippet above and translate it like a professional would. push rbp; mov rbp, rsp builds the stack frame — the function's workspace. sub rsp, 0x20 reserves 32 bytes for local variables. The first argument arrives in edi and is stored at [rbp-0x4]. Then comes the decision: cmp DWORD PTR [rbp-0x4], 0x1337 compares that argument against 0x1337 (4919 in decimal). jne jumps away if they are not equal — so only the exact value 0x1337 falls through to call grant_admin_access. In one paragraph of assembly you have found a hardcoded check: this binary grants access to whoever supplies the magic value. That small act — patient, line-by-line translation — is the entire discipline in miniature. Everything else is scale.
Key Takeaways
- Compilation turns readable logic into opcodes; disassemblers and decompilers reverse the trip.
- Registers, the stack, and calling conventions are 80% of the assembly you need.
- In Ghidra: strings first, cross-references second, rename as you learn.
- Alternate static reading with dynamic observation in an isolated lab — never on a real machine.
