/** * @brief * @param * @see * @remarks * @code * @endcode * @return **/ bool ModuleInfo::initialize( _In_ const LOAD_DLL_DEBUG_INFO* dll_debug_info, _In_ DWORD module_size ) { _ASSERTE(NULL != dll_debug_info); if (NULL==dll_debug_info) return false; _file_handle = dll_debug_info->hFile; _dll_base_address = (DWORD_PTR)dll_debug_info->lpBaseOfDll; _debug_info_file_offset = dll_debug_info->dwDebugInfoFileOffset; _debug_info_size = dll_debug_info->nDebugInfoSize; _is_unicode = (0 != dll_debug_info->fUnicode) ? true : false; if (true != get_filepath_by_handle(_file_handle, _image_name)) { log_err L"get_filepath_by_handle(proces = 0x%08x, file = 0x%08x)" log_end return false; }
/// @brief int main() { // create process with /dbg STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; wchar_t* target = L".\\debuggee.exe"; if (TRUE != CreateProcessW( target, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_PROCESS, NULL, NULL, &si, &pi)) { log("CreateProcess() failed. gle = %u", GetLastError()); return -1; } log("process created. pid = %u", pi.dwProcessId); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); DEBUG_EVENT debug_event = {0}; while (true) { if (TRUE != WaitForDebugEvent(&debug_event, 100)) continue; DWORD continue_status = DBG_CONTINUE; switch (debug_event.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: { PDEBUGGEE dbge = NULL; for (int i = 0; i < sizeof(_debuggees) / sizeof(DEBUGGEE); ++i) { if (_debuggees[i]._pid == debug_event.dwProcessId) { dbge = &_debuggees[i]; } } if (NULL == dbge) break; LPEXCEPTION_DEBUG_INFO edi = &debug_event.u.Exception; switch (edi->ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: if (true != dbge->_initial_bp_hit) { dbge->_initial_bp_hit = true; log( "\n" "[EXCEPTION_DEBUG_EVENT] \n"\ " img = %ws \n"\ " pid = %u, tid = %u \n"\ " + initial bp triggered at 0x%llx", dbge->_image_name.c_str(), debug_event.dwProcessId, debug_event.dwThreadId, edi->ExceptionRecord.ExceptionAddress); // // install breakpoint at ep. // dbge->_bp_param = { 0 }; HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, debug_event.dwThreadId); if (NULL == thread_handle) { _ASSERTE(!"oops"); break; } dbge->_bp_param.hthread = thread_handle; dbge->_bp_param.hproc = dbge->_proc_handle; dbge->_bp_addr = dbge->_start_address; bool bp_ret = set_break_point( &dbge->_bp_param, (DWORD_PTR)dbge->_bp_addr, &dbge->_opcode); if (true != bp_ret) { _ASSERTE(true == bp_ret); break; } continue_status = DBG_EXCEPTION_HANDLED; log(" + break point installed at 0x%llx", dbge->_bp_addr); _pause; } else { log( "\n" "[EXCEPTION_DEBUG_EVENT] \n"\ " img = %ws \n"\ " pid = %u, tid = %u \n"\ " + break point at 0x%llx", dbge->_image_name.c_str(), debug_event.dwProcessId, debug_event.dwThreadId, edi->ExceptionRecord.ExceptionAddress); // // restore opcode and resume // if (edi->ExceptionRecord.ExceptionAddress != dbge->_bp_addr) { _ASSERTE(!"oops"); break; } dbge->_bp_param.context.ContextFlags = CONTEXT_ALL; if (TRUE != GetThreadContext( dbge->_bp_param.hthread, &dbge->_bp_param.context)) { _ASSERTE(!"oops!"); break; } if (true != clear_break_point( &dbge->_bp_param, (DWORD_PTR)dbge->_bp_addr, dbge->_opcode, true)) { _ASSERTE(!"oops"); break; } continue_status = DBG_EXCEPTION_HANDLED; log(" + breakpoint un-installed at 0x%llx", dbge->_bp_addr); // single step enable ch_param param = { 0 }; param.hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, debug_event.dwThreadId); if (NULL != param.hthread) { param.context.ContextFlags = CONTEXT_ALL; if (TRUE != GetThreadContext(param.hthread, ¶m.context)) { _ASSERTE(!"oops!"); break; } set_single_step(¶m); } _pause; } break; case EXCEPTION_SINGLE_STEP: { //log( // "\n" // "[EXCEPTION_DEBUG_EVENT] \n"\ // " pid = %u, tid = %u\n"\ // " + handle single step at 0x%llx", // debug_event.dwProcessId, // debug_event.dwThreadId, // edi->ExceptionRecord.ExceptionAddress); // call 명령이라면 log log_branch(edi->ExceptionRecord.ExceptionAddress, debug_event.dwProcessId, debug_event.dwThreadId); //continue_status = DBG_EXCEPTION_NOT_HANDLED; continue_status = DBG_EXCEPTION_HANDLED; break; } default: if (0 != edi->dwFirstChance) { log("\n" "[EXCEPTION_DEBUG_EVENT]\n"\ " pid = %u, tid = %u\n"\ " + %s (first chance) at 0x%llx", debug_event.dwProcessId, debug_event.dwThreadId, exception_code_str(edi->ExceptionRecord.ExceptionCode), edi->ExceptionRecord.ExceptionAddress ); } else { log("\n" "[EXCEPTION_DEBUG_EVENT]\n"\ " + %s (second chance) at 0x%llx, can't handle anymore.", exception_code_str(edi->ExceptionRecord.ExceptionCode), edi->ExceptionRecord.ExceptionAddress ); } continue_status = DBG_EXCEPTION_NOT_HANDLED; break; } break; } case CREATE_THREAD_DEBUG_EVENT: { //str = "CREATE_THREAD_DEBUG_EVENT"; break; } case CREATE_PROCESS_DEBUG_EVENT: { LPCREATE_PROCESS_DEBUG_INFO cpi = &debug_event.u.CreateProcessInfo; std::wstring image; if (true != get_filepath_by_handle(cpi->hFile, image)) { image = L"unknown image path"; } log("\n"\ "[CREATE_PROCESS_DEBUG_EVENT]\n"\ " img = %ws\n"\ " pid = %u, tid = %u, ep = 0x%llx", image.c_str(), debug_event.dwProcessId, debug_event.dwThreadId, cpi->lpStartAddress ); for (int i = 0; i < sizeof(_debuggees) / sizeof(DEBUGGEE); ++i) { if (_debuggees[i]._pid == 0) { _debuggees[i]._initial_bp_hit = 0; _debuggees[i]._pid = debug_event.dwProcessId; _debuggees[i]._file_handle = debug_event.u.CreateProcessInfo.hFile; _debuggees[i]._proc_handle = debug_event.u.CreateProcessInfo.hProcess; _debuggees[i]._thread_handle = debug_event.u.CreateProcessInfo.hThread; _debuggees[i]._base_of_image = debug_event.u.CreateProcessInfo.lpBaseOfImage; _debuggees[i]._thread_local_base = debug_event.u.CreateProcessInfo.lpThreadLocalBase; _debuggees[i]._start_address = debug_event.u.CreateProcessInfo.lpStartAddress; _debuggees[i]._image_name = image; break; } } break; } case EXIT_THREAD_DEBUG_EVENT: { //str = "EXIT_THREAD_DEBUG_EVENT"; break; } //case EXIT_PROCESS_DEBUG_EVENT: // { // str = "EXIT_PROCESS_DEBUG_EVENT"; // break; // } case LOAD_DLL_DEBUG_EVENT: { LPLOAD_DLL_DEBUG_INFO lddi = &debug_event.u.LoadDll; std::wstring dll_path; if (true != get_filepath_by_handle(lddi->hFile, dll_path)) { dll_path = L"Unknown dll path"; } // get dll file size if (0 != k32_base) break; HANDLE hFile = CreateFileW(dll_path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (NULL == hFile) break; LARGE_INTEGER file_size = { 0 }; if (TRUE != GetFileSizeEx(lddi->hFile, &file_size)) { return false; } if (std::wstring::npos != dll_path.rfind(L"ntdll.dll")) { log("\n" "gotcha!\n"\ " pid = %u, tid = %u, img = %ws, addr ragne = 0x%08x ~ 0x%08x", debug_event.dwProcessId, debug_event.dwThreadId, dll_path.c_str(), lddi->lpBaseOfDll, (DWORD_PTR)lddi->lpBaseOfDll + file_size.LowPart ); k32_base = (DWORD_PTR)lddi->lpBaseOfDll; k32_max = (DWORD_PTR)lddi->lpBaseOfDll + file_size.LowPart; } //log("\n" // "[LOAD_DLL_DEBUG_EVENT]\n"\ // " pid = %u, tid = %u, img = %ws", // debug_event.dwProcessId, // debug_event.dwThreadId, // dll_path.c_str() // ); break; } case UNLOAD_DLL_DEBUG_EVENT: { LPUNLOAD_DLL_DEBUG_INFO uddi = &debug_event.u.UnloadDll; // todo 3 break; } case OUTPUT_DEBUG_STRING_EVENT: { break; } case RIP_EVENT: { //str = "RIP_EVENT"; break; } default: //str = "unknown"; break; } //> continue_status 값이 //> //> DBG_CONTINUE //> EXCEPTION_DEBUG_EVENT 인 경우 //> 모든 exception processing 을 멈추고 스레드를 계속 실행 //> EXCEPTION_DEBUG_EVENT 이 아닌 경우 //> 스레드 계속 실행 //> //> DBG_EXCEPTION_NOT_HANDLED //> EXCEPTION_DEBUG_EVENT 인 경우 //> exception processing 을 계속 진행. //> first-chance exception 인 경우 seh 핸들러의 search, dispatch 로직이 실행 //> first-chance exception 이 아니라면 프로세스는 종료 됨 //> EXCEPTION_DEBUG_EVENT 이 아닌 경우 //> 스레드 계속 실행 ContinueDebugEvent(debug_event.dwProcessId,debug_event.dwThreadId,continue_status); //> debuggee is terminating if (EXIT_PROCESS_DEBUG_EVENT == debug_event.dwDebugEventCode) { int i = 0; for (; i < sizeof(_debuggees) / sizeof(DEBUGGEE); ++i) { if (_debuggees[i]._pid == debug_event.dwProcessId) { _debuggees[i]._initial_bp_hit = 0; _debuggees[i]._pid = 0; break; } } if (i == 0) { log("\n"\ "[EXIT_PROCESS_DEBUG_EVENT] \n"\ " img = %ws\n"\ " pid = %u, tid = %u\n"\ " + debuggee is terminated.", _debuggees[i]._image_name.c_str(), debug_event.dwProcessId, debug_event.dwThreadId); _pause; break; } // do nothing... } } //log("press any key to terminate..."); //getchar(); }