디버그 이벤트 핸들러 구현
이벤트가 발생했을 때 그 이벤트에 반응하기 위해서는 각 디버깅 이벤트에 대한 핸들러를 구현해야 한다.
DEBUG_EVENT구조체에대해 자세히 알아보고 구조체 내부의 정보를 이용해 어떻게 디버깅이벤트를 처리할 것인지 판단할 것이다.
DEBUG_EVENT
-----------------------------------------------------
typedef struct DEBUG_EVENT {
DWORD dwDebugEventCode;
DWORD dwProcessId;
DWORD dwThreadId;
union {
EXCEPTION_DEBUG_INfO Exception;
CREATE_THREAD_DBUG_INFO CreateThread;
CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
EXIT_THREAD_DEBUG_INFO ExitThread;
EXIT_PROCESS_DEBUG_INFO ExitProcess;
LOAD_DLL_DEBUG_INFO LoadDll;
UNLOAD_DLL_DEBUG_INFO InloadDll;
OUTPUT_DEBUG_STRING_INFO DebugString;
RIP_INFO Ripinfo;
}u;
};
-----------------------------------------------------
DEBUG_EVENT 구조체 안에는 유용한 정보가 많이 포함돼 있다.
특히 dwDebugEventCode를 통해 발생한 이벤트가 어떤 종류의 이벤트인지 알 수 있다.
또한 발생한 이벤트의 종류를 알게 되면 u 유니언에서 어떤 구조체를 사용해야 하는지도 알 수 있게 된다.
각 이벤트에서 어떤 구조체를 사용해야 하는지에 대한 표다.
이벤트 코드 |
이벤트 코드 값 |
유니언 u의 값 |
|
0x1 |
EXCEPTION_DEBUG_EVENT |
u.Exception |
|
0x2 |
CREATE_THREAD_DEBUG_EVENT |
u.CreateThread |
|
0x3 |
CREATE_PROCESS_DEBUG_EVENT |
u.CreateProcessinfo |
|
0x4 |
EXIT_THREAD_DEBUG_EVENT |
u.ExitThread |
|
0x5 |
EXIT_PROCESS_DEBUG_EVENT |
u.ExitProcess |
|
0x6 |
LOAD_DLL_DEBUG_EVENT |
u.LoadDll |
|
0x7 |
UNLOAD_DLL_DEBUG_EVENT |
u.unloadDll |
|
0x8 |
OUTPUT_DEBUG_STRING_EVENT |
u.DebugString |
|
0x9 |
RIP_EVENT |
u.Ripinfo |
dwDebugEventCode 값을 조사함으로써 u 유니언 내부의 어떤 구조체를 사용해야 하는지 알 수 있다. 그럼 어떤 이벤트가 발생했는지 판단할 수 있게 my_debugger.py와 my_test.py의 코드를 변경해보자.
my_debugger.py
-----------------------------------------------------
# -*- coding: cp949 -*-
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.h_thread = None
self.context = None
def load(self,path_to_exe):
creation_flags = DEBUG_PROCESS
startupinfo = STARTUPINFO()
process_information = 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(process_information)):
print "[*] We have successfully launched the process!"
print "[*] PID : %d" % process_information.dwProcessId
self.h_process = self.open_process(process_information.dwProcessId)
else:
print "[*] Error : 0x%08x." % kernel32.GetLastError()
def open_process(self,pid):
# PROCESS_ALL_ACCESS = 0x0x001F0FFF
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid)
return h_process
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."
return False
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=None, h_thread=None):
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 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):
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)
def detach(self):
if kernel32.DebugActiveProcessStop(self.pid):
print "[*] Finished debugging. Exiting..."
return True
else:
print "There was an error"
return False
-----------------------------------------------------
my_test.py
-----------------------------------------------------
# -*- coding: cp949 -*-
import my_debugger
debugger = my_debugger.debugger()
pid = raw_input("Enter the PID of the process to attach to: ")
debugger.attach(int(pid))
debugger.run()
debugger.detach()
-----------------------------------------------------
실행화면
위 사진을 보면 CREATE_PROCESS_EVENT(0x3)이 가장 먼저 발생됐다.
그 다음으론 LOAD_DLL_DEBUG_EVENT(0x6)이 발생됐다.
그 이후에는 CREATE_THREAD_DEBUG_EVENT(0x2)와 EXCEPTION_DEBUG_EVENT(0x1)가 발생됐다.
EXCETION_DEBUG_EVENT(0x1)는 윈도우가 처리하는 이벤트로 디버거가 해당 프로세스가 계속 실행되게 만들기 전에 그 프로세스의 상태 정보를 조사할 수 있게 만들어 준다.
마지막으로 EXIT_THREAD_DEBUG_EVENT(0x4)는 단순히 TID가 2044인 스레드가 종료된다는것을 뜻한다.
'파이썬 스터디 과제 > 파이썬 해킹 프로그래밍' 카테고리의 다른 글
3장-4 브레이크포인트-2 (하드브레이크포인트) (0) | 2015.01.17 |
---|---|
3장-4 브레이크포인트-1 (소프트브레이크포인트) (0) | 2015.01.16 |
3장-2 CPU 레지스터 상태 얻기 (0) | 2015.01.14 |
3장-1 디버기 (0) | 2015.01.14 |
2장-디버거 (0) | 2015.01.12 |
댓글