反调试之去除硬件断点
反调试之去除硬件断点
首先介绍几个X86下调试寄存器D0…D7,已经没有D4,D5了在wiki上说是被D6,D7取代了。
D0…D3
Each of these registers contains the linear address associated with one of four breakpoint conditions. Each breakpoint condition is further defined by bits in DR7.
The debug address registers are effective whether or not paging is enabled. The addresses in these registers are linear addresses. If paging is enabled, the linear addresses are translated into physical addresses by the processor’s paging mechanism. If paging is not enabled, these linear addresses are the same as physical addresses.
Note that when paging is enabled, different tasks may have different linear-to-physical address mappings. When this is the case, an address in a debug address register may be relevant to one task but not to another. For this reason the x86 has both global and local enable bits in DR7. These bits indicate whether a given debug address has a global (all tasks) or local (current task only) relevance.
D6
The debug status register permits the debugger to determine which debug conditions have occurred. When the processor detects an enabled debug exception, it sets the low-order bits of this register (0,1,2,3) before entering the debug exception handler.
Note that the bits of DR6 are never cleared by the processor. To avoid any confusion in identifying the next debug exception, the debug handler should move zeros to DR6 immediately before returning.
D7
The low-order eight bits of DR7 (0,2,4,6 and 1,3,5,7) selectively enable the four address breakpoint conditions. There are two levels of enabling: the local (0,2,4,6) and global (1,3,5,7) levels. The local enable bits are automatically reset by the processor at every task switch to avoid unwanted breakpoint conditions in the new task. The global enable bits are not reset by a task switch; therefore, they can be used for conditions that are global to all tasks.
Bits 16-17 (DR0), 20-21 (DR1), 24-25 (DR2), 28-29 (DR3), define when breakpoints trigger. Each breakpoint has a two-bit entry that specifies whether they break on execution (00b), data write (01b), data read or write (11b). 10b is defined to mean break on IO read or write but no hardware supports it.[citation needed] Bits 18-19 (DR0), 22-23 (DR1), 26-27 (DR2), 30-31 (DR3), define how large an area of memory is watched by breakpoints. Again each breakpoint has a two-bit entry that specifies whether they watch one (00b), two (01b), eight (10b)[1] or four (11b) bytes.[2]
D7有点难看懂,所以我自己尝试总结一下
;******************************************
;coded by Hume,2K+
;《加密与解密(第四版)》
;(c) 看雪学院 www.kanxue.com 2000-2018
;******************************************
;例子1.演示在SEH回调函数中清空Dr寄存器以达到反调试的目的
;******************************************
include ..\asminc.h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.DATA
Text db "SEH程序没有运行!",0
TextSEH db "Hello,SEH!",0
Caption db "SEH",0
.DATA?
.code
_start:
assume fs:nothing
;------------------------------------------------
push offset _except_handler
push fs:[0]
mov fs:[0],esp
;---------------------------------------------------
mov esi,0
mov eax,[esi]
WouldBeOmit:
invoke MessageBox,0,addr Text,addr Caption,MB_OK ; 这一句永远无法被执行
;---------------------------------------------------
ExecuteHere:
invoke MessageBox,0,addr TextSEH,addr Caption,MB_OK
;--------------------------------------------------
pop fs:[0]
add esp,4
invoke ExitProcess,NULL
;-------------------------------------------------
_except_handler proc uses ebx pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
mov eax,pContext
Assume eax:ptr CONTEXT
lea ebx, ExecuteHere
mov [eax].regEip,ebx
xor ebx,ebx
mov [eax].iDr0,ebx
mov [eax].iDr1,ebx
mov [eax].iDr2,ebx
mov [eax].iDr3,ebx
mov [eax].iDr7,341
mov eax,0
ret
_except_handler endp
end _start
ba e1 401000
ba r2 40107e
DR0…DR7 | Values |
---|---|
DR0 | 401000 |
DR1 | 40107e |
DR2 | 0 |
DR3 | 0 |
DR6 | ffff4ff0 |
DR7 | 700105 |
Dr7 |----------------|----------------|
7 0 0 1 0 5h = 111 0000 0000 0001 0000 0101b
Dr7 (high)|0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0|0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1|(low)
16-17bits —>DR0—>00—>execution
18-19bits —>DR0—>00—>one bytes
20-21bits —>DR1—>11—>data read or write
22-23bits —>DR1—>01—>two bytes
0:000> bp ntdll!KiUserExceptionDispatcher
0:000> gn
Breakpoint 2 hit
eax=0019ffcc ebx=00364000 ecx=00401000 edx=00401000 esi=00401000 edi=00401000
eip=772242b0 esp=0019fa34 ebp=0019ff80 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!KiUserExceptionDispatcher:
0:000> dd esp
0:000> dt _CONTEXT 0019fa8c
ntdll!_CONTEXT
+0x000 ContextFlags : 0x1007f
+0x004 Dr0 : 0x401000
+0x008 Dr1 : 0x40107e
+0x00c Dr2 : 0
+0x010 Dr3 : 0
+0x014 Dr6 : 0xffff4ff0
+0x018 Dr7 : 0x700105
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : 0x2b
+0x090 SegFs : 0x53
+0x094 SegEs : 0x2b
+0x098 SegDs : 0x2b
+0x09c Edi : 0x401000
+0x0a0 Esi : 0x401000
+0x0a4 Ebx : 0x364000
+0x0a8 Edx : 0x401000
+0x0ac Ecx : 0x401000
+0x0b0 Eax : 0x19ffcc
+0x0b4 Ebp : 0x19ff80
+0x0b8 Eip : 0x401013
+0x0bc SegCs : 0x23
+0x0c0 EFlags : 0x246
+0x0c4 Esp : 0x19ff6c
+0x0c8 SegSs : 0x2b
+0x0cc ExtendedRegisters : [512] "???"
从中可见context已经封装了dr0…dr7
0:000> bp 401080
我在handler的返回的地方下了一个断点,看看seh执行完是否修改了调试寄存器
0:000> g
Breakpoint 3 hit
eax=00000000 ebx=00000000 ecx=00401051 edx=77238e90 esi=00000000 edi=00000000
eip=00401080 esp=0019f938 ebp=0019f958 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ClearDr+0x1080:
00401080 c21000 ret 10h
0:000> dt _CONTEXT 0019fa8c
ntdll!_CONTEXT
+0x000 ContextFlags : 0x1007f
+0x004 Dr0 : 0
+0x008 Dr1 : 0
+0x00c Dr2 : 0
+0x010 Dr3 : 0
+0x014 Dr6 : 0xffff4ff0
+0x018 Dr7 : 0x155
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : 0x2b
+0x090 SegFs : 0x53
+0x094 SegEs : 0x2b
+0x098 SegDs : 0x2b
+0x09c Edi : 0x401000
+0x0a0 Esi : 0x401000
+0x0a4 Ebx : 0x364000
+0x0a8 Edx : 0x401000
+0x0ac Ecx : 0x401000
+0x0b0 Eax : 0x19ffcc
+0x0b4 Ebp : 0x19ff80
+0x0b8 Eip : 0x40102d
+0x0bc SegCs : 0x23
+0x0c0 EFlags : 0x246
+0x0c4 Esp : 0x19ff6c
+0x0c8 SegSs : 0x2b
+0x0cc ExtendedRegisters : [512] "???"
context中封装的调试寄存器和eip被改了,如果恢复执行的话,在上级函数的帮助下这些修改就会成真,所以这操作挺骚的。不过也显而易见有缺陷。
第八章的异常处理勉强看完,有点爽。