/* * loadProg - load the task to sample */ static void loadProg( const char *exe, char *cmdline ) { STARTUPINFO sinfo; PROCESS_INFORMATION pinfo; int rc; memset( &sinfo, 0, sizeof( sinfo ) ); sinfo.cb = sizeof( sinfo ); // set ShowWindow default value for nCmdShow parameter sinfo.dwFlags = STARTF_USESHOWWINDOW; sinfo.wShowWindow = SW_SHOWNORMAL; rc = CreateProcess( NULL, /* application name */ cmdline, /* command line */ NULL, /* process attributes */ NULL, /* thread attributes */ FALSE, /* inherit handles */ DEBUG_PROCESS,//DEBUG_ONLY_THIS_PROCESS, /* creation flags */ NULL, /* environment block */ NULL, /* starting directory */ &sinfo, /* startup info */ &pinfo /* process info */ ); if( !rc ) { internalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] ); } rc = WaitForDebugEvent( &debugEvent, INFINITE ); if( !rc || (debugEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) || (debugEvent.dwProcessId != pinfo.dwProcessId) ) { internalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] ); } taskPid = debugEvent.dwProcessId; processHandle = debugEvent.u.CreateProcessInfo.hProcess; newThread( debugEvent.dwThreadId, debugEvent.u.CreateProcessInfo.hThread ); codeLoad( debugEvent.u.CreateProcessInfo.hFile, (DWORD)debugEvent.u.CreateProcessInfo.lpBaseOfImage, exe, SAMP_MAIN_LOAD ); } /* loadProg */
BOOL CDbgHook::DbgAttatch(DWORD dwPid) { CProcessChecker pck; /* pck.SetData(dwPid); if (!pck.IsProcess()) return FALSE; */ if (!DebugActiveProcess(dwPid)) return FALSE; if (!WaitForDebugEvent(&m_de, INFINITE)) return FALSE; if (m_de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) return FALSE; memcpy(&m_cpdi, &m_de.u.CreateProcessInfo, sizeof(CREATE_PROCESS_DEBUG_INFO)); return TRUE; }
void DebugLoop() { DEBUG_EVENT de; //int dwContinuesStatus; //wait for event.... while(WaitForDebugEvent(&de,INFINITE)) { //dwContinuesStatus=0x00010002; //被调试进程生成或者附加事件 if(CREATE_PROCESS_DEBUG_EVENT==de.dwDebugEventCode) { printf("created debug !\n"); OnCreateProcessDebugEvent(&de); printf("seccessfully created int 3\n"); } //异常事件 else if (EXCEPTION_DEBUG_EVENT==de.dwDebugEventCode) { printf("Exception debug event !code =%X\n",de.dwDebugEventCode); if(OnExceptionDebugEvent(&de)) { printf("on exception debug event\n"); continue; } } //被调试进程终止事件 else if (EXIT_PROCESS_DEBUG_EVENT==de.dwDebugEventCode) //被调试者终止-调试器终止 { printf("debugee exited \n"); break; } //再次运行被调试者 ContinueDebugEvent(de.dwProcessId,de.dwThreadId,0x00010002) ; } }
void ContextOverride::OnPreExecute( PreExecuteEvent &event, bool firstTime ) { if (!firstTime) return; if (m_done) return; u32 entry = LxEmulator.Proc()->GetEntryPoint(); if (event.Cpu->EIP != entry) return; CONTEXT ctx; RefProcess *refproc = LxEmulator.RefProc(); m_pi = refproc->GetProcessInformation(); m_event = refproc->GetDebugEvent(); byte origByte = refproc->SetInt3(entry); ContinueDebugEvent(m_pi->dwProcessId, m_pi->dwThreadId, DBG_CONTINUE); while (WaitForDebugEvent(m_event, INFINITE)) { if (m_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT && m_event->u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) { refproc->GetMainContext(&ctx, CONTEXT_CONTROL); ctx.Eip--; if (ctx.Eip != entry) { LxFatal("SyncDiff: Unexpected sync address %08x, should be %08x\n", ctx.Eip, entry); } refproc->SetMainContext(&ctx); refproc->RestoreInt3(ctx.Eip, origByte); break; } ContinueDebugEvent(m_pi->dwProcessId, m_pi->dwThreadId, DBG_CONTINUE); } refproc->SetTF(); LxInfo("Overriding Context..\n"); OverrideContext(event.Cpu); m_done = true; }
/* Kill all inferiors. */ static void win32_kill (void) { if (current_process_handle == NULL) return; TerminateProcess (current_process_handle, 0); for (;;) { if (!child_continue (DBG_CONTINUE, -1)) break; if (!WaitForDebugEvent (¤t_event, INFINITE)) break; if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { struct target_waitstatus our_status = { 0 }; handle_output_debug_string (&our_status); } } win32_clear_inferiors (); }
int _tmain( int argc, _TCHAR* argv[] ) { BOOL bRet = FALSE; STARTUPINFO startupInfo = { sizeof startupInfo }; PROCESS_INFORMATION procInfo = { 0 }; DEBUG_EVENT event = { 0 }; _EventCallback callback; Exec exec; HRESULT hr = S_OK; LaunchInfo info = { 0 }; InitDebug(); //char* s1 = new ( _NORMAL_BLOCK, __FILE__, __LINE__ ) char[100]; //strcpy( s1, "hello, yo!" ); //char* s2 = (char*) malloc( 300 ); //strcpy( s2, "say what?" ); callback.SetExec( &exec ); hr = exec.Init( &callback ); if ( FAILED( hr ) ) goto Error; #if 0 bRet = CreateProcess( L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\test1\\Debug\\test1.exe", //bRet = CreateProcess( L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\test1\\x64\\Debug\\test1.exe", NULL, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &procInfo ); if ( !bRet ) goto Error; #else //#define TEST_APP64 #ifndef TEST_APP64 info.CommandLine = L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\Debug\\test1.exe\""; info.Exe = L"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\Debug\\test1.exe"; #else info.CommandLine =L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\x64\\Debug\\test1.exe\""; info.Exe = L"\"F:\\Users\\Magus\\Documents\\Visual Studio 2008\\Projects\\Debugger1\\x64\\Debug\\test1.exe\""; #endif IProcess* proc = NULL; //hr = exec.Attach( 5336, proc ); hr = exec.Launch( &info, proc ); if ( FAILED( hr ) ) goto Error; #endif #if 0 bRet = WaitForDebugEvent( &event, INFINITE ); if ( !bRet ) goto Error; #else int stepCount = 0; for ( int i = 0; /* doesn't end */ ; i++ ) { hr = exec.WaitForEvent( 1000 ); if ( FAILED( hr ) ) goto Error; hr = exec.DispatchEvent(); if ( FAILED( hr ) ) goto Error; #if 1 if ( proc->IsStopped() ) { if ( callback.GetHitBp() ) { stepCount++; //11728 IModule* mod = NULL; UINT_PTR baseAddr = 0; callback.GetModule( mod ); baseAddr = (UINT_PTR) mod->GetImageBase(); mod->Release(); //hr = exec.StepOut( proc, (void*) (baseAddr + 0x00011728) ); //hr = exec.StepInstruction( proc, true ); if ( stepCount > 1 ) hr = exec.StepInstruction( proc, true, true ); else { //113A5 AddressRange range = { baseAddr + 0x0001137A, baseAddr + 0x000113A5 }; hr = exec.StepRange( proc, false, range, true ); } if ( FAILED( hr ) ) goto Error; } else { hr = exec.Continue( proc, true ); if ( FAILED( hr ) ) goto Error; } } #endif #if 1 if ( i == 0 ) { IModule* mod = NULL; UINT_PTR baseAddr = 0; callback.GetModule( mod ); baseAddr = (UINT_PTR) mod->GetImageBase(); // 0x003C137A, 0x003C1395 // 1137A, 11395 //exec.SetBreakpoint( proc, baseAddr + 0x0001138C, 255 ); exec.SetBreakpoint( proc, baseAddr + 0x0001137A ); //exec.SetBreakpoint( proc, baseAddr + 0x00011395, 129 ); mod->Release(); } #endif } #endif Error: //exec.Detach( proc ); // when the debugger goes away, so does the debuggee automatically //if ( procInfo.hThread != NULL ) //{ // CloseHandle( procInfo.hThread ); //} //if ( procInfo.hProcess != NULL ) //{ // TerminateProcess( procInfo.hProcess, MAXINT ); // CloseHandle( procInfo.hProcess ); //} if ( proc != NULL ) proc->Release(); return 0; }
/* * StartProg - start sampling a program */ void StartProg( char *cmd, char *prog, char *full_args, char *dos_args ) { DWORD code; DWORD tid; CONTEXT con; BOOL waiting_for_first_bp; SIZE_T len; DWORD continue_how; BOOL rc; seg_offset where; DWORD ttid; HANDLE tth; cmd = cmd; strcpy( utilBuff, prog ); strcat( utilBuff, " " ); strcat( utilBuff, full_args ); loadProg( prog, utilBuff ); tid = debugEvent.dwThreadId; tth = CreateThread( NULL, 1024, TimerThread, NULL, 0, &ttid ); if( !tth ) { internalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] ); } /* attempt to ensure that we can get all of our samples in one shot */ SetThreadPriority( tth, THREAD_PRIORITY_TIME_CRITICAL ); Output( MsgArray[MSG_SAMPLE_1 - ERR_FIRST_MESSAGE] ); Output( prog ); Output( "\r\n" ); waiting_for_first_bp = TRUE; continue_how = DBG_CONTINUE; for( ;; ) { ContinueDebugEvent( taskPid, tid, continue_how ); rc = WaitForDebugEvent( &debugEvent, INFINITE ); continue_how = DBG_CONTINUE; tid = debugEvent.dwThreadId; switch( debugEvent.dwDebugEventCode ) { case EXCEPTION_DEBUG_EVENT: code = debugEvent.u.Exception.ExceptionRecord.ExceptionCode; switch( code ) { case STATUS_SINGLE_STEP: if( timeOut ) { myGetThreadContext( tid, &con ); RecordSample( con.Eip, con.SegCs, tid ); timeOut = FALSE; } break; case STATUS_BREAKPOINT: if( !waiting_for_first_bp ) { myGetThreadContext( tid, &con ); con.Eip--; if( (con.Edx & 0xffff) != 0 ) { /* this is a mark */ ReadProcessMemory( processHandle, (LPVOID)con.Eax, utilBuff, BUFF_SIZE - 1, len ); utilBuff[len] = '\0'; where.segment = con.SegCs; where.offset = con.Eip; WriteMark( utilBuff, where ); } else { /* this passes CommonAddr */ commonAddr.segment = con.Ecx & 0xffff; commonAddr.offset = con.Ebx; } } else { waiting_for_first_bp = FALSE; } break; case STATUS_DATATYPE_MISALIGNMENT: case STATUS_ACCESS_VIOLATION: case STATUS_IN_PAGE_ERROR: case STATUS_NO_MEMORY: case STATUS_ILLEGAL_INSTRUCTION: case STATUS_NONCONTINUABLE_EXCEPTION: case STATUS_INVALID_DISPOSITION: case STATUS_ARRAY_BOUNDS_EXCEEDED: case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: case STATUS_FLOAT_INVALID_OPERATION: case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: case STATUS_FLOAT_UNDERFLOW: case STATUS_INTEGER_DIVIDE_BY_ZERO: case STATUS_INTEGER_OVERFLOW: case STATUS_PRIVILEGED_INSTRUCTION: case STATUS_STACK_OVERFLOW: case STATUS_CONTROL_C_EXIT: if( debugEvent.u.Exception.dwFirstChance ) { continue_how = DBG_EXCEPTION_NOT_HANDLED; } else { Output( MsgArray[MSG_SAMPLE_4 - ERR_FIRST_MESSAGE] ); Output( "\r\n" ); doneSample = TRUE; TerminateProcess( processHandle, 0 ); report(); return; } break; default: continue_how = DBG_EXCEPTION_NOT_HANDLED; break; } break; case LOAD_DLL_DEBUG_EVENT: if( GetDllName( &debugEvent.u.LoadDll, utilBuff, sizeof( utilBuff ) ) ) { codeLoad( debugEvent.u.LoadDll.hFile, (DWORD) debugEvent.u.LoadDll.lpBaseOfDll, utilBuff, SAMP_CODE_LOAD ); } break; case CREATE_THREAD_DEBUG_EVENT: newThread( debugEvent.dwThreadId, debugEvent.u.CreateThread.hThread ); break; case EXIT_THREAD_DEBUG_EVENT: deadThread( debugEvent.dwThreadId ); break; case EXIT_PROCESS_DEBUG_EVENT: doneSample = TRUE; // TerminateProcess( processHandle, 0 ); - already gone!! report(); return; } } } /* StartProg */
bool Pdb::RunToException() { DR_LOG("RunToException"); LLOG("RUN TO EXCEPTION"); TimeStop ts; bool disasfocus = disas.HasFocus(); bool locked = false; bool frestored = false; invalidpage.Clear(); mempage.Clear(); int opn = 0; for(;;) { if(terminated) { if(locked) Unlock(); return false; } opn++; DR_LOG("WaitForDebugEvent"); if(WaitForDebugEvent(&event, 0)) { DR_LOG("WaitForDebugEvent ended"); debug_threadid = event.dwThreadId; opn = 0; running = false; switch(event.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: { DR_LOG("EXCEPTION_DEBUG_EVENT"); LLOG("Exception: " << FormatIntHex(event.u.Exception.ExceptionRecord.ExceptionCode) << " at: " << FormatIntHex(event.u.Exception.ExceptionRecord.ExceptionAddress) << " first: " << event.u.Exception.dwFirstChance); SaveForeground(); const EXCEPTION_RECORD& x = event.u.Exception.ExceptionRecord; if(findarg(x.ExceptionCode, EXCEPTION_BREAKPOINT, EXCEPTION_SINGLE_STEP, STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP) < 0) { LLOG("Non-debug EXCEPTION"); if(event.u.Exception.dwFirstChance) { LLOG("First chance " << FormatIntHex(x.ExceptionCode)); break; } String desc = Format("Exception: [* %lX] at [* %16llX]&", (int64)x.ExceptionCode, (int64)x.ExceptionAddress); for(int i = 0; i < __countof(ex_desc); i++) if(ex_desc[i].code == x.ExceptionCode) desc << "[* " << DeQtf(ex_desc[i].text) << "]&"; if(x.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { desc << (x.ExceptionInformation[0] ? "[*@3 writing]" : "[*@4 reading]"); desc << Format(" at [* %08llX]", (int64)x.ExceptionInformation[1]); } ToForeground(); PromptOK(desc); } #ifdef CPU_64 if(!win64 && x.ExceptionCode == EXCEPTION_BREAKPOINT && !break_running) // Ignore x64 breakpoint in wow64 break; #endif if(break_running) debug_threadid = mainThreadId; break_running = false; ToForeground(); if(disasfocus) disas.SetFocus(); if(locked) Unlock(); if(refreshmodules) LoadModuleInfo(); LLOG("event.dwThreadId = " << event.dwThreadId); bool isbreakpoint = findarg(x.ExceptionCode, EXCEPTION_BREAKPOINT, STATUS_WX86_BREAKPOINT) >= 0; for(int i = 0; i < threads.GetCount(); i++) { Thread& t = threads[i]; (Context&)t = ReadContext(threads[i].hThread); if(event.dwThreadId == threads.GetKey(i)) { LLOG("Setting current context"); if(isbreakpoint #ifdef CPU_64 && bp_set.Find((win64 ? t.context64.Rip : t.context32.Eip) - 1) >= 0 #else && bp_set.Find(t.context32.Eip - 1) >= 0 #endif ) // We have stopped at breakpoint, need to move address back #ifdef CPU_64 if(win64) t.context64.Rip--; else #endif t.context32.Eip--; context = t; } } RemoveBp(); return true; } case CREATE_THREAD_DEBUG_EVENT: DR_LOG("CREATE_THREAD_DEBUG_EVENT"); LLOG("Create thread: " << event.dwThreadId); AddThread(event.dwThreadId, event.u.CreateThread.hThread); break; case EXIT_THREAD_DEBUG_EVENT: DR_LOG("EXIT_THREAD_DEBUG_EVENT"); LLOG("Exit thread: " << event.dwThreadId); RemoveThread(event.dwThreadId); break; case CREATE_PROCESS_DEBUG_EVENT: DR_LOG("CREATE_PROCESS_DEBUG_EVENT"); LLOG("Create process: " << event.dwProcessId); processid = event.dwProcessId; AddThread(event.dwThreadId, event.u.CreateProcessInfo.hThread); CloseHandle(event.u.CreateProcessInfo.hFile); CloseHandle(event.u.CreateProcessInfo.hProcess); break; case EXIT_PROCESS_DEBUG_EVENT: DR_LOG("EXIT_PROCESS_DEBUG_EVENT"); LLOG("Exit process: " << event.dwProcessId); if(locked) Unlock(); terminated = true; return false; case LOAD_DLL_DEBUG_EVENT: { DR_LOG("LOAD_DLL_DEBUG_EVENT"); LLOG("Load dll: " << event.u.LoadDll.lpBaseOfDll); CloseHandle(event.u.LoadDll.hFile); refreshmodules = true; break; } case UNLOAD_DLL_DEBUG_EVENT: DR_LOG("UNLOAD_DLL_DEBUG_EVENT"); LLOG("UnLoad dll: " << event.u.UnloadDll.lpBaseOfDll); refreshmodules = true; break; case RIP_EVENT: DR_LOG("RIP_EVENT"); LLOG("RIP!"); Exclamation("Process being debugged died unexpectedly!"); terminated = true; if(locked) Unlock(); return false; } DR_LOG("ContinueDebugEvent"); ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); running = true; } if(ts.Elapsed() > 200) { DR_LOG("ts.Elpsed() > 200"); if(!lock) { Lock(); locked = true; } if(!frestored) { RestoreForeground(); frestored = true; } } if(lock) { DR_LOG("GuiSleep"); GuiSleep(opn < 1000 ? 0 : 100); Ctrl::ProcessEvents(); } else { DR_LOG("Sleep"); Sleep(opn < 1000 ? 0 : 100); } } }
static void test_debug_loop(int argc, char **argv) { const char *arguments = " debugger child "; struct child_blackbox blackbox; char blackbox_file[MAX_PATH]; PROCESS_INFORMATION pi; STARTUPINFOA si; BOOL debug; DWORD pid; char *cmd; BOOL ret; if (!pDebugActiveProcessStop || !pCheckRemoteDebuggerPresent) { win_skip("DebugActiveProcessStop or CheckRemoteDebuggerPresent not available, skipping test.\n"); return; } pid = GetCurrentProcessId(); ret = DebugActiveProcess(pid); ok(!ret, "DebugActiveProcess() succeeded on own process.\n"); get_file_name(blackbox_file); cmd = HeapAlloc(GetProcessHeap(), 0, strlen(argv[0]) + strlen(arguments) + strlen(blackbox_file) + 10); sprintf(cmd, "%s%s%08x %s", argv[0], arguments, pid, blackbox_file); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ret = CreateProcessA(NULL, cmd, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); HeapFree(GetProcessHeap(), 0, cmd); ret = pCheckRemoteDebuggerPresent(pi.hProcess, &debug); ok(ret, "CheckRemoteDebuggerPresent failed, last error %#x.\n", GetLastError()); ok(debug, "Expected debug != 0, got %#x.\n", debug); for (;;) { DEBUG_EVENT ev; ret = WaitForDebugEvent(&ev, INFINITE); ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); if (!ret) break; if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); if (!ret) break; } ret = CloseHandle(pi.hThread); ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); ret = CloseHandle(pi.hProcess); ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); load_blackbox(blackbox_file, &blackbox, sizeof(blackbox)); ok(!blackbox.failures, "Got %d failures from child process.\n", blackbox.failures); ret = DeleteFileA(blackbox_file); ok(ret, "DeleteFileA failed, last error %#x.\n", GetLastError()); }
BOOL DebugMainLoop(const DebugOptions *pOptions) { BOOL fFinished = FALSE; BOOL fBreakpointSignalled = FALSE; BOOL fWowBreakpointSignalled = FALSE; BOOL fTerminating = FALSE; while(!fFinished) { DEBUG_EVENT DebugEvent; // debugging event information DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation PPROCESS_INFO pProcessInfo; PTHREAD_INFO pThreadInfo; HANDLE hProcess; // Wait for a debugging event to occur. The second parameter indicates // that the function does not return until a debugging event occurs. if(!WaitForDebugEvent(&DebugEvent, INFINITE)) { OutputDebug("WaitForDebugEvent: 0x%08lx", GetLastError()); return FALSE; } // Process the debugging event code. switch (DebugEvent.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: { PEXCEPTION_RECORD pExceptionRecord = &DebugEvent.u.Exception.ExceptionRecord; NTSTATUS ExceptionCode = pExceptionRecord->ExceptionCode; // Process the exception code. When handling // exceptions, remember to set the continuation // status parameter (dwContinueStatus). This value // is used by the ContinueDebugEvent function. if (pOptions->verbose_flag) { lprintf("EXCEPTION PID=%lu TID=%lu ExceptionCode=0x%lx dwFirstChance=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, pExceptionRecord->ExceptionCode, DebugEvent.u.Exception.dwFirstChance ); } // Find the process in the process list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; if (DebugEvent.u.Exception.dwFirstChance) { if (pExceptionRecord->ExceptionCode == (DWORD)STATUS_BREAKPOINT) { // Signal the aedebug event if (!fBreakpointSignalled) { fBreakpointSignalled = TRUE; if (pOptions->hEvent) { SetEvent(pOptions->hEvent); CloseHandle(pOptions->hEvent); } if (pOptions->dwThreadId) { DWORD dwThreadId = pOptions->dwThreadId; const DWORD dwFailed = (DWORD)-1; DWORD dwRet = dwFailed; pThreadInfo = &pProcessInfo->Threads[dwThreadId]; HANDLE hThread = pThreadInfo->hThread; if (hThread != NULL) { dwRet = ResumeThread(hThread); } if (dwRet == dwFailed) { lprintf("error: failed to resume thread %lu\n", dwThreadId); } } /* * We ignore first-chance breakpoints by default. * * We get one of these whenever we attach to a process. * But in some cases, we never get a second-chance, e.g., * when we're attached through MSVCRT's abort(). */ if (!pOptions->breakpoint_flag) { dwContinueStatus = DBG_CONTINUE; break; } } } if (ExceptionCode == STATUS_WX86_BREAKPOINT) { if (!fWowBreakpointSignalled) { fWowBreakpointSignalled = TRUE; dwContinueStatus = DBG_CONTINUE; break; } } /* * Ignore thread naming exception. * * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx * * TODO: Note down the thread name */ if (ExceptionCode == 0x406d1388) { dwContinueStatus = DBG_CONTINUE; break; } if (!pOptions->first_chance) { break; } } // XXX: Deferred symbols don't get loaded without this SymRefreshModuleList(pProcessInfo->hProcess); dumpException(pProcessInfo->hProcess, &DebugEvent.u.Exception.ExceptionRecord); // Find the thread in the thread list THREAD_INFO_LIST::const_iterator it; for (it = pProcessInfo->Threads.begin(); it != pProcessInfo->Threads.end(); ++it) { DWORD dwThreadId = it->first; HANDLE hThread = it->second.hThread; if (dwThreadId != DebugEvent.dwThreadId && ExceptionCode != STATUS_BREAKPOINT && ExceptionCode != STATUS_WX86_BREAKPOINT) { continue; } dumpStack(pProcessInfo->hProcess, hThread, NULL); } if (!DebugEvent.u.Exception.dwFirstChance) { /* * Terminate the process. As continuing would cause the JIT debugger * to be invoked again. */ fTerminating = TRUE; TerminateProcess(pProcessInfo->hProcess, (UINT)ExceptionCode); } break; } case CREATE_THREAD_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("CREATE_THREAD PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } // Add the thread to the thread list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; pThreadInfo->hThread = DebugEvent.u.CreateThread.hThread; break; case CREATE_PROCESS_DEBUG_EVENT: { HANDLE hFile = DebugEvent.u.CreateProcessInfo.hFile; char szImageName[MAX_PATH]; char *lpImageName = NULL; if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) { lpImageName = szImageName; } if (pOptions->verbose_flag) { PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : ""; lprintf("CREATE_PROCESS PID=%lu TID=%lu lpBaseOfImage=%p %s\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.CreateProcessInfo.lpBaseOfImage, lpModuleName ); } hProcess = DebugEvent.u.CreateProcessInfo.hProcess; pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; pProcessInfo->hProcess = hProcess; pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; pThreadInfo->hThread = DebugEvent.u.CreateProcessInfo.hThread; if (!InitializeSym(hProcess, FALSE)) { OutputDebug("error: SymInitialize failed: 0x%08lx\n", GetLastError()); exit(EXIT_FAILURE); } SymRegisterCallback64(hProcess, &symCallback, 0); loadModule(hProcess, hFile, lpImageName, DebugEvent.u.CreateProcessInfo.lpBaseOfImage); break; } case EXIT_THREAD_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("EXIT_THREAD PID=%lu TID=%lu dwExitCode=0x%lx\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.ExitThread.dwExitCode ); } // Remove the thread from the thread list pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; // Dump the stack on abort() if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) { pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread); } pProcessInfo->Threads.erase(DebugEvent.dwThreadId); break; case EXIT_PROCESS_DEBUG_EVENT: { if (pOptions->verbose_flag) { lprintf("EXIT_PROCESS PID=%lu TID=%lu dwExitCode=0x%lx\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.ExitProcess.dwExitCode ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; // Dump the stack on abort() if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) { pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId]; refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread); } // Remove the process from the process list g_Processes.erase(DebugEvent.dwProcessId); if (!SymCleanup(hProcess)) { OutputDebug("SymCleanup failed with 0x%08lx\n", GetLastError()); } if (g_Processes.empty()) { fFinished = TRUE; } break; } case LOAD_DLL_DEBUG_EVENT: { HANDLE hFile = DebugEvent.u.LoadDll.hFile; char szImageName[MAX_PATH]; char *lpImageName = NULL; if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) { lpImageName = szImageName; } if (pOptions->verbose_flag) { PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : ""; lprintf("LOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p %s\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.LoadDll.lpBaseOfDll, lpModuleName ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; loadModule(hProcess, hFile, lpImageName, DebugEvent.u.LoadDll.lpBaseOfDll); break; } case UNLOAD_DLL_DEBUG_EVENT: if (pOptions->verbose_flag) { lprintf("UNLOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId, DebugEvent.u.UnloadDll.lpBaseOfDll ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; hProcess = pProcessInfo->hProcess; SymUnloadModule64(hProcess, (UINT_PTR)DebugEvent.u.UnloadDll.lpBaseOfDll); break; case OUTPUT_DEBUG_STRING_EVENT: { if (pOptions->verbose_flag) { lprintf("OUTPUT_DEBUG_STRING PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } pProcessInfo = &g_Processes[DebugEvent.dwProcessId]; assert(!DebugEvent.u.DebugString.fUnicode); LPSTR lpDebugStringData = readProcessString(pProcessInfo->hProcess, DebugEvent.u.DebugString.lpDebugStringData, DebugEvent.u.DebugString.nDebugStringLength); lprintf("%s", lpDebugStringData); free(lpDebugStringData); break; } case RIP_EVENT: if (pOptions->verbose_flag) { lprintf("RIP PID=%lu TID=%lu\r\n", DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } break; default: if (pOptions->verbose_flag) { lprintf("EVENT%lu PID=%lu TID=%lu\r\n", DebugEvent.dwDebugEventCode, DebugEvent.dwProcessId, DebugEvent.dwThreadId ); } break; } // Resume executing the thread that reported the debugging event. ContinueDebugEvent( DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinueStatus ); } return TRUE; }
ErrorCode Process::wait(int *status, bool hang) { if (_terminated) return kSuccess; DEBUG_EVENT de; bool keepGoing = true; while (keepGoing) { BOOL result = WaitForDebugEvent(&de, hang ? INFINITE : 0); if (!result) return Platform::TranslateError(); keepGoing = false; switch (de.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: #define CHECK_AND_CLOSE(HAN) \ do { \ if ((de.u.CreateProcessInfo.HAN) != NULL) \ CloseHandle(de.u.CreateProcessInfo.HAN); \ } while (0) CHECK_AND_CLOSE(hFile); CHECK_AND_CLOSE(hProcess); CHECK_AND_CLOSE(hThread); #undef CHECK_AND_CLOSE return kSuccess; case EXIT_PROCESS_DEBUG_EVENT: _terminated = true; return kSuccess; case CREATE_THREAD_DEBUG_EVENT: { auto threadHandle = de.u.CreateThread.hThread; auto tid = GetThreadId(threadHandle); // No need to save the new thread pointer, as it gets added automatically // to the process. new Thread(this, tid, threadHandle); resume(); keepGoing = true; } break; case EXIT_THREAD_DEBUG_EVENT: { auto threadIt = _threads.find(de.dwThreadId); DS2ASSERT(threadIt != _threads.end()); auto tid = threadIt->second->tid(); ContinueDebugEvent(_pid, tid, DBG_CONTINUE); removeThread(threadIt->second->tid()); keepGoing = true; } break; case RIP_EVENT: DS2LOG(Fatal, "debug event RIP"); case EXCEPTION_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT: case OUTPUT_DEBUG_STRING_EVENT: { auto threadIt = _threads.find(de.dwThreadId); DS2ASSERT(threadIt != _threads.end()); threadIt->second->updateState(de); } break; default: DS2BUG("unknown debug event code: %lu", de.dwDebugEventCode); } } return kSuccess; }
void DoParentProcess() { TCHAR szPath[MAX_PATH] = {0,}; STARTUPINFO si = {sizeof(STARTUPINFO),}; PROCESS_INFORMATION pi = {0,}; DEBUG_EVENT de = {0,}; CONTEXT ctx = {0,}; BYTE pBuf[0x20] = {0,}; DWORD dwExcpAddr = 0, dwExcpCode = 0; const DWORD DECODING_SIZE = 0x14; const DWORD DECODING_KEY = 0x7F; const DWORD EXCP_ADDR_1 = 0x0040103F; const DWORD EXCP_ADDR_2 = 0x00401048; // create debug process GetModuleFileName( GetModuleHandle(NULL), szPath, MAX_PATH); if( !CreateProcess( NULL, szPath, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi) ) { printf("CreateProcess() failed! [%d]\n", GetLastError()); return; } printf("Parent Process\n"); // debug loop while( TRUE ) { ZeroMemory(&de, sizeof(DEBUG_EVENT)); if( !WaitForDebugEvent(&de, INFINITE) ) { printf("WaitForDebugEvent() failed! [%d]\n", GetLastError()); break; } if( de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT ) { dwExcpAddr = (DWORD)de.u.Exception.ExceptionRecord.ExceptionAddress; dwExcpCode = de.u.Exception.ExceptionRecord.ExceptionCode; if( dwExcpCode == EXCEPTION_ILLEGAL_INSTRUCTION ) { if( dwExcpAddr == EXCP_ADDR_1 ) { // decoding ReadProcessMemory( pi.hProcess, (LPCVOID)(dwExcpAddr + 2), pBuf, DECODING_SIZE, NULL); for(DWORD i = 0; i < DECODING_SIZE; i++) pBuf[i] ^= DECODING_KEY; WriteProcessMemory( pi.hProcess, (LPVOID)(dwExcpAddr + 2), pBuf, DECODING_SIZE, NULL); // change EIP ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(pi.hThread, &ctx); ctx.Eip += 2; SetThreadContext(pi.hThread, &ctx); } else if( dwExcpAddr == EXCP_ADDR_2 ) { pBuf[0] = 0x68; pBuf[1] = 0x1C; WriteProcessMemory( pi.hProcess, (LPVOID)dwExcpAddr, pBuf, 2, NULL); } } } else if( de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT ) { break; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); } }
static void *Ploopcreate(LPVOID args) { STARTUPINFO si; PROCESS_INFORMATION pi; DEBUG_EVENT dbg; DWORD cont; BOOL wow = 0; DWORD Options = SymGetOptions(), excep, size = 0; TCHAR pszFilename[MAX_PATH+1]; struct proc_uc *tmp = args; struct ps_prochandle *P = tmp->ps; int first_execp = 0; char *s, targs[256], *ctmp; char *const *argv = tmp->args; int len; ctmp = targs; while (*argv != NULL) { len = strlen(*argv); sprintf(ctmp, "%s ", *argv); ctmp = ctmp + len + 1; argv++; } *ctmp = '\0'; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if(!CreateProcess( NULL, // module name targs, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE DEBUG_ONLY_THIS_PROCESS, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi ) // Pointer to PROCESS_INFORMATION structure ) { pthread_mutex_lock(&P->mutex); P->status = PS_STOP; P->flags = CREATE_FAILED; pthread_cond_signal(&P->cond); pthread_mutex_unlock(&P->mutex); return NULL; } P->pid = pi.dwProcessId; P->tid = pi.dwThreadId; P->wstat = 0; P->exitcode = 0; P->event = CreateEvent(NULL,FALSE,FALSE,NULL); P->dll_load_order = 1; #if __amd64__ /* There seems to be a bug in 64 bit version of dbghelp.dll * when SYMOPT_DEFERRED_LOADS is set, * dtrace -n "pid$target:kernel32::entry, pid$target:KernelBase::entry" -c test.exe, * when SymEnumSymbols (Psymbol_iter_by_addr) is called on this two dll, * the second call (KernelBase) will enumerate the * symbols from the previous enumurated (kernel32) dll (from the first call). * This behaviour is not present in 32 bit. */ Options &= ~SYMOPT_DEFERRED_LOADS; #endif SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEBUG); while (1) { if (WaitForDebugEvent(&dbg, INFINITE) == 0) { return NULL; } cont = DBG_CONTINUE; pthread_mutex_lock(&P->mutex); switch (dbg.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: P->phandle = dbg.u.CreateProcessInfo.hProcess; P->thandle = dbg.u.CreateProcessInfo.hThread; if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) { dprintf("SymInitialize failed: %d\n", GetLastError()); break; } s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename); addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage, PE_TYPE_EXE, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } if (SymLoadModuleEx(P->phandle, dbg.u.CreateProcessInfo.hFile, s, NULL, (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0) == 0) { dprintf("SymLoadModule64 failed for %s:%d\n", s, GetLastError()); break; } #if __amd64__ if (Is32bitProcess(P->phandle)) { P->model = PR_MODEL_ILP32; wow = 1; } else P->model = PR_MODEL_ILP64; #else P->model = PR_MODEL_ILP32; #endif P->status = PS_STOP; P->msg.type = 0; CloseHandle(dbg.u.CreateProcessInfo.hFile); pthread_cond_signal(&P->cond); break; case CREATE_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case LOAD_DLL_DEBUG_EVENT: s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename); if (first_execp == 2) { P->dll_load_order++; } addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order); size = GetFileSize(dbg.u.LoadDll.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } #if __amd64__ /* Not tracing 64 bit dlls for 32 bit process */ if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) { CloseHandle(dbg.u.LoadDll.hFile ); break; } #endif if (SymLoadModuleEx(P->phandle, dbg.u.LoadDll.hFile, s, NULL, (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0) == FALSE) { dprintf("SymLoadModule64 dailed for %s:%d\n", s, GetLastError()); break; } CloseHandle(dbg.u.LoadDll.hFile ); P->status = PS_STOP; P->msg.type = RD_DLACTIVITY; break; case UNLOAD_DLL_DEBUG_EVENT: if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) == FALSE) { dprintf("SymUnloadModule64 failed-Imagebase %p:%d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError()); break; } delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll); P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; break; case EXIT_PROCESS_DEBUG_EVENT: P->exitcode = dbg.u.ExitProcess.dwExitCode; P->status = PS_UNDEAD; P->msg.type = RD_NONE; break; case EXIT_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case EXCEPTION_DEBUG_EVENT: switch(excep = dbg.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: case 0x4000001F: /* WOW64 exception breakpoint */ /* NOTE: Dtrace sets a BP at main (entry point of the process), which is implemented * with Psetbkpt, Pdelbkpt & Pexecbkpt. But I have implemnted it here. */ if ((excep == EXCEPTION_BREAKPOINT && first_execp == 0 && wow == 0) || (excep == 0x4000001F && first_execp == 0 && wow == 1) ) { SYMBOL_INFO *Symbol; GElf_Sym sym; ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; Symbol = (SYMBOL_INFO *) buffer; Symbol->SizeOfStruct= sizeof(SYMBOL_INFO ); Symbol->MaxNameLen = MAX_SYM_NAME; if (Pxlookup_by_name(P, LM_ID_BASE, "a.out", "main", &sym, NULL) != 0 && Pxlookup_by_name(P, LM_ID_BASE, "a.out", "WinMain", &sym, NULL) != 0) { dprintf("failed to find entry point (main):%d\n", GetLastError()); break; } if (setbkpt(P, (uintptr_t) sym.st_value) != 0) { dprintf("failed to set breakpoint for %s at address %p\n", Symbol->Name, Symbol->Address); break; } first_execp = 1; P->status = PS_RUN; P->msg.type = 0; break; } if (dbg.u.Exception.ExceptionRecord.ExceptionAddress != (PVOID) P->addr) { dprintf("expecting execption at %p:but recived from %p\n", P->addr, dbg.u.Exception.ExceptionRecord.ExceptionAddress); P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } if (delbkpt(P, P->addr) != 0) { dprintf("failed to delete brk point at %p:(main)\n", P->addr); break; } if (adjbkpt(P, wow) != 0) { dprintf("failed to normalize brk point (main)\n"); break; } first_execp = 2; P->status = PS_STOP; P->msg.type = RD_MAININIT; break;/* if (first_execp == 0) { P->status = PS_STOP; P->msg.type = RD_MAININIT; first_execp = 2; } else { P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; } break;*/ default: if (dbg.u.Exception.dwFirstChance == 0) P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode; P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } break; default: P->status = PS_RUN; dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode); break; } if (P->status != PS_RUN) SetEvent(P->event); while (P->status == PS_STOP) pthread_cond_wait(&P->cond, &P->mutex); pthread_mutex_unlock(&P->mutex); ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont); } }
// Algo benchmark, crash-safe, system-dependent stage static double bench_algo_stage2( enum sha256_algos algo ) { // Here, the gig is to safely run a piece of code that potentially // crashes. Unfortunately, the Right Way (tm) to do this is rather // heavily platform dependent :( double rate = -1.23457; #if defined(unix) // Make a pipe: [readFD, writeFD] int pfd[2]; int r = pipe(pfd); if (r<0) { perror("pipe - failed to create pipe for --algo auto"); exit(1); } // Make pipe non blocking set_non_blocking(pfd[0], 1); set_non_blocking(pfd[1], 1); // Don't allow a crashing child to kill the main process sighandler_t sr0 = signal(SIGPIPE, SIG_IGN); sighandler_t sr1 = signal(SIGPIPE, SIG_IGN); if (SIG_ERR==sr0 || SIG_ERR==sr1) { perror("signal - failed to edit signal mask for --algo auto"); exit(1); } // Fork a child to do the actual benchmarking pid_t child_pid = fork(); if (child_pid<0) { perror("fork - failed to create a child process for --algo auto"); exit(1); } // Do the dangerous work in the child, knowing we might crash if (0==child_pid) { // TODO: some umask trickery to prevent coredumps // Benchmark this algorithm double r = bench_algo_stage3(algo); // We survived, send result to parent and bail int loop_count = 0; while (1) { ssize_t bytes_written = write(pfd[1], &r, sizeof(r)); int try_again = (0==bytes_written || (bytes_written<0 && EAGAIN==errno)); int success = (sizeof(r)==(size_t)bytes_written); if (success) break; if (!try_again) { perror("write - child failed to write benchmark result to pipe"); exit(1); } if (5<loop_count) { applog(LOG_ERR, "child tried %d times to communicate with parent, giving up", loop_count); exit(1); } ++loop_count; sleep(1); } exit(0); } // Parent waits for a result from child int loop_count = 0; while (1) { // Wait for child to die int status; int r = waitpid(child_pid, &status, WNOHANG); if ((child_pid==r) || (r<0 && ECHILD==errno)) { // Child died somehow. Grab result and bail double tmp; ssize_t bytes_read = read(pfd[0], &tmp, sizeof(tmp)); if (sizeof(tmp)==(size_t)bytes_read) rate = tmp; break; } else if (r<0) { perror("bench_algo: waitpid failed. giving up."); exit(1); } // Give up on child after a ~60s if (60<loop_count) { kill(child_pid, SIGKILL); waitpid(child_pid, &status, 0); break; } // Wait a bit longer ++loop_count; sleep(1); } // Close pipe r = close(pfd[0]); if (r<0) { perror("close - failed to close read end of pipe for --algo auto"); exit(1); } r = close(pfd[1]); if (r<0) { perror("close - failed to close read end of pipe for --algo auto"); exit(1); } #elif defined(WIN32) // Get handle to current exe HINSTANCE module = GetModuleHandle(0); if (!module) { applog(LOG_ERR, "failed to retrieve module handle"); exit(1); } // Create a unique name char unique_name[33]; snprintf( unique_name, sizeof(unique_name)-1, "bfgminer-%p", (void*)module ); // Create and init a chunked of shared memory HANDLE map_handle = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits 4096, // size: low 32-bits unique_name // name of map object ); if (NULL==map_handle) { applog(LOG_ERR, "could not create shared memory"); exit(1); } void *shared_mem = MapViewOfFile( map_handle, // object to map view of FILE_MAP_WRITE, // read/write access 0, // high offset: map from 0, // low offset: beginning 0 // default: map entire file ); if (NULL==shared_mem) { applog(LOG_ERR, "could not map shared memory"); exit(1); } SetEnvironmentVariable("BFGMINER_SHARED_MEM", unique_name); CopyMemory(shared_mem, &rate, sizeof(rate)); // Get path to current exe char cmd_line[256 + MAX_PATH]; const size_t n = sizeof(cmd_line)-200; DWORD size = GetModuleFileName(module, cmd_line, n); if (0==size) { applog(LOG_ERR, "failed to retrieve module path"); exit(1); } // Construct new command line based on that char *p = strlen(cmd_line) + cmd_line; sprintf(p, " --bench-algo %d", algo); SetEnvironmentVariable("BFGMINER_BENCH_ALGO", "1"); // Launch a debug copy of BFGMiner STARTUPINFO startup_info; PROCESS_INFORMATION process_info; ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&process_info, sizeof(process_info)); startup_info.cb = sizeof(startup_info); BOOL ok = CreateProcess( NULL, // No module name (use command line) cmd_line, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE DEBUG_ONLY_THIS_PROCESS,// We're going to debug the child NULL, // Use parent's environment block NULL, // Use parent's starting directory &startup_info, // Pointer to STARTUPINFO structure &process_info // Pointer to PROCESS_INFORMATION structure ); if (!ok) { applog(LOG_ERR, "CreateProcess failed with error %ld\n", (long)GetLastError() ); exit(1); } // Debug the child (only clean way to catch exceptions) while (1) { // Wait for child to do something DEBUG_EVENT debug_event; ZeroMemory(&debug_event, sizeof(debug_event)); BOOL ok = WaitForDebugEvent(&debug_event, 60 * 1000); if (!ok) break; // Decide if event is "normal" int go_on = CREATE_PROCESS_DEBUG_EVENT== debug_event.dwDebugEventCode || CREATE_THREAD_DEBUG_EVENT == debug_event.dwDebugEventCode || EXIT_THREAD_DEBUG_EVENT == debug_event.dwDebugEventCode || EXCEPTION_DEBUG_EVENT == debug_event.dwDebugEventCode || LOAD_DLL_DEBUG_EVENT == debug_event.dwDebugEventCode || OUTPUT_DEBUG_STRING_EVENT == debug_event.dwDebugEventCode || UNLOAD_DLL_DEBUG_EVENT == debug_event.dwDebugEventCode; if (!go_on) break; // Some exceptions are also "normal", apparently. if (EXCEPTION_DEBUG_EVENT== debug_event.dwDebugEventCode) { int go_on = EXCEPTION_BREAKPOINT== debug_event.u.Exception.ExceptionRecord.ExceptionCode; if (!go_on) break; } // If nothing unexpected happened, let child proceed ContinueDebugEvent( debug_event.dwProcessId, debug_event.dwThreadId, DBG_CONTINUE ); } // Clean up child process TerminateProcess(process_info.hProcess, 1); CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread); // Reap return value and cleanup CopyMemory(&rate, shared_mem, sizeof(rate)); (void)UnmapViewOfFile(shared_mem); (void)CloseHandle(map_handle); #else // Not linux, not unix, not WIN32 ... do our best rate = bench_algo_stage3(algo); #endif // defined(unix) // Done return rate; }
static int fork_and_ptraceme(const char *cmd) { PROCESS_INFORMATION pi; STARTUPINFO si = { sizeof (si) }; DEBUG_EVENT de; int pid, tid; HANDLE th = INVALID_HANDLE_VALUE; if (!*cmd) return -1; setup_tokens (); /* TODO: with args */ if (!CreateProcess (cmd, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("CreateProcess"); return -1; } /* get process id and thread id */ pid = pi.dwProcessId; tid = pi.dwThreadId; #if 0 /* load thread list */ { HANDLE h; THREADENTRY32 te32; HANDLE WINAPI (*win32_openthread)(DWORD, BOOL, DWORD) = NULL; win32_openthread = (HANDLE WINAPI (*)(DWORD, BOOL, DWORD)) GetProcAddress (GetModuleHandle ("kernel32"), "OpenThread"); th = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, pid); if (th == INVALID_HANDLE_VALUE || !Thread32First(th, &te32)) r_sys_perror ("CreateToolhelp32Snapshot"); do { if (te32.th32OwnerProcessID == pid) { h = win32_openthread (THREAD_ALL_ACCESS, 0, te32.th32ThreadID); if (h == NULL) r_sys_perror ("OpenThread"); else eprintf ("HANDLE=%p\n", h); } } while (Thread32Next (th, &te32)); } #endif #if 0 // Access denied here :? if (ContinueDebugEvent (pid, tid, DBG_CONTINUE) == 0) { r_sys_perror ("ContinueDebugEvent"); goto err_fork; } #endif /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) goto err_fork; /* check if is a create process debug event */ if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto err_fork; } if (th != INVALID_HANDLE_VALUE) CloseHandle (th); eprintf ("PID=%d\n", pid); eprintf ("TID=%d\n", tid); return pid; err_fork: eprintf ("ERRFORK\n"); TerminateProcess (pi.hProcess, 1); if (th != INVALID_HANDLE_VALUE) CloseHandle (th); return -1; }
// EnterDebugLoop was taken from: // http://msdn.microsoft.com/en-us/library/ms681675(VS.85).aspx // // Note that we don't actually *want* to be a debugger, but CreateProcess has // some bug or security dependency which is leading it to (in some situations) // not show the window of the process it launches. Somehow, calling a debug // loop addresses this. I've left the full code from the sample here in order // to make it easier to set breakpoints to discover what's going wrong if // there is a problem with the technique of working around CreateProcess's // flaw with the debug API. // DWORD WINAPI DebugLoopMain(LPVOID lpParam) // returns a MainReturn { DebugArgs & debugArgs = *static_cast<DebugArgs *>(lpParam); HMODULE ntDllModule = sm_LoadNTDLLFunctions(); debugInfo(L"Got to DebugLoopMain thread code."); PROCESS_INFORMATION processInfo; processInfo.hProcess = NULL; processInfo.hThread = NULL; // Windows can modify the command line, so we have to make a copy std::vector<WCHAR> commandLineCopy ( debugArgs.commandLine.begin(), debugArgs.commandLine.end() ); commandLineCopy.push_back(L'\0'); DWORD dwCreationFlags = #ifdef USE_STARTUPINFO_FOR_WINDOW_POSITION // These options don't work :-( (config->runWindowPosition ? STARTF_USEPOSITION : 0) | (config->runWindowSize ? STARTF_USESIZE : 0) | #endif (config->shutdownEvent ? 0 : DEBUG_PROCESS) | STARTF_USESHOWWINDOW; // REVIEW: for security should lpApplicationName be the same as the // name in the command line? WindowsVerify( L"CreateProcess", CreateProcess( 0, // lpApplicationName &commandLineCopy[0], // lpCommandLine (no .data() in C++98) 0, // lpProcessAttributes 0, // lpThreadAttributes config->shutdownEvent == NULL ? TRUE : FALSE, // bInheritHandles dwCreationFlags, 0, // lpEnvironment 0, // lpCurrentDirectory debugArgs.startupInfo, // lpStartupInfo &processInfo // lpProcessInformation ) ); Verify(L"Thread or process was null.", processInfo.hThread and processInfo.hProcess ); debugInfo(L"CreateProcess(%s) - Id = %d\n", debugArgs.commandLine.c_str(), processInfo.dwProcessId ); debugInfo(L"Entering debugger loop...\n"); HANDLE suspendedThread = NULL; BOOL previouslyWaited = FALSE; DEBUG_EVENT Ev; const LPDEBUG_EVENT DebugEv = &Ev; while (TRUE) { // Wait for a debugging event to occur. The second parameter indicates // that the function does not return until a debugging event occurs. BOOL gotDebugEvent = FALSE; BOOL handledEvent = TRUE; DWORD tickBefore = GetTickCount(); if (WaitForDebugEvent( DebugEv, suspendedThread ? 1000 : *debugArgs.msecLeft )) { gotDebugEvent = TRUE; } else { DWORD lastError = GetLastError(); if (lastError == 0x79) { // The semaphore timeout period has expired, that is ok } else { ExitProgramOnWindowsError(L"WaitForDebugEvent", lastError); } } if (suspendedThread) { switch(WaitForSingleObject(debugArgs.retryEvent, 0)) { case WAIT_OBJECT_0: { WindowsVerify(L"ResetEvent", ResetEvent(debugArgs.retryEvent)); // need to poll processes again... std::wstring exeImageName; if (PreviousStillRunning(exeImageName, 0)) { debugInfo(L"Retry failed, show message box again."); WindowsVerify(L"SetEvent", SetEvent(debugArgs.deferEvent)); } else { debugInfo(L"Resuming thread handle 0x%x", suspendedThread); WindowsVerify(L"ResumeThread", ResumeThread(suspendedThread) != -1 ); WindowsVerify(L"CloseHandle", CloseHandle(suspendedThread)); suspendedThread = NULL; previouslyWaited = TRUE; } break; } case WAIT_TIMEOUT: // nope, do nothing, try again in a second... break; default: WindowsVerify(L"WaitForSingleObject", FALSE); } } DWORD tickAfter = GetTickCount(); if (*debugArgs.msecLeft != INFINITE) { bool timedOut = false; if (tickAfter < tickBefore) { // happens once every 28 days, the tick count rolls over... // account for the rollover only if (tickBefore > *debugArgs.msecLeft) { timedOut = true; } else { *debugArgs.msecLeft = *debugArgs.msecLeft - tickBefore; } } else { if (tickAfter - tickBefore > *debugArgs.msecLeft) { timedOut = true; } else { *debugArgs.msecLeft = *debugArgs.msecLeft - (tickAfter - tickBefore); } } if (timedOut) { // Need to take the screenshot here, because if we return from // the DebugLoop the windows will be closed and the state lost // by the time we return to the caller if (not config->timeoutSnapshot.empty()) { Verify(L"Screen Capture Failed", TakeScreenshotToFile(config->timeoutSnapshot.c_str()) ); } return TitleWait::TimeoutReturn; } } // Process the debugging event code. if (gotDebugEvent) { 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. debugInfo(L"EXCEPTION_ACCESS_VIOLATION"); if (not config->crashSnapshot.empty()) { Verify(L"Screen Capture Failed", TakeScreenshotToFile(config->crashSnapshot.c_str()) ); } debugInfo(L"Child Process Crashed - Quitting"); return TitleWait::CrashedReturn; } case EXCEPTION_BREAKPOINT: { // First chance: Display the current // instruction and register values. debugInfo(L"EXCEPTION_BREAKPOINT"); // No process functions during CREATE_PROCESS_DEBUG_EVENT // have to wait for a later time if (!config->defer or previouslyWaited or suspendedThread) break; if (PreviousStillRunning( debugArgs.exeImageName, DebugEv->dwProcessId )) { WindowsVerify(L"SetEvent", SetEvent(debugArgs.deferEvent)); // don't block, keep processing debug events... // but suspend the thread! debugInfo( L"About to suspend thread handle 0x%x", DebugEv->dwThreadId ); suspendedThread = OpenThread( THREAD_SUSPEND_RESUME, FALSE, DebugEv->dwThreadId ); WindowsVerify(L"OpenThread", suspendedThread != NULL); WindowsVerify(L"Suspend Thread", SuspendThread(suspendedThread) != -1 ); } } break; case EXCEPTION_DATATYPE_MISALIGNMENT: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. debugInfo(L"EXCEPTION_DATATYPE_MISALIGNMENT"); break; case EXCEPTION_SINGLE_STEP: // First chance: Update the display of the // current instruction and register values. debugInfo(L"EXCEPTION_SINGLE_STEP"); break; case DBG_CONTROL_C: // First chance: Pass this on to the system. // Last chance: Display an appropriate error. debugInfo(L"DBG_CONTROL_C"); break; default: debugInfo( L"EXCEPTION_(0x%x) (unrecognized, passing through)", DebugEv->u.Exception.ExceptionRecord.ExceptionCode ); // We have debugger behaviors for everything we // understand, but not random exceptions...pass on up // the chain and say we don't handle it. handledEvent = false; 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. debugInfo( L"CREATE_THREAD_DEBUG_EVENT - H: 0x%x - P: 0x%x", DebugEv->u.CreateThread.hThread, DebugEv->dwProcessId ); 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. SetLastError(0); DWORD processId = GetProcessId( DebugEv->u.CreateProcessInfo.hProcess ); DWORD lastError = GetLastError(); if (lastError != ERROR_SUCCESS) { ExitProgramOnWindowsError(L"GetProcessId", lastError); } debugInfo( L"CREATE_PROCESS_DEBUG_EVENT - P: 0x%x - T: 0x%x", processId, DebugEv->dwThreadId ); DWORD processMonThreadId; HANDLE processMonThread = CreateThread( NULL, // default security attributes 0, // use default stack size ProcessMonitorMain, // thread function name // argument to thread function DebugEv->u.CreateProcessInfo.hProcess, CREATE_SUSPENDED, // create the thread as suspended &processMonThreadId); // returns thread identifier if (processMonThread == NULL) { WindowsVerify(L"CreateThread", FALSE); } // lock process list mutex and append tracking data for thread if (WaitForSingleObject(processListMutex, INFINITE) != WAIT_OBJECT_0) { WindowsVerify(L"WaitForSingleObject", FALSE); } processIds[numProcesses] = processId; processMonThreads[numProcesses] = processMonThread; numProcesses++; WindowsVerify(L"ReleaseMutex", ReleaseMutex(processListMutex)); WindowsVerify(L"ResumeThread", ResumeThread(processMonThread) != -1 ); // "Be sure to close the handle to the process image // file with CloseHandle." Ok, sure. WindowsVerify(L"CloseHandle", CloseHandle(DebugEv->u.CreateProcessInfo.hFile) ); break; } case EXIT_THREAD_DEBUG_EVENT: debugInfo(L"EXIT_THREAD_DEBUG_EVENT"); break; case EXIT_PROCESS_DEBUG_EVENT: { // Display the process's exit code. We should only get this if // the main spawn has returned. This should not happen, ever, // but if we catch the first spawn we can perhaps watch on it // and pipe its result back. debugInfo( L"EXIT_PROCESS_DEBUG_EVENT - ExitCode: 0x%x", DebugEv->u.ExitProcess.dwExitCode ); #ifdef QUIT_WHEN_MAIN_PROCESS_EXITS // we used to exit here, but now we wait for the LAST // process exiting signal. We could in theory return // ClosedReturn if we want the behavior of quitting // just because the main process we spawned quit...but that // is not a good default when people are using things like // iexplore which launches a child.... so // make that a non-default option? if (WaitForSingleObject(lastProcessExitedEvent, INFINITE) != WAIT_OBJECT_0 ) { WindowsVerify(L"WaitForSingleObject", FALSE); } if (processInfo.hThread) { WindowsVerify(L"CloseHandle", CloseHandle(processInfo.hThread) ); } if (processInfo.hProcess) { WindowsVerify(L"CloseHandle", CloseHandle(processInfo.hProcess) ); } sm_FreeNTDLLFunctions(ntDllModule); return ClosedReturn; #endif 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. WindowsVerify(L"CloseHandle", CloseHandle(DebugEv->u.LoadDll.hFile) ); #ifdef DEBUG_DLL_EVENTS // A lot of these go by, disable by default debugInfo(L"LOAD_DLL_DEBUG_EVENT"); #endif break; case UNLOAD_DLL_DEBUG_EVENT: #ifdef DEBUG_DLL_EVENTS // A lot of these go by, disable by default debugInfo(L"UNLOAD_DLL_DEBUG_EVENT"); #endif break; case OUTPUT_DEBUG_STRING_EVENT: // Client wants us to display the output debug string. // Pass through to WinDbg or display ourselves? // For now, say we don't handle it. handledEvent = false; debugInfo( L"OUTPUT_DEBUG_STRING_EVENT - ExceptionCode 0x%x", DebugEv->u.Exception.ExceptionRecord.ExceptionCode ); break; case RIP_EVENT: debugInfo(L"RIP_EVENT"); break; } // Resume executing the thread that reported the debugging event. WindowsVerify( L"ContinueDebugEvent", ContinueDebugEvent( DebugEv->dwProcessId, DebugEv->dwThreadId, handledEvent ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED ) ); } } // end while(TRUE) loop if (processInfo.hThread) { WindowsVerify(L"CloseHandle", CloseHandle(processInfo.hThread)); } if (processInfo.hProcess) { WindowsVerify(L"CloseHandle", CloseHandle(processInfo.hProcess)); } sm_FreeNTDLLFunctions(ntDllModule); // unreachable point return TitleWait::InternalErrorReturn; }
static void test_NtSuspendProcess(char *process_name) { PROCESS_INFORMATION info; DEBUG_EVENT ev; STARTUPINFOA startup; NTSTATUS status; HANDLE event; char buffer[MAX_PATH]; ULONG count; DWORD ret; status = pNtResumeProcess(GetCurrentProcess()); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); event = CreateEventA(NULL, TRUE, FALSE, "wine_suspend_event"); ok(!!event, "Failed to create event: %u\n", GetLastError()); memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); sprintf(buffer, "%s tests/process.c dummy_process wine_suspend_event", process_name); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); ok(ret, "CreateProcess failed with error %u\n", GetLastError()); ret = WaitForSingleObject(event, 500); ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret); status = pNtSuspendProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ResetEvent(event); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = NtResumeThread(info.hThread, &count); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ok(count == 1, "Expected count 1, got %d\n", count); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret); status = pNtResumeProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); status = pNtSuspendThread(info.hThread, &count); ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status); ok(count == 0, "Expected count 0, got %d\n", count); ResetEvent(event); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = pNtResumeProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret); status = pNtSuspendThread(info.hThread, &count); ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status); ok(count == 0, "Expected count 0, got %d\n", count); status = pNtSuspendThread(info.hThread, &count); ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status); ok(count == 1, "Expected count 1, got %d\n", count); ResetEvent(event); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = pNtResumeProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = pNtResumeProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret); ret = DebugActiveProcess(info.dwProcessId); ok(ret, "Failed to debug process: %d\n", GetLastError()); ResetEvent(event); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); for (;;) { ret = WaitForDebugEvent(&ev, INFINITE); ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); if (!ret) break; if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) break; ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); if (!ret) break; } ResetEvent(event); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = pNtResumeProcess(info.hProcess); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); status = NtResumeThread(info.hThread, &count); ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status); ok(count == 0, "Expected count 0, got %d\n", count); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret); ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); ret = WaitForSingleObject(event, 200); ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret); TerminateProcess(info.hProcess, 0); CloseHandle(info.hProcess); CloseHandle(info.hThread); }
bool DebuggingLoop() { DEBUG_EVENT DebugEvent; CONTEXT ctxThreadContext; DWORD dwDebugState = NULL; PTCHAR sTemp = (PTCHAR)malloc(255 * sizeof(TCHAR)); szTempSym = (PCHAR)malloc(MAX_SYM_NAME); ctxThreadContext.ContextFlags = CONTEXT_FULL; while(bDebugging) { if(!WaitForDebugEvent(&DebugEvent,INFINITE)) { free(sTemp); free(szTempSym); return false; } switch(DebugEvent.dwDebugEventCode) { case LOAD_DLL_DEBUG_EVENT: { SymRefreshModuleList(piProcInfo.hProcess); dwDebugState = DBG_CONTINUE; break; } case CREATE_PROCESS_DEBUG_EVENT: { if(!bSymInit) bSymInit = SymInitialize(piProcInfo.hProcess,NULL,FALSE); dwDebugState = DBG_CONTINUE; break; } case CREATE_THREAD_DEBUG_EVENT: { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false,DebugEvent.dwThreadId); GetThreadContext(hThread,&ctxThreadContext); ctxThreadContext.EFlags |= 0x100; SetThreadContext(hThread,&ctxThreadContext); dwDebugState = DBG_CONTINUE; break; } case EXIT_PROCESS_DEBUG_EVENT: { bDebugging = false; dwDebugState = DBG_CONTINUE; break; } case EXCEPTION_DEBUG_EVENT: { switch(DebugEvent.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: { dwDebugState = DBG_CONTINUE; break; } case EXCEPTION_SINGLE_STEP: { HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false,DebugEvent.dwThreadId); GetThreadContext(hThread,&ctxThreadContext); InsertInfo((DWORD)DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress,DebugEvent.dwThreadId,sTemp); ctxThreadContext.EFlags |= 0x100; SetThreadContext(hThread,&ctxThreadContext); dwDebugState = DBG_CONTINUE; break; } default: dwDebugState = DBG_EXCEPTION_NOT_HANDLED; } break; } default: dwDebugState = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(DebugEvent.dwProcessId,DebugEvent.dwThreadId,dwDebugState); } free(sTemp); free(szTempSym); return false; }
static int doldd(const char* filename) { STARTUPINFO si; HANDLE ph; DEBUG_EVENT event; struct spawndata sdata; char* av[2]; pid_t pid; int status; int r = 0; char dllname[PATH_MAX+1]; char dllpath[PATH_MAX+1]; memset(&sdata, 0, sizeof(sdata)); memset(&si, 0, sizeof(si)); sdata.start = &si; sdata.flags = DEBUG_PROCESS; si.cb = sizeof(si); si.dwFlags = STARTF_FORCEONFEEDBACK|STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWNORMAL; av[0] = (char*)filename; av[1] = 0; if ((pid = uwin_spawn(filename, av, NULL, &sdata)) < 0) { error(ERROR_system(0), "%s cannot create process", filename); return -1; } ph = sdata.handle; for (;;) { if (!WaitForDebugEvent(&event, 1500)) break; if (event.dwProcessId != uwin_ntpid(pid)) continue; switch(event.dwDebugEventCode) { case EXIT_PROCESS_DEBUG_EVENT: CloseHandle(ph); ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); wait(&status); return 0; case LOAD_DLL_DEBUG_EVENT: if (event.u.LoadDll.hFile) { if (modulenamepath(ph, &event.u.LoadDll, dllname, sizeof(dllname), dllpath, sizeof(dllpath)) < 0) r = -1; else sfprintf(sfstdout, "\t%s => %s\n", dllname, dllpath); } ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); break; case CREATE_PROCESS_DEBUG_EVENT: ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); break; case CREATE_THREAD_DEBUG_EVENT: case EXCEPTION_DEBUG_EVENT: kill(pid, SIGTERM); ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_TERMINATE_PROCESS); break; default: ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); break; } } return 0; }
/* * StartProg - start sampling a program */ void StartProg( const char *cmd, const char *prog, char *full_args, char *dos_args ) { DWORD code; DWORD tid; CONTEXT con; BOOL waiting_for_first_bp; DWORD continue_how; BOOL rc; DWORD ttid; HANDLE tth; uint_32 Fir; /* unused parameters */ (void)cmd; strcpy( utilBuff, prog ); strcat( utilBuff, " " ); strcat( utilBuff, full_args ); loadProg( prog, utilBuff ); tid = debugEvent.dwThreadId; tth = CreateThread( NULL, 2048, TimerThread, NULL, 0, &ttid ); if( !tth ) { internalError( MsgArray[MSG_SAMPLE_3 - ERR_FIRST_MESSAGE] ); } /* Attempt to ensure that we can record our samples in one shot */ SetThreadPriority( tth, THREAD_PRIORITY_TIME_CRITICAL ); Output( MsgArray[MSG_SAMPLE_1 - ERR_FIRST_MESSAGE] ); Output( prog ); Output( "\r\n" ); waiting_for_first_bp = TRUE; continue_how = DBG_CONTINUE; for( ;; ) { ContinueDebugEvent( taskPid, tid, continue_how ); rc = WaitForDebugEvent( &debugEvent, INFINITE ); continue_how = DBG_CONTINUE; tid = debugEvent.dwThreadId; switch( debugEvent.dwDebugEventCode ) { case EXCEPTION_DEBUG_EVENT: code = debugEvent.u.Exception.ExceptionRecord.ExceptionCode; switch( code ) { case STATUS_SINGLE_STEP: if( timeOut ) { myGetThreadContext( tid, &con ); Fir = LODWORD( con.Fir ); RecordSample( Fir, SEGMENT, tid ); timeOut = FALSE; } break; case STATUS_BREAKPOINT: /* Skip past the breakpoint in the startup code */ if( waiting_for_first_bp ) { SkipBreakpoint( tid ); waiting_for_first_bp = FALSE; } break; case STATUS_DATATYPE_MISALIGNMENT: case STATUS_ACCESS_VIOLATION: case STATUS_IN_PAGE_ERROR: case STATUS_NO_MEMORY: case STATUS_ILLEGAL_INSTRUCTION: case STATUS_NONCONTINUABLE_EXCEPTION: case STATUS_INVALID_DISPOSITION: case STATUS_ARRAY_BOUNDS_EXCEEDED: case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: case STATUS_FLOAT_INVALID_OPERATION: case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: case STATUS_FLOAT_UNDERFLOW: case STATUS_INTEGER_DIVIDE_BY_ZERO: case STATUS_INTEGER_OVERFLOW: case STATUS_PRIVILEGED_INSTRUCTION: case STATUS_STACK_OVERFLOW: case STATUS_CONTROL_C_EXIT: if( debugEvent.u.Exception.dwFirstChance ) { continue_how = DBG_EXCEPTION_NOT_HANDLED; } else { Output( MsgArray[MSG_SAMPLE_4 - ERR_FIRST_MESSAGE] ); Output( "\r\n" ); doneSample = TRUE; TerminateProcess( processHandle, 0 ); report(); return; } break; default: continue_how = DBG_EXCEPTION_NOT_HANDLED; break; } break; case LOAD_DLL_DEBUG_EVENT: if( GetDllName( &debugEvent.u.LoadDll, utilBuff, sizeof( utilBuff ) ) ) { codeLoad( debugEvent.u.LoadDll.hFile, (DWORD) debugEvent.u.LoadDll.lpBaseOfDll, utilBuff, SAMP_CODE_LOAD ); } break; case CREATE_THREAD_DEBUG_EVENT: newThread( debugEvent.dwThreadId, debugEvent.u.CreateThread.hThread ); break; case EXIT_THREAD_DEBUG_EVENT: deadThread( debugEvent.dwThreadId ); break; case EXIT_PROCESS_DEBUG_EVENT: doneSample = TRUE; // TerminateProcess( processHandle, 0 ); - already gone!! report(); return; } } } /* StartProg */
void stAttachDebugger( DWORD processId, std::string fnIncludes, std::string fnExcludes, bool activeProcess = true) /*++ Routine Description: Our mini-debugger implementation. It does following things: - Attach to a running process - On first breakpoint, inject the IAT patching DLL into target - Print information of any exception in target process - Print the debug spew from target process Arguments: processId - PID of the process to attach fnIncludes - List of include filters fnExclude - List of exclude filters activeProcess - If we are attaching to an already running process then we pass activeProcess = true, this causes us to call DebugActiveProcess and not wait for process creation event --*/ { int threadCount = 0; bool processInfected = false; if (activeProcess) { if (!DebugActiveProcess(processId)) { gView->PrintError(L"\nCould not attach to the process (PID = %d).", processId); stHandleError(GetLastError()); goto funcExit; } } HMODULE hMod = GetModuleHandle(L"Kernel32.dll"); if (hMod) { PFNDEBUGSETPROCESSKILLONEXIT pfnDebugSetProcessKillOnExit = (PFNDEBUGSETPROCESSKILLONEXIT)GetProcAddress(hMod, "DebugSetProcessKillOnExit"); if (pfnDebugSetProcessKillOnExit) { pfnDebugSetProcessKillOnExit(FALSE); } } gProcessId = processId; DEBUG_EVENT debugEvent; DWORD dwContinueStatus = DBG_CONTINUE; bool keepAlive = true; while(keepAlive) { WaitForDebugEvent(&debugEvent, INFINITE); dwContinueStatus = DBG_CONTINUE; if (debugEvent.dwProcessId == processId) { switch (debugEvent.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: { switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: { //IHU_DBG_LOG(TRC_STRACE, HX_LEVEL_INFO, (L"EXCEPTION_BREAKPOINT\n")); if (!processInfected) { if (gRemovePatchOnExit) { HRSRC hRes; HGLOBAL hResG; LPVOID pRes; DWORD dwResSize; hRes = FindResource( NULL, MAKEINTRESOURCE(IDR_BIN_DLL), L"BIN"); hResG = LoadResource(NULL, hRes); pRes = LockResource(hResG); dwResSize = SizeofResource(NULL, hRes); wchar_t tempPath[MAX_PATH]; wchar_t tempFile[MAX_PATH]; GetTempPath(MAX_PATH, tempPath); GetTempFileName(tempPath, L"", 0, tempFile); gInjectorDllPath = tempFile; HANDLE oFile = CreateFile( gInjectorDllPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (oFile == INVALID_HANDLE_VALUE) { gView->PrintError( L"Failed to create the temporary DLL [%s]. Error code = %x\n", gInjectorDllPath.c_str(), GetLastError()); return; } DWORD bytesWritten; if (!WriteFile( oFile, pRes, dwResSize, &bytesWritten, NULL)) { gView->PrintError( L"Failed to write the temporary DLL. Error code = %x\n", GetLastError()); return; } CloseHandle(oFile); } else { wchar_t exePath[MAX_PATH]; if (GetModuleFileName( NULL, exePath, MAX_PATH)) { std::wstring dllPath = exePath; int slashPos = dllPath.find_last_of(L'\\'); if (slashPos != -1) { dllPath = dllPath.substr(0, slashPos + 1); } dllPath += L"stserum.dll"; gInjectorDllPath = dllPath; } } ihiInjectDll( ghProcess, (LPCWSTR)gInjectorDllPath.c_str(), (LPCSTR)fnIncludes.c_str(), (LPCSTR)fnExcludes.c_str()); processInfected = true; } break; } default: { if (debugEvent.u.Exception.dwFirstChance) { gView->PrintWarning(L"Exception = %x, Address = %x (first-chance!)\n", debugEvent.u.Exception.ExceptionRecord.ExceptionCode, debugEvent.u.Exception.ExceptionRecord.ExceptionAddress); } else { gView->PrintError(L"Exception = %x, Address = %x (second-chance!)\n", debugEvent.u.Exception.ExceptionRecord.ExceptionCode, debugEvent.u.Exception.ExceptionRecord.ExceptionAddress); } // // If this was a second chance exception, it will cause // the process to terminate // dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; break; } } break; } case CREATE_THREAD_DEBUG_EVENT: { ++threadCount; break; } case CREATE_PROCESS_DEBUG_EVENT: { if (ghProcess == INVALID_HANDLE_VALUE) { ghProcess = debugEvent.u.CreateProcessInfo.hProcess; } //IHU_DBG_LOG(TRC_STRACE, HX_LEVEL_INFO, (L"Create Process\n")); break; } case EXIT_THREAD_DEBUG_EVENT: { --threadCount; break; } case EXIT_PROCESS_DEBUG_EVENT: { gView->PrintMessage( L"Target process has been terminated. Exit Code = %d.\n", debugEvent.u.ExitProcess.dwExitCode); keepAlive = false; break; } case LOAD_DLL_DEBUG_EVENT: { break; } case UNLOAD_DLL_DEBUG_EVENT: { break; } case OUTPUT_DEBUG_STRING_EVENT: { DWORD cbRead = 0; ReadProcessMemory( ghProcess, debugEvent.u.DebugString.lpDebugStringData, gDbgString, debugEvent.u.DebugString.nDebugStringLength, &cbRead); if (debugEvent.u.DebugString.fUnicode) { if (gDbgString[0] == L'$') { gView->PrintTrace(L"%ws", &gDbgString[1]); } else if (gDbgString[0] == L'#') { gView->PrintError(L"%ws", &gDbgString[1]); } else { gView->PrintTraceOrig(L"%ws", gDbgString); } } else { if (gDbgString[0] == L'$') { gView->PrintTraceA("%s", &gDbgString[1]); } else if (gDbgString[0] == L'#') { gView->PrintErrorA("%s", &gDbgString[1]); } else { gView->PrintTraceOrigA("%s", gDbgString); } } break; } } } ContinueDebugEvent( debugEvent.dwProcessId, debugEvent.dwThreadId, dwContinueStatus); } // // If we need to remove the patching on exit, it means we created a // temporary injector dll, we should delete that now // if (gRemovePatchOnExit) { DeleteFile(gInjectorDllPath.c_str()); } //IHU_DBG_LOG(TRC_STRACE, HX_LEVEL_INFO, (L"Total thread count = %d\n", threadCount)); funcExit: return; }
int main(int argc, char **argv){ if( argc<2){ printf("Usage: %s <ip address>\n", argv[0]); return 1; } if( IsDebuggerPresent()){ HANDLE iphlpapi=LoadLibrary("iphlpapi.dll"); if( !iphlpapi){ perror("iphlpapi.dll"); return 1; } FARPROC IcmpSendEcho=GetProcAddress(iphlpapi, "IcmpSendEcho"); FARPROC IcmpCreateFile=GetProcAddress(iphlpapi, "IcmpCreateFile"); FARPROC IcmpCloseHandle=GetProcAddress(iphlpapi, "IcmpCloseHandle"); if( (IcmpSendEcho && IcmpCreateFile && IcmpCloseHandle)==0){ perror("icmp functions"); return 1; } unsigned long ipaddr=INADDR_NONE, params[2]; HANDLE hIcmpFile; char data[32], *reply; int replySize=sizeof(ICMP_ECHO_REPLY)+sizeof(data); if( (ipaddr=inet_addr(argv[1]))==INADDR_NONE){ perror("Illegal IP address!"); return 1; } if( (hIcmpFile=(HANDLE)IcmpCreateFile())==INVALID_HANDLE_VALUE){ perror("IcmpCreateFile"); return 1; } reply=(char *)malloc(replySize); ZeroMemory(data, sizeof(data)); params[0]=PARAM; params[1]=(unsigned long)GetProcAddress(iphlpapi, "IcmpSendEcho2Ex"); RaiseException(EXCEPTION_BREAKPOINT, 0, 2, params); puts("Exception raised!"); IcmpSendEcho(hIcmpFile, ipaddr, data, sizeof(data), NULL, reply, replySize, 1000); puts("This line should never be shown..."); IcmpCloseHandle(hIcmpFile); return 0; } PROCESS_INFORMATION pi; STARTUPINFO si; HANDLE hProcess, hThread; DEBUG_EVENT debugEvent; EXCEPTION_RECORD *ExceptionRecord=&debugEvent.u.Exception.ExceptionRecord; CONTEXT context; FARPROC IcmpSendEcho2Ex=NULL; char path[256], args[512], originalByte[1]; ZeroMemory(?, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); ZeroMemory(&debugEvent, sizeof(DEBUG_EVENT)); ZeroMemory(&context, sizeof(CONTEXT)); ZeroMemory(path, sizeof(path)); ZeroMemory(args, sizeof(args)); si.cb=sizeof(STARTUPINFO); si.dwFlags=STARTF_USESHOWWINDOW; si.wShowWindow=SW_HIDE; context.ContextFlags=CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; GetModuleFileName(NULL, path, sizeof(path)-1); snprintf(args, sizeof(args)-1, "%s %s", path, argv[1]); if( !CreateProcess( NULL, args, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, ? )){ perror("CreateProcess"); return 1; } if( (hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId))==NULL){ perror("OpenProcess"); return 1; } HANDLE kernel32=LoadLibrary("kernel32.dll"); FARPROC DebugSetProcessKillOnExit=GetProcAddress(kernel32, "DebugSetProcessKillOnExit"); FARPROC DebugActiveProcessStop=GetProcAddress(kernel32, "DebugActiveProcessStop"); FARPROC OpenThread=GetProcAddress(kernel32, "OpenThread"); CloseHandle(kernel32); DebugSetProcessKillOnExit(TRUE); while(WaitForDebugEvent(&debugEvent, INFINITE) && debugEvent.dwDebugEventCode!=EXIT_PROCESS_DEBUG_EVENT){ if( debugEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT && ExceptionRecord->ExceptionCode==EXCEPTION_BREAKPOINT){ if( ExceptionRecord->NumberParameters>1 && ExceptionRecord->ExceptionInformation[0]==PARAM){ IcmpSendEcho2Ex=(FARPROC)ExceptionRecord->ExceptionInformation[1]; printf("IcmpSendEcho2Ex %p\n", IcmpSendEcho2Ex); if( !BreakpointSet(hProcess, IcmpSendEcho2Ex, &originalByte)){ perror("BreakpointSet"); break; } } else if( ExceptionRecord->ExceptionAddress==IcmpSendEcho2Ex){ printf("EIP %p\n", IcmpSendEcho2Ex); if( !BreakpointRetrieve(hProcess, IcmpSendEcho2Ex, &originalByte)){ perror("BreakpointRetrieve"); break; } if((hThread=(HANDLE)OpenThread(THREAD_ALL_ACCESS, FALSE, debugEvent.dwThreadId))==NULL) puts("OpenThread"); if(!GetThreadContext(hThread, &context)) puts("GetThreadContext"); context.Eip -= 1; if(!SetThreadContext(hThread, &context)) puts("SetThreadContext"); CreateThread(NULL, 0, (void *)Terminate, hProcess, 0, NULL); } } else if( debugEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT){ puts("Exception!"); DebugActiveProcessStop(debugEvent.dwProcessId); break; } ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE); ZeroMemory(&debugEvent, sizeof(DEBUG_EVENT)); } return 0; }
void ProcessDebugEvent() { static wchar_t wszDbgText[1024]; static char szDbgText[1024]; BOOL lbNonContinuable = FALSE; DEBUG_EVENT evt = {0}; BOOL lbEvent = WaitForDebugEvent(&evt,10); #ifdef _DEBUG DWORD dwErr = GetLastError(); #endif static bool bFirstExitThreadEvent = false; // Чтобы вывести на экран подсказку по возможностям "дебаггера" //HMODULE hCOMDLG32 = NULL; //typedef BOOL (WINAPI* GetSaveFileName_t)(LPOPENFILENAMEW lpofn); //GetSaveFileName_t _GetSaveFileName = NULL; DWORD dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; if (lbEvent) { lbNonContinuable = FALSE; switch (evt.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: case CREATE_THREAD_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT: case RIP_EVENT: { LPCSTR pszName = "Unknown"; switch (evt.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: pszName = "CREATE_PROCESS_DEBUG_EVENT"; break; case CREATE_THREAD_DEBUG_EVENT: pszName = "CREATE_THREAD_DEBUG_EVENT"; break; case EXIT_PROCESS_DEBUG_EVENT: pszName = "EXIT_PROCESS_DEBUG_EVENT"; break; case EXIT_THREAD_DEBUG_EVENT: pszName = "EXIT_THREAD_DEBUG_EVENT"; break; case RIP_EVENT: pszName = "RIP_EVENT"; break; } _wsprintfA(szDbgText, SKIPLEN(countof(szDbgText)) "{%i.%i} %s\n", evt.dwProcessId,evt.dwThreadId, pszName); _printf(szDbgText); if (!bFirstExitThreadEvent && evt.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) { bFirstExitThreadEvent = true; if (gpSrv->DbgInfo.nDebugDumpProcess == 0) { _printf("ConEmuC: Press Ctrl+Break to create minidump of debugging process\n"); } else { // Сразу сделать дамп и выйти HandlerRoutine(CTRL_BREAK_EVENT); } } if (evt.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { gpSrv->DbgInfo.nProcessCount++; _ASSERTE(gpSrv->DbgInfo.pDebugTreeProcesses!=NULL); CEDebugProcessInfo pi = {evt.dwProcessId}; gpSrv->DbgInfo.pDebugTreeProcesses->Set(evt.dwProcessId, pi); UpdateDebuggerTitle(); } else if (evt.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { CEDebugProcessInfo pi = {}; if (gpSrv->DbgInfo.pDebugTreeProcesses && gpSrv->DbgInfo.pDebugTreeProcesses->Get(evt.dwProcessId, &pi, true) && pi.hProcess) { CloseHandle(pi.hProcess); } if (gpSrv->DbgInfo.nProcessCount > 0) gpSrv->DbgInfo.nProcessCount--; UpdateDebuggerTitle(); } break; } case LOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT: { LPCSTR pszName = "Unknown"; char szBase[32] = {}; char szFile[MAX_PATH+128] = {}; struct MY_FILE_NAME_INFO { DWORD FileNameLength; WCHAR FileName[1]; }; typedef BOOL (WINAPI* GetFileInformationByHandleEx_t)(HANDLE hFile, int FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); static GetFileInformationByHandleEx_t _GetFileInformationByHandleEx = NULL; switch (evt.dwDebugEventCode) { case LOAD_DLL_DEBUG_EVENT: //6 Reports a load-dynamic-link-library (DLL) debugging event. The value of u.LoadDll specifies a LOAD_DLL_DEBUG_INFO structure. pszName = "LOAD_DLL_DEBUG_EVENT"; if (evt.u.LoadDll.hFile) { if (gnOsVer >= 0x0600) { if (!_GetFileInformationByHandleEx) _GetFileInformationByHandleEx = (GetFileInformationByHandleEx_t)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetFileInformationByHandleEx"); if (_GetFileInformationByHandleEx) { DWORD nSize = sizeof(MY_FILE_NAME_INFO)+MAX_PATH*sizeof(wchar_t); MY_FILE_NAME_INFO* pfi = (MY_FILE_NAME_INFO*)calloc(nSize+2,1); if (pfi) { pfi->FileNameLength = MAX_PATH; if (_GetFileInformationByHandleEx(evt.u.LoadDll.hFile, 2/*FileNameInfo*/, pfi, nSize) && pfi->FileName[0]) { wchar_t szFullPath[MAX_PATH+1] = {}, *pszFile; DWORD n = GetFullPathName(pfi->FileName, countof(szFullPath), szFullPath, &pszFile); if (!n || (n >= countof(szFullPath))) { lstrcpyn(szFullPath, pfi->FileName, countof(szFullPath)); pszFile = (wchar_t*)PointToName(pfi->FileName); } else if (!pszFile) { pszFile = (wchar_t*)PointToName(szFullPath); } lstrcpyA(szFile, ", "); WideCharToMultiByte(CP_OEMCP, 0, pszFile, -1, szFile+lstrlenA(szFile), 80, 0,0); lstrcatA(szFile, "\n\t"); WideCharToMultiByte(CP_OEMCP, 0, szFullPath, -1, szFile+lstrlenA(szFile), MAX_PATH, 0,0); } free(pfi); } } } CloseHandle(evt.u.LoadDll.hFile); } _wsprintfA(szBase, SKIPLEN(countof(szBase)) " at " WIN3264TEST("0x%08X","0x%08X%08X"), WIN3264WSPRINT((DWORD_PTR)evt.u.LoadDll.lpBaseOfDll)); break; case UNLOAD_DLL_DEBUG_EVENT: //7 Reports an unload-DLL debugging event. The value of u.UnloadDll specifies an UNLOAD_DLL_DEBUG_INFO structure. pszName = "UNLOAD_DLL_DEBUG_EVENT"; _wsprintfA(szBase, SKIPLEN(countof(szBase)) " at " WIN3264TEST("0x%08X","0x%08X%08X"), WIN3264WSPRINT((DWORD_PTR)evt.u.UnloadDll.lpBaseOfDll)); break; } _wsprintfA(szDbgText, SKIPLEN(countof(szDbgText)) "{%i.%i} %s%s%s\n", evt.dwProcessId,evt.dwThreadId, pszName, szBase, szFile); _printf(szDbgText); break; } case EXCEPTION_DEBUG_EVENT: //1 Reports an exception debugging event. The value of u.Exception specifies an EXCEPTION_DEBUG_INFO structure. { lbNonContinuable = (evt.u.Exception.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE)==EXCEPTION_NONCONTINUABLE; //static bool bAttachEventRecieved = false; //if (!bAttachEventRecieved) //{ // bAttachEventRecieved = true; // StringCchPrintfA(szDbgText, countof(szDbgText),"{%i.%i} Debugger attached successfully. (0x%08X address 0x%08X flags 0x%08X%s)\n", // evt.dwProcessId,evt.dwThreadId, // evt.u.Exception.ExceptionRecord.ExceptionCode, // evt.u.Exception.ExceptionRecord.ExceptionAddress, // evt.u.Exception.ExceptionRecord.ExceptionFlags, // (evt.u.Exception.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE) ? "(EXCEPTION_NONCONTINUABLE)" : ""); //} //else switch (evt.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: // The thread tried to read from or write to a virtual address for which it does not have the appropriate access. { if (evt.u.Exception.ExceptionRecord.NumberParameters>=2) { _wsprintfA(szDbgText, SKIPLEN(countof(szDbgText)) "{%i.%i} EXCEPTION_ACCESS_VIOLATION at " WIN3264TEST("0x%08X","0x%08X%08X") " flags 0x%08X%s %s of " WIN3264TEST("0x%08X","0x%08X%08X") " FC=%u\n", evt.dwProcessId,evt.dwThreadId, WIN3264WSPRINT((DWORD_PTR)evt.u.Exception.ExceptionRecord.ExceptionAddress), evt.u.Exception.ExceptionRecord.ExceptionFlags, ((evt.u.Exception.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE) ? "(EXCEPTION_NONCONTINUABLE)" : ""), ((evt.u.Exception.ExceptionRecord.ExceptionInformation[0]==0) ? "Read" : (evt.u.Exception.ExceptionRecord.ExceptionInformation[0]==1) ? "Write" : (evt.u.Exception.ExceptionRecord.ExceptionInformation[0]==8) ? "DEP" : "???"), WIN3264WSPRINT(evt.u.Exception.ExceptionRecord.ExceptionInformation[1]), evt.u.Exception.dwFirstChance ); } else { _wsprintfA(szDbgText, SKIPLEN(countof(szDbgText)) "{%i.%i} EXCEPTION_ACCESS_VIOLATION at " WIN3264TEST("0x%08X","0x%08X%08X") " flags 0x%08X%s FC=%u\n", evt.dwProcessId,evt.dwThreadId, WIN3264WSPRINT((DWORD_PTR)evt.u.Exception.ExceptionRecord.ExceptionAddress), evt.u.Exception.ExceptionRecord.ExceptionFlags, (evt.u.Exception.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE) ? "(EXCEPTION_NONCONTINUABLE)" : "", evt.u.Exception.dwFirstChance); } _printf(szDbgText); } break; default: { char szName[32]; LPCSTR pszName; pszName = szName; #define EXCASE(s) case s: pszName = #s; break switch(evt.u.Exception.ExceptionRecord.ExceptionCode) { EXCASE(EXCEPTION_ARRAY_BOUNDS_EXCEEDED); // The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking. EXCASE(EXCEPTION_BREAKPOINT); // A breakpoint was encountered. EXCASE(EXCEPTION_DATATYPE_MISALIGNMENT); // The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on. EXCASE(EXCEPTION_FLT_DENORMAL_OPERAND); // One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value. EXCASE(EXCEPTION_FLT_DIVIDE_BY_ZERO); // The thread tried to divide a floating-point value by a floating-point divisor of zero. EXCASE(EXCEPTION_FLT_INEXACT_RESULT); // The result of a floating-point operation cannot be represented exactly as a decimal fraction. EXCASE(EXCEPTION_FLT_INVALID_OPERATION); // This exception represents any floating-point exception not included in this list. EXCASE(EXCEPTION_FLT_OVERFLOW); // The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type. EXCASE(EXCEPTION_FLT_STACK_CHECK); // The stack overflowed or underflowed as the result of a floating-point operation. EXCASE(EXCEPTION_FLT_UNDERFLOW); // The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type. EXCASE(EXCEPTION_ILLEGAL_INSTRUCTION); // The thread tried to execute an invalid instruction. EXCASE(EXCEPTION_IN_PAGE_ERROR); // The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network. EXCASE(EXCEPTION_INT_DIVIDE_BY_ZERO); // The thread tried to divide an integer value by an integer divisor of zero. EXCASE(EXCEPTION_INT_OVERFLOW); // The result of an integer operation caused a carry out of the most significant bit of the result. EXCASE(EXCEPTION_INVALID_DISPOSITION); // An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception. EXCASE(EXCEPTION_NONCONTINUABLE_EXCEPTION); // The thread tried to continue execution after a noncontinuable exception occurred. EXCASE(EXCEPTION_PRIV_INSTRUCTION); // The thread tried to execute an instruction whose operation is not allowed in the current machine mode. EXCASE(EXCEPTION_SINGLE_STEP); // A trace trap or other single-instruction mechanism signaled that one instruction has been executed. EXCASE(EXCEPTION_STACK_OVERFLOW); // The thread used up its stack. default: _wsprintfA(szName, SKIPLEN(countof(szName)) "Exception 0x%08X", evt.u.Exception.ExceptionRecord.ExceptionCode); } _wsprintfA(szDbgText, SKIPLEN(countof(szDbgText)) "{%i.%i} %s at " WIN3264TEST("0x%08X","0x%08X%08X") " flags 0x%08X%s FC=%u\n", evt.dwProcessId,evt.dwThreadId, pszName, WIN3264WSPRINT((DWORD_PTR)evt.u.Exception.ExceptionRecord.ExceptionAddress), evt.u.Exception.ExceptionRecord.ExceptionFlags, (evt.u.Exception.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE) ? "(EXCEPTION_NONCONTINUABLE)" : "", evt.u.Exception.dwFirstChance); _printf(szDbgText); } } BOOL bDumpOnBreakPoint = gpSrv->DbgInfo.bDebuggerRequestDump; if (gpSrv->DbgInfo.bDebugProcessTree && (!lbNonContinuable && (evt.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT))) { // Когда отладчик цепляется к процессу в первый раз - возникает EXCEPTION_BREAKPOINT CEDebugProcessInfo pi = {}; if (gpSrv->DbgInfo.pDebugTreeProcesses && gpSrv->DbgInfo.pDebugTreeProcesses->Get(evt.dwProcessId, &pi)) { if (!pi.bWasBreak) { pi.bWasBreak = TRUE; gpSrv->DbgInfo.pDebugTreeProcesses->Set(evt.dwProcessId, pi); } else { bDumpOnBreakPoint = TRUE; } } } if (gpSrv->DbgInfo.bDebuggerRequestDump || (!lbNonContinuable && !gpSrv->DbgInfo.bDebugProcessTree && (evt.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT)) || (gpSrv->DbgInfo.bDebugProcessTree && ((evt.u.Exception.ExceptionRecord.ExceptionCode>=0xC0000000) || (bDumpOnBreakPoint && (evt.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)))) ) { BOOL bGenerateTreeBreak = gpSrv->DbgInfo.bDebugProcessTree && (gpSrv->DbgInfo.bDebuggerRequestDump || lbNonContinuable); if (gpSrv->DbgInfo.bDebugProcessTree && !bGenerateTreeBreak && (evt.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)) { if (gpSrv->DbgInfo.nWaitTreeBreaks == 0) { bGenerateTreeBreak = TRUE; gpSrv->DbgInfo.nWaitTreeBreaks++; } } gpSrv->DbgInfo.bDebuggerRequestDump = FALSE; // один раз char szConfirm[2048]; if (evt.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { if (gpSrv->DbgInfo.nDebugDumpProcess) szConfirm[0] = 0; else lstrcpynA(szConfirm, szDbgText, countof(szConfirm)); } else { _wsprintfA(szConfirm, SKIPLEN(countof(szConfirm)) "%s exception (FC=%u)\n", lbNonContinuable ? "Non continuable" : "Continuable", evt.u.Exception.dwFirstChance); StringCchCatA(szConfirm, countof(szConfirm), szDbgText); } StringCchCatA(szConfirm, countof(szConfirm), "\nCreate minidump (<No> - fulldump)?"); //GenerateTreeDebugBreak WriteMiniDump(evt.dwProcessId, evt.dwThreadId, &evt.u.Exception.ExceptionRecord, szConfirm, bGenerateTreeBreak); if (gpSrv->DbgInfo.bDebugProcessTree && (evt.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)) { if (gpSrv->DbgInfo.nWaitTreeBreaks > 0) gpSrv->DbgInfo.nWaitTreeBreaks--; } } if (!lbNonContinuable /*|| (evt.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)*/) { dwContinueStatus = DBG_CONTINUE; } } break; case OUTPUT_DEBUG_STRING_EVENT: //8 Reports an output-debugging-string debugging event. The value of u.DebugString specifies an OUTPUT_DEBUG_STRING_INFO structure. { wszDbgText[0] = 0; if (evt.u.DebugString.nDebugStringLength >= 1024) evt.u.DebugString.nDebugStringLength = 1023; DWORD_PTR nRead = 0; HANDLE hProcess = GetProcessHandleForDebug(evt.dwProcessId); if (evt.u.DebugString.fUnicode) { if (!ReadProcessMemory(hProcess, evt.u.DebugString.lpDebugStringData, wszDbgText, 2*evt.u.DebugString.nDebugStringLength, &nRead)) { wcscpy_c(wszDbgText, L"???"); } else { wszDbgText[min(1023,nRead+1)] = 0; } static int nPrefixLen = lstrlen(CONEMU_CONHOST_CREATED_MSG); if (memcmp(wszDbgText, CONEMU_CONHOST_CREATED_MSG, nPrefixLen*sizeof(wszDbgText[0])) == 0) { LPWSTR pszEnd = NULL; DWORD nConHostPID = wcstoul(wszDbgText+nPrefixLen, &pszEnd, 10); if (nConHostPID && !gpSrv->DbgInfo.pDebugTreeProcesses->Get(nConHostPID, NULL)) { AttachConHost(nConHostPID); } } } else { if (!ReadProcessMemory(hProcess, evt.u.DebugString.lpDebugStringData, szDbgText, evt.u.DebugString.nDebugStringLength, &nRead)) { wcscpy_c(wszDbgText, L"???"); } else { szDbgText[min(1023,nRead+1)] = 0; // CP_ACP differs from CP_OEMCP, thats why we need some overhead... MultiByteToWideChar(CP_ACP, 0, szDbgText, -1, wszDbgText, 1024); } } WideCharToMultiByte(CP_OEMCP, 0, wszDbgText, -1, szDbgText, 1024, 0, 0); #ifdef CRTPRINTF { _printf("{PID=%i.TID=%i} ", evt.dwProcessId,evt.dwThreadId, wszDbgText); } #else { _printf("{PID=%i.TID=%i} %s", evt.dwProcessId,evt.dwThreadId, szDbgText); int nLen = lstrlenA(szDbgText); if (nLen > 0 && szDbgText[nLen-1] != '\n') _printf("\n"); } #endif dwContinueStatus = DBG_CONTINUE; } break; } // Продолжить отлаживаемый процесс ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, dwContinueStatus); } //if (hCOMDLG32) // FreeLibrary(hCOMDLG32); }
static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { PROCESS_INFORMATION pi; STARTUPINFO si = { sizeof (si) }; DEBUG_EVENT de; int pid, tid; HANDLE th = INVALID_HANDLE_VALUE; if (!*cmd) return -1; setup_tokens (); char **argv = r_str_argv (cmd, NULL); // We need to build a command line with quoted argument and escaped quotes int cmd_len = 0; int i = 0; while (argv[i]) { char *current = argv[i]; int quote_count = 0; while ((current = strchr (current, '"'))) quote_count ++; cmd_len += strlen (argv[i]); cmd_len += quote_count; // The quotes will add one backslash each cmd_len += 2; // Add two enclosing quotes; i++; } cmd_len += i-1; // Add argc-1 spaces char *cmdline = malloc ((cmd_len + 1) * sizeof (char)); int cmd_i = 0; // Next character to write in cmdline i = 0; while (argv[i]) { if (i != 0) cmdline[cmd_i++] = ' '; cmdline[cmd_i++] = '"'; int arg_i = 0; // Index of current character in orginal argument while (argv[i][arg_i]) { char c = argv[i][arg_i]; if (c == '"') { cmdline[cmd_i++] = '\\'; } cmdline[cmd_i++] = c; arg_i++; } cmdline[cmd_i++] = '"'; i++; } cmdline[cmd_i] = '\0'; if (!CreateProcess (argv[0], cmdline, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("CreateProcess"); return -1; } free (cmdline); r_str_argv_free (argv); /* get process id and thread id */ pid = pi.dwProcessId; tid = pi.dwThreadId; #if 0 /* load thread list */ { HANDLE h; THREADENTRY32 te32; HANDLE WINAPI (*win32_openthread)(DWORD, BOOL, DWORD) = NULL; win32_openthread = (HANDLE WINAPI (*)(DWORD, BOOL, DWORD)) GetProcAddress (GetModuleHandle ("kernel32"), "OpenThread"); th = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, pid); if (th == INVALID_HANDLE_VALUE || !Thread32First(th, &te32)) r_sys_perror ("CreateToolhelp32Snapshot"); do { if (te32.th32OwnerProcessID == pid) { h = win32_openthread (THREAD_ALL_ACCESS, 0, te32.th32ThreadID); if (h == NULL) r_sys_perror ("OpenThread"); else eprintf ("HANDLE=%p\n", h); } } while (Thread32Next (th, &te32)); } #endif #if 0 // Access denied here :? if (ContinueDebugEvent (pid, tid, DBG_CONTINUE) == 0) { r_sys_perror ("ContinueDebugEvent"); goto err_fork; } #endif /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) goto err_fork; /* check if is a create process debug event */ if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto err_fork; } if (th != INVALID_HANDLE_VALUE) CloseHandle (th); eprintf ("PID=%d\n", pid); eprintf ("TID=%d\n", tid); return pid; err_fork: eprintf ("ERRFORK\n"); TerminateProcess (pi.hProcess, 1); if (th != INVALID_HANDLE_VALUE) CloseHandle (th); return -1; }
static int get_child_debug_event (struct target_waitstatus *ourstatus) { ptid_t ptid; last_sig = TARGET_SIGNAL_0; ourstatus->kind = TARGET_WAITKIND_SPURIOUS; /* Check if GDB sent us an interrupt request. */ check_remote_input_interrupt_request (); if (soft_interrupt_requested) { soft_interrupt_requested = 0; fake_breakpoint_event (); goto gotevent; } #ifndef _WIN32_WCE attaching = 0; #else if (attaching) { /* WinCE doesn't set an initial breakpoint automatically. To stop the inferior, we flush all currently pending debug events -- the thread list and the dll list are always reported immediatelly without delay, then, we suspend all threads and pretend we saw a trap at the current PC of the main thread. Contrary to desktop Windows, Windows CE *does* report the dll names on LOAD_DLL_DEBUG_EVENTs resulting from a DebugActiveProcess call. This limits the way we can detect if all the dlls have already been reported. If we get a real debug event before leaving attaching, the worst that will happen is the user will see a spurious breakpoint. */ current_event.dwDebugEventCode = 0; if (!WaitForDebugEvent (¤t_event, 0)) { OUTMSG2(("no attach events left\n")); fake_breakpoint_event (); attaching = 0; } else OUTMSG2(("got attach event\n")); } else #endif { /* Keep the wait time low enough for confortable remote interruption, but high enough so gdbserver doesn't become a bottleneck. */ if (!WaitForDebugEvent (¤t_event, 250)) { DWORD e = GetLastError(); if (e == ERROR_PIPE_NOT_CONNECTED) { /* This will happen if the loader fails to succesfully load the application, e.g., if the main executable tries to pull in a non-existing export from a DLL. */ ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = 1; return 1; } return 0; } } gotevent: switch (current_event.dwDebugEventCode) { case CREATE_THREAD_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " "for pid=%d tid=%x)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); /* Record the existence of this thread. */ child_add_thread (current_event.dwProcessId, current_event.dwThreadId, current_event.u.CreateThread.hThread, current_event.u.CreateThread.lpThreadLocalBase); break; case EXIT_THREAD_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); child_delete_thread (current_event.dwProcessId, current_event.dwThreadId); current_inferior = (struct thread_info *) all_threads.head; return 1; case CREATE_PROCESS_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); CloseHandle (current_event.u.CreateProcessInfo.hFile); current_process_handle = current_event.u.CreateProcessInfo.hProcess; main_thread_id = current_event.dwThreadId; ourstatus->kind = TARGET_WAITKIND_EXECD; ourstatus->value.execd_pathname = "Main executable"; /* Add the main thread. */ child_add_thread (current_event.dwProcessId, main_thread_id, current_event.u.CreateProcessInfo.hThread, current_event.u.CreateProcessInfo.lpThreadLocalBase); ourstatus->value.related_pid = debug_event_ptid (¤t_event); #ifdef _WIN32_WCE if (!attaching) { /* Windows CE doesn't set the initial breakpoint automatically like the desktop versions of Windows do. We add it explicitly here. It will be removed as soon as it is hit. */ set_breakpoint_at ((CORE_ADDR) (long) current_event.u .CreateProcessInfo.lpStartAddress, auto_delete_breakpoint); } #endif break; case EXIT_PROCESS_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; child_continue (DBG_CONTINUE, -1); CloseHandle (current_process_handle); current_process_handle = NULL; break; case LOAD_DLL_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); CloseHandle (current_event.u.LoadDll.hFile); handle_load_dll (); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.sig = TARGET_SIGNAL_TRAP; break; case UNLOAD_DLL_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); handle_unload_dll (); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.sig = TARGET_SIGNAL_TRAP; break; case EXCEPTION_DEBUG_EVENT: OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); handle_exception (ourstatus); break; case OUTPUT_DEBUG_STRING_EVENT: /* A message from the kernel (or Cygwin). */ OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT " "for pid=%d tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); handle_output_debug_string (ourstatus); break; default: OUTMSG2 (("gdbserver: kernel event unknown " "for pid=%d tid=%x code=%ld\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, current_event.dwDebugEventCode)); break; } ptid = debug_event_ptid (¤t_event); current_inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid); return 1; }
static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { PROCESS_INFORMATION pi; STARTUPINFO si = { 0 } ; DEBUG_EVENT de; int pid, tid; HANDLE th = INVALID_HANDLE_VALUE; if (!*cmd) { return -1; } setup_tokens (); char *_cmd = io->args ? r_str_appendf (strdup (cmd), " %s", io->args) : strdup (cmd); char **argv = r_str_argv (_cmd, NULL); // We need to build a command line with quoted argument and escaped quotes int cmd_len = 0; int i = 0; si.cb = sizeof (si); while (argv[i]) { char *current = argv[i]; int quote_count = 0; while ((current = strchr (current, '"'))) { quote_count ++; } cmd_len += strlen (argv[i]); cmd_len += quote_count; // The quotes will add one backslash each cmd_len += 2; // Add two enclosing quotes; i++; } cmd_len += i-1; // Add argc-1 spaces char *cmdline = malloc ((cmd_len + 1) * sizeof (char)); int cmd_i = 0; // Next character to write in cmdline i = 0; while (argv[i]) { if (i != 0) { cmdline[cmd_i++] = ' '; } cmdline[cmd_i++] = '"'; int arg_i = 0; // Index of current character in orginal argument while (argv[i][arg_i]) { char c = argv[i][arg_i]; if (c == '"') { cmdline[cmd_i++] = '\\'; } cmdline[cmd_i++] = c; arg_i++; } cmdline[cmd_i++] = '"'; i++; } cmdline[cmd_i] = '\0'; LPTSTR appname_ = r_sys_conv_utf8_to_utf16 (argv[0]); LPTSTR cmdline_ = r_sys_conv_utf8_to_utf16 (cmdline); if (!CreateProcess (appname_, cmdline_, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { r_sys_perror ("fork_and_ptraceme/CreateProcess"); free (appname_); free (cmdline_); return -1; } free (appname_); free (cmdline_); free (cmdline); r_str_argv_free (argv); /* get process id and thread id */ pid = pi.dwProcessId; tid = pi.dwThreadId; /* catch create process event */ if (!WaitForDebugEvent (&de, 10000)) goto err_fork; /* check if is a create process debug event */ if (de.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { eprintf ("exception code 0x%04x\n", (ut32)de.dwDebugEventCode); goto err_fork; } if (th != INVALID_HANDLE_VALUE) { CloseHandle (th); } eprintf ("Spawned new process with pid %d, tid = %d\n", pid, tid); winbase = (ut64)de.u.CreateProcessInfo.lpBaseOfImage; wintid = tid; return pid; err_fork: eprintf ("ERRFORK\n"); TerminateProcess (pi.hProcess, 1); if (th != INVALID_HANDLE_VALUE) CloseHandle (th); return -1; }
void *Ploopgrab(LPVOID args) { DEBUG_EVENT dbg; DWORD cont = DBG_CONTINUE, size = 0; TCHAR pszFilename[MAX_PATH+1]; DWORD64 mod; struct proc_uc *tmp = args; struct ps_prochandle *P = tmp->ps; int first_execp = 0; BOOL wow = 0; char *s; DWORD Options = SymGetOptions(); if (DebugActiveProcess(P->pid) == 0) { dprintf( "failed to debug process (%d): %d\n", P->pid, GetLastError() ); pthread_mutex_lock(&P->mutex); P->status = PS_STOP; P->flags = CREATE_FAILED; if (P->status == PS_STOP) pthread_cond_signal(&P->cond); pthread_mutex_unlock(&P->mutex); return NULL; } DebugSetProcessKillOnExit(FALSE); P->wstat = 0; P->exitcode = 0; P->event = CreateEvent(NULL,FALSE,FALSE,NULL); P->dll_load_order = 1; SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); while (1) { if (WaitForDebugEvent(&dbg, INFINITE) == 0) { return NULL; } cont = DBG_CONTINUE; pthread_mutex_lock(&P->mutex); switch (dbg.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: P->thandle = dbg.u.CreateProcessInfo.hThread; P->phandle = dbg.u.CreateProcessInfo.hProcess; if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) { dprintf("SymInitialize failed (%d): %d\n", P->pid, GetLastError()); break; } s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename); addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage, PE_TYPE_EXE, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } if ((mod = SymLoadModuleEx(P->phandle, dbg.u.CreateProcessInfo.hFile, s, NULL, (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0)) == FALSE) { dprintf("SymLoadModule64 Failed for %s: %d\n", s, GetLastError()); break; } #if __amd64__ if (Is32bitProcess(P->phandle)) { P->model = PR_MODEL_ILP32; wow = 1; } else P->model = PR_MODEL_ILP64; #else P->model = PR_MODEL_ILP32; #endif CloseHandle(dbg.u.CreateProcessInfo.hFile); P->status = PS_RUN; P->msg.type = 0; break; case CREATE_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case LOAD_DLL_DEBUG_EVENT: s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename); if (first_execp) { P->dll_load_order++; } addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order); size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL); if (size == INVALID_FILE_SIZE) { size = 0; } #if __amd64__ /* Not tracing 64 bit dlls for 32 bit process */ if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) { CloseHandle(dbg.u.LoadDll.hFile ); break; } #endif if ((mod = SymLoadModuleEx(P->phandle, dbg.u.LoadDll.hFile, s, NULL, (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0)) == FALSE) { dprintf("SymLoadModule64 failed for %s: %d\n", s, GetLastError()); break; } CloseHandle(dbg.u.LoadDll.hFile ); if (first_execp == 0) { P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; } else { P->status = PS_STOP; P->msg.type = RD_DLACTIVITY; } break; case UNLOAD_DLL_DEBUG_EVENT: if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) == FALSE) { dprintf("SymUnloadModule64 failed-Imagebase %p: %d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError()); break; } delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll); P->status = PS_RUN; P->msg.type = RD_DLACTIVITY; break; case EXIT_PROCESS_DEBUG_EVENT: P->exitcode = dbg.u.ExitProcess.dwExitCode; P->status = PS_UNDEAD; P->msg.type = RD_NONE; //SymCleanup(P->phandle); break; case EXIT_THREAD_DEBUG_EVENT: P->status = PS_RUN; P->msg.type = 0; break; case EXCEPTION_DEBUG_EVENT: switch(dbg.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: if (first_execp++ == 0) { pthread_cond_signal(&P->cond); } P->status = PS_STOP; P->msg.type = 0; break; default: if (dbg.u.Exception.dwFirstChance == 0) P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode; P->status = PS_RUN; cont = DBG_EXCEPTION_NOT_HANDLED; break; } break; default: P->status = PS_RUN; dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode); break; } if (P->status != PS_RUN) SetEvent(P->event); while (P->status == PS_STOP) pthread_cond_wait(&P->cond, &P->mutex); pthread_mutex_unlock(&P->mutex); ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont); } }
bool CODebugger::run(unsigned int msec) { DEBUG_EVENT deDebugEvent; //调试事件信息 bool bResult = true; // 等待调试事件 if(m_bActive && WaitForDebugEvent(&deDebugEvent, msec)) { //处理调试事件 switch(deDebugEvent.dwDebugEventCode) { //调试异常事件 case EXCEPTION_DEBUG_EVENT: { bResult = OnDebugException(deDebugEvent); break; } //创建线程 case CREATE_THREAD_DEBUG_EVENT: { AddThread(deDebugEvent.dwThreadId, deDebugEvent.u.CreateThread.hThread, (DWORD)deDebugEvent.u.CreateThread.lpStartAddress, (DWORD)deDebugEvent.u.CreateThread.lpThreadLocalBase); // call overloady D_CreateThread(&deDebugEvent); break; } //创建进程 case CREATE_PROCESS_DEBUG_EVENT: { //m_hProcess = deDebugEvent.u.CreateProcessInfo.hProcess; //m_hThread = deDebugEvent.u.CreateProcessInfo.hThread; //将主线程添加到线程链表 DEBUGGER_THREAD* pDebuggerThread = AddThread(deDebugEvent.dwThreadId,deDebugEvent.u.CreateProcessInfo.hThread,0,0); pDebuggerThread->m_bIsMainThread = true; // call overloady D_CreateProcess(&deDebugEvent); // 关闭进程文件句柄 if(deDebugEvent.u.CreateProcessInfo.hFile) { CloseHandle(deDebugEvent.u.CreateProcessInfo.hFile); } break; } //结束线程 case EXIT_THREAD_DEBUG_EVENT: { RemoveThread(deDebugEvent.dwThreadId); // call overloady D_ExitThread(&deDebugEvent); break; } //结束进程 case EXIT_PROCESS_DEBUG_EVENT: { if(exitfunc != NULL) { (*exitfunc)(&deDebugEvent); } // call overloady D_ExitProcess(&deDebugEvent); break; } //加载DLL case LOAD_DLL_DEBUG_EVENT: { break; } //卸载DLL case UNLOAD_DLL_DEBUG_EVENT: break; //输出调试字符串 case OUTPUT_DEBUG_STRING_EVENT: { // call overloady D_OutputDebugString(&deDebugEvent); break; } default: { bResult = false; } } DWORD dwContinueStatus; dwContinueStatus = bResult?DBG_CONTINUE:DBG_EXCEPTION_NOT_HANDLED; ContinueDebugEvent(deDebugEvent.dwProcessId, deDebugEvent.dwThreadId,dwContinueStatus); } else { return false; } return true; }
int main(int argc, char* argv[]) { if ( argc != 2 ) { printf("usage: %s crackme.exe \r\n", argv[0]); return -1; } // 保存文件名 char *pszFileName = argv[1]; // 启动信息 STARTUPINFO si = { 0 }; si.cb = sizeof(STARTUPINFO); GetStartupInfo(&si); // 进程信息 PROCESS_INFORMATION pi = { 0 }; // 创建被调试进程 BOOL bRet = CreateProcess(pszFileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); if ( bRet == FALSE ) { printf("CreateProcess Error \r\n"); return -1; } DEBUG_EVENT de = { 0 }; CONTEXT context = { 0 }; // 保存原始的机器码 BYTE bOldByte = 0; DWORD dwReadWriteNum = 0; // 保存正确密码使用 char pszPassword[MAXBYTE] = { 0 }; // 保存错误密码使用 char pszErrorPass[MAXBYTE] = { 0 }; while ( TRUE ) { // 获取调试事件 WaitForDebugEvent(&de, INFINITE); // 判断事件类型 switch ( de.dwDebugEventCode ) { // 创建进程时的调试事件 case CREATE_PROCESS_DEBUG_EVENT: { // 读取欲设置INT3断点处的机器码 // 方便后面恢复 ReadProcessMemory(pi.hProcess, (LPVOID)BP_VA, (LPVOID)&bOldByte, sizeof(BYTE), &dwReadWriteNum); // 将INT3的机器码0xCC写入断点处 WriteProcessMemory(pi.hProcess, (LPVOID)BP_VA, (LPVOID)&bInt3, sizeof(BYTE), &dwReadWriteNum); break; } // 产生异常时的调试事件 case EXCEPTION_DEBUG_EVENT: { // 判断异常类型 switch ( de.u.Exception.ExceptionRecord.ExceptionCode ) { // INT3类型的异常 case EXCEPTION_BREAKPOINT: { // 获取线程环境 context.ContextFlags = CONTEXT_FULL; GetThreadContext(pi.hThread, &context); // 判断是否断在我们设置的断点位置处 if ( (BP_VA + 1) == context.Eip ) { // 读取正确的密码 ReadProcessMemory(pi.hProcess, (LPVOID)context.Edx, (LPVOID)pszPassword, MAXBYTE, &dwReadWriteNum); // 读取错误密码 ReadProcessMemory(pi.hProcess, (LPVOID)context.Ecx, (LPVOID)pszErrorPass, MAXBYTE, &dwReadWriteNum); printf("你输入的密码是: %s \r\n", pszErrorPass); printf("正确的密码是: %s \r\n", pszPassword); // 因为我们的指令执行了INT3因此被中断 // INT3的机器指令长度为一个字节 // 因此我们需要将EIP减一来修正EIP // EIP是指令指针寄存器 // 其中保存着下条要执行指令的地址 context.Eip --; // 修正原来该地址的机器码 WriteProcessMemory(pi.hProcess, (LPVOID)BP_VA, (LPVOID)&bOldByte, sizeof(BYTE), &dwReadWriteNum); // 设置当前的线程环境 SetThreadContext(pi.hThread, &context); } break; } } } } ContinueDebugEvent(de.dwProcessId,de.dwThreadId,DBG_CONTINUE); } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return 0; }
/** * @brief 运行监视函数 * 监视进程运行状态、时间、内存以及输出等信息 * * @param hProcess 进程句柄 * @param lim_time 时间限制 * @param lim_memo 内存限制 * @param lim_size 输出文件长度限制 * @param cs 用于接收代码状态的引用 * @return 若运行期间未出现异常则返回true,否则返回false */ bool CNBUTOJCore::WatchCode(const HANDLE hProcess, const __int64 lim_time, const SIZE_T lim_memo, const DWORD lim_size, const char *outputFilename, CodeState &cs, const PROCESS_INFORMATION ProcInfo) { DWORD maxMemo = 0; ///< 使用的内存 __int64 RunTime = -1; ///< 使用的时间 DWORD nowSize; ///< 使用的输出大小 DEBUG_EVENT DBE; ///< 调试信息结构体 while(true) { /** 继续调试(时间是为了忽略断点的) */ bool flag = WaitForDebugEvent(&DBE, lim_time + 200); if(!flag) { RunTime = _GetRunTime(hProcess) + lim_time + 200; return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, TIME_LIMIT_EXCEEDED_2, RunTime, maxMemo); } /** 获取运行时间 */ RunTime = _GetRunTime(hProcess); if(-1 == RunTime) return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, SYSTEM_ERROR, RunTime, maxMemo, "Can't get running time."); /** 获取运行内存 */ DWORD memo = _GetRunMemo(hProcess); if(-1 == memo) return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, SYSTEM_ERROR, RunTime, maxMemo, "Can't get occupied memory."); else maxMemo = (memo > maxMemo) ? memo : maxMemo; /** 获取运行文件输出大小 */ nowSize = _GetRunSize(outputFilename); /** 若超时 */ if(RunTime > lim_time) return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, TIME_LIMIT_EXCEEDED_1, RunTime, maxMemo); //cout << RunTime << " " << maxMemo << " " << nowSize << " " << DBE.dwDebugEventCode << endl; /** 若超内存 */ if(maxMemo > lim_memo) return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, MEMORY_LIMIT_EXCEEDED, RunTime, maxMemo); /** 若超输出 */ //if(nowSize > lim_size) // return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, OUTPUT_LIMIT_EXCEEDED, RunTime, maxMemo); if(DBE.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { ContinueDebugEvent(DBE.dwProcessId, DBE.dwThreadId, DBG_CONTINUE); if(DBE.u.CreateProcessInfo.hFile) CloseHandle(DBE.u.CreateProcessInfo.hFile); if(DBE.u.CreateProcessInfo.hProcess) CloseHandle(DBE.u.CreateProcessInfo.hProcess); if(DBE.u.CreateProcessInfo.hThread) CloseHandle(DBE.u.CreateProcessInfo.hThread); break; } else if(DBE.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { if(DBE.u.Exception.ExceptionRecord.ExceptionCode != 0x80000003) { //printf("0x%x\n", DBE.u.Exception.ExceptionRecord.ExceptionCode); /** 复制错误 */ switch(DBE.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: { strcpy(cs.err_code, "ACCESS_VIOLATION"); break; } case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: { strcpy(cs.err_code, "ARRAY_BOUNDS_EXCEEDED"); break; } case EXCEPTION_FLT_DENORMAL_OPERAND: { strcpy(cs.err_code, "FLOAT_DENORMAL_OPERAND"); break; } case EXCEPTION_FLT_DIVIDE_BY_ZERO: { strcpy(cs.err_code, "FLOAT_DIVIDE_BY_ZERO"); break; } case EXCEPTION_FLT_OVERFLOW: { strcpy(cs.err_code, "FLOAT_OVERFLOW"); break; } case EXCEPTION_FLT_UNDERFLOW: { strcpy(cs.err_code, "FLOAT_UNDERFLOW"); break; } case EXCEPTION_INT_DIVIDE_BY_ZERO: { strcpy(cs.err_code, "INTEGER_DIVIDE_BY_ZERO"); break; } case EXCEPTION_INT_OVERFLOW: { strcpy(cs.err_code, "INTEGER_OVERFLOW"); break; } case EXCEPTION_STACK_OVERFLOW: { strcpy(cs.err_code, "STACK_OVERFLOW"); break; } default: { strcpy(cs.err_code, "OTHER_ERRORS"); break; } } /** 关闭句柄,否则调试进程不能被结束 */ if(DBE.u.CreateProcessInfo.hFile) CloseHandle(DBE.u.CreateProcessInfo.hFile); if(DBE.u.CreateProcessInfo.hProcess) CloseHandle(DBE.u.CreateProcessInfo.hProcess); if(DBE.u.CreateProcessInfo.hThread) CloseHandle(DBE.u.CreateProcessInfo.hThread); return _ErrExit(hProcess, ProcInfo.dwProcessId, cs, RUNTIME_ERROR, RunTime, maxMemo); } } /** 继续调试 */ ContinueDebugEvent(DBE.dwProcessId, DBE.dwThreadId, DBG_CONTINUE); if(DBE.u.CreateProcessInfo.hFile) CloseHandle(DBE.u.CreateProcessInfo.hFile); if(DBE.u.CreateProcessInfo.hProcess) CloseHandle(DBE.u.CreateProcessInfo.hProcess); if(DBE.u.CreateProcessInfo.hThread) CloseHandle(DBE.u.CreateProcessInfo.hThread); } cs.exe_time = RunTime; cs.exe_memory = maxMemo; return true; }