📄 sehbpx.asm
字号:
;******************************************
;coded by ljtt
;******************************************
;演示检测BPX断点
;******************************************
;---------------------------------------AntiBpx1.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,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层级
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -