Reverse Engineering (1/5): foundations — from source code to binaries and assembly
TL;DR
Reverse engineering is compilation in reverse. The compilation pipeline, import tables, strings, about 30 assembly instructions and calling conventions are enough to start reading binaries.
You are handed an executable with no source: a broken third-party library, an undocumented legacy device, or a suspected malware sample. To understand it, you have to run compilation backwards. This is part 1 of the 5-part Reverse Engineering for Developers series: the foundations for reading binaries — the compilation pipeline, executable formats, the minimum assembly you need, and calling conventions.
What does compilation throw away?
Reverse engineering is essentially compilation in reverse. Each stage destroys a layer of information you will later have to rebuild:
- Preprocessing (
gcc -E): macros and#includeare expanded — macro names disappear. - Compilation (
gcc -S): C becomes assembly — variable names, types and loop structure are lost; only registers and stack offsets remain. - Assembly (
as): assembly becomes an object file with relocations. - Linking (
ld): objects and libraries are combined. Static linking pulls in thousands of library functions you must learn to ignore.
Try it on a tiny program and compare optimisation levels:
gcc -O0 -g -o hello_O0 hello.c
gcc -O2 -s -o hello_O2 hello.c # -s strips symbols
objdump -d -M intel hello_O0 | less
At -O2, functions get inlined, loops unrolled and variables live only in registers. That gap is exactly what makes real-world binaries hard to read.
Executable formats
| Format | Platform | Key structures | Inspect with |
|---|---|---|---|
| ELF | Linux, Android, embedded | Segments, .text/.rodata sections, .plt/.got | readelf -a, objdump, nm |
| PE / PE32+ | Windows | Import Address Table (IAT), export table, sections | PE-bear, CFF Explorer, dumpbin |
| Mach-O | macOS, iOS | Load commands, __TEXT/__DATA segments, code signature | otool -l, nm |
Two maps before you read a single instruction: the import table (a binary calling connect and CryptEncrypt already tells a story) and the strings (strings -n 8 file): error messages, URLs and format strings point straight at interesting functions.
The minimum assembly you need
You do not need to memorise the Intel manual. About thirty instructions cover most compiler output:
- Data:
mov,lea,push,pop,movzx,movsx - Arithmetic:
add,sub,imul,xor,and,or,shl,shr,sar - Control flow:
cmp,test,jmp,je/jne,jl/jg(signed),jb/ja(unsigned),call,ret
Patterns to spot instantly: xor eax, eax sets zero; lea rax, [rbx+rbx*4] is usually multiplication by 5, not a memory read; signed versus unsigned jumps reveal the original variable type.
Calling conventions
| Convention | Platform | Integer args | Return |
|---|---|---|---|
| System V AMD64 | Linux, macOS x86-64 | rdi, rsi, rdx, rcx, r8, r9 | rax |
| Microsoft x64 | Windows x86-64 | rcx, rdx, r8, r9 + 32-byte shadow space | rax |
| AAPCS64 | ARM64 (Android, Apple Silicon) | x0–x7 | x0 |
Recognising C constructs in assembly
- if/else:
cmp+ a conditional jump that skips a block. - for/while: a backward jump to a label above.
- switch: a bounds check, then
jmp [table + rax*8](a jump table). - struct: the same base register with fixed offsets
[rdi+0x8],[rdi+0x10]. - C++ virtual call:
mov rax, [rdi](load the vtable), thencall [rax+0x18].
Caveats
- Legal: only analyse software you own, are authorised to test, or that is published for practice (crackmes, CTFs). EU Directive 2009/24/EC (Art. 6) and DMCA §1201(f) allow decompilation for interoperability, but licences and local law still apply.
- Isolated lab: use a Linux VM with snapshots; never run unknown samples on your work machine.
How to apply it
- Dev: write five small C functions (if, loop, switch, struct, virtual), paste them into Compiler Explorer and compare
-O0with-O2until you can predict the assembly. - Tech Lead: make reading crash dumps and disassembly part of the team's debugging skills — some production bugs only show up at the binary level.
- PM: when integrating an undocumented device or legacy system, reversing the format is a legitimate option; budget time and a legal review for it.
Sources & references
- Reverse Engineering for Beginners — Dennis Yurichev
- Compiler Explorer — Matt Godbolt
- ELF specification (Tool Interface Standard) — Linux Foundation Refspecs
- PE Format — Microsoft Learn
- x64 calling convention — Microsoft Learn
- Directive 2009/24/EC on the legal protection of computer programs — EUR-Lex
- 17 U.S. Code § 1201 — Cornell LII