1. 程式人生 > >《python灰帽子》原始碼三,獲取暫存器狀態

《python灰帽子》原始碼三,獲取暫存器狀態

今天才發現自己的python3是64位的,一直以為是32位的,所以我後面的程式碼都將使用python 3.5 - 32位

win10系統,python3.5-32位,編碼軟體vscode

因為跟上一章程式碼有重複的就以。。。帶過了,新新增的程式碼都會顯示出來

上程式碼

首先my_debugger_defines.py檔案

from ctypes import *

# 為了清晰起見,讓我們將Microsoft型別對映到ctypes
BYTE                            = c_ubyte
WORD                            = c_ushort
DWORD                           = c_ulong
LPBYTE                          = POINTER(c_ubyte)
LPTSTR                          = POINTER(c_char)
HANDLE                          = c_void_p

LONG = c_long
PVOID = c_void_p
ULONG_PTR =c_ulong
ULONG = c_ulong

DEBUG_PROCESS                   = 0x00000001
CREATE_NEW_CONSOLE              = 0x00000010

# 常量
PROCESS_ALL_ACCESS              = 0x001F0FFF
INFINITE                        = 0xFFFFFFFF

DBG_CONTINUE                    = 0x00010002
TH32CS_SNAPTHREAD               = 0x00000004    # 包括快照中系統中的所有執行緒。要列舉執行緒

# 執行緒常量
THREAD_ALL_ACCESS               = 0x001F03FF

# GetThreadContext()的上下文標誌   
CONTEXT_FULL                    = 0x00010007   
CONTEXT_DEBUG_REGISTERS         = 0x00010010

。。。。。。。。。

class THREADENTRY32(Structure):
    _fields_ = [
        ("dwSize",DWORD),
        ("cntUsage",DWORD),
        ("th32ThreadID",DWORD),
        ("th32OwnerProcessID",DWORD),
        ("tpBasePri",LONG),
        ("tpDeltaPri",LONG),
        ("dwFlags",DWORD),
    ]

# Used by the CONTEXT structure   
class FLOATING_SAVE_AREA(Structure):   
   _fields_ = [
        ("ControlWord", DWORD),   
        ("StatusWord", DWORD),   
        ("TagWord", DWORD),   
        ("ErrorOffset", DWORD),   
        ("ErrorSelector", DWORD),   
        ("DataOffset", DWORD),   
        ("DataSelector", DWORD),   
        ("RegisterArea", BYTE * 80),   
        ("Cr0NpxState", DWORD),   
]   
   
# The CONTEXT structure which holds all of the    
# register values after a GetThreadContext() call   
class CONTEXT(Structure):   
    _fields_ = [
        ("ContextFlags", DWORD),   
        ("Dr0", DWORD),   
        ("Dr1", DWORD),   
        ("Dr2", DWORD),   
        ("Dr3", DWORD),   
        ("Dr6", DWORD),   
        ("Dr7", DWORD),   
        ("FloatSave", FLOATING_SAVE_AREA),   
        ("SegGs", DWORD),   
        ("SegFs", DWORD),   
        ("SegEs", DWORD),   
        ("SegDs", DWORD),   
        ("Edi", DWORD),   
        ("Esi", DWORD),   
        ("Ebx", DWORD),   
        ("Edx", DWORD),   
        ("Ecx", DWORD),   
        ("Eax", DWORD),   
        ("Ebp", DWORD),   
        ("Eip", DWORD),   
        ("SegCs", DWORD),   
        ("EFlags", DWORD),   
        ("Esp", DWORD),   
        ("SegSs", DWORD),   
        ("ExtendedRegisters", BYTE * 512),   
]

定義的常量,型別,以及新增結構體都貼了出來,但是還有很多結構體可以從上一章中獲取到,就不貼出來。

my_debugger.py檔案

from ctypes import * 
from my_debugger_defines import * 
kernel32 = windll.kernel32 
class debugger(): 
    def __init__(self): 
        self.h_process              = None          # 程序控制代碼
        self.pid                    = None          # 程序pid
        self.debugger_active        = False         # 程序活躍狀態
        self.h_thread               = None          # 執行緒id
        self.context                = None          # 暫存器內容
        pass 

    def load(self,path_to_exe):

        
    def open_process(self,pid):

    
    def attach(self,pid):


    def run(self):

    
    def get_debug_event(self):

    
    def detach(self):

    def enumerate_threads(self):
        """
        列舉執行緒
        """
        thread_entry                = THREADENTRY32()
        thread_list                 = []                        # 執行緒列表
        # 獲取指定程序的快照,以及這些程序使用的堆,模組和執行緒
        snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,self.pid)
        if snapshot is not None:
            thread_entry.dwSize     = sizeof(thread_entry)
            # 通過Thread32First列舉出執行緒
            success = kernel32.Thread32First(snapshot,byref((thread_entry)))
            while success:
                # 執行緒擁有的程序id必須與我們輸入的pid相同
                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):
        """
        獲取暫存器內容
        """
        context                 = CONTEXT()
        context.ContextFlags    = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
        # 獲得一個執行緒控制代碼
        h_thread = self.open_thread(thread_id)
        if kernel32.GetThreadContext(h_thread,byref(context)):
            kernel32.CloseHandle(h_thread)
            return context
        else:
            return False

    def open_thread(self,thread_id):
        """
        開啟執行緒,獲取執行緒控制代碼
        :param thread_id 執行緒id類似程序pid
        :return 執行緒控制代碼
        """
        h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS,None,thread_id)
        if h_thread is not None:
            return h_thread
        else:
            print("[*] 無法獲得有效的執行緒控制代碼")
            return False
    

新新增的屬性以及方法都貼了出來,有些方法可以從上一章找,不然貼出來就太長了。

最後my_test.py

from my_debugger import debugger
debugger = debugger() 

pid = input("輸入需要依附的程式的pid:")
debugger.attach(int(pid))

list = debugger.enumerate_threads()
for thread in list:
    thread_context = debugger.get_thread_context(thread)
    print("[*] 執行緒id:0x%08x" % thread)
    print("[*] EIP:0x%08x" % thread_context.Eip)
    print("[*] ESP:0x%08x" % thread_context.Esp)
    print("[*] EBP:0x%08x" % thread_context.Ebp)
    print("[*] EAX:0x%08x" % thread_context.Eax)
    print("[*] EBX:0x%08x" % thread_context.Ebx)
    print("[*] ECX:0x%08x" % thread_context.Ecx)
    print("[*] EDX:0x%08x" % thread_context.Edx)

debugger.detach()

我覺得執行這次程式碼最主要是確定python是32位的,剛開始我是用python3.6的64位執行,一直都有問題出現,後來換成32位就成功了,但是換了之後卻不能用在系統自帶的計算器上了,老是在attach()這個函式報錯,根據kernel32.GetLastError()返回來的值是50,表示不支援該請求,用在系統自帶的截圖工具軟體上也是一樣,但是使用酷狗這些軟體就可以。