2013-05-09 17 views
0

我正在閱讀'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完成。

+0

我有一個問題用相同的代碼,但在我的情況下,代碼編譯好,問題是:通過代碼印刷寄存器的內容永遠是:00000000 好像代碼只能在32位平臺上 – 2013-06-21 23:04:36

+0

你怎麼會去改變32位代碼在x64上運行?我們是否需要僅更新win32API函數調用和ctypes?或者它是導致這些與x64不兼容的Python代碼?我有興趣重新編寫本書的所有代碼作爲x64代碼作爲改進python技巧的副項目。 @ a.u.r – Info5ek 2013-08-04 04:04:40

回答

3

確認本書的代碼僅適用於32位平臺。此外,在書籍網站上提到的源代碼中存在一些錯誤,這些錯誤會阻止程序正常工作。如果您從網站下載源代碼,這些錯誤已被刪除。

如果你想獲得的代碼添加到您的機器上運行,並在運行64位,你可以下載「Windows XP模式」,這是一個虛擬的32位Windows XP環境中進行由微軟免費提供的。 http://www.microsoft.com/en-us/download/details.aspx?id=3702。在那裏安裝Python IDE,代碼應該運行。

+0

32bit?謝謝你的提升。我運行64並有一些問題。 – Vnge 2014-08-20 02:14:55

0

沒有爲在64位Windows上運行64位從蟒實例的調試器的解決方案。但是您應該堅持調試32位應用程序或實現64位調試器,64位32位寄存器之間有區別。

我添加了一些代碼,在64位系統上運行它。 1.您是否想在64位窗口上調試/運行32位應用程序。 Windows爲它使用Wow64,所以你必須使用一些在msdn上解釋的其他函數。

要測試進程運行在WOW 64 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()