在 32 位 Windows 二进制文件中,我看到以下代码:
push next
push fs:[0]
mov fs:[0], esp
int3
...
next:
我看到int3
(错误)发生了一些事情,但我不明白为什么,以及如何在保持控制的同时跟踪执行。
在 32 位 Windows 二进制文件中,我看到以下代码:
push next
push fs:[0]
mov fs:[0], esp
int3
...
next:
我看到int3
(错误)发生了一些事情,但我不明白为什么,以及如何在保持控制的同时跟踪执行。
前 3 行设置了一个异常处理程序(一个“错误捕捉器”)
在int3
产生异常
执行在 next
这个技巧是(ab)使用结构化异常处理,一种定义异常处理程序的机制,通常由编译器在使用try
/catch
块时。
在 32 位版本的 Windows 中,它们可以即时设置,无需任何预先要求(除非二进制文件是使用 /SafeSEH 编译的)。
异常处理程序链的第一个元素由线程信息块 (TIB)的第一个成员指向,又是线程环境块 (TEB)的成员,由fs:0
(也可以“直接”访问) - 通过类似的东西ds:7efdd00
,取决于操作系统版本等)
所以这是发生的事情:
前两个push
为结构保留堆栈空间_EXCEPTION_REGISTRATION_RECORD
。
fs:[0]
的mov
设定作为新的结构中的当前堆叠位置。当异常发生时,next
现在将是第一个被调用的处理程序。
int3
立即触发异常(还有许多其他类型的异常触发器)。
当异常被触发时,Windows 将异常分派给第一个处理程序,如果没有处理,则将下一个处理程序分派,直到其中一个处理了它。
这是在 OllyDbg 1.10 下完成的。天啊。
由于我们想自己处理异常,我们不得不要求 OllyDbg 不要处理它们:
转到调试选项:Alt- O,选项卡Exceptions
取消选择 INT3 breaks
当异常被触发时,我们必须强制执行是通过异常完成的(见下文)。
这里有 3 种增加级别的方法,以安全地跟踪异常处理执行:
由于刚刚在堆栈上设置了处理程序,您可以手动设置断点然后运行。
在堆栈上选择新的处理程序地址
右键单击或 F10
Follow in Dump
在转储窗口中,打开菜单(相同的快捷方式)
BreakPoint
,然后Hardware, on execution
执行:菜单Debug/Run
/快捷方式F9/命令行g
会触发异常
执行异常处理: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 跳过异常,因为在任何情况下您仍然会手动中断执行。您可能还想将它与脚本结合起来。
当然,一些高级代码可能会在触发异常之前检查您是否在其上设置了断点。