private void ExecuteCommand(IDebugControl6 debugControl, string command, string comment = null) { debugControl.Execute(DEBUG_OUTCTL.ALL_CLIENTS, " ", DEBUG_EXECUTE.DEFAULT); // empty new line Echo(debugControl, $"now running command '{command}'" + (string.IsNullOrEmpty(comment) ? string.Empty : $" ({comment})")); Echo(debugControl, "======================================================================="); LogOnErrorHR(debugControl.Execute(DEBUG_OUTCTL.ALL_CLIENTS, command, DEBUG_EXECUTE.DEFAULT), $"failed to run '{command}'"); }
private static void LoadExtensions(IDebugControl6 debugControl) { LoadExtension(debugControl, @"ext.dll"); LoadExtension(debugControl, @"exts.dll"); LoadExtension(debugControl, @"uext.dll"); LoadExtension(debugControl, @"ntsdexts.dll"); }
private static ulong LoadExtension(IDebugControl6 debugControl, string path) { ulong handle; LogOnErrorHR(debugControl.AddExtension(path, 0, out handle), $"failed to load '{path}'"); return(handle); }
public WdbgExts(IDebugControl6 debugControl) { if (null == debugControl) { throw new ArgumentNullException("debugControl"); } m_debugControl = debugControl; } // end constructor
public static void ExecuteDbgEngCommand(this DataTarget target, string command, CommandExecutionContext context) { IDebugControl6 control = (IDebugControl6)target.DebuggerInterface; int hr = control.ExecuteWide( DEBUG_OUTCTL.THIS_CLIENT, command, DEBUG_EXECUTE.DEFAULT); if (HR.Failed(hr)) { context.WriteErrorLine("Command execution failed with hr = {0:x8}", hr); } }
/// <summary> /// Initializes a new instance of the <see cref="DebugEngineProxy" /> class. /// </summary> /// <param name="control">The control.</param> /// <param name="client">The client.</param> /// <param name="registers">The registers.</param> /// <param name="systemObjects">The system objects.</param> /// <param name="debugDataSpaces">The debug data spaces.</param> public DebugEngineProxy(IDebugControl6 control, IDebugClient5 client, IDebugRegisters2 registers, IDebugSystemObjects systemObjects, IDebugDataSpaces debugDataSpaces, IExecuteWrapper executeWrapper) { Control = control; Client = client; Registers = registers; Dataspaces = debugDataSpaces; ExecuteWrapper = executeWrapper; RegisterEngine = new RegisterEngine(); // todo: inject MemoryEngine = new MemoryEngine(); SystemObjects = systemObjects; Is32Bit = Regex.Match(ExecuteWrapper.Execute("!peb"), @"PEB at (?<peb>[a-fA-F0-9]+)").Groups["peb"].Value .Length == 8; }
private DebugClient(object client, TaskScheduler scheduler) { _scheduler = scheduler; Client = (IDebugClient5)client; Control = (IDebugControl6)client; DataSpaces = (IDebugDataSpaces4)client; SystemObjects = (IDebugSystemObjects2)client; Symbols = (IDebugSymbols5)client; Advanced = (IDebugAdvanced3)client; Client.SetEventCallbacksWide(this).ThrowIfFailed(); Client.SetOutputCallbacksWide(this).ThrowIfFailed(); Control.AddEngineOptions(DEBUG_ENGOPT.INITIAL_BREAK); }
internal static void INIT_API() { LastHR = HRESULT.S_OK; if (client == null) { try { client = (IDebugClient5)CreateIDebugClient(); control = (IDebugControl6)client; } catch { LastHR = HRESULT.E_UNEXPECTED; } } }
private static void LoadExtensions(IDebugControl6 debugControl) { if (Environment.Is64BitProcess) { LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\ext.dll"); // do we need this configurable? should we ship these? LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP\exts.dll"); LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP\uext.dll"); LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\WINXP\ntsdexts.dll"); } else { LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\winext\ext.dll"); // do we need this configurable? should we ship these? LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\WINXP\exts.dll"); LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\WINXP\uext.dll"); LoadExtension(debugControl, @"C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\WINXP\ntsdexts.dll"); } }
public void Attach() { Task.Run(() => { this.Client = DebugClient.DebugCreate(); IDebugClient7 client = this.Client as IDebugClient7; IDebugControl6 control = this.Client as IDebugControl6; client.SetOutputCallbacksWide(new OutputCallBacks()); client.SetEventCallbacksWide(new EventCallBacks(control)); this.Client.AttachProcess(0, unchecked ((UInt32)this.SystemProcess.Id), DebugAttach.InvasiveNoInitialBreak); while (true) { control.WaitForEvent(0, UInt32.MaxValue); } }); }
private void Analyze(IDebugControl6 debugControl, string logfilepath) { debugControl.OpenLogFile(logfilepath, false); try { LoadExtensions(debugControl); ExecuteCommand(debugControl, "|.", "status about process"); //ExecuteCommand(debugControl, ".loadby sos clr", "try to find sos"); // this will load sos.dll from the location of clr.dll. if symbol servers work correctly, this is not what we need ExecuteCommand(debugControl, ".cordll -ve -u -l", "verbose loading of mscordacwks"); ExecuteCommand(debugControl, ".chain", "list loaded debug-extensions"); ExecuteCommand(debugControl, "!eeversion"); // clr version ExecuteCommand(debugControl, "!threads"); ExecuteCommand(debugControl, "!tp", "threadpool info"); ExecuteCommand(debugControl, "lmf"); // list loaded .dlls ExecuteCommand(debugControl, ".exr -1"); // last exception ExecuteCommand(debugControl, "!analyze -v"); ExecuteCommand(debugControl, "~* k", "native stacks"); ExecuteCommand(debugControl, "~*e !clrstack", "managed stacks"); ExecuteCommand(debugControl, "x *!", "symbol paths"); // only shows symbols of modules that have been requested, so it's important to do this after listing stacks } finally { debugControl.CloseLogFile(); } }
/// <summary> /// Initializes the API. /// </summary> /// <param name="log">The log.</param> internal static void InitApi(ILog log = null) { LastHR = HRESULT.S_OK; if (client != null) { return; } try { log?.Debug("Client did not exist. Creating a new client and associated interfaces."); client = (IDebugClient5)CreateIDebugClient(); control = (IDebugControl6)client; registers = (IDebugRegisters2)client; symbols = (IDebugSymbols5)client; systemObjects = (IDebugSystemObjects)client; debugDataSpaces = (IDebugDataSpaces)client; } catch (Exception e) { log?.Fatal("Unable to create debug client. Are you missing DLLs?"); log?.Fatal(e); LastHR = HRESULT.E_UNEXPECTED; } }
} // end UpdateCmdlet() public int StartInput(uint BufferSize) { try { // TODO: powershell-ize Console.Write("StartInput( {0} )> ", BufferSize); string input = Console.ReadLine(); // TODO: should this be in the debugger class? IDebugControl6 dc6 = (IDebugControl6)m_cmdlet.Debugger.DebuggerInterface; int hresult = dc6.ReturnInputWide(input); // TODO: apparently it can return S_FALSE, meaning it "already // received the input", because it asks all clients for input. How // should I inform the user? if (hresult < 0) { Util.FailFast("ReturnInput failed", new Win32Exception(hresult)); } } catch (Exception e) { Util.FailFast("Unexpected exception in StartInput callback.", e); } return(0); }
private static void Echo(IDebugControl6 debugControl, string msg) { LogOnErrorHR(debugControl.Execute(DEBUG_OUTCTL.ALL_CLIENTS, $"$$ {msg}", DEBUG_EXECUTE.DEFAULT), $"failed to " + $"$$ {msg}"); }
public EventCallbacks(IDebugControl6 control) { _control = control; }
public static void Run(Process clProcess) { ProcessModuleCollection clProcessModules = clProcess.Modules; ///////////////////////////////// Guid guid = typeof(IDebugClient).GUID; // create debug client object //object obj; //CheckHr(Native.NativeMethods.DbgEng.DebugCreate(ref guid, out obj)); IntPtr pObj = IntPtr.Zero; CheckHr(Native.NativeMethods.DbgEng.DebugCreate(ref guid, ref pObj)); IDebugClient5Fixed client = (IDebugClient5Fixed)Marshal.GetTypedObjectForIUnknown(pObj, typeof(IDebugClient5Fixed)); IDebugDataSpaces4 dataSpaces = client as IDebugDataSpaces4; IDebugRegisters2Fixed registers = client as IDebugRegisters2Fixed; //IDebugClient5Fixed client = obj as IDebugClient5Fixed; IDebugControl6 control = client as IDebugControl6; var events = new EventCallbacks(control); client.SetEventCallbacksWide(events); client.SetOutputCallbacksWide(new OutputCallbacks()); Console.CancelKeyPress += (s, e) => { e.Cancel = true; //control.SetInterrupt(DEBUG_INTERRUPT.ACTIVE); }; CheckHr(client.AttachProcess(0, (uint)clProcess.Id, DEBUG_ATTACH.DEFAULT)); /////////// ProcessModule progModule = null; foreach (ProcessModule module in clProcessModules) { if (module.ModuleName == "prog.dll") { progModule = module; break; } } Console.WriteLine( $"Module: {progModule.ModuleName}\r\n" + $" BaseAddress: {progModule.BaseAddress.FormatAsHex()}\r\n" + $" EntryPointAddress: {progModule.EntryPointAddress.FormatAsHex()}\r\n" + $" ModuleMemorySize: 0x{progModule.ModuleMemorySize:X8}\r\n" + $""); //callbackProvider = new UnmanagedCodeSupplier((PickUpWeaponDelegate)ttExecutionCallback, IntPtr.Size == sizeof(int) ? x86CodeForFastcallWrapperForExecutionDelegate : x64CodeForFastcallWrapperForExecutionDelegate, IntPtr.Size == sizeof(int) ? new UIntPtr(0xF0F0F0F0) : new UIntPtr(0xF0F0F0F0F0F0F0F0)); //byte[] progMemory = new byte[progModule.ModuleMemorySize]; //return; //////// CheckHr(control.WaitForEvent(DEBUG_WAIT.DEFAULT, 5000)); byte[] progMemory = new byte[progModule.ModuleMemorySize]; uint readMemoryBytes; ulong validbase; uint validsize; CheckHr(dataSpaces.GetValidRegionVirtual((ulong)progModule.BaseAddress, (uint)progMemory.Length, out validbase, out validsize)); //Console.WriteLine($"Read {readMemoryBytes} bytes"); byte[] pickUpWeaponSignature; byte[] wildcard; ParseSearchPattern( "55 8B EC 83 E4 F8 80 3D A9 0F ?? 0F 00 56 57 8B F2 8B F9 75 23 80 3D 9A 0E ?? 0F 00 75 1A 56 E8 9C 94 F9 FF 83 FE 0F 75 0F 83 F8 32 7C 0A B9 D4", out pickUpWeaponSignature, out wildcard ); //wildcard[3] = 1; ulong matchOffset; CheckHr(dataSpaces.ReadVirtualUncached((ulong)progModule.BaseAddress, progMemory, (uint)progMemory.Length, out readMemoryBytes)); fixed(void *progMemoryPtr = progMemory, pickUpWeaponSignaturePtr = pickUpWeaponSignature, wildcardPtr = wildcard) { //pickUpWeaponAddress = (IntPtr) IndexOfUnchecked(progMemoryPtr, progMemory.Length, pickUpWeaponSignaturePtr, pickUpWeaponSignature.Length, wildcardPtr); int pickUpWeaponAddressOffset = IndexOfUnchecked(progMemoryPtr, progMemory.Length, pickUpWeaponSignaturePtr, pickUpWeaponSignature.Length, wildcardPtr); Console.WriteLine($"PickUpWeapon offset: 0x{pickUpWeaponAddressOffset:X8}"); if (pickUpWeaponAddressOffset == -1) { throw new Exception("Pattern not found!"); } pickUpWeaponAddress = new IntPtr(pickUpWeaponAddressOffset + (int)progModule.BaseAddress); } //dataSpaces.SearchVirtual((ulong) progModule.BaseAddress, (ulong) progModule.ModuleMemorySize, pickUpWeaponSignature, (uint) pickUpWeaponSignature.Length, 1, out matchOffset); //pickUpWeaponAddress = (IntPtr) matchOffset; Console.WriteLine($"PickUpWeapon address: {pickUpWeaponAddress.FormatAsHex()}"); control.AddBreakpoint2(DEBUG_BREAKPOINT_TYPE.CODE, uint.MaxValue, out pickUpWeaponBreakpoint); pickUpWeaponBreakpoint.SetOffset((ulong)pickUpWeaponAddress); pickUpWeaponBreakpoint.SetFlags(DEBUG_BREAKPOINT_FLAG.ENABLED); pickUpWeaponBreakpoint.SetCommandWide(".echo WEAPON PICKUP!"); // fixed (void* progMemoryPtr = progMemory, pickUpWeaponSignaturePtr = pickUpWeaponSignature) { // int pickUpWeaponAddressOffset = // IndexOfUnchecked(progMemoryPtr, progMemory.Length, pickUpWeaponSignaturePtr, pickUpWeaponSignature.Length); // Console.WriteLine($"PickUpWeapon offset: 0x{pickUpWeaponAddressOffset:X8}"); // if (pickUpWeaponAddressOffset == -1) // throw new Exception("Pattern not found!"); // // pickUpWeaponAddress = new IntPtr(pickUpWeaponAddressOffset + (int) progModule.BaseAddress); // Console.WriteLine($"PickUpWeapon address: {pickUpWeaponAddress.FormatAsHex()}"); // } control.SetExecutionStatus(DEBUG_STATUS.GO); File.WriteAllBytes("dump.bin", progMemory); DEBUG_STATUS status; int hr; while (true) { CheckHr(control.GetExecutionStatus(out status)); if (status == DEBUG_STATUS.NO_DEBUGGEE) { Console.WriteLine("No Target"); break; } if (status == DEBUG_STATUS.GO || status == DEBUG_STATUS.STEP_BRANCH || status == DEBUG_STATUS.STEP_INTO || status == DEBUG_STATUS.STEP_OVER) { hr = control.WaitForEvent(DEBUG_WAIT.DEFAULT, uint.MaxValue); continue; } if (events.StateChanged) { Console.WriteLine(); events.StateChanged = false; if (events.BreakpointHit) { control.OutputCurrentState(DEBUG_OUTCTL.THIS_CLIENT, DEBUG_CURRENT.DEFAULT); events.BreakpointHit = false; } } control.OutputPromptWide(DEBUG_OUTCTL.THIS_CLIENT, null); Console.Write(" "); Console.ForegroundColor = ConsoleColor.Gray; string command = Console.ReadLine(); if (command == ".detach") { client.DetachCurrentProcess(); } else { control.ExecuteWide(DEBUG_OUTCTL.THIS_CLIENT, command, DEBUG_EXECUTE.DEFAULT); } } }
public EventCallBacks(IDebugControl6 control) { this.Control = control; }