I'm reading 'Gray Hat Python.'
There's an example where we get the thread of the process and dump all the register values.
I copied down the source from the book, and it won't work.
Here's a part of the source that I think is the trouble.
def run(self):
# Now we have to poll the debuggee for debugging events
while self.debugger_active == True:
self.get_debug_event()
def get_debug_event(self):
debug_event = DEBUG_EVENT()
continue_status = DBG_CONTINUE
if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
# We aren't going to build any event handlers
# just yet. Let's just resume the process for now.
# raw_input("Press a key to continue...")
# self.debugger_active = False
kernel32.ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, continue_status)
These two lines were used for previous examples and were commented out in this one.
# raw_input("Press a key to continue...")
# self.debugger_active = False
These two lines were commented out
The problem is when self.debugger_active is True,
it runs through the WaitForDebugEvent and ContinueDebugEvent.
But do not open thread or anything. It just runs 39 times which I have no idea why.
Here is the full source.
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger():
def __init__(self):
self.h_process = None
self.pid = None
self.debugger_active = False
def load(self, path_to_exe):
# dwCreation flag determines how to create the process
# set creation_flags = CREATE_NEW_CONSOLE if you want
# to see the calculator GUI
creation_flags = DEBUG_PROCESS
# instantiate the structs
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
# The following two options allow the started process
# to be shown as a separate window. This also illustrates
# how different settings in the STARTUPINFO struct can affect the debuggee
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
# We then initialize the cb variable in the STARTUPINFO struct
# which is just the size of the struct itself
startupinfo.cb = sizeof(startupinfo)
if kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)):
print "[*] We have successfully launched the process!"
print "[*] PID: %d" % process_information.dwProcessId
# Obtain a valid handle to the newly created process
# and store it for future access
self.h_process = self.open_process(process_information.dwProcessId)
else:
print "[*] Error: 0x%08x." % kernel32.GetLastError()
def open_process(self, pid):
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, pid, False)
return h_process
def attach(self, pid):
self.h_process = self.open_process(pid)
# We attempt to attach to the process
# if this fails we exit the call
if kernel32.DebugActiveProcess(pid):
self.debugger_active = True
self.pid = int(pid)
self.run()
else:
print "[*] Unable to attach to the process. Error: 0x%08x." % kernel32.GetLastError()
def run(self):
# Now we have to poll the debuggee for debugging events
self.count = 1;
while self.debugger_active == True:
self.get_debug_event()
def get_debug_event(self):
debug_event = DEBUG_EVENT()
continue_status = DBG_CONTINUE
if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):
# We aren't going to build any event handlers
# just yet. Let's just resume the process for now.
# raw_input("Press a key to continue...")
# self.debugger_active = False
kernel32.ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, continue_status)
print "Just finished ContinueDebugEvent %d" % self.count
self.count += 1
def detach(self):
if kernel32.DebugActiveProcessStop(self.pid):
print "[*] Finished debugging. Exiting..."
return True
else:
print "There was an error finishing debugging"
return False
def open_thread(self, thread_id):
print "open_thread"
h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
if h_thread is not None:
return h_thread
else:
print "[*] Could not obtain a valid thread handle."
return False
def enumerate_threads(self):
print "enumerate_threads"
thread_entry = THREADENTRY32()
thread_list = []
snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
if snapshot is not None:
# You have to set the size of the struct
# or the call will fail
thread_entry.dwSize = sizeof(thread_entry)
success = kernel32.Thread32First(snapshot, byref(thread_entry))
while success:
if thread_entry.th32OwnerProcessID == self.pid:
thread_list.append(thread_entry.th32ThreadID)
success = kernel32.Thread32Next(snapshot, byref(thread_entry))
kernel32.CloseHandle(snapshot)
return thread_list
else:
return False
def get_thread_context(self, thread_id):
print "get_thread_context"
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
ADDED
I debugged this a little bit, and found out that when get_thread_context
is called, it always returns false.
Also, at the end of the ContinueDebugEvent
, it does not call EXIT_THREAD_DEBUG_EVENT
. It just terminates the program right after calling EXEPTION_DEBUG_EVENT
.
I'm not sure if these two are related, but just as an update.
Thank you very much.
PART SOLUTION
I found one huge error in the code.
I don't know if the book has some kind of edited version or not.
Anyway, one of my problems was that get_thread_context
didn't work.
The source should change to
def get_thread_context(self, h_thread):
context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
if kernel32.GetThreadContext(h_thread, byref(context)):
kernel32.CloseHandle(h_thread)
return context
else:
return False
For some reason, the source in the book gave the thread handle as the parameter of open_thread
. You already had got the thread handle before and gave that as the parameter of get_thread_context
. So no need for that again.
===============
Still haven't found any solution for the other error.
Which the ContinueDebugEvent
won't finish with EXIT_THREAD_DEBUG_EVENT
.