/// <summary> /// Waits for a debug event from any of the processes in the wait set. /// </summary> /// <param name="timeout">timeout in milliseconds to wait. If 0, checks for a debug event and returns immediately</param> /// <returns>Null if no event is available</returns> /// <remarks>Debug events should be continued by calling ContinueEvent. The debuggee is completely stopped when a /// debug event is dispatched and until it is continued.</remarks> public NativeEvent WaitForDebugEvent(int timeout) { EnsureIsOnWin32EventThread(); bool fHasEvent; if (IntPtr.Size == sizeof(Int32)) { DebugEvent32 event32 = new DebugEvent32(); fHasEvent = NativeMethods.WaitForDebugEvent32(ref event32, timeout); if (fHasEvent) { return(NativeEvent.Build(this, ref event32.header, ref event32.union)); } } else { DebugEvent64 event64 = new DebugEvent64(); fHasEvent = NativeMethods.WaitForDebugEvent64(ref event64, timeout); if (fHasEvent) { return(NativeEvent.Build(this, ref event64.header, ref event64.union)); } } // Not having an event could be a timeout, or it could be a real failure. // Empirically, timeout produces GetLastError()=121 (ERROR_SEM_TIMEOUT), but MSDN doesn't spec that, so // we don't want to rely on it. So if we don't have an event, just return NULL and // don't try to probe any further. return(null); }
private static bool WaitForDebugEvent(ref dynamic debugEvent32Or64, int dwMilliseconds) { bool is64BitProcess = (IntPtr.Size == 8); if (is64BitProcess) { var debugEvent64 = new DebugEvent64(); if (!NativeDebuggingMethods.WaitForDebugEvent64(ref debugEvent64, dwMilliseconds)) { return(false); } debugEvent32Or64 = debugEvent64; } else { var debugEvent32 = new DebugEvent32(); if (!NativeDebuggingMethods.WaitForDebugEvent32(ref debugEvent32, dwMilliseconds)) { return(false); } debugEvent32Or64 = debugEvent32; } return(true); }
public void DebugThread(string executable) { var lpStartupInfo = new STARTUPINFO(); var lpProcessInformation = new PROCESS_INFORMATION(); if (!NativeMethods.CreateProcess(executable, "", IntPtr.Zero, IntPtr.Zero, false, NativeMethods.CreateProcessFlags.DEBUG_PROCESS | NativeMethods.CreateProcessFlags.DEBUG_ONLY_THIS_PROCESS, IntPtr.Zero, null, lpStartupInfo, lpProcessInformation)) { Console.WriteLine($"FAIL with {Marshal.GetLastWin32Error()}"); } var process = Process.GetProcessById(lpProcessInformation.dwProcessId); ProcessContext context = null; var loop = true; while (loop) { var debugEvent = new DebugEvent64(); NativeMethods.WaitForDebugEvent64(ref debugEvent, -1); try { switch (debugEvent.header.dwDebugEventCode) { case NativeDebugEventCode.None: break; case NativeDebugEventCode.EXCEPTION_DEBUG_EVENT: switch (debugEvent.union.Exception.ExceptionRecord.ExceptionCode) { case ExceptionCode.STATUS_BREAKPOINT: OnProcessBreakpoint(new ProcessBreakpointEventArgs(context, lpProcessInformation.hProcess, debugEvent.header.dwProcessId, debugEvent.header.dwThreadId)); break; } break; case NativeDebugEventCode.CREATE_THREAD_DEBUG_EVENT: break; case NativeDebugEventCode.CREATE_PROCESS_DEBUG_EVENT: { context = new ProcessContext(process); OnProcessCreated(new ProcessCreatedEventArgs(context, lpProcessInformation.hProcess, debugEvent.header.dwProcessId, debugEvent.header.dwThreadId)); break; } case NativeDebugEventCode.EXIT_THREAD_DEBUG_EVENT: break; case NativeDebugEventCode.EXIT_PROCESS_DEBUG_EVENT: { loop = false; break; } case NativeDebugEventCode.LOAD_DLL_DEBUG_EVENT: { var loadDllDebugInfo = debugEvent.union.LoadDll; string value = null; if (loadDllDebugInfo.lpImageName != IntPtr.Zero) { var intPtr = context.Memory[loadDllDebugInfo.lpImageName, false].Read <IntPtr>(); if (intPtr != IntPtr.Zero) { value = context.Memory[intPtr, false] .ReadString(loadDllDebugInfo.fUnicode != 0 ? Encoding.Unicode : Encoding.ASCII); } } OnProcessModuleLoad(new ProcessModuleLoadEventArgs(context, lpProcessInformation.hProcess, debugEvent.header.dwProcessId, debugEvent.header.dwThreadId) { Name = value }); break; } case NativeDebugEventCode.UNLOAD_DLL_DEBUG_EVENT: break; case NativeDebugEventCode.OUTPUT_DEBUG_STRING_EVENT: { var outputDebugStringInfo = debugEvent.union.OutputDebugString; var value = context.Memory[outputDebugStringInfo.lpDebugStringData, false] .ReadString(outputDebugStringInfo.fUnicode != 0 ? Encoding.Unicode : Encoding.ASCII); OnProcessDebugOutput(new ProcessDebugOutputEventArgs(context, lpProcessInformation.hProcess, debugEvent.header.dwProcessId, debugEvent.header.dwThreadId) { Value = value }); break; } case NativeDebugEventCode.RIP_EVENT: break; default: throw new ArgumentOutOfRangeException(); } } catch (Exception e) { OnDebugException(new DebugExceptionEventArgs(context, lpProcessInformation.hProcess, debugEvent.header.dwProcessId, debugEvent.header.dwThreadId) { Exception = e }); NativeMethods.ContinueDebugEvent(debugEvent.header.dwProcessId, debugEvent.header.dwThreadId, NativeMethods.ContinueStatus.DBG_EXCEPTION_NOT_HANDLED); continue; } NativeMethods.ContinueDebugEvent(debugEvent.header.dwProcessId, debugEvent.header.dwThreadId, NativeMethods.ContinueStatus.DBG_CONTINUE); } }