디버거의 메인 루프 작성
디버거가 기본 루프의 시작 부분에서 WaitForDebugEvent 함수를 사용합니다. 이 함수는 디버깅 이벤트가 발생할 때까지 디버거를 차단합니다. 디버깅 이벤트가 발생하면 시스템은 디버깅 중인 프로세스의 모든 스레드를 일시 중단하고 디버거에 이벤트를 알립니다.
디버거는 GetThreadContext, GetThreadSelectorEntry, ReadProcessMemory, SetThreadContext 및 WriteProcessMemory 함수를 사용하여 사용자와 상호 작용하거나 디버그되는 프로세스의 상태를 조작할 수 있습니다. GetThreadSelectorEntry는 지정된 선택기 및 스레드에 대한 설명자 테이블 항목을 반환합니다. 디버거는 설명자 테이블 항목을 사용하여 세그먼트 관련 주소를 선형 가상 주소로 변환합니다. ReadProcessMemory 및 WriteProcessMemory 함수에는 선형 가상 주소가 필요합니다.
디버거는 디버깅 중인 프로세스의 메모리를 자주 읽고 명령이 포함된 메모리를 명령 캐시에 씁니다. 명령이 작성된 후 디버거는 FlushInstructionCache 함수를 호출하여 캐시된 명령을 실행합니다.
디버거는 기본 루프의 끝에서 ContinueDebugEvent 함수를 사용합니다. 이 함수를 사용하면 디버깅 중인 프로세스가 계속 실행될 수 있습니다.
다음 예에서는 WaitForDebugEvent 및 ContinueDebugEvent 함수를 사용하여 간단한 디버거를 구성하는 방법을 보여 줍니다.
#include <windows.h>
DWORD OnCreateThreadDebugEvent(const LPDEBUG_EVENT);
DWORD OnCreateProcessDebugEvent(const LPDEBUG_EVENT);
DWORD OnExitThreadDebugEvent(const LPDEBUG_EVENT);
DWORD OnExitProcessDebugEvent(const LPDEBUG_EVENT);
DWORD OnLoadDllDebugEvent(const LPDEBUG_EVENT);
DWORD OnUnloadDllDebugEvent(const LPDEBUG_EVENT);
DWORD OnOutputDebugStringEvent(const LPDEBUG_EVENT);
DWORD OnRipEvent(const LPDEBUG_EVENT);
void EnterDebugLoop(const LPDEBUG_EVENT DebugEv)
{
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
for(;;)
{
// Wait for a debugging event to occur. The second parameter indicates
// that the function does not return until a debugging event occurs.
WaitForDebugEvent(DebugEv, INFINITE);
// Process the debugging event code.
switch (DebugEv->dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
// Process the exception code. When handling
// exceptions, remember to set the continuation
// status parameter (dwContinueStatus). This value
// is used by the ContinueDebugEvent function.
switch(DebugEv->u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_BREAKPOINT:
// First chance: Display the current
// instruction and register values.
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_SINGLE_STEP:
// First chance: Update the display of the
// current instruction and register values.
break;
case DBG_CONTROL_C:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
default:
// Handle other exceptions.
break;
}
break;
case CREATE_THREAD_DEBUG_EVENT:
// As needed, examine or change the thread's registers
// with the GetThreadContext and SetThreadContext functions;
// and suspend and resume thread execution with the
// SuspendThread and ResumeThread functions.
dwContinueStatus = OnCreateThreadDebugEvent(DebugEv);
break;
case CREATE_PROCESS_DEBUG_EVENT:
// As needed, examine or change the registers of the
// process's initial thread with the GetThreadContext and
// SetThreadContext functions; read from and write to the
// process's virtual memory with the ReadProcessMemory and
// WriteProcessMemory functions; and suspend and resume
// thread execution with the SuspendThread and ResumeThread
// functions. Be sure to close the handle to the process image
// file with CloseHandle.
dwContinueStatus = OnCreateProcessDebugEvent(DebugEv);
break;
case EXIT_THREAD_DEBUG_EVENT:
// Display the thread's exit code.
dwContinueStatus = OnExitThreadDebugEvent(DebugEv);
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Display the process's exit code.
dwContinueStatus = OnExitProcessDebugEvent(DebugEv);
break;
case LOAD_DLL_DEBUG_EVENT:
// Read the debugging information included in the newly
// loaded DLL. Be sure to close the handle to the loaded DLL
// with CloseHandle.
dwContinueStatus = OnLoadDllDebugEvent(DebugEv);
break;
case UNLOAD_DLL_DEBUG_EVENT:
// Display a message that the DLL has been unloaded.
dwContinueStatus = OnUnloadDllDebugEvent(DebugEv);
break;
case OUTPUT_DEBUG_STRING_EVENT:
// Display the output debugging string.
dwContinueStatus = OnOutputDebugStringEvent(DebugEv);
break;
case RIP_EVENT:
dwContinueStatus = OnRipEvent(DebugEv);
break;
}
// Resume executing the thread that reported the debugging event.
ContinueDebugEvent(DebugEv->dwProcessId,
DebugEv->dwThreadId,
dwContinueStatus);
}
}