在C ++编译器输出中使用“xor eax,ebp”
我只是在VS2010上编译了一些C ++代码片段,并分析了IDA Pro上的可执行文件。 我注意到的是,他们中的大多数在开始时具有类似于以下内容的东西(在调用__security_check_cookie之后不久)
xor eax, ebp
和类似的东西
xor ecx, ebp
在底部。 为什么会这样呢? 编译器优化已closures。
这些是缓冲区溢出保护方法,与编译器优化无关。 MSVC将(如果指定/GS
开关)将安全Cookie推送到返回地址附近的堆栈上,以便它可以检测到堆栈损坏的常见情况。
堆栈损坏可能是由以下错误代码造成的:
char buff[5]; strcpy (buff, "Man, this string is waaay too long!!");
或者恶意用户利用不好的编码做法,比如使用scanf ("%s", myBuff)
进行用户input。 像这样精心制作的攻击可能会使你的程序无法做你可能不想要的东西。
通过将cookie放在返回地址附近,可以防止大量的错误(和攻击媒介),这仅仅是因为内存损坏往往是连续的。 换句话说,如果你覆盖了返回地址,这可能是因为你开始在cookie的一边写入内容,一直到cookie另一边的返回地址(因此cookie将被覆盖以及)。
它没有捕获所有的错误,因为你可能有一些代码:
char buff[5]; buff[87] = 'x';
这可能会在不接触cookie的情况下破坏返回地址。 但是它会捕获所有那些依赖于input比预期更长的string的恶意程序,这个恶意程序会破坏到返回地址(包括cookie)。
你可能在代码中看到的序列是这样的:
mov eax, dword ptr ds:___sec_cookie ; fixed value. xor eax, ebp ; adjust based on base pointer. mov [ebp+SOMETHING], eax ; store adjusted value.
根据当前的基址指针来定制cookie。
这将改变每个堆栈级别上实际放置在堆栈上的内容(也取决于参数数量和大小),可能是通过确保将可变签名写入堆栈来尝试进一步保护恶意代码的安全而不是固定值(否则攻击者可以input包括有效cookie的字符)。
而最后的序列将运行如下所示:
mov ecx, [ebp+SOMETHING] ; get the adjusted cookie. xor ecx, ebp ; un-adjust it, since ; ((N xor X) xor X) == N. call @__sec_check_cookie ; check the cookie.
这基本上就是上述的相反过程。 只有当ecx
设置为正确的cookie值时, @__sec_check_cookie
调用才会返回。 否则会引发一个错误,正如这里所证实的那样:
__security_check_cookie()
例程很简单:如果cookie没有改变,则执行RET
指令并结束函数调用。 如果cookie不匹配,则例程调用report_failure()
。
report_failure()
函数然后调用__security_error_handler()
。 这两个函数都在C运行时(CRT)源文件的seccook.c
文件中定义。CRT支持是需要使这些安全检查工作。 当安全检查失败时,程序的控制被传递给
__security_error_handler()
,这里总结了这一点:
void __cdecl __security_error_handler(int code, void *data) { if (user_handler != NULL) { __try { user_handler(code, data); } __except (EXCEPTION_EXECUTE_HANDLER) {} } else { //...prepare outmsg... __crtMessageBoxA( outmsg, "Microsoft Visual C++ Runtime Library", MB_OK|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); } _exit(3); }
默认情况下,安全检查失败的应用程序将显示一个对话框,指出“检测到缓冲区溢出!”。 当对话框被解除时,应用程序终止。