Log in

View Full Version : SEH's in action


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?

autarky
May 29th, 2006, 05:28
Quote:
[Originally Posted by WaxfordSqueers]
1)what's with the data bytes at 401013? I see a lot of extraneos db's in disassemblies. Is it from the compiler?


0F0B decodes to UD2 according to Olly and the Intel documentation. The intel documentation has this to say:

"Generates an invalid opcode. This instruction is provided for software testing to explicitly
generate an invalid opcode. The opcode for this instruction is reserved for this purpose.
Other than raising the invalid opcode exception, this instruction is the same as the NOP instruction."

It is this that is causing the exception.

Quote:
[Originally Posted by WaxfordSqueers]
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.
?


Not quite. The context of the thread that caused the exception is referenced by the instruction:

mov ecx, [ebp+arg_8] ;(ecx -> CONTEXT)

You correctly intuit that it is the push 0's that result in the debug registers being overwritten - however, it is the pop dword ptr [ecx+X] that does the actual overwriting. You'd need to either nop all the pushes/pops, or nop the pops and add an add esp, 10h (the same as the code preceding it).

This also explains why there are only 5 push/pops to erase the debug registers 0-3 and 7 (which is the debug flags register) - the debug registers are in the structure referenced by ecx.

For a better understainding, check the MSDN documentation for a description of the exception handling function's prototype, and basic information about the data structures passed to it. The following is a good enough description of what the context structure will contain after an exception on an IA32 compatible processor (context's are architecture specific):

http://www.anticracking.sk/Articles/How_working_with_debug_breakpoints.txt

There are also some common anti-debugging ideas on that site (it is after all the home of SVK Protector).

Quote:
[Originally Posted by WaxfordSqueers]
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?


I have seen several Olly plugins (such as antiAnti) that can apparently stop the debug registers being modified. Try the following site:

http://tuts4you.com/ollyplugin/

It is possible (afaik) to write code to automatially do it, either by writing a driver or using a VectoredExceptionHandler, and setting a bit in the debug flags register so that an exception is generated whenever a debug register is about to be modified. I'm not sure if this would work in situations where the thread is to be scheduled, and the context loaded (as when an exception is generated) rather than the debug registers being modified at run time (eg by a device driver). Check the debugging section of the Intel Systems Programming Guide if you want to know more:

http://www.intel.com/design/pentium4/manuals/index_new.htm

WaxfordSqueers
May 29th, 2006, 11:14
Quote:
[Originally Posted by autarky]0F0B decodes to UD2 according to Olly and the Intel documentation. The intel documentation has this to say:
"Generates an invalid opcode.


thanks for the detailed and informative reply, autarky. It's interesting. They used a similar ploy in the Asprotected protection, only it was an XOR opcode that made no sense. It pays to look closely at the code around an SEH. Come to think of it, Neitsa must have put it in there. He's one of our resident gurus.

addendum: come to think of it deeper, I should have read Neitsa'a source code more closely. It's right there in the source: UD2. And it's well commented to boot.



Quote:
[Originally Posted by autarky]Not quite. The context of the thread that caused the exception is referenced by the instruction:

mov ecx, [ebp+arg_8] ;(ecx -> CONTEXT)


again!!...it was right there in the source code. I don't want to go reprinting Neitsa'a source without his permission. If I'd run the app through softice with the source enabled, it would have shown me that. I'll let myself off a bit in that it was very late at night and my eyes were sore from lack of sleep.

Quote:
[Originally Posted by autarky]You correctly intuit that it is the push 0's that result in the debug registers being overwritten - however, it is the pop dword ptr [ecx+X] that does the actual overwriting. You'd need to either nop all the pushes/pops, or nop the pops and add an add esp, 10h (the same as the code preceding it).thanks.
I was aware of the effect of the POPs since I've stepped through some sneaky tricks in self-modifying code. I was trying to make the point that the actual content of the debug registers had been pushed farther onto the stack and the 0's were being popped in their place.

If I just NOPed the PUSH 0's, wouldn't that do the same thing? The 0's wouldn't get PUSHed onto the stack and the debug values should be in the correct position when POPed.

Quote:
[Originally Posted by autarky]For a better understainding, check the MSDN documentation for a description of the exception handling function's prototype, and basic information about the data structures passed to it.
thanks for the info.
Quote:
[Originally Posted by autarky]I have seen several Olly plugins (such as antiAnti) that can apparently stop the debug registers being modified. Try the following site:
http://tuts4you.com/ollyplugin/


