public void StartProcessAndWaitForDebugger(IEnumerable <String> args) { STARTUPINFO si = new STARTUPINFO(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); // disable the hook so won't call ourselves recursively ImageFileExecutionWrapper.SetupHook(imagePath, false); var sargs = String.Join(" ", args); sargs = String.Join(" ", "\"" + imagePath + "\"", sargs); bool success = NativeMethods.CreateProcess(null, sargs, IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED, IntPtr.Zero, null, ref si, out pi); // enable the hook again ImageFileExecutionWrapper.SetupHook(imagePath, true); if (!success) { throw new Win32Exception(); } var hthread = pi.hThread; var failuresCnt = 0; var isDebuggerPresent = false; while (!isDebuggerPresent) { if (failuresCnt > 3) { Trace.Write("Too many failures while waiting for the debugger to appear - I give up."); break; } if (!NativeMethods.CheckRemoteDebuggerPresent(pi.hProcess, ref isDebuggerPresent)) { failuresCnt++; continue; } Thread.Sleep(1000); // sleep for 1s before the next check } // resume the process thread NativeMethods.ResumeThread(hthread); }
static void Main(string[] args) { var result = CommandLine.Parser.Default.ParseArguments <Options>(args); if (result.Errors.Any()) { return; } if (!IsUserAdmin()) { Console.WriteLine("You need to be an administrator to use this application."); return; } if (result.Value.ShouldInstall && result.Value.ShouldUninstall) { Console.WriteLine("You need to decide whether you would like to install or uninstall a hook."); return; } if (result.Value.ListHooks) { ImageFileExecutionWrapper.ListHooks(); return; } if (result.Value.Timeout > 0) { SetServiceTimeout(result.Value.Timeout); } else { if (GetServiceTimeout() < 60000) { // service will be killed if it does not respond under 1 min. Console.WriteLine("Warning: current ServicePipeTimeout is set under 1 min - this time might not be enough " + "to attach with the debugger to the service and start debugging it. It's highly recommended to set this " + "value to at least 4 min (you may use -timeout option for this purpose)"); } } var svcpath = result.Value.ServiceExePath; if (svcpath == null) { Console.WriteLine("A path to the service exe file must be provided."); return; } if (result.Value.ShouldInstall) { ImageFileExecutionWrapper.SetupHook(svcpath, true); } else if (result.Value.ShouldUninstall) { ImageFileExecutionWrapper.SetupHook(svcpath, false); } else { // here the logic will be a bit more complicated - we will start the process // as suspended and then wait for the debugger to appear var s = new Suspender(svcpath); s.StartProcessAndWaitForDebugger(result.Value.ServiceArgs); } }