Thursday, August 06, 2009

Gray Hat Python Chapter 3.4.2 Love, Part 1 (and some 3.4.1 pillow talk)

So, yeah, 3.4.2 didn't go well either. Going back to my write-up on Chapter 3.4.1, I realize I missed an error and as well propagated it:
It looks like self.context.Eip is causing some grief. Looking ahead, it looks like it's covered on page 48. Comment out the following:

self.context = self.get_thread_context(h_thread=self.h_thread)
self.context.Eip -= 1

kernel32.SetThreadContext(self.h_thread,byref(self.context))


self.context.Eip should have been able to be set to the CONTEXT() structure from my_debugger_defines. Since it's not being set, then something is amiss.

Here's the code for get_thread_context from the book:

def get_thread_context(self, thread_id=None, h_thread=None):

context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

# Obtain a handle to the thread
h_thread = self.open_thread(thread_id)
if kernel32.GetThreadContext(h_thread, byref(context)):
kernel32.CloseHandle(h_thread)
return context
else:
return False

Here's the code for get_thread_context from the src files:

def get_thread_context (self, thread_id=None,h_thread=None):

context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

# Obtain a handle to the thread
if h_thread is None:
self.h_thread = self.open_thread(thread_id)

if kernel32.GetThreadContext(self.h_thread, byref(context)):

return context
else:
return False


So, the book example blindly sets the local h_thread versus the revised code. Funny enough, the revised code I am assuming is assuming that the passed h_thread is also self.h_thread, since no latter assignment is made. The other difference is kernel32.CloseHandle() is called in the book example whilst not in the src code example.

There are two times that h_thread is already set for us: one in get_debug_event() and the other in exception_handler_breakpoint(). There are two times it is not set: bp_set_hw() and bp_del_hw(). So, we want to still test to see if h_thread is None and if so, set. If it isn't, well, then use it :-)

def get_thread_context (self, thread_id=None,h_thread=None):

context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS

# Obtain a handle to the thread
if h_thread is None:
h_thread = self.open_thread(thread_id)
self.h_thread = h_thread

if kernel32.GetThreadContext(h_thread, byref(context)):

return context
else:
return False

And, I'll remove the CloseHandle call for now. Looking at the functions where the handle is passed to us, exception_handler_breakpoint() would be very unhappy with us if we closed the handle prematurely. And, we'll set self.h_thread, so it's in the instance itself.

And, here's the run:

Enter the PID of the process to attach to: 3000
[*] Address of printf: 0x77c4186a
Event Code: 3 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 6 Thread ID: 3008
Event Code: 2 Thread ID: 1444
Event Code: 1 Thread ID: 1444
[*] Exception address: 0x7c90120e
[*] Hit the first breakpoint.
Event Code: 4 Thread ID: 1444
Event Code: 1 Thread ID: 3008
Traceback (most recent call last):
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_test.py", line 21, in
debugger.run()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 90, in run
self.get_debug_event()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 125, in get_debug_event
self.exception_handler_single_step()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 343, in exception_handler_single_step
continue_status = DBG_EXCEPTION_NOT_HANDLED
NameError: global name 'DBG_EXCEPTION_NOT_HANDLED' is not defined

DBG_EXCEPTION_NOT_HANDLED is not defined in my_debugger_defines. Put this below DBG_CONTINUE:

DBG_EXCEPTION_NOT_HANDLED = 0x80010001


Oh, also since you see my path, I'm running this in a VM, hence Administrator running all of this. Why not?! :-)

Next run:

Enter the PID of the process to attach to: 3068
[*] Address of printf: 0x77c4186a
Event Code: 3 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 6 Thread ID: 3076
Event Code: 2 Thread ID: 3140
Event Code: 1 Thread ID: 3140
[*] Exception address: 0x7c90120e
[*] Hit the first breakpoint.
Event Code: 4 Thread ID: 3140
Event Code: 1 Thread ID: 3076
Traceback (most recent call last):
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_test.py", line 21, in
debugger.run()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 90, in run
self.get_debug_event()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 125, in get_debug_event
self.exception_handler_single_step()
File "C:\Documents and Settings\Administrator\workspace\Grey Hat Python\src\my_debugger.py", line 346, in exception_handler_single_step
if self.bp_del_hw(slot):
UnboundLocalError: local variable 'slot' referenced before assignment


Here's the code snippet:

if self.context.Dr6 & 0x1 and self.hardware_breakpoints.has_key(0):
slot = 0
elif self.context.Dr6 & 0x2 and self.hardware_breakpoints.has_key(1):
slot = 1
elif self.context.Dr6 & 0x4 and self.hardware_breakpoints.has_key(2):
slot = 2
elif self.context.Dr6 & 0x8 and self.hardware_breakpoints.has_key(3):
slot = 3
else:
# This wasn't an INT1 generated by a hw breakpoint
continue_status = DBG_EXCEPTION_NOT_HANDLED

# now let's remove the breakpoint from the list
if self.bp_del_hw(slot):
continue_status = DBG_CONTINUE


I'm troubleshooting this. Throwing a print in there shows Dr6 as 4294905840 / 0xFFFF0FF0, which is the power-up state [1]. So, we're at 0, which seems to me that the register is not being set. Also, this shows a coding error. The conditional does not set slot and assumes 'slot' it's set. I'll ignore that issue. But, now, I gotta take off...


[1] Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3A: System Programming Guide, Table 9-1

1 comments:

MacFlecknoe said...

I am having issues with this method not returning ANY context data:

def get_thread_context(self, thread_id=None, h_thread=None):
context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
# obtain a handle to the thread
if h_thread is None:
h_thread = self.open_thread(thread_id)

if kernel32.GetThreadContext(h_thread, byref(context)):
#kernel32.CloseHandle(h_thread)
return context
else:
return False

The page 38 test returns empty register values:

[*] Dumping registers for thread ID: 0x00000158
[**] EIP: 0x00000000
[**] ESP: 0x00000000
[**] EBP: 0x00000000
[**] EAX: 0x00000000
[**] EBX: 0x00000000
[**] ECX: 0x00000000
[**] EDX: 0x00000000
END DUMP

I am runnig Windows 7 64 bit. Did you have similar issues? What OS are you running and if it is Windows 7 can you please preovide a copy of your code?

Blog Archive