WaxfordSqueers
May 29th, 2006, 04:18
hi...I thought I'd post in the Newbie section because I still consider myself an advanced newbie.
Also, SEH's are tricky for a Newbie and I am inviting comments to be sure I've got it right.
In this post of Neitsa, http://www.woodmann.com/forum/showpost.php?p=45492&postcount=6 , he kindly included the source and an exe file giving an example of an SEH (exception handler) being set up to erase a breakpoint being set in a debug register (DRx). Here's the disassembly of the exe file, EraseDrx.exe, found in the zip file of Neitsa's post:
00401000
.text:00401000 ; Segment type: Pure code
.text:00401000 _text segment para public 'CODE' use32
.text:00401000 assume cs:_text
.text:00401000 ;org 401000h
.text:00401000 assume es:nothing, ss:nothing, ds:nothing,
fs:nothing, gs:nothing
.text:00401000
.text:00401000 public start
.text:00401000 start:
.text:00401000 push offset sub_401026
.text:00401005 push large dword ptr fs:0
.text:0040100C mov large fs:0, esp
.text:0040100C ; ------------------------------------------------
.text:00401013 db 0Fh, 0Bh
.text:00401015 ; ------------------------------------------------
.text:00401015
.text:00401015 loc_401015: ; DATA XREF: sub_401026+2Eo
.text:00401015 fnop
.text:00401017 nop
.text:00401018 nop
.text:00401019 nop
.text:0040101A nop
.text:0040101B pop large dword ptr fs:0
.text:00401022 add esp, 4
.text:00401025 retn
.text:00401026
.text:00401026 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401026
.text:00401026 ; Attributes: bp-based frame
.text:00401026
.text:00401026 sub_401026 proc near ; DATA XREF: .text:00401000o
.text:00401026
.text:00401026 arg_8 = dword ptr 10h
.text:00401026
.text:00401026 push ebp
.text:00401027 mov ebp, esp
.text:00401029 mov ecx, [ebp+arg_8]
.text:0040102C push dword ptr [ecx+4]
.text:0040102F push dword ptr [ecx+8]
.text:00401032 push dword ptr [ecx+0Ch]
.text:00401035 push dword ptr [ecx+10h]
.text:00401038 add esp, 10h
.text:0040103B push 0
.text:0040103D push 0
.text:0040103F push 0
.text:00401041 push 0
.text:00401043 pop dword ptr [ecx+4]
.text:00401046 pop dword ptr [ecx+8]
.text:00401049 pop dword ptr [ecx+0Ch]
.text:0040104C pop dword ptr [ecx+10h]
.text:0040104F push 0
.text:00401051 pop dword ptr [ecx+18h]
.text:00401054 push offset loc_401015
.text:00401059 pop dword ptr [ecx+0B8h]
.text:0040105F mov eax, 0
.text:00401064 leave
.text:00401065 retn
.text:00401065 sub_401026 endp
.text:00401065
.text:00401065 ; -----------------------------------------
.text:00401066 align 200h
.text:00401066 _text ends
.text:00401066
.text:00401066
.text:00401066 end start
At address 401000, the address for the program SEH handler is pushed onto the stack. This is the routine written by the programmer to erase the breakpoints. The value in fs:0, which points to the 'per-thread exception handler' installed at runtime, is also saved on the stack with the next push.
The current top of stack is moved to fs:0. Neitsa's instructions were to set a breakpoint (bpx) at the address of one of the NOP's, in addresses 401017 to 40101A, and that the address used should show up in one of the debug registers, DRx.
I'm not too sure what throws the exception, but it seems from examining the code, that it's the breakpoint set in place of one of the NOP statements. Could someone verify this for me? According to Jeremy Gordon:
"Windows decides first whether it is an exception which it is willing to send to the program's exception handler. If so, if the program is being debugged, Windows will notify the debugger of the exception by suspending the program and sending EXCEPTION_DEBUG_EVENT (value 1h) to the debugger". Then he says:
"If the program is not being debugged or if the exception is not dealt with by the debugger, the system sends the exception to your per-thread exception handler if you have installed one. A per-thread handler is installed at run-time and is pointed to by the first dword in the Thread Information Block whose address is at FS:[0]"
Obviously, this program is being debugged, since it was written that way. Equally obvious is that the debugger doesn't handle the exception. Or does it? I'm not clear on how softice handles exceptions or what IceExt does with the UnhandledExceptionFilter. I know Sten claims the CC inserted by softice should be changed to NOP (90).
With apologies to Jeremy Gordon, I'll cut the rest of his explanation short. With the exception picked up, control is transferred to 401026, which is the program's exception handler. I'm not too clear on what is in the ECX register, but it seems the next four PUSHes are pushing the debug registers onto the stack. The next 4 PUSHes of 0's, effectively erase the debug registers, because they would have been POPed at 401043. Instead, 4 zero DWORDS will be POPed into the 4 debug registers.
According to Neitsa's ASM file commentary, the next PUSH 0, at 40104F erases the DR7 register, which would have been POPed at 401051. I'm not clear on this because only 4 values were pushed. Could someone explain? I'll PM Neitsa to tell him I referenced his app.
I have the following questions:
1)what's with the data bytes at 401013? I see a lot of extraneos db's in disassemblies. Is it from the compiler?
2)I assume that NOPing the 5 PUSH 0's would restore the debug registers. Is that right? I know someone will tell me to go try it.
3)In a protection like Asprotect, there are SEH's all through the app. Is there an easy way to detect and bypass the SEH debug register clearing code without tracing up to each one?

