zoukankan      html  css  js  c++  java
  • 利用SEH防范BP(int 3)断点

    利用SEH技术实现反跟踪,这个方法比单纯用判断API函数第一个字节是否为断点更加有效,可以防止在API函数内部的多处地址设置断点

    通过int 3指令故意产生一个异常,从而让系统转入自己的异常处理函数,修改CONTEXT结构的regFlag中的TF位设置为1,并且将ContextFlags修改为CONTEXT_NULL,那么当程序恢复执行时,标志寄存器TF位也将为1,这样当程序执行一条指令后,将产生EXCEPTION_SINGLE_STEP异常,系统将再次转出我们的异常处理函数中

    如果每次对EXCEPTION_SINGLE_STEP异常的处理中把CONTEXT结构的regFlag中的TF位设置为1,那么程序就如同我们单步执行程序的效果一样

    此时可以在EXCEPTION_SINGLE_STEP异常处理中判断当前IP处的自己是否为CC(INT 3)即可

    ;******************************************
    ;coded by 
    ;******************************************
    ;演示检测BPX断点
    ;******************************************
    ;---------------------------------------asm------------------------------------------------
    COMMENT    $
        编译使用:
        masm32inml /c /coff antibpx1.asm
        masm32inLink /SECTION:.text,ERW /SUBSYSTEM:WINDOWS antibpx1.obj
    $
    
    .586P
    .MODEL FLAT,STDCALL
    OPTION CASEMAP:NONE
    
    include        e:masm32includewindows.inc
    include        e:masm32includekernel32.inc
    include        e:masm32includeuser32.inc
    include        e:masm32includecomctl32.inc
    
    includelib    e:masm32libkernel32.lib
    includelib    e:masm32libuser32.lib
    includelib    e:masm32libcomctl32.lib
    
    .Data                                        
    szDebugMsg            db    0Dh,0Ah,0Dh,0Ah
                        db    '你可以通过在以下API函数中设置断点来进行测试:'
                        db    0Dh,0Ah,0Dh,0Ah
                        db    'MessageBoxA',0Dh,0Ah,'MessageBeep',0Dh,0Ah
                        db    0Dh,0Ah,0Dh,0Ah,0
    szNoFoundTracerMsg    db    '我没有发现被跟踪...:)',0
    szFoundTracerMsg    db    '我发现你了!....你在跟踪我....哈哈...',0
    szTitle                db    '样例:利用SEH技术进行反跟踪',0
    
    SafeEsp                dd    0
    CallLevel            dd    0
    ReturnAddrEsp        dd    255 dup(0)
    
    hKernel32            dd    0
    szKernel32Dll        db    'KERNEL32.DLL',0
    szSleepEx            db    'SleepEx',0
    szFormat            db    'KERNEL32.SleepEx : %08lX',0
    szText                db    255 dup(0)
    
    
    .Code
                assume    fs:nothing
    ;---------------------------------------------主程序开始------------------------------------------------
    Main:
                ; 建立异常处理机制:结构化异常处理
                push    xMyHandler
                push    fs:[0]
                mov        fs:[0],esp            ; 
                mov        [SafeEsp],esp
    
                invoke    MessageBoxA,NULL,addr szDebugMsg,addr szTitle,MB_OK
    
                ; 故意产生一个异常
                int        3h                    ; 异常!!将被系统捕获,系统将调用我们的异常处理过程 xApiHandler
                nop
                ; 运行在 start_anti_trace 到 stop_anti_trace 之间的代码时,都处在
                ; 程序通过SEH机制建立的单步调试状态,程序将对每一条指令进行识别(包括API函数中的指令),
                ; 如果这些指令中存在断点,都将被程序发现。
    start_anti_trace:    ;===反跟踪开始===
                invoke    MessageBeep,100
                invoke    LoadLibraryA,addr szKernel32Dll
                mov        [hKernel32],eax
                invoke    GetProcAddress,[hKernel32],addr szSleepEx
                invoke    wsprintf,addr szText,addr szFormat,eax
                invoke    MessageBoxA,NULL,addr szText,addr szTitle,MB_OK
    stop_anti_trace:    ;===反跟踪结束===
    
                ; 如果在以上进行反跟踪的代码执行中没有设置断点,程序将执行到此处,
                ; 并且显示"没有发现跟踪者...:)"的提示信息
                invoke    MessageBoxA,NULL,addr szNoFoundTracerMsg,addr szTitle,MB_OK
                jmp        stop_self_trace_addr
    found_tracer:
                ; 如果在以上进行反跟踪的代码执行中发现设置断点,程序将执行到此处,
                ; 并且显示"我发现你了....!"等提示信息(可能仅在此测试样例中我会这样做 :)
                invoke    MessageBoxA,NULL,addr szFoundTracerMsg,addr szTitle,MB_OK
    
    stop_self_trace_addr:
                ; 解除自己建立的SEH结构化异常处理,然后结束进程
                mov        esp,[SafeEsp]
                pop        fs:[0]
                add        esp,4
                invoke    ExitProcess,0
    ;---------------------------------------------主程序结束------------------------------------------------
    
    ;--------------------------------------------异常处理函数------------------------------------------------
    xMyHandler    proc    C uses ebx esi edi pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
                mov        esi,pExcept
                assume    esi:ptr EXCEPTION_RECORD
                mov        edi,pContext
                assume    edi:ptr CONTEXT
    
                ; 如果发生严重错误,则不进行处理直接返回,从而转向下一级异常处理程序
                test    [esi].ExceptionFlags,1
                jnz        lm0_continue_search
    
                ; 如果异常进行展开,则不进行处理直接返回。
                test    [esi].ExceptionFlags,6
                jnz        lm0_unwind
    
                ; 对"软断点异常"进行处理
                cmp        [esi].ExceptionCode,EXCEPTION_BREAKPOINT
                jz        lm0_start_self_trace
    
                ; 对"单步异常"进行处理
                cmp        [esi].ExceptionCode,EXCEPTION_SINGLE_STEP
                jz        lm0_self_trace
    
                ; 其他情况,都直接返回,转向下一级异常处理程序
    lm0_continue_search:
    lm0_unwind:    mov        eax,ExceptionContinueSearch
                jmp        lm0_ret
    
    lm0_start_self_trace:
                ; 开始启动单步自跟踪,即初始化变量、设置TF标志等
                ;mov        [CallLevel],0                    ; 初始化 CALL层级  
                inc         [edi].regEip
    lm0_trap_it:or        byte ptr [edi+1].regFlag,01h    ; 设置 TF 标志
    lm0_modify_drx_reg:
                mov        [edi].iDr0,0
                and        [edi].iDr6,0FFFF0FF0h
                mov        [edi].iDr7,0h                    ; 清除调试寄存器设置的信息
                mov        [edi].ContextFlags,CONTEXT_FULL OR CONTEXT_DEBUG_REGISTERS
                jmp        lm0_continue_exec
    
    lm0_self_trace:
                ; 判断是否自跟踪到达结束地址,是,则停止单步自跟踪
                mov        ebx,[edi].regEip
                cmp        ebx,stop_anti_trace
                jnz        @F                                ; 不是,则跳转
                mov        [CallLevel],0                    ; 初始化CALL层级
                and        byte ptr [edi+1].regFlag,00h    ; 复位 TF 标志,停止单步自跟踪
                jmp        lm0_modify_drx_reg                ; 
    
    @@:            lea        eax,[ebx+5]                        ; 获取下下一条要执行的指令地址到 EAX 寄存器
                cmp        byte ptr [ebx],0E8h                ; 判断下一条要执行的指令是否为 CALL x 指令
                jz        lm0_do_call_instr
                inc        eax
                cmp        word ptr [ebx],015FFh            ; 判断下一条要执行的指令是否为 CALL [x] 指令
                jz        lm0_do_call_instr
                cmp        byte ptr [ebx],0C2h                ; 判断下一条要执行的指令是否为 ret n 指令
                jz        lm0_do_ret_instr
                cmp        byte ptr [ebx],0C3h                ; 判断下一条要执行的指令是否为 retn 指令
                jz        lm0_do_ret_instr
                cmp        byte ptr [ebx],0CCh                ; 判断下一条要执行的指令是否为 INT 3h 指令
                jz        lm0_do_int3_instr
                cmp        word ptr [ebx],08964h            ; 判断下一条要执行的指令是否为修改FS:[0]之类指令
                jz        lm0_do_fs_instr
                jmp        lm0_trap_it                        ; 都不是以上的指令,则继续进行单步自跟踪
    
    lm0_do_fs_instr:                                    ; 
                mov        al,byte ptr [ebx+2]
                and        al,11100111b
                cmp        al,00000101b                    ; 判断下一条要执行的指令是否为 mov fs:[0],reg 指令
                jnz        lm0_do_other_fs_instr
                movzx    eax,byte ptr [ebx+2]
                and        eax,00011000b
                shr        eax,3
                not        eax
                and        eax,00000011b
                mov        eax,[edi+eax*4].regEbx
                cmp        eax,xMyHandler
                jz        @F
                mov        eax,[eax+4]
                mov        [ApiHandler],eax
                jmp        lm0_skip_this_instr
    @@:            mov        [ApiHandler],0
    lm0_skip_this_instr:
                lea        eax,[ebx+7]
                mov        [edi].regEip,eax
                jmp        lm0_trip_it
    
    
    lm0_do_other_fs_instr:                                ; 针对其他修改FS:[x]的指令,改用调试寄存器断点跟踪
                mov        ebx,[CallLevel]
                mov        eax,[ReturnAddrEsp+ebx*4]
                mov        eax,[eax]                        ; 取得最后一个CALL调用的返回地址
                dec        [CallLevel]
    lm0_bp_trace:
                mov        [edi].iDr0,eax                    ; 在CALL指令的返回地址处设置调试寄存器断点
                and        [edi].iDr6,0FFFF0FF0h
                mov        [edi].iDr7,155h
                mov        [edi].ContextFlags,CONTEXT_FULL OR CONTEXT_DEBUG_REGISTERS
                jmp        lm0_continue_exec                ; 继续
    
    lm0_do_int3_instr:
                mov        [edi].regEip,found_tracer        ; 发现设置API函数断点,则修改CONTEXT.EIP
                mov        eax,[SafeEsp]
                mov        [edi].regEsp,eax                ; 修改CONTEXT.ESP
                jmp        lm0_modify_drx_reg                ; 
    
    lm0_do_ret_instr:
                dec        [CallLevel]                        ; 下一步将执行 ret 指令, CALL层级 减一
                jmp        lm0_trap_it                        ; 继续进行单步自跟踪
    
    lm0_do_call_instr:
                ; 通过判断CALL层级,可以知道是否已经执行进入到API函数内
                cmp        [CallLevel],0                    ; 
                jnz        lm0_bp_trace                    ; 对API函数内部的CALL调用不再进行单步自跟踪,
                                                        ; 而改用调试寄存器断点自跟踪方式
    
                inc        [CallLevel]                        ; 下一步将执行 CALL 指令, CALL 层级 加一
                mov        ebx,[CallLevel]
                mov        eax,[edi].regEsp
                sub        eax,4                            ; 计算 CALL 返回地址的CONTEXT.ESP堆栈指针
                mov        [ReturnAddrEsp+ebx*4],eax        ; 保存
                jmp        lm0_trap_it                        ; 继续进行单步自跟踪
    
    lm0_continue_exec:
                mov        eax,ExceptionContinueExecution
    lm0_ret:    ret
    xMyHandler    endp
    
    End Main                        ;End of code, Main is the entrypoint
  • 相关阅读:
    React
    移动端
    Flask 框架小记
    PyTorch 学习
    CNN 小结
    Django 环境下常用的模型设计
    Linux用户和用户组
    Linux下查看进程的命令输出的内容解释
    linux下配置tomcat开机自启动
    商业智能概述
  • 原文地址:https://www.cnblogs.com/qintangtao/p/7156875.html
Copyright © 2011-2022 走看看