there are many things I have been intending to do but there doesn't seem to be enough time in a day for me to do it. I want to learn Olly, Masm and C++. I have avoided C++ due to the Greek they use to describe OOP. All that nonsense about abstracting common ideas and terms. It turns out abstraction has nothing to do with abstraction in the common usage of that word.

Here's a laugh, and a bit of a digression. After reading many authors on C++, I finally came across a book on C++ by the guy who invented it, Bjarne Stroustrup. It's the clearest explanation of C++ concepts I have ever read. Here's an example: "A class is a userdefined type". Why couldn't any other author have put it so concisely instead of obfuscating the meaning? Suddenly a light goes on...a class is a type, just like int, char or float. He gives the same concise definitions for constructors, destructors, objects and anything else I was thoroughly confused about.

He said one other thing very simply that turned lights on for me. After trudging through abstracted definitions of 'objects' by other authors, I came to this enlightenment by Stroustrop: "C++ retains C’s ability to deal efficiently with the fundamental objects of the hardware (bits, bytes, words, addresses, etc.). Now I have a concrete example of an object, specifically, a hardware object: bit's, bytes, words....I can relate to that. To anyone familiar with C++, they are probably wondering what the fuss is about. I couldn't for the life of me figure out why everything I read was so darned abstracted. What comes through to me now is that most authors probably don't get it themselves. They fumble with the definitions.

Back to the thread.

Quote:
[Originally Posted by autarky]It is possible (afaik) to write code to automatially do it....snip.... Check the debugging section of the Intel Systems Programming Guide if you want to know more:
I'm sure there is a way to write code and that's why I need to learn some basic languages like MASM and C++. Thanks for all your tips and URL's.

autarky
May 29th, 2006, 12:06
Quote:

I was aware of the effect of the POPs since I've stepped through some sneaky tricks in self-modifying code. I was trying to make the point that the actual content of the debug registers had been pushed farther onto the stack and the 0's were being popped in their place.

If I just NOPed the PUSH 0's, wouldn't that do the same thing? The 0's wouldn't get PUSHed onto the stack and the debug values should be in the correct position when POPed.


Sorry, I was being presumptive; though I didn't think of getting round it your way (which would be easier). However, you'd need to nop the add esp, 10h too, otherwise the debug register values you want will be off the bottom of the stack, so to speak (reminds me of an ancient DOS armour technique).

Another possibility for circumventing such techniques could be found using a Vectored Exception Handler. There are various documents on MSDN describing VEH, and about the relevant APIs - I've used it for a loader for a target that was packed with TELock (because I'm lazy). VEH callbacks are process wide, and are called before the SEH callbacks, so you would be able to save the original debug registers before any SEH could get its hands on them. You could even zero them, if the SEH was detecting on non-zero DRs. It's then a question if restoring them once the exception has been handled. I'll have a think on how that could be done.

Anyway, glad to be of help.

WaxfordSqueers
May 29th, 2006, 12:50
Quote:
[Originally Posted by autarky]you'd need to nop the add esp, 10h too, otherwise the debug register values you want will be off the bottom of the stack, so to speak (reminds me of an ancient DOS armour technique).
thanks for pointing that out. I was wondering about cleaning up the stack. If you go pushing data deeper into it, it would be wise to clean it up after you. I really need to cement the stack process in my head. I know a fair amount about it, but I have to put it all together.

Speaking of stacks, and the earlier reference to Bjarne Stroustroup's book on C++, he uses some examples in the intro part of the book about stack implementation. He explains the approach of the C++ language using those stack examples. It's pretty interesting stuff.

Quote:
[Originally Posted by autarky]Another possibility for circumventing such techniques could be found using a Vectored Exception Handler.....snip
thanks again for the info. I enjoy these sneaky methods (or should I say elegant?) methods for countering protections.

In a thread I was reading last night, there was a discussion about the implementation of DRM into mainstream processors, and how the focus may shift from software to hardware reversing. That kinda suits me because my expertise is in electronics/hardware. However, I'm hoping this Draconian, Orwellian, McCarthyist thinking will go with Bush when his term ends.

The hardware approach could be fun as well through rerouting busses into friendlier processors that are set up to decode Big Brother's code. Instead of softice, we'd have a DSP chip set up to analyze the code from a CD or DVD. I really think Intel would be nuts to go along with these right-wing loonies. When you consider what Sony did with rootkits before they were exposed, I think that's nothing compared to what malware and protection outfits will do with the DRM setup.