Smashing The Stack, Revisited
"smash the stack" [C programming] n. On many C implementations it is > possible to corrupt the execution stack by writing past the end of an > array declared auto in a routine.
The original text is thirty years old and still the cleanest explanation of why memory-unsafe languages bite. This phile is a guided re-read.
Process memory layout
A process's memory is carved into regions. From low to high addresses: +------------------+ low addresses | text (code) | +------------------+ | data / bss | +------------------+ | heap | grows up | | | | v | | | | ^ | | | | | stack | grows down +------------------+ high addresses The stack grows toward lower addresses; buffers fill toward higher ones. That mismatch is the whole game.
The vulnerable shape
void vuln(char src) { char buf[64]; strcpy(buf, src); / no bounds check */ } If src is longer than 64 bytes, strcpy walks buf straight into the saved return address. Control the return address, control execution.
What changed since 1996
The technique is the same; the mitigations are not:
Stack canaries — a guard value before the saved return address.
ASLR — randomized base addresses defeat hardcoded targets.
NX / DEP — the stack is no longer executable, killing naive shellcode.
CFI — control-flow integrity narrows where
retmay land.
None of these are silver bullets. Info-leaks defeat ASLR; ROP defeats NX; mis-scoped canaries leave gaps. The arms race continues — which is exactly why the primer still matters.
Exercise
Build the snippet above with -fno-stack-protector -z execstack and overflow it under a debugger. Watch the saved rip change. That moment of "oh" is the whole point of this magazine.