Int3+pushfd/popfd 反调试不算一门新技术,最早见于 TTProtect,当时还引起看雪大
牛们的围观。然而,这项技术却没有因为岁月而褪色,它的踪迹,或者说是变体,至今还可
以在safengine上找到。那么,就让我们深入了解一下 Int3+pushfd/popfd反调试技术的前
世今生。
Int3+pushfd/popfd反调试技术其实分为两部分,第一部分是int3,也就是触发异常部
分。为了说清触发异常部分的作用,先得做一个实验。用原版OD载入 test.exe,F9,稍作运
行后 OD 将自动暂停(图1):

可以看到,Test 程序的核心部分,就是 int3+popfd。int3 触发了异常,当 OD 捕获异
常时,就暂停在 popfd 上。这个看似理所当然的结果,却道出了触发异常部分的作用:让
OD 暂停在 pushfd/popfd指令上。
这是异常部分一切工作的核心,只要能够达到这个效果,具体实现不必拘泥于 int3。
因为实际使用时,OD 如果设置了忽略int3 异常,那么暂停的位置就是int3而不是 popfd,
功夫就白费了。所以,要充分发挥想象力,灵活实现触发异常的方法,例如可以用 int1,
或者像 safengine那样利用硬件断点,将异常触发到底。
接着是第二部分,也就是pushfd/popfd,可以称之为硬断部分。这部分利用到OD的一
个特性:一旦遇到 pushfd/popfd 指令,OD 将会在被调试程序 eip+2 的地方,也即
pushfd/popfd的下一条指令设置临时的硬件断点:
00434E2B |. 8A840D CCFDFF>mov al, byte ptr [ebp+ecx-234]
00434E32 |. 3D 9C000000 cmp eax, 9C
00434E37 |. 74 0D je short 00434E46
00434E39 |. 8B95 68FAFFFF mov edx, [local.358]
00434E3F |. 3D 9D000000 cmp eax, 9D
00434E44 |. 75 17 jnz short 00434E5D
00434E46 |> 8B75 E8 mov esi, [local.6]
00434E49 |. 03F3 add esi, ebx
00434E4B |. C745 F8 02000>mov [local.2], 2
00434E52 |. 8935 30814D00 mov dword ptr [4D8130], esi
00434E58 |. E9 5C010000 jmp 00434FB9
这是OD 调试器的反汇编码。其中eax 在00434E2B处获取当前指令的操作码,如果操作
码为 0x9C,或者为0x9D,也即为pushfd或 popfd指令时,跳转到00434FB9。
00434FB9之后发生了很多事,我们只挑重要的看:
004352A3 |. 837D F4 00 cmp [local.3], 0
004352A7 |. 74 14 je short 004352BD
004352A9 |. 6A 00 push 0
004352AB |. 6A 00 push 0
004352AD |. 68 00500000 push 5000
004352B2 |. 56 push esi
004352B3 |. E8 A842FEFF call _Setbreakpointext
004352B8 |. 83C4 10 add esp, 10
004352BB |. EB 24 jmp short 004352E1
004352BD |> 68 00500000 push 5000
004352C2 |. 56 push esi
004352C3 |. E8 544CFEFF call _Tempbreakpoint
004352C8 |. 83C4 08 add esp, 8
004352CB |. EB 14 jmp short 004352E1
如无意外,被调用的不是Setbreakpointext函数而是Tempbreakpoint函数,这个函数
就是 OD 设置临时断点的地方。F7 跟进,我们就发现这次 OD是要设置硬件断点了:
00419F6B |> \81FE 00500000 cmp esi, 5000 |