“异或eax,ebp”用于 C++编译器输出

发布于 2024-11-15 15:24:12 字数 226 浏览 3 评论 0原文

我只是尝试在 VS2010 上编译几个 C++ 片段,并在 IDA Pro 上分析可执行文件。我注意到,它们中的大多数在开始时都有类似以下内容(在调用 __security_check_cookie 之后不久)

xor eax, ebp

和类似

xor ecx, ebp

在底部。为什么会出现这种情况?编译器优化已关闭。

I just tried compiling a couple of C++ snippets on VS2010 and analyzed the executables on IDA Pro. Something I noticed is that there most of them have something like the following at the start(shortly after a call to __security_check_cookie)

xor eax, ebp

and something like

xor ecx, ebp

at the bottom. Why does this happen? The compiler optimization was turned off.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青丝拂面 2024-11-22 15:24:12

这些是缓冲区溢出保护方法,与编译器优化无关。 MSVC 将会(如果您指定 /GS switch)将安全cookie推送到返回地址附近的堆栈上,以便它可以检测堆栈损坏的常见情况。

堆栈损坏可能是由以下原因引起的:不良代码

char buff[5];
strcpy (buff, "Man, this string is waaay too long!!");

,或者是恶意用户利用不良编码实践,例如使用 scanf ("%s", myBuff) 进行用户输入。像这样精心设计的攻击可能会诱使您的程序去做您可能不希望它做的事情。

通过将 cookie 放置在返回地址附近,可以防止大量错误(和攻击向量),这仅仅是因为内存损坏本质上往往是连续的。换句话说,如果您覆盖了返回地址,可能是因为您开始在 cookie 的一侧写入,并一直损坏内存直到 cookie 另一侧的返回地址(因此 cookie 将被覆盖)以及)。

它无法捕获所有错误,因为您可能有一些类似以下的代码:

char buff[5];
buff[87] = 'x';

在不接触 cookie 的情况下可能会破坏返回地址。但它会捕获所有那些依赖输入比预期更长的字符串的恶意软件,这些恶意软件会破坏返回地址(包括 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。

这将改变每个堆栈级别实际放入堆栈的内容(也取决于参数计数和大小),并且可能是通过确保变量来进一步保护代码免受恶意意图的尝试。 > 签名被写入堆栈而不是固定值(否则攻击者可以输入字符包括有效的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) 源文件的 secook.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);
}

默认情况下,未通过安全检查的应用程序会显示一个对话框,指出“检测到缓冲区溢出!”。当对话框关闭时,应用程序终止。

These are buffer overrun protection methods, and have nothing to do with compiler optimisation. MSVC will (if you specify the /GS switch) push a security cookie onto the stack near the return address so that it can detect a common case of stack corruption.

Stack corruption can either be caused by bad code along the lines of:

char buff[5];
strcpy (buff, "Man, this string is waaay too long!!");

or by malicious users taking advantage of bad coding practices, like the use of scanf ("%s", myBuff) for user input. Carefully crafted attacks like that can suborn your program to do things you probably don't want it to.

By placing a cookie close to the return address, a large number of bugs (and attack vectors) can be prevented, simply due to the fact that the memory corruptions tend to be sequential in nature. In other words, if you've overwritten the return address, it's probably because you started writing on one side of the cookie and corrupted memory all the way up to the return address on the other side of the cookie (hence the cookie will be overwritten as well).

It doesn't catch all bugs since you may have some code like:

char buff[5];
buff[87] = 'x';

which could potentially corrupt the return address without touching the cookie. But it will catch all those malicious ones which rely on entering a longer string than expected, which corrupt up to the return address (including cookie).

The sequence you're probably seeing in the code is something like:

mov  eax, dword ptr ds:___sec_cookie   ; fixed value.
xor  eax, ebp                          ; adjust based on base pointer.
mov  [ebp+SOMETHING], eax              ; store adjusted value.

which is customising the cookie, depending on the current base pointer.

This will change what is actually put on the stack at each stack level (and also depending on parameter count and sizes as well) and is probably an attempt to further secure the code from malicious intent, by ensuring a variable signature is written to the stack rather than a fixed value (otherwise the attacker could enter characters including a valid cookie).

And the sequence at the end will run something like this:

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.

It's basically just the reverse process of that described above. The @__sec_check_cookie call will only return if ecx is set to the correct cookie value. Otherwise it will raise a fault, as confirmed here:

The __security_check_cookie() routine is straightforward: if the cookie was unchanged, it executes the RET instruction and ends the function call. If the cookie fails to match, the routine calls report_failure().

The report_failure() function then calls __security_error_handler(). Both functions are defined in the seccook.c file of the C run-time (CRT) source files.

CRT support is needed to make these security checks work. When a security check failure occurs, control of the program is passed to __security_error_handler(), which is summarized here:

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);
}

By default, an application that fails a security check displays a dialog that states "Buffer overrun detected!". When the dialog is dismissed, the application terminates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文