Figure 7.1 A function’s stack, before and after a stack overwrite.
For instance, you know that each time you run a program the stack is allo-
cated in the same place, so you can try and guess how much stack space the
program has used so far and try and jump to the right place. Alternatively, you
could pad our shellcode with NOPs and jump to the memory area where you
think the buffer has been copied. The NOPs give you significant latitude
because you don’t have to jump to an exact location—you can jump to any
address that contains your NOPs and execution will just flow into your code.
A Simple Stack Vulnerability
The most trivial overflow bugs happen when an application stores a temporary
buffer in the stack and receives variable-length input from the outside world
into that buffer. The classic case is a function that receives a null-terminated
string as input and copies that string into a local variable. Here is an example
that was disassembled using WinDbg.
Chapter7!launch:
00401060 mov eax,[esp+0x4]
00401064 sub esp,0x64
00401067 push eax
00401068 lea ecx,[esp+0x4]
0040106c push ecx
0040106d call Chapter7!strcpy (00401180)
00401072 lea edx,[esp+0x8]
00401076 push 0x408128
0040107b push edx
Parameter 2
32 bits
Parameter 1
Return Address
Saved EBP
number
string[3]..[7]
string[0]..[3]
counter
CopiedBuffer + 0x18
32 bits
CopiedBuffer + 0x14
CopiedBuffer + 0x10
CopiedBuffer + 0x0C
CopiedBuffer + 0x08
CopiedBuffer + 0x04
CopiedBuffer
counter
Current
Value of
ESP
Current
Value of
EBP
Current
Value of
ESP
Current
Value of
EBP
Before Reading string After Reading string
Auditing Program Binaries 247