利用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 $
编译使用:
\masm32\bin\ml /c /coff antibpx1.asm
\masm32\bin\Link /SECTION:.text,ERW /SUBSYSTEM:WINDOWS antibpx1.obj
$ .586P
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE include e:\masm32\include\windows.inc
include e:\masm32\include\kernel32.inc
include e:\masm32\include\user32.inc
include e:\masm32\include\comctl32.inc includelib e:\masm32\lib\kernel32.lib
includelib e:\masm32\lib\user32.lib
includelib e:\masm32\lib\comctl32.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,
szNoFoundTracerMsg db '我没有发现被跟踪...:)',
szFoundTracerMsg db '我发现你了!....你在跟踪我....哈哈...',
szTitle db '样例:利用SEH技术进行反跟踪', SafeEsp dd
CallLevel dd
ReturnAddrEsp dd dup() hKernel32 dd
szKernel32Dll db 'KERNEL32.DLL',
szSleepEx db 'SleepEx',
szFormat db 'KERNEL32.SleepEx : %08lX',
szText db dup() .Code
assume fs:nothing
;---------------------------------------------主程序开始------------------------------------------------
Main:
; 建立异常处理机制:结构化异常处理
push xMyHandler
push fs:[]
mov fs:[],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,
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:[]
add esp,
invoke ExitProcess,
;---------------------------------------------主程序结束------------------------------------------------ ;--------------------------------------------异常处理函数------------------------------------------------
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,
jnz lm0_continue_search ; 如果异常进行展开,则不进行处理直接返回。
test [esi].ExceptionFlags,
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], ; 初始化 CALL层级
inc [edi].regEip
lm0_trap_it:or byte ptr [edi+].regFlag,01h ; 设置 TF 标志
lm0_modify_drx_reg:
mov [edi].iDr0,
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], ; 初始化CALL层级
and byte ptr [edi+].regFlag,00h ; 复位 TF 标志,停止单步自跟踪
jmp lm0_modify_drx_reg ; @@: lea eax,[ebx+] ; 获取下下一条要执行的指令地址到 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:[]之类指令
jz lm0_do_fs_instr
jmp lm0_trap_it ; 都不是以上的指令,则继续进行单步自跟踪 lm0_do_fs_instr: ;
mov al,byte ptr [ebx+]
and al,11100111b
cmp al,00000101b ; 判断下一条要执行的指令是否为 mov fs:[],reg 指令
jnz lm0_do_other_fs_instr
movzx eax,byte ptr [ebx+]
and eax,00011000b
shr eax,
not eax
and eax,00000011b
mov eax,[edi+eax*].regEbx
cmp eax,xMyHandler
jz @F
mov eax,[eax+]
mov [ApiHandler],eax
jmp lm0_skip_this_instr
@@: mov [ApiHandler],
lm0_skip_this_instr:
lea eax,[ebx+]
mov [edi].regEip,eax
jmp lm0_trip_it lm0_do_other_fs_instr: ; 针对其他修改FS:[x]的指令,改用调试寄存器断点跟踪
mov ebx,[CallLevel]
mov eax,[ReturnAddrEsp+ebx*]
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], ;
jnz lm0_bp_trace ; 对API函数内部的CALL调用不再进行单步自跟踪,
; 而改用调试寄存器断点自跟踪方式 inc [CallLevel] ; 下一步将执行 CALL 指令, CALL 层级 加一
mov ebx,[CallLevel]
mov eax,[edi].regEsp
sub eax, ; 计算 CALL 返回地址的CONTEXT.ESP堆栈指针
mov [ReturnAddrEsp+ebx*],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

