internal Debuggee(string executable, IntPtr procHandle, uint procId, IntPtr mainThreadHandle, uint mainThreadId, ExecutableMetaInfo emi = null) { // Note: The CodeView information extraction will be done per module, i.e. when the module/process is loaded into the memory. Memory = new MemoryManagement(this); Breakpoints = new BreakpointManagement(this); CodeStepping = new Stepping(this); var mProc = new DebugProcess(this, executable, procHandle, procId, mainThreadHandle, mainThreadId, emi); CurrentThread = mProc.MainThread; processes.Add(mProc); }
/// <summary> /// Executes until the currently executed method's point of return has been reached. /// </summary> public void StepOut(DebugThread th) { var returnPtr = APIIntermediate.Read<IntPtr>(th.OwnerProcess.Handle, new IntPtr( th.Context.lastReadCtxt.ebp + 4)); var tempBreakPoint = Breakpoints.ByAddress(returnPtr); bool keepBpAfterStepComplete = false; if (keepBpAfterStepComplete = tempBreakPoint == null) tempBreakPoint = Breakpoints.CreateBreakpoint(returnPtr); th.ContinueDebugging(); Debuggee.WaitForDebugEvent(); if (!keepBpAfterStepComplete) Breakpoints.Remove(tempBreakPoint); }
public DebugProcess(Debuggee dbg, string executableFile, IntPtr processHandle, uint processId, IntPtr mainThreadHandle, uint mainThreadId, ExecutableMetaInfo emi) { this.Debuggee = dbg; Handle = processHandle; Id = processId; MainModule = new DebugProcessModule(new IntPtr(emi.PEHeader.OptionalHeader32.ImageBase),executableFile, emi); RegModule(MainModule); MainThread = new DebugThread(this, mainThreadHandle, mainThreadId, MainModule.StartAddress, IntPtr.Zero); RegThread(MainThread); }
public DebugProcess(Debuggee dbg, string executableFile, IntPtr processHandle, uint processId, IntPtr mainThreadHandle, uint mainThreadId, ExecutableMetaInfo emi) { this.Debuggee = dbg; Handle = processHandle; Id = processId; MainModule = new DebugProcessModule(new IntPtr(emi.PEHeader.OptionalHeader32.ImageBase), executableFile, emi); RegModule(MainModule); MainThread = new DebugThread(this, mainThreadHandle, mainThreadId, MainModule.StartAddress, IntPtr.Zero); RegThread(MainThread); }
public DebugProcess(Debuggee dbg, Win32.CREATE_PROCESS_DEBUG_INFO info, uint id, uint threadId) { this.Debuggee = dbg; Handle = info.hProcess; Id = id == 0 ? API.GetProcessId(Handle) : id; var moduleFile = APIIntermediate.GetModulePath(Handle, info.lpBaseOfImage, info.hFile); // Deduce main module MainModule = new DebugProcessModule(info.lpBaseOfImage, moduleFile, ExecutableMetaInfo.ExtractFrom(moduleFile)); RegModule(MainModule); // Create main thread MainThread = new DebugThread(this, info.hThread, threadId == 0 ? API.GetThreadId(info.hThread) : threadId, info.lpStartAddress, info.lpThreadLocalBase); RegThread(MainThread); }
internal bool RemThread(DebugThread th) { return(threads.Remove(th)); }
void HandleDebugEvent(DebugEventData de) { var p = ProcessById(de.dwProcessId); var th = CurrentThread = p.ThreadById(de.dwThreadId); switch (de.dwDebugEventCode) { case DebugEventCode.EXCEPTION_DEBUG_EVENT: HandleException(th, de.Exception); break; case DebugEventCode.CREATE_PROCESS_DEBUG_EVENT: var cpi = de.CreateProcessInfo; if (MainProcess != null && de.dwProcessId == MainProcess.Id) { API.CloseHandle(cpi.hProcess); API.CloseHandle(cpi.hThread); API.CloseHandle(cpi.hFile); foreach (var l in DDebugger.EventListeners) { l.OnCreateProcess(MainProcess); } break; } // After a new process was created (also occurs after initial WaitForDebugEvent()!!), p = new DebugProcess(this, cpi, de.dwProcessId, de.dwThreadId); API.CloseHandle(cpi.hFile); // enlist it processes.Add(p); // and call the listeners foreach (var l in DDebugger.EventListeners) { l.OnCreateProcess(p); } break; case DebugEventCode.CREATE_THREAD_DEBUG_EVENT: p = ProcessById(de.dwProcessId); // Create new thread wrapper th = CurrentThread = new DebugThread(p, de.CreateThread.hThread, de.dwThreadId, de.CreateThread.lpStartAddress, de.CreateThread.lpThreadLocalBase); // Register it to main process p.RegThread(th); // Call listeners foreach (var l in DDebugger.EventListeners) { l.OnCreateThread(th); } break; case DebugEventCode.EXIT_PROCESS_DEBUG_EVENT: foreach (var l in DDebugger.EventListeners) { l.OnProcessExit(p, de.ExitProcess.dwExitCode); } processes.Remove(p); p.Dispose(); break; case DebugEventCode.EXIT_THREAD_DEBUG_EVENT: foreach (var l in DDebugger.EventListeners) { l.OnThreadExit(th, de.ExitThread.dwExitCode); } p.RemThread(th); th.Dispose(); break; case DebugEventCode.LOAD_DLL_DEBUG_EVENT: var loadParam = de.LoadDll; var modName = APIIntermediate.GetModulePath(p.Handle, loadParam.lpBaseOfDll, loadParam.hFile); API.CloseHandle(loadParam.hFile); var mod = new DebugProcessModule(loadParam.lpBaseOfDll, modName, ExecutableMetaInfo.ExtractFrom(modName)); p.RegModule(mod); foreach (var l in DDebugger.EventListeners) { l.OnModuleLoaded(p, mod); } break; case DebugEventCode.UNLOAD_DLL_DEBUG_EVENT: mod = p.ModuleByBase(de.UnloadDll.lpBaseOfDll); foreach (var l in DDebugger.EventListeners) { l.OnModuleUnloaded(p, mod); } p.RemModule(mod); break; case DebugEventCode.OUTPUT_DEBUG_STRING_EVENT: var message = APIIntermediate.ReadString(p.Handle, de.DebugString.lpDebugStringData, de.DebugString.fUnicode == 0 ? Encoding.ASCII : Encoding.Unicode, (int)de.DebugString.nDebugStringLength); foreach (var l in DDebugger.EventListeners) { l.OnDebugOutput(th, message); } break; } }
public virtual void OnBreakpoint(DebugThread thread, Breakpoint breakpoint) { }
public override void OnDebugOutput(DebugThread thread, string outputString) { base.OnDebugOutput(thread, outputString); }
public override void OnStepComplete(DebugThread thread) { form.HighlightCurrentInstruction(thread); }
public virtual void OnDebugOutput(DebugThread thread, string outputString) { }
public override void OnBreakpoint(DebugThread thread, DDebugger.Breakpoints.Breakpoint breakpoint) { form.HighlightCurrentInstruction(thread); }
/// <summary> /// Executes the next single code instruction. /// Returns false if the single step could be executed but wasn't completed due to a breakpoint or an other exception/debug event. /// </summary> bool StepToNextInstruction(DebugThread th) { if (!Debuggee.IsAlive) return false; if (lastUnhandledBreakpoint != null) SkipAndRestoreLastBreakpoint(false); bool lastStepState = th.Context.TrapFlagSet; if (!lastStepState) th.Context.TrapFlagSet = true; th.ContinueDebugging(); expectsSingleStep = true; Debuggee.WaitForDebugEvent(); //TODO: What if there's a non-ss exception? // Answer: return false if (!lastStepState) th.Context.TrapFlagSet = false; return !expectsSingleStep; }
/// <summary> /// Executes the next instruction. /// </summary> public void StepIn(DebugThread th) { DoSingleStep(th); }
public virtual void OnCreateThread(DebugThread newThread) { }
void DoSingleStep(DebugThread th) { if (SourceBoundStepping) StepToNextSrcLine(th); else StepToNextInstruction(th); }
public virtual void OnThreadExit(DebugThread thread, uint exitCode) { }
public virtual void OnStepComplete(DebugThread thread) { }
public virtual void OnException(DebugThread thread, DebugException exception) { }
public virtual void OnBreakComplete(DebugThread thread) { }
/// <summary> /// See <see cref="StepIn"/>. /// If there's a call as next instruction, it'll be skipped. /// </summary> public void StepOver(DebugThread th) { var code = APIIntermediate.ReadArray<byte>(th.OwnerProcess.Handle, th.CurrentInstruction, DisAsm86.MaximumInstructionLength); int instructionLength = 0; var instrType = DisAsm86.GetInstructionType(code, false, out instructionLength); /* * If there's a call, set a breakpoint right after the call to skip the called subroutine */ if (instrType == InstructionType.Call) { var bpAddr = IntPtr.Add(th.CurrentInstruction, instructionLength); var tempBreakPoint = Breakpoints.ByAddress(bpAddr); bool keepBpAfterStepComplete = false; if (keepBpAfterStepComplete = tempBreakPoint == null) tempBreakPoint = Breakpoints.CreateBreakpoint(bpAddr); th.ContinueDebugging(); Debuggee.WaitForDebugEvent(); if (!keepBpAfterStepComplete) Breakpoints.Remove(tempBreakPoint); } else StepIn(th); }
void SkipAndRestoreLastBreakpoint(bool resetStepFlag = true) { if (lastUnhandledBreakpoint == null) throw new Exception("lastUnhandledBreakpoint must not be null"); if (!lastUnhandledBreakpoint.temporarilyDisabled) throw new Exception("breakpoint must be marked as temporarily disabled!"); if (lastUnhandledBreakpointThread == null) throw new Exception("lastUnhandledBreakpointThread must not be null"); if (postBreakpointResetStepCompleted) throw new Exception("why is postBreakpointResetStepCompleted set to true?"); // Immediately after the breakpoint was hit, the bp code was taken out of the code // and the instruction pointer was decreased, so the original instruction will be executed then afterwards. // 1) Enable single-stepping (SS flag) // 2) Step one forward (execute original instruction) // 3) Re-enable breakpoint // 4) (optionally) disable single-stepping again // 1) lastUnhandledBreakpointThread.Context.TrapFlagSet = true; // 2) lastUnhandledBreakpointThread.ContinueDebugging(); postBreakpointResetStepCompleted = false; Debuggee.WaitForDebugEvent(); if (!postBreakpointResetStepCompleted) return; // 3) lastUnhandledBreakpoint.Enable(); // 4) if(resetStepFlag) lastUnhandledBreakpointThread.Context.TrapFlagSet = false; lastUnhandledBreakpointThread = null; lastUnhandledBreakpoint = null; postBreakpointResetStepCompleted = false; }
/// <summary> /// Steps until there's an associated code location for the currently executed instruction /// or if there aren't any debug information. /// </summary> void StepToNextSrcLine(DebugThread th) { string file = null; ushort line = 0; var mainMod = Debuggee.MainProcess.MainModule; var modMetaInfo = mainMod.ModuleMetaInfo; do{ StepToNextInstruction(th); } while(Debuggee.IsAlive && mainMod.ContainsSymbolData && !modMetaInfo.TryDetermineCodeLocation((uint)Debuggee.CurrentThread.CurrentInstruction.ToInt32(), out file, out line)); }
void HighlightCurrentInstruction(DebugThread th) { if (currentFrameMarker != null) currentFrameMarker.Delete(); ushort line = 0; string file = null; if (th.OwnerProcess.MainModule.ContainsSymbolData && th.OwnerProcess.MainModule.ModuleMetaInfo.TryDetermineCodeLocation((uint)th.CurrentInstruction.ToInt32(), out file, out line)) { LoadSourceFileIntoEditor(file); currentFrameMarker = new CurrentFrameMarker(MarkerStrategy, editor.Document, line); MarkerStrategy.Add(currentFrameMarker); currentFrameMarker.Redraw(); } }
public override void OnCreateThread(DebugThread newThread) { base.OnCreateThread(newThread); }
void HandleDebugEvent(DebugEventData de) { var p = ProcessById(de.dwProcessId); var th = CurrentThread = p.ThreadById(de.dwThreadId); switch (de.dwDebugEventCode) { case DebugEventCode.EXCEPTION_DEBUG_EVENT: HandleException(th, de.Exception); break; case DebugEventCode.CREATE_PROCESS_DEBUG_EVENT: var cpi = de.CreateProcessInfo; if (MainProcess != null && de.dwProcessId == MainProcess.Id) { API.CloseHandle(cpi.hProcess); API.CloseHandle(cpi.hThread); API.CloseHandle(cpi.hFile); foreach(var l in DDebugger.EventListeners) l.OnCreateProcess(MainProcess); break; } // After a new process was created (also occurs after initial WaitForDebugEvent()!!), p = new DebugProcess(this,cpi, de.dwProcessId, de.dwThreadId); API.CloseHandle(cpi.hFile); // enlist it processes.Add(p); // and call the listeners foreach (var l in DDebugger.EventListeners) l.OnCreateProcess(p); break; case DebugEventCode.CREATE_THREAD_DEBUG_EVENT: p = ProcessById(de.dwProcessId); // Create new thread wrapper th = CurrentThread = new DebugThread(p, de.CreateThread.hThread, de.dwThreadId, de.CreateThread.lpStartAddress, de.CreateThread.lpThreadLocalBase); // Register it to main process p.RegThread(th); // Call listeners foreach (var l in DDebugger.EventListeners) l.OnCreateThread(th); break; case DebugEventCode.EXIT_PROCESS_DEBUG_EVENT: foreach (var l in DDebugger.EventListeners) l.OnProcessExit(p, de.ExitProcess.dwExitCode); processes.Remove(p); p.Dispose(); break; case DebugEventCode.EXIT_THREAD_DEBUG_EVENT: foreach (var l in DDebugger.EventListeners) l.OnThreadExit(th, de.ExitThread.dwExitCode); p.RemThread(th); th.Dispose(); break; case DebugEventCode.LOAD_DLL_DEBUG_EVENT: var loadParam = de.LoadDll; var modName = APIIntermediate.GetModulePath(p.Handle, loadParam.lpBaseOfDll, loadParam.hFile); API.CloseHandle(loadParam.hFile); var mod = new DebugProcessModule(loadParam.lpBaseOfDll, modName, ExecutableMetaInfo.ExtractFrom(modName)); p.RegModule(mod); foreach (var l in DDebugger.EventListeners) l.OnModuleLoaded(p, mod); break; case DebugEventCode.UNLOAD_DLL_DEBUG_EVENT: mod = p.ModuleByBase(de.UnloadDll.lpBaseOfDll); foreach (var l in DDebugger.EventListeners) l.OnModuleUnloaded(p, mod); p.RemModule(mod); break; case DebugEventCode.OUTPUT_DEBUG_STRING_EVENT: var message = APIIntermediate.ReadString(p.Handle, de.DebugString.lpDebugStringData, de.DebugString.fUnicode == 0 ? Encoding.ASCII : Encoding.Unicode, (int)de.DebugString.nDebugStringLength); foreach (var l in DDebugger.EventListeners) l.OnDebugOutput(th, message); break; } }
public override void OnException(DebugThread thread, DebugException exception) { form.HighlightCurrentInstruction(thread); }
void HandleException(DebugThread th, EXCEPTION_DEBUG_INFO e) { th.Context.Update(); var code = e.ExceptionRecord.Code; // The instruction var targetSiteAddress = e.ExceptionRecord.ExceptionAddress; if (code == ExceptionCode.Breakpoint) { if (CodeStepping.lastUnhandledBreakpoint != null) CodeStepping.postBreakpointResetStepCompleted = true; var bp = Breakpoints.ByAddress(targetSiteAddress); if (bp == null) return; //APIIntermediate.GetCallStack_x86(th.OwnerProcess.Handle, (uint)th.StartAddress.ToInt32(), th.Context["ebp"], th.Context["eip"]); /* var sf = new STACKFRAME64(); sf.AddrPC.Offset = th.Context["eip"]; sf.AddrFrame.Offset = th.Context["ebp"]; sf.AddrStack.Offset = th.Context["esp"]; sf.AddrReturn.Mode = sf.AddrStack.Mode = sf.AddrPC.Mode = sf.AddrFrame.Mode = ADDRESS_MODE.AddrModeFlat; if(!API.StackWalk64(MachineType.i386, th.OwnerProcess.Handle, th.Handle, ref sf, ref th.Context.lastReadCtxt)) throw new Win32Exception(Marshal.GetLastWin32Error()); */ th.CurrentInstruction = targetSiteAddress; bp.Disable(); bp.temporarilyDisabled = true; CodeStepping.lastUnhandledBreakpoint = bp; CodeStepping.lastUnhandledBreakpointThread = th; bp.WasHit(); foreach (var l in DDebugger.EventListeners) l.OnBreakpoint(th, bp); } else if (code == ExceptionCode.SingleStep) { if (CodeStepping.lastUnhandledBreakpoint != null) CodeStepping.postBreakpointResetStepCompleted = true; else foreach (var l in DDebugger.EventListeners) l.OnStepComplete(th); } else { var ex = new DebugException(e.ExceptionRecord, e.dwFirstChance != 0); foreach (var l in DDebugger.EventListeners) l.OnException(th, ex); LastException = ex; } }
public override void OnThreadExit(DebugThread thread, uint exitCode) { base.OnThreadExit(thread, exitCode); }
internal void RegThread(DebugThread th) { threads.Add(th); }
void HandleException(DebugThread th, EXCEPTION_DEBUG_INFO e) { th.Context.Update(); var code = e.ExceptionRecord.Code; // The instruction var targetSiteAddress = e.ExceptionRecord.ExceptionAddress; if (code == ExceptionCode.Breakpoint) { if (CodeStepping.lastUnhandledBreakpoint != null) { CodeStepping.postBreakpointResetStepCompleted = true; } var bp = Breakpoints.ByAddress(targetSiteAddress); if (bp == null) { return; } //APIIntermediate.GetCallStack_x86(th.OwnerProcess.Handle, (uint)th.StartAddress.ToInt32(), th.Context["ebp"], th.Context["eip"]); /* * var sf = new STACKFRAME64(); * sf.AddrPC.Offset = th.Context["eip"]; * sf.AddrFrame.Offset = th.Context["ebp"]; * sf.AddrStack.Offset = th.Context["esp"]; * sf.AddrReturn.Mode = sf.AddrStack.Mode = sf.AddrPC.Mode = sf.AddrFrame.Mode = ADDRESS_MODE.AddrModeFlat; * * if(!API.StackWalk64(MachineType.i386, th.OwnerProcess.Handle, th.Handle, ref sf, ref th.Context.lastReadCtxt)) * throw new Win32Exception(Marshal.GetLastWin32Error()); */ th.CurrentInstruction = targetSiteAddress; bp.Disable(); bp.temporarilyDisabled = true; CodeStepping.lastUnhandledBreakpoint = bp; CodeStepping.lastUnhandledBreakpointThread = th; bp.WasHit(); foreach (var l in DDebugger.EventListeners) { l.OnBreakpoint(th, bp); } } else if (code == ExceptionCode.SingleStep) { if (CodeStepping.lastUnhandledBreakpoint != null) { CodeStepping.postBreakpointResetStepCompleted = true; } else { foreach (var l in DDebugger.EventListeners) { l.OnStepComplete(th); } } } else { var ex = new DebugException(e.ExceptionRecord, e.dwFirstChance != 0); foreach (var l in DDebugger.EventListeners) { l.OnException(th, ex); } LastException = ex; } }
internal bool RemThread(DebugThread th) { return threads.Remove(th); }
public DebugThreadContext(DebugThread thread) { this.Thread = thread; }