1 from ctypes import * 2 3 BYTE = c_ubyte 4 WORD = c_ushort 5 DWORD = c_ulong 6 LPBYTE = POINTER(c_ubyte) 7 LPTSTR = POINTER(c_char) 8 HANDLE = c_void_p 9 PVOID = c_void_p10 ULONG_PTR = POINTER(c_ulong)11 LPVOID = c_void_p12 UINT_PTR = c_ulong13 SIZE_T = c_ulong14 DWORD64 = c_uint64
1 from ctypes import *2 from main_package.my_debugger_defines import *3 4 kernel32 = windll.LoadLibrary("kernel32.dll")
1 class debugger():2 3 def __init__(self):4 self.h_process = None5 self.pid = None6 self.debugger_active = False
1 DEBUG_PROCESS = 0X00000001
1 class STARTUPINFO(Structure): 2 _fields_ = [ 3 ("cb", DWORD), 4 ("lpReserved", LPTSTR), 5 ("lpDesktop", LPTSTR), 6 ("lpTitle", LPTSTR), 7 ("dwX", DWORD), 8 ("dwY", DWORD), 9 ("dwXSize", DWORD),10 ("dwYSize", DWORD),11 ("dwXCountChars", DWORD),12 ("dwYCountChars", DWORD),13 ("dwFillAttribute", DWORD),14 ("dwFlags", DWORD),15 ("wShowWindow", WORD),16 ("cbReserved2", WORD),17 ("lpReserved2", LPBYTE),18 ("hStdInput", HANDLE),19 ("hStdOutput", HANDLE),20 ("hStdError", HANDLE)21 ] 22 23 class PROCESS_INFORMATION(Structure):24 _fields_ = [25 ("hProcess", HANDLE),26 ("hThread", HANDLE),27 ("dwProcessId", DWORD),28 ("dwThreadId", DWORD)29 ]
1 PROCESS_ALL_ACCESS = 0X1F0FFF
1 1 #get process handle2 2 def open_process(self,pid):3 3 h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid)4 4 return h_process
1 def load(self, path_to_exe): 2 3 creation_flags = DEBUG_PROCESS 4 5 startupinfo = STARTUPINFO() 6 process_information = PROCESS_INFORMATION() 7 8 startupinfo.dwFlags = 0X1 9 startupinfo.wShowWindow = 0X010 startupinfo.cb = sizeof(startupinfo)11 12 if kernel32.CreateProcessA(path_to_exe,13 None,14 None,15 None,16 None,17 creation_flags,18 None,19 None,20 byref(startupinfo),21 byref(process_information)):22 print "[*] We have successfully launched the process!!"23 print "[*] PID: %d" % process_information.dwProcessId24 self.h_process = self.open_process(process_information.dwProcessId) #keep a process handle25 self.debugger_active = True26 else:27 print "[*] Error: 0x%08x." % kernel32.GetLastError()
1 startupinfo.dwFlags = 0X12 startupinfo.wShowWindow = 0X03 startupinfo.cb = sizeof(startupinfo)
1 def attach(self,pid):2 self.h_process = self.open_process(pid)3 if kernel32.DebugActiveProcess(pid):4 self.debugger_active = True5 self.pid = int(pid)6 else:7 print "[*] Unable to attach the process."
1 def run(self):2 while self.debugger_active == True:3 self.get_debug_event()
1 class DEBUG_EVENT(Structure):2 _fields_ = [3 ("dwDebugEventCode", DWORD),4 ("dwProcessId", DWORD),5 ("dwThreadId", DWORD),6 ("u", _DEBUG_EVENT_UNION)7 ]
1 class _DEBUG_EVENT_UNION(Union):2 _fields_ = [3 ("Exception", EXCEPTION_DEBUG_INFO),4 ]
1 class EXCEPTION_DEBUG_INFO(Structure): 2 _fields_ = [ 3 ("ExceptionRecord", EXCEPTION_RECORD), 4 ("dwFirstChance", DWORD) 5 ] 6 class EXCEPTION_RECORD(Structure): 7 Pass 8 EXCEPTION_RECORD._fields_ = [ 9 ("ExceptionCode", DWORD),10 ("ExceptionFlags", DWORD),11 ("ExceptionRecord", POINTER(EXCEPTION_RECORD)),12 ("ExceptionAddress", PVOID),13 ("NumberParameters", DWORD),14 ("ExceptionInformation", UINT_PTR * 15),15 ]
1 def get_debug_event(self):2 3 debug_event = DEBUG_EVENT()4 continue_status = DBG_CONTINUE5 if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE):6 kernel32.ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId, continue_status )
1 INFINITE = 0xFFFFFFFF2 DBG_CONTINUE = 0X00010002
1 def read_process_memory(self,address,length): 2 data = "" 3 read_buf = create_string_buffer(length) 4 count = c_ulong(0) 5 if not kernel32.ReadProcessMemory(self.h_process, 6 address, 7 read_buf, 8 length, 9 byref(count)):10 return False11 else:12 data += read_buf.raw13 return data14 15 def write_process_memory(self,address,data):16 count = c_ulong(0)17 length = len(data)18 c_data = c_char_p(data[count.value:])19 if not kernel32.WriteProcessMemory(self.h_process,20 address,21 c_data,22 length,23 byref(count)):24 return False25 else:26 return True
1 self.breakpoints = {}
1 def bp_set(self,address): 2 print "[*] Setting breakpoint at: 0x%08x" % address 3 if not self.breakpoints.has_key(address): 4 try: 5 original_byte = self.read_process_memory(address, 1) 6 self.write_process_memory(address, '\xCC') 7 self.breakpoints[address] = original_byte 8 except: 9 return False10 return True
1 HW_ACCESS = 0x000000032 HW_EXECUTE = 0x000000003 HW_WRITE = 0x00000001
class WOW64_CONTEXT(Structure): _pack_ = 16 _fields_ = [ ("P1Home", DWORD64), ("P2Home", DWORD64), ("P3Home", DWORD64), ("P4Home", DWORD64), ("P5Home", DWORD64), ("P6Home", DWORD64), ("ContextFlags", DWORD), ("MxCsr", DWORD), ("SegCs", WORD), ("SegDs", WORD), ("SegEs", WORD), ("SegFs", WORD), ("SegGs", WORD), ("SegSs", WORD), ("EFlags", DWORD), ("Dr0", DWORD64), ("Dr1", DWORD64), ("Dr2", DWORD64), ("Dr3", DWORD64), ("Dr6", DWORD64), ("Dr7", DWORD64), ("Rax", DWORD64), ("Rcx", DWORD64), ("Rdx", DWORD64), ("Rbx", DWORD64), ("Rsp", DWORD64), ("Rbp", DWORD64), ("Rsi", DWORD64), ("Rdi", DWORD64), ("R8", DWORD64), ("R9", DWORD64), ("R10", DWORD64), ("R11", DWORD64), ("R12", DWORD64), ("R13", DWORD64), ("R14", DWORD64), ("R15", DWORD64), ("Rip", DWORD64), ("DebugControl", DWORD64), ("LastBranchToRip", DWORD64), ("LastBranchFromRip", DWORD64), ("LastExceptionToRip", DWORD64), ("LastExceptionFromRip", DWORD64), ("DUMMYUNIONNAME", DUMMYUNIONNAME), ("VectorRegister", M128A * 26), ("VectorControl", DWORD64)] class DUMMYUNIONNAME(Union): _fields_=[ ("FltSave", XMM_SAVE_AREA32), ("DummyStruct", DUMMYSTRUCTNAME) ] class DUMMYSTRUCTNAME(Structure): _fields_=[ ("Header", M128A * 2), ("Legacy", M128A * 8), ("Xmm0", M128A), ("Xmm1", M128A), ("Xmm2", M128A), ("Xmm3", M128A), ("Xmm4", M128A), ("Xmm5", M128A), ("Xmm6", M128A), ("Xmm7", M128A), ("Xmm8", M128A), ("Xmm9", M128A), ("Xmm10", M128A), ("Xmm11", M128A), ("Xmm12", M128A), ("Xmm13", M128A), ("Xmm14", M128A), ("Xmm15", M128A) ] class XMM_SAVE_AREA32(Structure): _pack_ = 1 _fields_ = [ ('ControlWord', WORD), ('StatusWord', WORD), ('TagWord', BYTE), ('Reserved1', BYTE), ('ErrorOpcode', WORD), ('ErrorOffset', DWORD), ('ErrorSelector', WORD), ('Reserved2', WORD), ('DataOffset', DWORD), ('DataSelector', WORD), ('Reserved3', WORD), ('MxCsr', DWORD), ('MxCsr_Mask', DWORD), ('FloatRegisters', M128A * 8), ('XmmRegisters', M128A * 16), ('Reserved4', BYTE * 96) ] class M128A(Structure): _fields_ = [ ("Low", DWORD64), ("High", DWORD64) ]
1 # Context flags for GetThreadContext() 2 CONTEXT_FULL = 0x00010007 3 CONTEXT_DEBUG_REGISTERS = 0x00010010 4 5 #get thread context 6 def get_thread_context(self, thread_id): 7 8 #64-bit context 9 context64 = WOW64_CONTEXT()10 context64.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS11 12 self.h_thread = self.open_thread(thread_id)13 if kernel32.GetThreadContext(self.h_thread, byref(context64)):14 kernel32.CloseHandle(self.h_thread)15 return context6416 else:17 print '[*] Get thread context error. Error code: %d' % kernel32.GetLastError()18 return False
1 class THREADENTRY32(Structure): 2 _fields_ = [ 3 ("dwSize", DWORD), 4 ("cntUsage", DWORD), 5 ("th32ThreadID", DWORD), 6 ("th32OwnerProcessID", DWORD), 7 ("tpBasePri", DWORD), 8 ("tpDeltaPri", DWORD), 9 ("dwFlags", DWORD),10 ]11 12 TH32CS_SNAPTHREAD = 0x00000004
1 # enumerate threads 2 def enumerate_threads(self): 3 thread_entry = THREADENTRY32() 4 thread_list = [] 5 snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid) 6 if snapshot is not None: 7 thread_entry.dwSize = sizeof(thread_entry) 8 success = kernel32.Thread32First(snapshot, byref(thread_entry)) 9 while success:10 if thread_entry.th32OwnerProcessID == self.pid:11 thread_list.append(thread_entry.th32ThreadID)12 kernel32.CloseHandle(snapshot)13 success = kernel32.Thread32Next(snapshot, byref(thread_entry))14 return thread_list15 else:16 return False
1 def bp_set_hw(self, address, length, condition): 2 if length not in (1,2,4): 3 return False 4 else: 5 length -= 1 6 if condition not in (HW_ACCESS, HW_EXECUTE, HW_WRITE): 7 return False 8 if not self.hardware_breakpoints.has_key(0): 9 available = 010 elif not self.hardware_breakpoints.has_key(1):11 available = 112 elif not self.hardware_breakpoints.has_key(2):13 available = 214 elif not self.hardware_breakpoints.has_key(3):15 available = 316 else:17 return False18 for thread_id in self.enumerate_threads():19 context64 = self.get_thread_context(thread_id)20 context64.Dr7 |= 1 << (available * 2)21 if available == 0:22 context64.Dr0 = address 23 elif available == 1:24 context64.Dr1 = address25 elif available == 2:26 context64.Dr2 = address27 elif available == 3:28 context64.Dr3 = address29 #set condition30 context64.Dr7 |= condition << ((available * 4) + 16)31 #set length32 context64.Dr7 |= length << ((available * 4) + 18)33 #update context34 h_thread = self.open_thread(thread_id)35 if not kernel32.SetThreadContext(h_thread, byref(context64)):36 print '[*] Set thread context error.'37 38 #update breakpoint list39 self.hardware_breakpoints[available] = (address, length, condition)40 return True41
1 def bp_del_hw(self, slot): 2 for thread_id in self.enumerate_threads(): 3 context = self.get_thread_context(thread_id) 4 context.Dr7 &= ~(1 << (slot * 2)) 5 if slot == 0: 6 context.Dr0 = 0x00000000 7 elif slot == 1: 8 context.Dr1 = 0x00000000 9 elif slot == 2:10 context.Dr2 = 0x0000000011 elif slot == 3:12 context.Dr3 = 0x0000000013 #condition14 context.Dr7 &= ~(3 << ((slot * 4) + 16))15 #length16 context.Dr7 &= ~(3 << ((slot * 4) + 18))17 18 h_thread = self.open_thread(thread_id)19 kernel32.SetThreadContext(h_thread,byref(context))20 del self.hardware_breakpoints[slot] 21 return True22
class MEMORY_BASIC_INFORMATION(Structure): _fields_ = [ ("BaseAddress", PVOID), ("AllocationBase", PVOID), ("AllocationProtect", DWORD), ("RegionSize", SIZE_T), ("State", DWORD), ("Protect", DWORD), ("Type", DWORD),]
1 # Memory page permissions, used by VirtualProtect() 2 PAGE_NOACCESS = 0x00000001 3 PAGE_READONLY = 0x00000002 4 PAGE_READWRITE = 0x00000004 5 PAGE_WRITECOPY = 0x00000008 6 PAGE_EXECUTE = 0x00000010 7 PAGE_EXECUTE_READ = 0x00000020 8 PAGE_EXECUTE_READWRITE = 0x00000040 9 PAGE_EXECUTE_WRITECOPY = 0x0000008010 PAGE_GUARD = 0x0000010011 PAGE_NOCACHE = 0x0000020012 PAGE_WRITECOMBINE = 0x00000400
1 def bp_set_mem(self, address, size): 2 mbi = MEMORY_BASIC_INFORMATION() 3 4 if kernel32.VirtualQueryEx(self.h_process, address, byref(mbi), sizeof(mbi)) < sizeof(mbi): 5 return False 6 7 current_page = mbi.BaseAddress 8 9 while current_page <= address + size:10 self.guarded_pages.append(current_page)11 old_protection = c_ulong(0)12 if not kernel32.VirtualProtectEx(self.h_process, current_page,size,mbi.Protect | PAGE_GUARD,byref(old_protection)):13 return False14 current_page += self.page_size15 self.memory_breakpoints[address] = (address, size, mbi)16 return True17
1 def get_debug_event(self): 2 3 debug_event = DEBUG_EVENT() 4 continue_status = DBG_CONTINUE 5 bpflag = False 6 7 if kernel32.WaitForDebugEvent(byref(debug_event), INFINITE): 8 9 self.thread_id = debug_event.dwThreadId10 self.h_thread = self.open_thread(self.thread_id)11 self.context = self.get_thread_context(self.thread_id)12 13 print 'Event code: %s Thread ID: %d' % (EVENTCODE_MAP[debug_event.dwDebugEventCode],14 debug_event.dwThreadId)15 16 if debug_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT:17 18 self.exception = debug_event.u.Exception.ExceptionRecord.ExceptionCode19 self.exception_address = debug_event.u.Exception.ExceptionRecord.ExceptionAddress20 21 if self.exception == EXCEPTION_ACCESS_VIOLATION:22 print 'Access Violation Detected.'23 24 elif self.exception == EXCEPTION_BREAKPOINT:25 print 'EXCEPTION_BREAKPOINT'26 bpflag = not self.first_breakpoint27 continue_status = self.exception_handler_breakpoint()28 29 30 elif self.exception == EXCEPTION_GUARD_PAGE:31 print 'Guard Page Access Detected.'32 continue_status == self.exception_handler_guard_page()33 34 elif self.exception == EXCEPTION_SINGLE_STEP:35 print 'Single Stepping.'36 continue_status = self.exception_handler_single_step()37 38 kernel32.ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId, continue_status )39 40 #if it is int3 breakpoint 41 if bpflag == True:42 self.write_process_memory(self.exception_address,'\xCC')
1 2 3 #deal with memory breakpoint exception 4 def exception_handler_guard_page(self): 5 print '[*] Hit the memory breakpoint.' 6 print '[**] Exception address: 0x%08x' % self.exception_address 7 return DBG_CONTINUE 8 9 #deal with breakpoint exception10 def exception_handler_breakpoint(self):11 print '[*] Inside the int3 breakpoint handler'12 print '[**] Exception address: 0x%08x' % self.exception_address13 if self.first_breakpoint == True:14 self.first_breakpoint = False15 print '[**] Hit the first breakpoint.'16 else:17 print '[**] Hit the user defined breakpoint.'18 # put the original byte back 19 self.write_process_memory(self.exception_address,20 self.breakpoints[self.exception_address]21 )22 return DBG_CONTINUE23 24 #deal with single step exception25 def exception_handler_single_step(self):26 27 if self.context == False:28 print '[*] Exception_handler_single_step get context error.'29 else:30 if self.context.Dr6 & 0x1 and self.hardware_breakpoints.has_key(0):31 slot = 032 elif self.context.Dr6 & 0x2 and self.hardware_breakpoints.has_key(1):33 slot = 134 elif self.context.Dr6 & 0x4 and self.hardware_breakpoints.has_key(2):35 slot = 236 elif self.context.Dr6 & 0x8 and self.hardware_breakpoints.has_key(3):37 slot = 338 else:39 continue_status = DBG_EXCEPTION_NOT_HANDLED40 # remove this hardware breakpoint41 if self.bp_del_hw(slot):42 continue_status = DBG_CONTINUE43 print '[*] Hardware breakpoint removed.'44 else :45 print '[*] Hardware breakpoint remove failed.'46 #raw_input('[*] Press any key to continue.')47 return continue_status48
联系客服