Python WaitForDebugEvent 和 ContinueDebugEvent(灰帽 Python)
Posted
技术标签:
【中文标题】Python WaitForDebugEvent 和 ContinueDebugEvent(灰帽 Python)【英文标题】:Python WaitForDebugEvent & ContinueDebugEvent (Gray Hat Python) 【发布时间】:2013-05-03 10:50:32 【问题描述】:我正在阅读“灰帽 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
添加
我调试了一下,发现当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
结束。
【问题讨论】:
我在使用相同的代码时遇到问题,但在我的情况下,代码编译得很好,问题是:代码打印的寄存器内容始终是:0x00000000 看起来代码有效仅在 32 位平台上 您将如何更改 32 位代码以在 x64 上运行?我们只需要更新 win32API 函数调用和 ctypes 吗?还是 Python 代码导致这些与 x64 不兼容?我有兴趣将本书的所有代码重做为 x64 代码作为辅助项目,以提高 Python 技能。 @a.u.r 【参考方案1】:OpenProcess 有另一个签名。
HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);
所以你应该把openprocess改成
def open_process(self, pid):
# h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, pid, False)
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
return h_process
【讨论】:
【参考方案2】:有一个解决方案可以在 64 位窗口上从 64 位 python 实例运行调试器。但是你应该坚持调试 32 位应用程序或实现 64 位调试器,64 和 32 位寄存器之间存在差异。
我添加了一些代码以在 64 位系统下运行它。 1. 如果您想在 64 位窗口上调试/运行 32 位应用程序。 Windows 使用 Wow64,因此您必须使用 msdn 上解释的其他一些功能。
在 wow64 中测试进程是否以 32 位运行:
i = c_int()
kernel32.IsWow64Process(self.h_process,byref(i))
if i:
print('[*] 32 bit process')
例子:
def wow64_get_thread_context(self,thread_id=None,h_thread=None):
context = CONTEXT()
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
if h_thread is None:
h_thread = self.open_thread(thread_id)
if kernel32.Wow64SuspendThread(h_thread) != -1:
if kernel32.Wow64GetThreadContext(h_thread,byref(context)) != 0:
kernel32.ResumeThread(h_thread)
kernel32.CloseHandle(h_thread)
return context
else:
testWinError()
return False
else:
testWinError()
return False
为了测试获胜错误,请使用:
def testWinError():
if kernel32.GetLastError() != 0:
raise WinError()
【讨论】:
【参考方案3】:已确认本书的代码仅适用于 32 位平台。此外,书籍网站上指出的源代码中存在一些错误,这些错误将阻止程序运行。如果您从该站点下载源代码,这些错误已被删除。
如果您想让代码在您的机器上运行并运行 x64,您可以下载“Windows XP 模式”,这是微软免费提供的虚拟 32 位 Windows XP 环境。 http://www.microsoft.com/en-us/download/details.aspx?id=3702。在那里安装你的 Python IDE,代码应该会运行。
【讨论】:
32 位?感谢您的提醒。我正在运行 64 并且遇到了一些问题。以上是关于Python WaitForDebugEvent 和 ContinueDebugEvent(灰帽 Python)的主要内容,如果未能解决你的问题,请参考以下文章
代写python,代写python编程,python代写,python编程代写,留学生python代写