Python WaitForDebugEvent & ContinueDebugEvent (Gray Hat Python)

人盡茶涼 提交于 2019-12-12 01:09:20

问题


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.


回答1:


It's confirmed that the code for this book only works on a 32 bit platform. Also, there are a few bugs in the source which are noted on the books website which will stop the programs from working. If you download the source from the site, these bugs have been removed.

If you want to get the code to run on your machine and you run x64, you can download "Windows XP mode" which is a virtual 32 bit windows XP environment made available for free by microsoft. http://www.microsoft.com/en-us/download/details.aspx?id=3702. Install your Python IDE there and the code should run.




回答2:


There is a solution for running the debugger from 64bit python instance on 64 bit windows. But you should stick to debugging 32 bit applications or implement 64 bit debugger, there is a difference between 64 a 32 bit registers ofc.

I added some code to run it under 64 bit system. 1. whe you wanna debug / run 32 bit application on 64 bit windows. Windows uses Wow64 for it so you have to use some other functions which are explained on msdn.

To test if process is run as 32 bit in wow64:

 i = c_int()
 kernel32.IsWow64Process(self.h_process,byref(i))
 if i:
     print('[*] 32 bit process')

Example:

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

For testing win errors use:

def testWinError():
    if kernel32.GetLastError() != 0:
        raise WinError()



回答3:


OpenProcess has another signature.

HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);

So you should change openprocess into

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


来源:https://stackoverflow.com/questions/16453691/python-waitfordebugevent-continuedebugevent-gray-hat-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!