再谈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 on.
;   . all relevent state has already been saved
;   . user mode code always runs with ints on
;
; If caller is kernel mode, we want them off!
;   . some state still in registers, must prevent races
;   . kernel mode code can run with ints off
;
;
; Arguments:
;     eax - ServiceClass - which call is to be performed
;     ecx - Arg1 - generic first argument
;     edx - Arg2 - generic second argument

        test    dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
        jnz     kit03_30                ; fault occured in V86 mode => Usermode

        test    word ptr [ebp]+TsSegCs,MODE_MASK
        jz      kit03_10

        cmp     word ptr [ebp]+TsSegCs,KGDT_R3_CODE OR RPL_MASK
        jne     kit03_30

kit03_05:
        sti
kit03_10:


;
; Set up exception record and arguments for raising breakpoint exception
;

        mov     esi, ecx                ; ExceptionInfo 2
        mov     edi, edx                ; ExceptionInfo 3
        mov     edx, eax                ; ExceptionInfo 1

        mov     ebx, [ebp]+TsEip
        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了,有时也会蓝。

posted @ 2011-05-09 22:11  Russinovich`s Blog  阅读(2538)  评论(2编辑  收藏  举报