'fs:[0]' 在做什么,我该如何逐步执行它?

逆向工程 视窗 x86
2021-07-06 01:57:57

在 32 位 Windows 二进制文件中,我看到以下代码:

    push next
    push fs:[0]
    mov fs:[0], esp
    int3
    ...
next:

我看到int3(错误)发生了一些事情,但我不明白为什么,以及如何在保持控制的同时跟踪执行。

1个回答

TL; 博士

  1. 前 3 行设置了一个异常处理程序(一个“错误捕捉器”)

  2. int3产生异常

  3. 执行在 next


解释

这个技巧是(ab)使用结构化异常处理,一种定义异常处理程序的机制,通常由编译器在使用try/catch

在 32 位版本的 Windows 中,它们可以即时设置,无需任何预先要求(除非二进制文件是使用 /SafeSEH 编译的)。

异常处理程序链的第一个元素由线程信息块 (TIB)的第一个成员指向,又是线程环境块 (TEB)的成员,fs:0(也可以“直接”访问) - 通过类似的东西ds:7efdd00,取决于操作系统版本等)

所以这是发生的事情:

  1. 前两个push为结构保留堆栈空间_EXCEPTION_REGISTRATION_RECORD

    1. 新的顶级处理程序
    2. 之前的顶级处理程序,直到现在 fs:[0]
  2. mov设定作为新的结构中的当前堆叠位置。当异常发生时,next现在将是第一个被调用的处理程序。

  3. int3立即触发异常(还有许多其他类型的异常触发器)。

  4. 当异常被触发时,Windows 将异常分派给第一个处理程序,如果没有处理,则将下一个处理程序分派,直到其中一个处理了它。

异常处理流程图

执行后

这是在 OllyDbg 1.10 下完成的。天啊。

由于我们想自己处理异常,我们不得不要求 OllyDbg 不要处理它们:

  1. 转到调试选项:Alt- O,选项卡Exceptions

  2. 取消选择 INT3 breaks

当异常被触发时,我们必须强制执行是通过异常完成的(见下文)。

这里有 3 种增加级别的方法,以安全地跟踪异常处理执行:

一步一步:手动设置断点

由于刚刚在堆栈上设置了处理程序,您可以手动设置断点然后运行。

  1. 在堆栈上选择新的处理程序地址

    堆栈上的新处理程序

  2. 右键单击或 F10

    • 选择 Follow in Dump
  3. 在转储窗口中,打开菜单(相同的快捷方式)

    • 选择BreakPoint,然后Hardware, on execution
  4. 执行:菜单Debug/Run/快捷方式F9/命令行g

  5. 会触发异常

  6. 执行异常处理:shortcut Shift- F9/ command-line ge

快捷方式:通过命令行执行直到异常处理程序

  • 由于地址在堆栈上,最简单的方法是通过命令行键入ge [esp+4],这意味着Go with Exceptions, 直到遇到堆栈上的第二个地址。因此,无需设置和取消设置断点。

    • 在更复杂的例子中,地址在堆栈上可能不再明显,那么绝对公式是ge ds:[fs:[0]+4],它只是从 TIB 中获取实际地址。

保持完全控制:打破 KiUserExceptionDispatcher

KiUserExceptionDispatcher是处理所有用户模式异常的 Windows API。在那里设置断点可以保证您保持完全控制 - 但是,您正处于 Windows API 的中间;)

在这种情况下,您可以要求 OllyDbg 跳过异常,因为在任何情况下您仍然会手动中断执行。您可能还想将它与脚本结合起来

当然,一些高级代码可能会在触发异常之前检查您是否在其上设置了断点。