python打造windows调试器
这几天也是在阅读《Python灰帽子》这本书,根据所学写一个python自制的调试器吧!!!
学逆向的人都要会一个库:ctype。ctype可以调用动态链接库的函数,还可以像C语言一样有底层操作能力。
调试器需要打开执行程序作为自身子程序执行
所以我们需要用到CreateProcessA()这个函数帮我们创建一个进程:
BOOL CreateProcess
(
LPCTSTR lpApplicationName, //可执行文件所在路径
LPTSTR lpCommandLine, //命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags, //可调式设置
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo, //STARTUPINFO结构体
LPPROCESS_INFORMATIONlpProcessInformation //PROCESS_INFORMATION结构体
);
重要的参数是:lpApplicationName、lpCommandLine、dwCreationFlags、lpStartupInfo和lpProcessInformation,其余参数可以设置为NULL。
我们也需要OpenProcess()这个函数帮我们进行获取进程句柄
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId// 进程标示符
);
DebugActiveProcess()来实现进程的附加(只有一个参数是PID)
BOOL WINAPI DebugActiveProcess(
__in DWORD dwProcessId
);
WaitForDebugEvent()则是不断获取调试事件的函数(将dwMilliseconds设置为:0xFFFFFFFF)
WaiteForDebugEvent(LPDEBUG_EVENT _DEBUG_EVENT,DWORD dwMilliseconds)
OpenThread()则使我们获得CPU寄存器状态
HANDLE WINAPI OpenThread(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwThreadId
);
CONTEXT结构体(寄存器信息)
typedef struct _CONTEXT
{
DWORD ContextFlags
DWORD Dr0
DWORD Dr1
DWORD Dr2
DWORD Dr3
DWORD Dr6
DWORD Dr7
FLOATING_SAVE_AREA FloatSave; //浮点寄存器
DWORD 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 EFlag
DWORD Esp
DWORD SegSs
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
my_debugger_defines.py(所有结构体及函数值)
1 from ctypes import * 2 3 4 WORD = c_ushort 5 DWORD = c_ulong 6 BYTE = c_ubyte 7 LPBYTE = POINTER(c_ubyte) 8 LPTSTR = POINTER(c_char) 9 HANDLE = c_void_p 10 PVOID = c_void_p 11 LPVOID = c_void_p 12 UNINT_PTR = c_ulong 13 SIZE_T = c_ulong 14 15 16 DEBUG_PROCESS = 0x00000001 17 CREATE_NEW_CONSOLE = 0x00000010 18 PROCESS_ALL_ACCESS = 0x001F0FFF 19 INFINITE = 0xFFFFFFFF 20 DBG_CONTINUE = 0x00010002 21 DBG_EXCEPTION_NOT_HANDLED = 0x80010001 22 23 24 EXCEPTION_DEBUG_EVENT = 0x01 25 CREATE_THREAD_DEBUG_EVENT = 0x02 26 CREATE_PROCESS_DEBUG_EVENT = 0x03 27 EXIT_THREAD_DEBUG_EVENT = 0x04 28 EXIT_PROCESS_DEBUG_EVENT = 0x05 29 LOAD_DLL_DEBUG_EVENT = 0x06 30 UNLOAD_DLL_DEBUG_EVENT = 0x07 31 OUTPUT_DEBUG_STRING_EVENT = 0x08 32 RIP_EVENT = 0x09 33 34 35 EXCEPTION_ACCESS_VIOLATION = 0xC0000005 36 EXCEPTION_BREAKPOINT = 0x80000003 37 EXCEPTION_GUARD_PAGE = 0x80000001 38 EXCEPTION_SINGLE_STEP = 0x80000004 39 40 TH32CS_SNAPTHREAD = 0x00000004 41 42 THREAD_ALL_ACCESS = 0x001F03FF 43 44 CONTEXT_FULL = 0x00010007 45 CONTEXT_DEBUG_REGISTERS = 0x00010010 46 47 HW_ACCESS = 0x00000003 48 HW_EXECUTE = 0x00000000 49 HW_WRITE = 0x00000001 50 51 PAGE_GUARD = 0x00000100 52 53 54 class STARTUPINFO(Structure): 55 _fields_ = [ 56 ("cb",DWORD), 57 ("IpReserved",LPTSTR), 58 ("IpDesktop",LPTSTR), 59 ("IpTitle",LPTSTR), 60 ("dwX",DWORD), 61 ("dwY",DWORD), 62 ("dwXSize",DWORD), 63 ("dwYSize",DWORD), 64 ("dwXCountChars",DWORD), 65 ("dwYCountChars",DWORD), 66 ("dwFillAttribute",DWORD), 67 ("dwFlags",DWORD), 68 ("wShowWindow",WORD), 69 ("cbReserved2",WORD), 70 ("IpReserved2",LPBYTE), 71 ("hStdInput",HANDLE), 72 ("hStdOutput",HANDLE), 73 ("hStdError",HANDLE), 74 ] 75 76 77 class PROCESS_INFORMATTION(Structure): 78 _fields_ = [ 79 ("hProcess",HANDLE), 80 ("hThread",HANDLE), 81 ("dwProcessId",DWORD), 82 ("dwThreadId",DWORD), 83 ] 84 85 86 class EXCEPTION_RECORD(Structure): 87 pass 88 class EXCEPTION_RECORD(Structure): 89 _fields_ = [ 90 ("ExceptionCode", DWORD), 91 ("ExceptionFlags", DWORD), 92 ("ExceptionRecord", POINTER(EXCEPTION_RECORD)), 93 ("ExceptionAddress", PVOID), 94 ("NumberParameters", DWORD), 95 ("ExceptionInformation", UNINT_PTR * 15), 96 ] 97 98 99 class EXCEPTION_DEBUG_INFO(Structure): 100 _fields_ = [ 101 ("ExceptionRecord", EXCEPTION_RECORD), 102 ("dwFirstChance", DWORD), 103 ] 104 105 106 class DEBUG_EVENT_UNION(Union): 107 _fields_ = [ 108 ("Exception",EXCEPTION_DEBUG_INFO), 109 ] 110 111 112 113 class DEBUG_EVENT(Structure): 114 _fields_ = [ 115 ("dwDebugEventCode",DWORD), 116 ("dwProcessId",DWORD), 117 ("dwThreadId",DWORD), 118 ("u",DEBUG_EVENT_UNION), 119 ] 120 121 122 class THREADENTRY32(Structure): 123 _fields_ = [ 124 ("dwSize",DWORD), 125 ("cntUsage",DWORD), 126 ("th32ThreadID",DWORD), 127 ("th32OwnerProcessID",DWORD), 128 ("tpBasePri",DWORD), 129 ("tpDeltapri",DWORD), 130 ("dwFlags",DWORD), 131 ] 132 133 134 class FLOAT_SAVE_AREA(Structure): 135 _fields_ = [ 136 ("ControlWord",DWORD), 137 ("StatusWord",DWORD), 138 ("TagWord",DWORD), 139 ("ErrorOffset",DWORD), 140 ("ErrorSelector",DWORD), 141 ("DataOffset",DWORD), 142 ("DataSelector",DWORD), 143 ("RegisterArea",BYTE * 80), 144 ("Cr0NpxState",DWORD) 145 ] 146 147 148 class CONTEXT(Structure): 149 _fields_ = [ 150 ("ContextFlags",DWORD), 151 ("Dr0",DWORD), 152 ("Dr1", DWORD), 153 ("Dr2", DWORD), 154 ("Dr3", DWORD), 155 ("Dr6", DWORD), 156 ("Dr7", DWORD), 157 ("FloatSave",FLOAT_SAVE_AREA), 158 ("SegGs",DWORD), 159 ("SegFs", DWORD), 160 ("SegEs", DWORD), 161 ("SegDs", DWORD), 162 ("Edi",DWORD), 163 ("Esi", DWORD), 164 ("Ebx", DWORD), 165 ("Edx", DWORD), 166 ("Ecx", DWORD), 167 ("Eax", DWORD), 168 ("Ebp", DWORD), 169 ("Eip", DWORD), 170 ("SegSS",DWORD), 171 ("EFlags",DWORD), 172 ("Esp",DWORD), 173 ("SegSs",DWORD), 174 ("ExtendedRegisters",BYTE * 512) 175 ] 176 177 class PROC_STRUCT(Structure): 178 _fields_ = [ 179 ("wProcessorArchitecture", WORD), 180 ("wReserved", WORD), 181 ] 182 183 184 class SYSTEM_INFO_UNION(Union): 185 _fields_ = [ 186 ("dsOemId", DWORD), 187 ("sProcStruc", PROC_STRUCT), 188 ] 189 190 class SYSTEM_INFO(Structure): 191 _fields_ = [ 192 ("uSysInfo", SYSTEM_INFO_UNION), 193 ("dwPageSize", DWORD), 194 ("lpMinimumApplicationAddress", LPVOID), 195 ("lpMaximumApplicationAddress", LPVOID), 196 ("dwActiveProcessMask", DWORD), 197 ("dwNumberOfProcessors", DWORD), 198 ("dwProcessorType", DWORD), 199 ("dwAllocationGranularity", DWORD), 200 ("wProcessorLevel", WORD), 201 ("wProcessorRevision", WORD), 202 ] 203 204 205 206 class SYSTEM_INFO(Structure): 207 _fields_ = [ 208 ("uSysInfo", SYSTEM_INFO_UNION), 209 ("dwPageSize", DWORD), 210 ("lpMinimumApplicationAddress", LPVOID), 211 ("lpMaximumApplicationAddress", LPVOID), 212 ("dwActiveProcessMask", DWORD), 213 ("dwNumberOfProcessors", DWORD), 214 ("dwProcessorType", DWORD), 215 ("dwAllocationGranularity", DWORD), 216 ("wProcessorLevel", WORD), 217 ("wProcessorRevision", WORD), 218 ] 219 220 class PROC_STRUCT(Structure): 221 _fields_ = [ 222 ("wProcessorArchitecture", WORD), 223 ("wReserved", WORD), 224 ] 225 class SYSTEM_INFO_UNION(Union): 226 _fields_ = [ 227 ("dsOemId", DWORD), 228 ("sProcStruc", PROC_STRUCT), 229 ] 230 231 class SYSTEM_INFO(Structure): 232 _fields_ = [ 233 ("uSysInfo", SYSTEM_INFO_UNION), 234 ("dwPageSize", DWORD), 235 ("lpMinimumApplicationAddress", LPVOID), 236 ("lpMaximumApplicationAddress", LPVOID), 237 ("dwActiveProcessMask", DWORD), 238 ("dwNumberOfProcessors", DWORD), 239 ("dwProcessorType", DWORD), 240 ("dwAllocationGranularity", DWORD), 241 ("wProcessorLevel", WORD), 242 ("wProcessorRevision", WORD), 243 ] 244 245 246 247 class MEMORY_BASIC_INFORMATION(Structure): 248 _fields_ = [ 249 ("BaseAddress", PVOID), 250 ("AllocationBase", PVOID), 251 ("AllocationProtect", DWORD), 252 ("RegionSize",SIZE_T), 253 ("State", DWORD), 254 ("Protect", DWORD), 255 ("Type", DWORD), 256 ]
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 self.debugger_active = False self.context = None self.exception = None self.exception_address = None self.software_breakpoints = {} self.hardware_breakpoints = {} self.memory_breakpoints = {} self.first_breakpoints = True system_info = SYSTEM_INFO() kernel32.GetSystemInfo(byref(system_info)) self.page_size = system_info.dwPageSize self.guarded_pages = [] def load(self,path_to_exe): create_flags = DEBUG_PROCESS startupinfo = STARTUPINFO() process_information = PROCESS_INFORMATTION() startupinfo.dwFlags = 0x1 startupinfo.wShowWindow = 0x0 startupinfo.cb = sizeof(startupinfo) if kernel32.CreateProcessA( path_to_exe, None, None, None, None, create_flags, None, None, byref(startupinfo), byref(process_information) ): print "We have successfully lauched the process" print "PID: %d" % process_information.dwProcessId else: print "ERROR:0x%08x." % kernel32.GetLastError() def open_process(self,pid): h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid) return h_process def attach(self,pid): self.h_process = self.open_process(pid) if kernel32.DebugActiveProcess(pid): self.debugger_active = True self.pid = int(pid) self.run() else: print "[*] Unable to attach to the process" def run(self): 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): raw_input("press a key to continue ...") self.debugger_active = False kernel32.ContinueDebugEvent( debug_event.dwProcessId, debug_event.dwThreadId, continue_status ) def open_thread(self,thread_id): 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" 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) 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): 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 exception_handler_breakpoint(self): print "[*] Inside the break handler." print "Exception adress:0x%08x" % self.exception_address print kernel32.GetLastError() if not self.exception_address in self.hardware_breakpoints.keys(): if self.first_breakpoints == True: self.first_breakpoints = False print "[*] Hit the first breakpoint." else: print "[*] Hit user defined breakpoint." return DBG_CONTINUE def get_debug_event(self): debug_event = DEBUG_EVENT() continue_status = DBG_CONTINUE if kernel32.WaitForDebugEvent(byref(debug_event),INFINITE): self.h_thread = self.open_thread(debug_event.dwThreadId) self.context = self.get_thread_context(self.h_thread) print "Event CODE: %d Thread ID : %d" % (debug_event.dwDebugEventCode,debug_event.dwThreadId) kernel32.ContinueDebugEvent( debug_event.dwProcessId, debug_event.dwThreadId, continue_status )
my_test.py
import my_debugger from ctypes import * debugger = my_debugger.debugger() debugger.load("C:\Users\Dell\Desktop\Auth.exe") pid = input() debugger.attach(int(pid)) list = debugger.enumerate_threads() for thread in list: thread_context = debugger.get_thread_context(thread) print "Dumping registers for thread ID: 0x%08x" % thread
运行结果为调试事件流
Event CODE: 3 Thread ID : 964
Event CODE: 3 Thread ID : 10428
Event CODE: 6 Thread ID : 10428
Event CODE: 2 Thread ID : 12008
Event CODE: 6 Thread ID : 10428
Event CODE: 6 Thread ID : 10428
Event CODE: 6 Thread ID : 10428
Event CODE: 2 Thread ID : 4456
Event CODE: 1 Thread ID : 4456
Event CODE: 4 Thread ID : 4456
Event CODE: 6 Thread ID : 964
Event CODE: 7 Thread ID : 964
Event CODE: 6 Thread ID : 964
Event CODE: 7 Thread ID : 964
Event CODE: 7 Thread ID : 964
Event CODE: 7 Thread ID : 964
Event CODE: 6 Thread ID : 964
Event CODE: 6 Thread ID : 964
Event CODE: 6 Thread ID : 964
Event CODE: 2 Thread ID : 968
Event CODE: 1 Thread ID : 964
下次我们来加入软硬和内存断点完善调试器。