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)的主要内容,如果未能解决你的问题,请参考以下文章

04 异常的处理流程

代写python,代写python编程,python代写,python编程代写,留学生python代写

001--python全栈--基础知识--python安装

Python代写,Python作业代写,代写Python,代做Python

Python开发

Python,python,python