push next
push fs:[0]
mov fs:[0], esp
int3
...
next:
我看到
int3
发生了某些事情(错误),但我不明白为什么,以及如何在保持控制的同时遵循执行。#1 楼
TL; DR前3行设置了异常处理程序(“错误捕获器”)
int3
生成异常执行从
next
恢复>
解释
此技巧是(ab)使用结构化异常处理,一种定义异常处理程序的机制,通常由使用
try
/ catch
块的编译器定义。 > 在Windows的32位版本中,可以随时进行设置,而无需任何先决条件(除非二进制文件使用/ SafeSEH编译)。
异常处理程序的第一个元素链由线程信息块(TIB)的第一个成员指向,而又由线程环境块(TEB)的成员指向,由
fs:0
指向(也可以直接通过“ ds:7efdd00
”访问, 所以会发生以下情况:
前两个
push
为结构_EXCEPTION_REGISTRATION_RECORD
保留堆栈空间。 br /> t新的顶级处理器
以前的顶级处理器,直到现在位于
fs:[0]
,
mov
将当前堆栈位置设置为新结构。当发生异常时,next
将成为第一个被调用的处理程序。int3
立即触发一个异常(还有许多其他类型的异常触发器)。当触发异常时,Windows会将异常分派给
执行之后
完成此操作在OllyDbg 1.10下。 YMMV。
当我们想自己处理异常时,我们必须要求OllyDbg不要处理它们:
转到调试选项:Alt-O,选项卡
Exceptions
取消选择
INT3 breaks
当触发异常时,我们必须强制执行通过异常执行(请参见下文)。
以下是3种提高级别的方法,可安全地遵循异常处理的执行:
分步操作:手动设置断点
由于刚刚在堆栈上设置了处理程序,您可以手动设置一个断点然后运行。
在堆栈上选择新的处理程序地址
右键单击或F10
在转储窗口中选择
Follow in Dump
,打开菜单(相同的快捷方式)
选择
BreakPoint
,然后选择Hardware, on execution
执行:菜单
Debug/Run
/快捷键F9 /命令行g
异常将被触发
通过异常处理执行:快捷键Shift-F9 /命令行
ge
。快捷方式:通过命令行执行直到异常处理程序
因为地址在堆栈上,所以最简单的方法是通过命令行
ge [esp+4]
键入,即Go with Exceptions
,直到堆栈上的第二个地址为enco没事。因此,不需要设置和取消设置断点。在更复杂的示例中,如果地址在堆栈上不再明显,则绝对公式为
ge ds:[fs:[0]+4]
,它只是从TIB获取实际地址。 Windows API处理所有用户模式异常。在此处设置断点可以确保您完全控制-但是,您现在处于Windows API的中间;)在这种情况下,您可以要求OllyDbg跳过异常,因为您仍然会在任何情况下都要手动中断执行。您可能还希望将其与脚本结合使用。
当然,一些高级代码可能会在触发异常之前检查您是否在该断点上设置了断点。
评论
“在Windows的32位版本中,可以随时进行设置,而无需任何先决条件。”这不是很正确,这取决于可执行文件的编译方式,例如,如果使用SafeSEH ntdll!RtlDispatchatchException(IIRC)进行编译,则如果您动态注册了SEH处理程序,则会终止您的进程。
– newgre
13年4月23日在13:22
同样,一种非常常见的混淆技术是修改传递给SEH处理程序的CPU上下文的指令指针。因此,通常最好在KiUserExceptionDispatcher中的NtContinue调用之前放置一个断点。 IDAStealth可以自动为您完成此操作。
– newgre
13年4月23日在13:31
执行会在下一次继续执行,并且由于操作系统不会强迫您从异常处理程序中返回,因此该语句在技术上是正确的。实际上,这正是在CRT中实现C ++异常的方式。
– newgre
13年4月23日在13:34
不要忘记,任何已经注册的Vectored Exception Handler都会首先收到控制权。 SEH可能根本不会执行。
–彼得·弗里
13年4月23日在17:59
这是一个非常不错的文章,我很想看到SEHOP出于完整性的考虑而添加到此。另外,非常挑剔:当int3触发时,确实发生了中断,并且调用了中断处理程序,对吗?我知道在ImmunityDebugger中(以及在使用Windbg,IIRC进行内核调试时)不可能单步执行内核调用,但是我只是想澄清一下自己的理解。
–mrduclaw
13年4月26日在2:14
评论
SEH PoCs