我正在閱讀'Gray Hat Python'。Python WaitForDebugEvent&ContinueDebugEvent(Gray Hat Python)
有一個例子,我們得到進程的線程並轉儲所有的寄存器值。
我抄下了本書的源代碼,它不起作用。
這是我認爲是麻煩的一部分來源。
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)
這兩行用於前面的例子,並在這一行中被註釋掉。
# raw_input("Press a key to continue...")
# self.debugger_active = False
這兩條線被註釋掉 問題是,當self.debugger_active爲True, 它通過WaitForDebugEvent和ContinueDebugEvent運行。
但是不要打開線程或任何東西。它只運行了39次,我不知道爲什麼。
這裏是完整的來源。
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
我這個調試一點點,並發現,當get_thread_context
被調用,它始終返回false。
此外,在ContinueDebugEvent
的末尾,它不稱爲EXIT_THREAD_DEBUG_EVENT
。它在調用EXEPTION_DEBUG_EVENT
之後立即終止程序。
我不確定這兩者是否相關,但只是作爲更新。
非常感謝。
部件解決方案
我在代碼中發現了一個巨大的錯誤。
我不知道這本書是否有某種編輯版本。
無論如何,我的問題之一是,get_thread_context
沒有奏效。
來源應該改爲
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
出於某種原因,在書源給線程處理作爲open_thread
參數。您之前已經獲得了線程句柄,並將其作爲參數get_thread_context
。所以再也不需要這個了。
=============== 還沒有找到任何解決方案的其他錯誤。 其中ContinueDebugEvent
將不會與EXIT_THREAD_DEBUG_EVENT
完成。
我有一個問題用相同的代碼,但在我的情況下,代碼編譯好,問題是:通過代碼印刷寄存器的內容永遠是:00000000 好像代碼只能在32位平臺上 – 2013-06-21 23:04:36
你怎麼會去改變32位代碼在x64上運行?我們是否需要僅更新win32API函數調用和ctypes?或者它是導致這些與x64不兼容的Python代碼?我有興趣重新編寫本書的所有代碼作爲x64代碼作爲改進python技巧的副項目。 @ a.u.r – Info5ek 2013-08-04 04:04:40