윈도우 디버거 구현 본문
최근에 보고있는 파이썬 해킹 프로그래밍(원제: Gray Hat Python)에서
윈도우 디버거 구현 예제가 있었는데
심심해서 카톡에 물려봄
my_debugger_defines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | from ctypes import * # Let's map the Microsoft types to ctypes for clarity BYTE = c_ubyte WORD = c_ushort DWORD = c_ulong LPBYTE = POINTER(c_ubyte) LPTSTR = POINTER(c_char) HANDLE = c_void_p PVOID = c_void_p LPVOID = c_void_p UINT_PTR = c_ulong SIZE_T = c_ulong # Constants DEBUG_PROCESS = 0x00000001 CREATE_NEW_CONSOLE = 0x00000010 PROCESS_ALL_ACCESS = 0x001F0FFF INFINITE = 0xFFFFFFFF DBG_CONTINUE = 0x00010002 #DSUM DBG_EXCEPTION_NOT_HANDLED = 0x80010001 # Debug event constants EXCEPTION_DEBUG_EVENT = 0x1 CREATE_THREAD_DEBUG_EVENT = 0x2 CREATE_PROCESS_DEBUG_EVENT = 0x3 EXIT_THREAD_DEBUG_EVENT = 0x4 EXIT_PROCESS_DEBUG_EVENT = 0x5 LOAD_DLL_DEBUG_EVENT = 0x6 UNLOAD_DLL_DEBUG_EVENT = 0x7 OUTPUT_DEBUG_STRING_EVENT = 0x8 RIP_EVENT = 0x9 # debug exception codes. EXCEPTION_ACCESS_VIOLATION = 0xC0000005 EXCEPTION_BREAKPOINT = 0x80000003 EXCEPTION_GUARD_PAGE = 0x80000001 EXCEPTION_SINGLE_STEP = 0x80000004 # Thread constants for CreateToolhelp32Snapshot() TH32CS_SNAPHEAPLIST = 0x00000001 TH32CS_SNAPPROCESS = 0x00000002 TH32CS_SNAPTHREAD = 0x00000004 TH32CS_SNAPMODULE = 0x00000008 TH32CS_INHERIT = 0x80000000 TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) THREAD_ALL_ACCESS = 0x001F03FF # Context flags for GetThreadContext() CONTEXT_FULL = 0x00010007 CONTEXT_DEBUG_REGISTERS = 0x00010010 # Memory permissions PAGE_EXECUTE_READWRITE = 0x00000040 # Hardware breakpoint conditions HW_ACCESS = 0x00000003 HW_EXECUTE = 0x00000000 HW_WRITE = 0x00000001 # Memory page permissions, used by VirtualProtect() PAGE_NOACCESS = 0x00000001 PAGE_READONLY = 0x00000002 PAGE_READWRITE = 0x00000004 PAGE_WRITECOPY = 0x00000008 PAGE_EXECUTE = 0x00000010 PAGE_EXECUTE_READ = 0x00000020 PAGE_EXECUTE_READWRITE = 0x00000040 PAGE_EXECUTE_WRITECOPY = 0x00000080 PAGE_GUARD = 0x00000100 PAGE_NOCACHE = 0x00000200 PAGE_WRITECOMBINE = 0x00000400 # Structures for CreateProcessA() function # STARTUPINFO describes how to spawn the process class STARTUPINFO(Structure): _fields_ = [ ("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", LPBYTE), ("hStdInput", HANDLE), ("hStdOutput", HANDLE), ("hStdError", HANDLE), ] # PROCESS_INFORMATION receives its information # after the target process has been successfully # started. class PROCESS_INFORMATION(Structure): _fields_ = [ ("hProcess", HANDLE), ("hThread", HANDLE), ("dwProcessId", DWORD), ("dwThreadId", DWORD), ] # When the dwDebugEventCode is evaluated class EXCEPTION_RECORD(Structure): pass EXCEPTION_RECORD._fields_ = [ ("ExceptionCode", DWORD), ("ExceptionFlags", DWORD), ("ExceptionRecord", POINTER(EXCEPTION_RECORD)), ("ExceptionAddress", PVOID), ("NumberParameters", DWORD), ("ExceptionInformation", UINT_PTR * 15), ] class _EXCEPTION_RECORD(Structure): _fields_ = [ ("ExceptionCode", DWORD), ("ExceptionFlags", DWORD), ("ExceptionRecord", POINTER(EXCEPTION_RECORD)), ("ExceptionAddress", PVOID), ("NumberParameters", DWORD), ("ExceptionInformation", UINT_PTR * 15), ] # Exceptions class EXCEPTION_DEBUG_INFO(Structure): _fields_ = [ ("ExceptionRecord", EXCEPTION_RECORD), ("dwFirstChance", DWORD), ] # it populates this union appropriately class DEBUG_EVENT_UNION(Union): _fields_ = [ ("Exception", EXCEPTION_DEBUG_INFO), # ("CreateThread", CREATE_THREAD_DEBUG_INFO), # ("CreateProcessInfo", CREATE_PROCESS_DEBUG_INFO), # ("ExitThread", EXIT_THREAD_DEBUG_INFO), # ("ExitProcess", EXIT_PROCESS_DEBUG_INFO), # ("LoadDll", LOAD_DLL_DEBUG_INFO), # ("UnloadDll", UNLOAD_DLL_DEBUG_INFO), # ("DebugString", OUTPUT_DEBUG_STRING_INFO), # ("RipInfo", RIP_INFO), ] # DEBUG_EVENT describes a debugging event # that the debugger has trapped class DEBUG_EVENT(Structure): _fields_ = [ ("dwDebugEventCode", DWORD), ("dwProcessId", DWORD), ("dwThreadId", DWORD), ("u", DEBUG_EVENT_UNION), ] # 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), ] # THREADENTRY32 contains information about a thread # we use this for enumerating all of the system threads class THREADENTRY32(Structure): _fields_ = [ ("dwSize", DWORD), ("cntUsage", DWORD), ("th32ThreadID", DWORD), ("th32OwnerProcessID", DWORD), ("tpBasePri", DWORD), ("tpDeltaPri", DWORD), ("dwFlags", DWORD), ] # Supporting struct for the SYSTEM_INFO_UNION union class PROC_STRUCT(Structure): _fields_ = [ ("wProcessorArchitecture", WORD), ("wReserved", WORD), ] # Supporting union for the SYSTEM_INFO struct class SYSTEM_INFO_UNION(Union): _fields_ = [ ("dwOemId", DWORD), ("sProcStruc", PROC_STRUCT), ] # SYSTEM_INFO structure is populated when a call to # kernel32.GetSystemInfo() is made. We use the dwPageSize # member for size calculations when setting memory breakpoints class SYSTEM_INFO(Structure): _fields_ = [ ("uSysInfo", SYSTEM_INFO_UNION), ("dwPageSize", DWORD), ("lpMinimumApplicationAddress", LPVOID), ("lpMaximumApplicationAddress", LPVOID), ("dwActiveProcessorMask", DWORD), ("dwNumberOfProcessors", DWORD), ("dwProcessorType", DWORD), ("dwAllocationGranularity", DWORD), ("wProcessorLevel", WORD), ("wProcessorRevision", WORD), ] # MEMORY_BASIC_INFORMATION contains information about a # particular region of memory. A call to kernel32.VirtualQuery() # populates this structure. class MEMORY_BASIC_INFORMATION(Structure): _fields_ = [ ("BaseAddress", PVOID), ("AllocationBase", PVOID), ("AllocationProtect", DWORD), ("RegionSize", SIZE_T), ("State", DWORD), ("Protect", DWORD), ("Type", DWORD), ] | cs |
my_debugger
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | from ctypes import * from my_debugger_defines import * kernel32 = windll.kernel32 class debugger(object): """docstring for debugger""" def __init__(self): self.h_process = None self.pid = None self.debugger_active = False def load(self, path_to_exe): creation_flags = DEBUG_PROCESS startupInfo = STARTUPINFO() processInfo = PROCESS_INFORMATION() startupInfo.dwFlags = 0x1 startupInfo.wShowWindow = 0x0 startupInfo.cb = sizeof(startupInfo) if kernel32.CreateProcessA(path_to_exe, None, None, None, None, creation_flags, None, None, byref(startupInfo), byref(processInfo)): print "[*] We have successfully launched the process!" print "[*] PID: %d" % processInfo.dwProcessId self.h_process = self.open_process(processInfo.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) 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 detach(self): if kernel32.DebugActiveProcessStop(self.pid): print "[*] Finished debugging. Exiting..." return True else: print "There was an error" return False | cs |
my_test
1 2 3 4 5 6 | import my_debugger debugger = my_debugger.debugger() debugger.load("d:\program files (x86)\kakao\kakaotalk\kakaotalk.exe") | cs |
[*] We have successfully launched the process!
[*] PID: 8556
위와 같은 메시지와 함께 종료..
'Study > Python' 카테고리의 다른 글
코드 인젝션 활용 (0) | 2017.07.09 |
---|---|
윈도우 DEP 우회 (0) | 2017.07.03 |
PyDbg 접근 위반 핸들 (0) | 2017.07.03 |
소켓 랜덤채팅 (0) | 2017.07.03 |
ctypes 파이썬 외부 함수 라이브러리 (0) | 2017.06.13 |
Comments