昨天看《黑客之道:漏洞挖掘的艺术》这本书的时候,看到格式化字符串漏洞小节的时候有点不明白原理,所以自己发汇编看了一下源码,恍然大悟。具体如下:

在我们使用printf(text)时,其中text是一个字符串,存在着安全漏洞。当用户输入"aaaa%08x.%08x.%08x.%08x"时,相当于printf("aaaa%08x.%08x.%08x.%08x"),显然printf的参数不够(缺少四个参数)。我们知道参数压栈的方式是从右往左,调用该函数的时候只压栈了一个参数。编译器是怎么处理的呢?编译器总是会认为第二个参数的地址是(ebp+0CH),ebp+4是调用者的ebp,ebp+8就是text的地址。

在windows下,main函数的前几行汇编语言是:

push ebp

mov ebp , esp

sub esp , 440h

push ebx

push esi

push edi

lea edi , [ebp - 440h]

mov ecx , 110h

mov eax,  0CCCCCCCCh

rep stos dword ptr [edi]

一定要记住esp是随着压栈和弹栈而改变的,所以printf函数的第二个参数实际上指向了压入edi的地址,后面依次类推。如果我们能巧妙的输入格式化符号,就可以查看和修改任意地址的内容。