/// <summary> /// Process the event, this is where most of the work for the debugger is done at run time. /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus ProcessEvent(Debug_Event e) { switch (e.Code) { case EventCode.CREATE_PROCESS_DEBUG_INFO: return this.HandleCreateProcess(e); case EventCode.CREATE_THREAD_DEBUG_INFO: return this.HandleThreadCreation(e); case EventCode.EXCEPTION_DEBUG_INFO: return this.HandleExceptions(e); case EventCode.EXIT_PROCESS_DEBUG_INFO: return this.HandleProcessExit(e); case EventCode.EXIT_THREAD_DEBUG_INFO: return this.HandleExitThread(e); case EventCode.LOAD_DLL_DEBUG_INFO: return HandleLoadDLL(e); case EventCode.UNLOAD_DLL_DEBUG_INFO: return this.HandleUnloadDLL(e); case EventCode.RIP_INFO: return this.HandleRIP(e); case EventCode.OUTPUT_DEBUG_STRING_INFO: return this.HandleOutputString(e); } return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when a DLL is unloaded /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleUnloadDLL(Debug_Event e) { return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// The main loop of the debugger, waits for events and processes actions accordingly. /// </summary> private void MainDebuggerLoop() { while (true) { if (this.enterTerminateSequence) { if (!WinAPI.DebugActiveProcessStop((uint)this.debuggee.Id)) throw new Exception("Error 0x" + WinAPI.GetLastError().ToString("X") + " - " + Enum.GetName(typeof(WinAPI.SYSTEM_ERROR_CODE), WinAPI.GetLastError()) + " - when detatching from process"); try { this.debuggee.Kill(); // XP seems to be choking on this. Errors out with permission denied, then the same call throws an exception that the process is already dead. // Adding a check to see if the process has exited yet before calling this did not seem to fix it. best fix so far is an empty try/catch, sloppy but it worked if (this.settings.EnableKillAlso) // Allows the debugger to kill other processes when it kills the debugee { Process[] processes = Process.GetProcessesByName(this.settings.KillAlso); if (processes.Length > 0) { foreach (Process p in processes) { if (p != this.debuggee) { if (!p.HasExited) { p.Kill(); } } } } } this.debuggee.WaitForExit(); } catch (Exception e) { try { if (!this.debuggee.HasExited) throw new Exception("Error - Debuggee Never Exited. " + e.Message); } catch (Exception exception) { if (!(exception is InvalidOperationException) && !(exception.Message == "There is no process associated with the object")) throw exception; } } finally { this.enterTerminateSequence = false; } return; } if (this.WindowThread == null) // Allows us to only have one thread cleaning windows at a time. { this.WindowThread = new Thread(this.CheckWindows); this.WindowThread.Start(); } Debug_Event Event = new Debug_Event(); if (!WinAPI.WaitForDebugEvent(out Event, 0)) if (WinAPI.GetLastError() == 121) // Error 121 is a timeout error, since we are not pausing at all for events. We don't pause so that we can continue to launch threads to check windows. continue; else throw new DebuggerException("Error 0x" + WinAPI.GetLastError().ToString("X") + " - " + Enum.GetName(typeof(WinAPI.SYSTEM_ERROR_CODE), WinAPI.GetLastError()) + " - while waiting for debug event"); this.lastEvent = DateTime.Now.Millisecond; WinAPI.ContinueStatus action = this.ProcessEvent(Event); if (!WinAPI.ContinueDebugEvent(Event.ProcessID, Event.ThreadID, action)) throw new DebuggerException("Error 0x" + WinAPI.GetLastError().ToString("X") + " - " + Enum.GetName(typeof(WinAPI.SYSTEM_ERROR_CODE), WinAPI.GetLastError()) + " - while attempting to continue a debug event."); } }
/// <summary> /// Performs any actions necessary when the debuggee exits a process /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleProcessExit(Debug_Event e) { if (this.debuggee.Id == e.ProcessID) { if (this.settings.ErrorCodes.Contains((ErrorCode)e.u.ExitProcess.ExitCode)) { this.ErrorInformation.Append("***PROCESS EXIT WITH WATCHED CODE***" + "\r\n"); } else { this.ErrorInformation.Append("PROCESS EXIT" + "\r\n"); } } else { this.ErrorInformation.Append("SPAWNED PROCESS EXIT" + "\r\n"); } this.ErrorInformation.Append("=============================================" + "\r\n"); this.ErrorInformation.Append("Process: " + e.ProcessID + "\r\n"); this.ErrorInformation.Append("Thread: " + e.ThreadID + "\r\n"); this.ErrorInformation.Append("Error: " + Enum.GetName(typeof(ErrorCode), e.u.ExitProcess.ExitCode) + " - " + e.u.ExitProcess.ExitCode.ToString("X") + "\r\n"); this.ErrorInformation.Append("\r\n" + this.GetRegisterContext(e.ThreadID) + "\r\n"); this.ErrorInformation.Append("\r\n\r\n" + "\r\n"); if (this.debuggee.Id == e.ProcessID) { this.debuggee.Kill(); this.debuggee.WaitForExit(); } return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when the debuggee creates a thread /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleThreadCreation(Debug_Event e) { return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when an output string is encountered. /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleOutputString(Debug_Event e) { // This function doesn't much matter because strings and Debug_Event in C# doesn't seem to get along very well, should probably look into that. Probably around the same time I start caring about debug strings. return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when a DLL is loaded /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleLoadDLL(Debug_Event e) { if (!WinAPI.CloseHandle(e.u.LoadDll.File)) throw new Exception("Error closing file handle during dll load"); return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when a thread exits /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleExitThread(Debug_Event e) { return WinAPI.ContinueStatus.DBG_CONTINUE; }
/// <summary> /// Performs any actions necessary when the debuggee raises an exception /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleExceptions(Debug_Event e) { // Handle the breakpoint exception at startup, this is where we hide the debugger if necessary if ((ErrorCode)e.u.Exception.ExceptionRecord.ExceptionCode == ErrorCode.STATUS_BREAKPOINT && !this.doneStarting) { this.doneStarting = true; if (this.settings.HideDebugger) { WinAPI.BasicProcessInformation ProcessInformation = new WinAPI.BasicProcessInformation(); int returnLength; WinAPI.SYSTEM_ERROR_CODE code = WinAPI.NtQueryInformationProcess(this.debuggee.Handle, 0x00, ref ProcessInformation, (uint)Marshal.SizeOf(ProcessInformation), out returnLength); if (code != 0) throw new DebuggerException("Error 0x" + WinAPI.GetLastError().ToString("X") + " - " + Enum.GetName(typeof(WinAPI.SYSTEM_ERROR_CODE), WinAPI.GetLastError()) + " - while getting PEB address. - 0x" + code.ToString("X") + " - " + Enum.GetName(typeof(ErrorCode), code)); byte[] DebuggerPresent = new Byte[1]; int Length; DebuggerPresent[0] = 0; WinAPI.WriteProcessMemory(this.debuggee.Handle, ProcessInformation.PebBaseAddress + 2, DebuggerPresent, 1, out Length); } return WinAPI.ContinueStatus.DBG_CONTINUE; } this.ErrorInformation.Append("EXCEPTION" + "\r\n"); this.ErrorInformation.Append("=============================================" + "\r\n"); this.ErrorInformation.Append("Process: " + e.ProcessID + "\r\n"); this.ErrorInformation.Append("Thread: " + e.ThreadID + "\r\n"); this.ErrorInformation.Append("Error: " + Enum.GetName(typeof(ErrorCode), e.u.Exception.ExceptionRecord.ExceptionCode) + " - " + e.u.Exception.ExceptionRecord.ExceptionCode.ToString("X") + "\r\n"); this.ErrorInformation.Append("\r\n" + this.GetRegisterContext(e.ThreadID) + "\r\n"); this.ErrorInformation.Append("\r\n\r\n" + "\r\n"); return WinAPI.ContinueStatus.DBG_EXCEPTION_NOT_HANDLED; }
/// <summary> /// Performs any actions necessary when a process is created. /// </summary> /// <param name="e"></param> /// <returns></returns> private WinAPI.ContinueStatus HandleCreateProcess(Debug_Event e) { if (!WinAPI.CloseHandle(e.u.CreateProcessInfo.File)) throw new Exception("Error closing file handle in create process event"); return WinAPI.ContinueStatus.DBG_CONTINUE; }