In this post of Neitsa, http://www.woodmann.com/forum/showpost.php?p=45492&postcount=6 , he kindly included the source and an exe file giving an example of an SEH (exception handler) being set up to erase a breakpoint being set in a debug register (DRx). Here's the disassembly of the exe file, EraseDrx.exe, found in the zip file of Neitsa's post:
00401000
.text:00401000 ; Segment type: Pure code
.text:00401000 _text segment para public 'CODE' use32
.text:00401000 assume cs:_text
.text:00401000 ;org 401000h
.text:00401000 assume es:nothing, ss:nothing, ds:nothing,
fs:nothing, gs:nothing
.text:00401000
.text:00401000 public start
.text:00401000 start:
.text:00401000 push offset sub_401026
.text:00401005 push large dword ptr fs:0
.text:0040100C mov large fs:0, esp
.text:0040100C ; ------------------------------------------------
.text:00401013 db 0Fh, 0Bh
.text:00401015 ; ------------------------------------------------
.text:00401015
.text:00401015 loc_401015: ; DATA XREF: sub_401026+2Eo
.text:00401015 fnop
.text:00401017 nop
.text:00401018 nop
.text:00401019 nop
.text:0040101A nop
.text:0040101B pop large dword ptr fs:0
.text:00401022 add esp, 4
.text:00401025 retn
.text:00401026
.text:00401026 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401026
.text:00401026 ; Attributes: bp-based frame
.text:00401026
.text:00401026 sub_401026 proc near ; DATA XREF: .text:00401000o
.text:00401026
.text:00401026 arg_8 = dword ptr 10h
.text:00401026
.text:00401026 push ebp
.text:00401027 mov ebp, esp
.text:00401029 mov ecx, [ebp+arg_8]
.text:0040102C push dword ptr [ecx+4]
.text:0040102F push dword ptr [ecx+8]
.text:00401032 push dword ptr [ecx+0Ch]
.text:00401035 push dword ptr [ecx+10h]
.text:00401038 add esp, 10h
.text:0040103B push 0
.text:0040103D push 0
.text:0040103F push 0
.text:00401041 push 0
.text:00401043 pop dword ptr [ecx+4]
.text:00401046 pop dword ptr [ecx+8]
.text:00401049 pop dword ptr [ecx+0Ch]
.text:0040104C pop dword ptr [ecx+10h]
.text:0040104F push 0
.text:00401051 pop dword ptr [ecx+18h]
.text:00401054 push offset loc_401015
.text:00401059 pop dword ptr [ecx+0B8h]
.text:0040105F mov eax, 0
.text:00401064 leave
.text:00401065 retn
.text:00401065 sub_401026 endp
.text:00401065
.text:00401065 ; -----------------------------------------
.text:00401066 align 200h
.text:00401066 _text ends
.text:00401066
.text:00401066
.text:00401066 end start
At address 401000, the address for the program SEH handler is pushed onto the stack. This is the routine written by the programmer to erase the breakpoints. The value in fs:0, which points to the 'per-thread exception handler' installed at runtime, is also saved on the stack with the next push.
The current top of stack is moved to fs:0. Neitsa's instructions were to set a breakpoint (bpx) at the address of one of the NOP's, in addresses 401017 to 40101A, and that the address used should show up in one of the debug registers, DRx.
I'm not too sure what throws the exception, but it seems from examining the code, that it's the breakpoint set in place of one of the NOP statements. Could someone verify this for me? According to Jeremy Gordon:
"Windows decides first whether it is an exception which it is willing to send to the program's exception handler. If so, if the program is being debugged, Windows will notify the debugger of the exception by suspending the program and sending EXCEPTION_DEBUG_EVENT (value 1h) to the debugger". Then he says:
"If the program is not being debugged or if the exception is not dealt with by the debugger, the system sends the exception to your per-thread exception handler if you have installed one. A per-thread handler is installed at run-time and is pointed to by the first dword in the Thread Information Block whose address is at FS:[0]"
Obviously, this program is being debugged, since it was written that way. Equally obvious is that the debugger doesn't handle the exception. Or does it? I'm not clear on how softice handles exceptions or what IceExt does with the UnhandledExceptionFilter. I know Sten claims the CC inserted by softice should be changed to NOP (90).
With apologies to Jeremy Gordon, I'll cut the rest of his explanation short. With the exception picked up, control is transferred to 401026, which is the program's exception handler. I'm not too clear on what is in the ECX register, but it seems the next four PUSHes are pushing the debug registers onto the stack. The next 4 PUSHes of 0's, effectively erase the debug registers, because they would have been POPed at 401043. Instead, 4 zero DWORDS will be POPed into the 4 debug registers.
According to Neitsa's ASM file commentary, the next PUSH 0, at 40104F erases the DR7 register, which would have been POPed at 401051. I'm not clear on this because only 4 values were pushed. Could someone explain? I'll PM Neitsa to tell him I referenced his app.
I have the following questions:
1)what's with the data bytes at 401013? I see a lot of extraneos db's in disassemblies. Is it from the compiler?
2)I assume that NOPing the 5 PUSH 0's would restore the debug registers. Is that right? I know someone will tell me to go try it.

3)In a protection like Asprotect, there are SEH's all through the app. Is there an easy way to detect and bypass the SEH debug register clearing code without tracing up to each one?