在學習GrayHatPython構建Window調試器過程中遇到的問題

編程環境:PyCharm 2017.1.3
Python 3.6.0

參考教程:《Python灰帽子》(Justin Seitz著)

暑期自學《Python灰帽子》的過程中在掌握基本理論知識後學習第三章的過程中一上手就遇到了下面的異常,稱之爲異常是因爲我編寫的代碼與書中所寫無異,考慮到Python2.x與3.x版本之間的差異修改了部分函數,測試的時候卻出現了問題。一再檢查調試問題沒有得到解決,故將其中信息列舉在此,希望可以從互聯網上得到幫助,或者自己在未來解決問題後可以來填坑。
本頁的所有代碼可以在我的[Github對應倉庫](https://github.com/LicheeGit/PythonProject/tree/master/GrayHatPython)找到
首先是兩個python腳本文件——my_debugger.py及my_debugger_defines.py。
# my_debugger.py
from ctypes import *
# from GrayHatPython.my_debugger_defines import *
from my_debugger_defines import *
# -*- coding: utf-8 -*-

kernel32 = windll.kernel32


class debugger():
    def __init__(self):
        pass

    def load(self, path_to_exe):
        # 參數 dwCreationFlags中的標誌位控制着進程的創建方式。
        # 若希望新創建的進程獨佔一個新的控制檯窗口,而不是與父進程共用同一個控制檯
        # 可以加上標誌位CREATE_NEW_CONSOLE

        creation_flags = DEBUG_PROCESS

        # 實例化之前定義的結構體
        startupinfo = STARTUPINFO()
        process_information = PROCESS_INFORMATION()

        '''
        在以下兩個成員變量的共同作用下,新建進程將在一個單獨的窗體中被顯示,
        可以通過改變結構體STARTUPINFO中的各成員變量的值來控制debugger進程的行爲
        '''

        startupinfo.dwFlags = 0x1
        startupinfo.wShowWindow = 0x0

        # 設置結構體STARTUPINFO中的成員變量cb的值,用以表示結構體本身的大小
        startupinfo.cb = sizeof(startupinfo)
        if kernel32.CreateProcessW(path_to_exe,
                                    None,
                                    None,
                                    None,
                                    None,
                                    creation_flags,
                                    None,
                                    None,
                                    byref(startupinfo),
                                    byref(process_information)):
            print("[*] We have successfully launched the process!")  # 問題出在這句之前,processInformation獲取不到
            # print(path_to_exe)  # b'C:\\Windows\\System32\\calc.exe'
            print("[*] PID: %d" % process_information.dwProcessId)  # 獲取PID的時候拋異常,其實是在啓動進程的時候出了問題
            # Process finished with exit code -1073741819 (0xC0000005)

        else:
            print("[*] Error: 0x%08x." % kernel32.GetLastError())

其中創建了一個核心基類debugger(),後續會逐步添加各項調試功能。
將所有的結構體,聯合體及常值定義放置於腳本文件my_debugger_defines.py之中。

# my_debugger_defines.py
# -*- coding: utf-8 -*-
from ctypes import *

# 爲ctype變量創建符合匈牙利命名風格的匿名,這樣可以使代碼更接近Win32的風格
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p

# 常值定義
DEBUG_PROCESS = 0x00000001
CREATE_NEW_CONSOLE = 0x00000010


# 定義函數CreateProcessA()所需的結構體
class STARTUPINFO(Structure):
    _fileds_ = [
        ("cb", DWORD),
        ("lpReserved", LPTSTR),
        ("lpDesktop", LPTSTR),
        ("lpTitle", LPTSTR),
        ("dwX", DWORD),
        ("dwY", DWORD),
        ("dwXSize", DWORD),
        ("dwYSize", DWORD),
        ("dwXCountChars", DWORD),
        ("dwYCountChars", DWORD),
        ("dwFillAttribute", DWORD),
        ("dwFlags", DWORD),
        ("wShowWindow", WORD),
        ("cbReserved2", WORD),
        ("lpReserved2", LPTSTR),
        ("hStdInput", HANDLE),
        ("hStdOutput", HANDLE),
        ("hStdError", HANDLE),
    ]


class PROCESS_INFORMATION(Structure):
    _fileds_ = [
        ("hProcess", HANDLE),
        ("hThread", HANDLE),
        ("dwProcessId", DWORD),
        ("dwThreadId", DWORD),
    ]

下面構建了一個測試用例my_test.py,與現有源碼文件置於相同目錄底下。

# my_test.py
import my_debugger
debugger = my_debugger.debugger()
debugger.load("C:\\Windows\\System32\\calc.exe")

測試腳本選擇了Windows自帶的計算器calc.exe作爲測試對象,按照書上的講解,通過命令行終端或者從IDE下執行這個腳本文件,會孵化一個新的計算器進程並輸出相應的PID後退出。我在運行了測試腳本後情況如下——
![my_test.py運行結果](https://img-blog.csdn.net/20170914231811612?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc3ODY4NTk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
首先輸出了"[*] We have successfully launched the process!"然後在過了一段時間後輸出進程結束並返回一個0xC0000005。經查閱相關信息,發現此錯誤通常出現在PyCharm上,在更換命令行終端運行後,仍能輸出"[*] We have successfully launched the process!",仍然要等很長時間之後程序彈出窗口提示Python停止運行。之後在PyCharm中加斷點調試也沒看出個所以然,程序執行到需要從PID獲取信息時就出現了停滯。我懷疑是在使用CreateProcessW()的時候出現了問題,因爲在測試過程中查看進程並沒有出現我們開啓的計算器進程,估計是程序不停地在嘗試開啓進程最終出現了進程數過多導致測試異常。
原書中作者使用了CreateProcessA()創建進程,考慮到Python3.x改用了[CreateProcessW()](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx)(忘記當時爲什麼要改成這個了,MSDN相關網頁不知道何由打不開了故無法查詢相關信息),測試使用CreateProcessA()時得到的結果是

[*] Error: 0x00000002.
Process finished with exit code 0

我的解決思路是接下來將先充分理解Python腳本開啓進程的代碼。
剛剛發現了一篇講CreateProcess用法的blog,裏面涉及到了Unicode,我覺得我的調試器可能有救了,明天再說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章