본문 바로가기
파이썬 스터디 과제/파이썬 해킹 프로그래밍

3장-3 디버그 이벤트 핸들러 구현

by laoching 2015. 1. 15.
728x90
반응형

디버그 이벤트 핸들러 구현

이벤트가 발생했을 때 그 이벤트에 반응하기 위해서는 각 디버깅 이벤트에 대한 핸들러를 구현해야 한다.

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인 스레드가 종료된다는것을 뜻한다.

728x90
반응형

댓글