利用SEH防范BP(int 3)断点的更多相关文章

  1. 利用c++编写bp神经网络实现手写数字识别详解

    利用c++编写bp神经网络实现手写数字识别 写在前面 从大一入学开始,本菜菜就一直想学习一下神经网络算法,但由于时间和资源所限,一直未展开比较透彻的学习.大二下人工智能课的修习,给了我一个学习的契机. ...

  2. 利用SEH进行代码混淆

    这几天在重看SEH机制,收获颇丰. 随手写了一个用SEH进行跳转的代码贴于此处以作纪念. 当发生异常,并捕捉了异常.在OS的异常处理机制下.会进入异常过滤函数. 过滤函数能够返回EXCEPTION_E ...

  3. PAT Advanced 1042 Shuffling Machine (20 分)(知识点:利用sstream进行转换int和string)

    Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techn ...

  4. 利用 gdb 探究main(int argc, char *argv[]){} 中的char *argv[]

    在 Linux 系统中编写小程序 代码如下 编译并采用gdb调试  在调试之前设置三个参数   a   bb   ccc 输入 start 执行代码到 return 0; 从这里可以看到 argc = ...

  5. 【系统篇】从int 3探索Windows应用程序调试原理

    探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令——int 3,也就是机器码0xCC,用于调试所用,当程序执行到int 3的时候会中断到调试器,如果程 ...

  6. INT 3 中断调试处理流程

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html INT 3 中断调试处理流程 一.调试器如何下INT 3 断点 1 ...

  7. [C++]深入解析结构化异常处理(SEH)

    http://www.cppblog.com/weiym/archive/2015/02/27/209884.html 尽管以前写过一篇SEH相关的文章<关于SEH的简单总结>, 但那真的 ...

  8. SEH

    @author: dlive SEH是Windows的异常处理机制,在程序源代码中使用__try,__catch,__finally关键字来具体实现. 但SEH与C++的try, catch异常处理不 ...

  9. “程序设计与算法训练”课程设计:“BP神经网络的实现”(C++类封装实现)

    一 题目: 71 BP神经网络的实现: 利用C++语言实现BP神经网络, 并利用BP神经网络解决螨虫分类问题: 蠓虫分类问题:对两种蠓虫(A与B)进行鉴别,依据的资料是触角和翅膀的长度,已知了9支Af ...

随机推荐

  1. android 职业 转行

    不知道多少人和我一样.学安卓安卓工作.成了一件很烦躁的事情.甚至迷茫.    起初学安卓,是因为安卓流行,所以有兴趣,想要学.那个时候想做一个应用,想对安卓手机有个了解,比如获取手机短信.没有太在意工 ...

  2. LeetCode(867)

    title: LeetCode(867) tags: Python Algorithm 题目描述 给定一个矩阵 A, 返回 A 的转置矩阵. 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索 ...

  3. [PA2014]Lustra

    [PA2014]Lustra 题目大意: 有n个工厂参加竞标.每个工厂能生产长度在\([a_i,b_i]\)之间,宽度在\([c_i,d_i]\)之间的镜子,镜子不可以旋转. 问是否有某个工厂能生产出 ...

  4. 微信公众号开发之通过获取token等信息

    <?php /** * 发送post请求 * @param string $url * @param string $param * @return bool|mixed */ function ...

  5. c c++ #define 定义假函数

    #define   Add(a,b)   ((a)+(b)) #define Max(a,b) ((a)>(b)?(a):(b)) 这就定义了一个假的函数 说白了就是字符串替换 这样在写代码时能 ...

  6. db2 load报文件系统满

    使用db2 load导入数据 数据量比较大时常常会报文件系统已满错误. 原因分析:导入表建有索引,在load的“索引复制”阶段会从系统临时表空间拷贝到目标表空间,导致系统临时表空间所在的文件系统满,l ...

  7. UltralEdit 替换回车换行符

    打开 Ue 工具,写下内容,如下图: 然后按 Ctrl + r,输入 ^p,点击按钮 “全部替换”, 如下图:

  8. 移动应用滑动屏幕方向判断解决方案,JS判断手势方向

    问题分类 滑动屏幕打开相应功能操作. 问题描述 1.用户手动滑动屏幕,根据滑动的方向,打开相应的功能(如:向上滑摇钱树经验明细,向下滑打开任务明细,向左滑打开聚宝盆物品查看等功能),滑动事件捕获问题. ...

  9. 分布式一致性hash算法

    写在前面  在学习Redis的集群内容时,看到这么一句话:Redis并没有使用一致性hash算法,而是引入哈希槽的概念.而分布式缓存Memcached则是使用分布式一致性hash算法来实现分布式存储. ...

  10. JSR 整理、翻译

    https://jcp.org/en/jsr/all https://github.com/search?l=Java&q=JSR&type=Repositories