中断处理例程,再谈Patch int 3 中断例程反调试

上篇文章Patch Intel int 3断点指令的功能中谈到利用int 3反调试方法,今天想更深入的谈谈关于int 3反调试的方法。
在上篇文章中的方法过于简单直接就返回了,这样容易被发现和恢复。我需要的是更加不容易被发现的方法。
我先把内核当中int 3的中断处理例程贴出来:
public _KiTrap03 _KiTrap03 proc push 0 ; push dummy error code ENTER_TRAP kit3_a, kit3_t cmp ds:_PoHiberInProgress, 0 jnz short kit03_01 lock inc ds:_KiHardwareTrigger ; trip hardware analyzer kit03_01: mov eax, BREAKPOINT_BREAK KiTrap03DebugService: ; ; If caller is user mode, we want interrupts back _disibledevent=> dec ebx ; (ebx)-> int3 instruction mov ecx, 3 mov eax, STATUS_BREAKPOINT call CommonDispatchException ; Never return kit03_30: ; Check to see if this process is a vdm mov ebx,PCR[PcPrcbData+PbCurrentThread] mov ebx,[ebx]+ThApcState+AsProcess test byte ptr [ebx]+PrVdmFlag,0fh ; is this a vdm process? jz kit03_05 stdCall _Ki386VdmReflectException_A, <03h> test ax,0FFFFh jz Kit03_10 jmp _KiExceptionExit _KiTrap03 endp
看了上面的代码,我发现把dec ebx这行nop掉也能起到很好的效果,为什么呢?
因为当CPU执行完int 3指令之后,对于原先没有下断点的汇编代码而言,这时的EIP是指向了这个汇编指令第二个字节,这样一来,一条完整的汇编代码被打破,因此要通过dec 减1的方法,向上移动一个字节,这样做可以让调试器停在被下断点的地方,而不是下断点的位置加1的地方。如果没有减1,那么被下断点的地方的指令被打破了,如果不是单字节的指令,下次运行一定会Crash。
不过,我用了更狠的方法让程序直接跑飞掉
---------------------------------------------------------------------
;小汇编之前的正常的代码
804dfb3c 4b dec ebx 804dfb3d b903000000 mov ecx,3 804dfb42 b803000080 mov eax,80000003h 804dfb47 e85af8ffff call nt!CommonDispatchException (804df3a6) 804dfb4c 648b1d24010000 mov ebx,dword ptr fs:[124h] 804dfb53 8b5b44 mov ebx,dword ptr [ebx+44h] 804dfb56 83bb5801000000 cmp dword ptr [ebx+158h],0
---------------------------------------------------------------------
;开始小汇编,我这儿把eip直接加10h,这样调试器就指飞了。当然也可以是其它的代码,反正就是让调试器跑飞。
kd> a 804dfb3c 804dfb3c add ebx, 10
804dfb3f mov ecx,3
804dfb44 mov eax, 80000003
804dfb49 call 804df3a6
kd> u 804dfb3c nt!KiTrap03+0x9e: 804dfb3c 83c310 add ebx,10h; 加10h了 当然也可以是其它的代码 804dfb3f b903000000 mov ecx,3 804dfb44 b803000080 mov eax,80000003h 804dfb49 e858f8ffff call nt!CommonDispatchException (804df3a6)
---------------------------------------------------------------------
还有一个最直接的方法就是替换掉IDT中断表中的int 3的中断处理例程,指向我们自已的中断处理例程。但是这个方法太明显了。而且还涉及到多核CPU的问题,CPU当中的每个核都会有独立的IDT表,需要全部替换掉。
如果上int 3反调试的最终的效果是:
1. ring3调试器
如果是在ring3层下软件断点,并执行到了,直接跑飞了或程序崩溃了
2. ring0调试器
如果int 3直接返回了,那么在内核调试器就不能break了,有时也会蓝。
Tags:  中断指令int int中断 int3中断 中断例程 中断处理例程

延伸阅读

最新评论

发表评论