zoukankan      html  css  js  c++  java
  • 再谈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了,有时也会蓝。

  • 相关阅读:
    jenkins 安装插件失败
    win10 右键新建卡顿
    Linux发布java jar包
    Linux搭建java环境
    java代码检出打包
    虚拟机Vmware使用记录
    地图坐标
    vs2019 扩展工具
    服务器内网穿透
    intelliJ 软件项目打开运行
  • 原文地址:https://www.cnblogs.com/russinovich/p/2041628.html
Copyright © 2011-2022 走看看