OpenProcess 로 handle 을 가져오고, DebugActiveProcess(pid) 로 process 에 attach 한다.
WaitForDebugEvent() 로 break 가 걸리면, process 가 멈추고, 이 함수에 lpDebugEvent 로 debug event 를 넘겨준다.
DebugActiveProcessStop() 은 detach 를 할 때 쓰인다.
아래는 PyDbg 를 이용한 source code 이다. 이미 실행되어진 process 의 pid 를 task-manager 로 알아낸 후에 입력을 해주면, 그 process 로 attach 를 하는 코드이다.
if kernel32.DebugActiveProcess(pid): self.debugger_active = True self.pid = int(pid) self.run() while self.debugger_active == True: debug_event = DEBUG_EVENT() continue_status = DBG_CONTINUE if kernel32.WaitForDebugEvent(byref(debug_event), INFINTE): raw_input("press a key to continue...") self.debugger_active = False kernel32.ContinuewDebugEvent(\ debug_event.dwProcessId,\ debug_event.dwThreadId,\ continue_status) if kernel32.DebugActiveProcessStop(self.pid): print "[*] Finished debugging. Exiting..." return True else: print "There was an error" return False
HANDLE WINAPI OpenProcess( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId );
BOOL WINAPI DebugActiveProcess( _In_ DWORD dwProcessId );
BOOL WINAPI WaitForDebugEvent( _Out_ LPDEBUG_EVENT lpDebugEvent, _In_ DWORD dwMilliseconds // INFINITE or maximum wait time );
BOOL WINAPI ContinueDebugEvent( _In_ DWORD dwProcessId, _In_ DWORD dwThreadId, _In_ DWORD dwContinueStatus );
BOOL WINAPI DebugActiveProcessStop( _In_ DWORD dwProcessId );
DEBUG_EVENT structure
typedef struct _DEBUG_EVENT {
DWORD dwDebugEventCode;
DWORD dwProcessId;
DWORD dwThreadId;
union {
EXCEPTION_DEBUG_INFO Exception;
CREATE_THREAD_DEBUG_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 UnloadDll;
OUTPUT_DEBUG_STRING_INFO DebugString;
RIP_INFO RipInfo;
} u;
} DEBUG_EVENT, *LPDEBUG_EVENT;
dwDebugEventCode : 어떤 종류의 event 로 인해 멈추게 되었는지 알려준다.
그리고 이 dwDebugEventCode 가 갖는 값에 따라 union 의 값도 결정된다. 예를 들면, dwDebugEventCode 가
EXCEPTION_DEBUG_EVENT (0x1) -> u.Exception, EXCEPTION_DEBUG_INFO structure.이런 식이 된다.
CREATE_THREAD_DEBUG_EVENT (0x2) -> u.CreateThread, CREATE_THREAD_DEBUG_INFO structure.
…
Test
아래 debuggee_process.py 를 실행한 상태에서 debugger.py 를 실행해서 debuggee process 에 attach 를 하게 되면, system 에서 debug event 를 보내주게 된다. 이 debug event 들을 debugger 에서는 보여주게 되어 있고, 이중에 printf 함수가 실행될 때 printf 함수의 주소를 출력해 준다.LOAD_DLL_DEBUG_EVENT
처음에 attach를 하게 되면 LOAD_DLL_DEBUG_EVENT 가 화면에 찍히게 된다. 이 이벤트가 이미 dll 이 load 가 끝난상태인데 왜 찍힐 까 생각했는데, ref. 1 에서 아래처럼 얘기하고 있다.
이 event 는 debuggee process(디버그 하고 있는 process) 가 LoadLibrary() 를 실행할 때에 발생하기도 하지만, PE loader 가 dll library 의 link 를 파악할 때도 발생한다.
그래서 아마도 attach 할 때 dll library 의 link 를 파악하는 과정이 있어서 event 가 발생하는 듯 하다.
Debug event 에 대한 설명은 ref. 1 을 참조하도록 하자.
debugger.py
#source from Gray Hat Python # memory_breakpoints = {} kernel32 = windll.kernel32 pid = raw_input("Enter the PID of the process to attach to: ") # attach kernel32.DebugActiveProcess(int(pid)) # func_resolve dll = "msvcrt.dll" function = "printf" handle = kernel32.GetModuleHandleA(dll) address = kernel32.GetProcAddress(handle, function) kernel32.CloseHandle(handle) # bp_set_mem mbi = MEMORY_BASIC_INFORMATION() size = 10 memory_breakpoints[address] = (address, size, mbi) # run debug_event = DEBUG_EVENT() continue_status = DBG_CONTINUE while True : if kernel32.WaitForDebugEvent(byref(debug_event),100): # grab various information with regards to the current exception. thread_id = debug_event.dwThreadId h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id) context = CONTEXT() context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS context = kernel32.GetThreadContext(h_thread, byref(context)) print "Event Code: %d Thread ID: %d" % \ (debug_event.dwDebugEventCode,debug_event.dwThreadId) if debug_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT: exception = debug_event.u.Exception.ExceptionRecord.ExceptionCode exception_address = debug_event.u.Exception.ExceptionRecord.ExceptionAddress # call the internal handler for the exception event that just occured. if exception == EXCEPTION_ACCESS_VIOLATION: print "Access Violation Detected." elif exception == EXCEPTION_BREAKPOINT: print "[*] Exception address: 0x%08x" % exception_address # check if the breakpoint is one that we set if not memory_breakpoints.has_key(exception_address): continue_status = DBG_CONTINUE elif exception == EXCEPTION_GUARD_PAGE: print "Guard Page Access Detected." elif exception == EXCEPTION_SINGLE_STEP: exception_handler_single_step() kernel32.ContinueDebugEvent(debug_event.dwProcessId,\ debug_event.dwThreadId, continue_status)
debugee_process.py
from ctypes import * import time msvcrt = cdll.msvcrt counter = 0 while 1: msvcrt.printf("Loop iteration %d!\n",counter) time.sleep(2) counter += 1
INT3 의 동작
INT3 interrupt 가 걸려서 WaitForDebugEvent() 에 control 을 넘겨주는 과정은 아래 경로를 참고하면 조금 이해가 될 것이다.
http://i5on9i.blogspot.kr/2013/04/int-3.html
댓글 없음:
댓글 쓰기