IDA 技巧(27) 修复栈指针

admin 2024年7月15日16:15:49评论170 views字数 1773阅读5分54秒阅读模式

拥有正确的堆栈变化信息对于正确的分析至关重要,虽然 IDA 尽力提供良好且正确的结果,然而,有时它仍然会失败(通常是由于错误或冲突的信息)。

在这篇文章中,我们将向您展示如何检测和解决以下问题:

“sp-analysis failed”

IDA 技巧(27) 修复栈指针

“positive sp value has been detected”

IDA 技巧(27) 修复栈指针

这两个示例均来自 Windows 10(版本 10.0.17763.475)的 notepad.exe 32 位版本,并使用了 Microsoft 公共符号服务器中的 PDB 符号。

注意:在许多情况下,反编译器会尝试恢复并仍然产生合理的反编译,但如果您需要 100% 确定结果,最好修复它们。

发现问题的源头

解决这些问题的第一步通常是:

  1. 切换到反汇编视图(如果您在反编译器中);
  2. 在“Option”>“General...” 中的 “Disassembly, Disassembly line parts ” 下启用“Stack pointer”;

IDA 技巧(27) 修复栈指针

  1. 查找每条指令之前添加的 SP 值(实际上是 SP 增量值)的异常或意外变化。

为了检测“异常变化”,我们首先需要知道什么是“通常”。

这里有些例子:

  • push 指令应将 SP 增量增加字节数(例如,push eax 增加 4,push rbp 增加 8)
  • 相反,pop 指令将其减少相同的量
  • call 指令通常要么减少 SP (由于参数压栈)(x86 上的 stdcall 或 thiscall 函数),要么保持不变,稍后通过单独的指令减少。
  • 跳转两端的值(有条件或无条件)应该相同
  • 函数入口和返回指令处的值应为 0
  • 在 prolog 和 epilog 之间,SP 增量应该保持相同,除了调用周围的小区域之外,它可以通过压入参数来增加,但随后应该在基本块结束之前返回到“中性”。

在第一个示例中,我们可以看到 loc_406F9D 的 SP 增量为 00C,第一次跳转也是 00C,但第二个跳转是 008。

因此问题可能出在第二个块中。

00C mov     ecx, offset dword_41D180
00C call    _TraceLoggingRegister@4 ; TraceLoggingRegister(x)
008 push    offset _TraceLogger__GetInstance____2____dynamic_atexit_destructor_for__s_instance__ ; void (__cdecl *)()
00C call    _atexit
00C pop     ecx
008 push    ebx
00C call    __Init_thread_footer
00C pop     ecx
008 jmp     short loc_406F9D

我们可以看到,在调用_TraceLoggingRegister@4之后,00C 变为 008。

乍一看,这是有道理的,因为 @4 后缀表示带有 4 个字节参数的 stdcall 函数(这意味着它从堆栈中删除了 4 个字节)。

然而,如果你真正深入分析它,你会发现它不使用堆栈参数,而是使用寄存器 ecx。该文件可能已使用链接时代码生成进行编译,该技术将 stdcall 转换为 fastcall 以加快代码速度。

在第二种情况下,反汇编如下所示:

IDA 技巧(27) 修复栈指针

在这里,问题立即显而易见:call 指令后 SP 增量变为负值。

看来 IDA 决定该函数从堆栈中减去 0x14 字节,而只有 3 次压入(3 * 4 = 12 或 0xC)。

您还可以进入 StringCopyWorkerW 并观察它以 retn 0Ch 结尾 – 这是一个正确的数字的指示符。

修正错误的栈指针增量

如何实际修复错误的增量取决于具体情况,但通常有两种方法:

  1. 仅修复出现问题的地方。为此,请按 Alt-K(Edit > Functions > Change stack pointer…)并输入正确的 SP 增量。在第一个示例中,它应该为 0(因为该函数不使用任何堆栈参数),而在第二个示例中,它应该为 12 或 0xc。通常这是间接调用的唯一选择。
  2. 如果从多个地方调用同一个函数会导致堆栈不平衡问题,编辑函数属性(Alt+P 或 Edit > Functions > Edit function…),修改 “Purged bytes” 值。

IDA 技巧(27) 修复栈指针

这个简单的示例表明,即使有调试符号也不能保证 100% 正确的结果,以及为什么为用户提供修改选项很重要。

原文始发于微信公众号(二进制磨剑):IDA 技巧(27) 修复栈指针

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月15日16:15:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   IDA 技巧(27) 修复栈指针http://cn-sec.com/archives/2956028.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息