Example #1
0
        /// <summary>
        /// This is the main debug loop, which is called as a single thread that attaches to the target process, using
        /// debugging privileges.
        /// </summary>
        private void DebugLoop()
        {
            WinApi.DEBUG_EVENT de = new WinApi.DEBUG_EVENT();
            WinApi.DbgCode continueStatus = WinApi.DbgCode.CONTINUE;
            bool isFirstInstBreakpointSet = false;

            while (this.Proc.HasExited == false && this.allowedToDebug == true)
            {
                if (!isFirstInstBreakpointSet && this.pauseOnFirstInst)
                {
                    try
                    {
                        // Attempt to set a breakpoint at the main module's entry point.
                        this.SetSoftBP(this.Proc.MainModule.EntryPointAddress);
                        isFirstInstBreakpointSet = true;
                    }
                    catch (NullReferenceException)
                    {
                        // Let the .NET Framework calm down and then continue once its feathers are unruffled.
                        continue;
                    }
                    catch (System.ComponentModel.Win32Exception e)
                    {
                        if (e.NativeErrorCode == 299)
                        {
                            // Catch and ignore the partial ReadProcessMemory/WriteProcessMemory exception.
                        }
                        else
                        {
                            // Otherwise, log the exception message.
                            this.Status.Log("Unhandled win32 exception: " + e.Message, Logger.Level.HIGH);
                        }
                    }
                }

                if (!WinApi.WaitForDebugEvent(ref de, this.DebugEventTimeout))
                {
                    continue;
                }

                this.IsBusy = true;
                bool pauseDebugger = false;
                bool isFirstBreakpointPass = false;

                switch (de.dwDebugEventCode)
                {
                    case (uint)WinApi.DebugEventType.EXCEPTION_DEBUG_EVENT:
                        // Only ignore first chance exceptions after the first breakpoint has been hit.
                        if (this.InitialBreakpointHit)
                        {
                            if (this.IgnoreFirstChanceExceptions && de.Exception.dwFirstChance != 0)
                            {
                                continueStatus = WinApi.DbgCode.EXCEPTION_NOT_HANDLED;
                                break;
                            }
                        }

                        switch (de.Exception.ExceptionRecord.ExceptionCode)
                        {
                            case (uint)WinApi.ExceptionType.STATUS_WX86_SINGLE_STEP:
                            case (uint)WinApi.ExceptionType.SINGLE_STEP:
                                continueStatus = this.OnSingleStepDebugException(ref de);
                                if (this.Settings.PauseOnSingleStep || this.stepOverOperationInProgress)
                                {
                                    pauseDebugger = true;
                                    this.stepOverOperationInProgress = false;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.ACCESS_VIOLATION:
                                continueStatus = this.OnAccessViolationDebugException(ref de);
                                if (this.Settings.PauseOnAccessViolation)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.ARRAY_BOUNDS_EXCEEDED:
                                continueStatus = this.OnArrayBoundsExceededDebugException(ref de);
                                if (this.Settings.PauseOnArrayBoundsExceeded)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.STATUS_WX86_BREAKPOINT:
                            case (uint)WinApi.ExceptionType.BREAKPOINT:
                                bool initialBreakpointStart = this.InitialBreakpointHit;
                                continueStatus = this.OnBreakpointDebugException(ref de);
                                bool initialBreakpointEnd = this.InitialBreakpointHit;
                                if (initialBreakpointStart != initialBreakpointEnd)
                                {
                                    isFirstBreakpointPass = true;
                                }

                                if (this.Settings.PauseOnBreakpoint)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.DATATYPE_MISALIGNMENT:
                                continueStatus = this.OnDatatypeMisalignmentDebugException(ref de);
                                if (this.Settings.PauseOnDatatypeMisalignment)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_DENORMAL_OPERAND:
                                continueStatus = this.OnFltDenormalOperandDebugException(ref de);
                                if (this.Settings.PauseOnFltDenormalOperand)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_DIVIDE_BY_ZERO:
                                continueStatus = this.OnFltDivideByZeroDebugException(ref de);
                                if (this.Settings.PauseOnFltDivideByZero)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_INEXACT_RESULT:
                                continueStatus = this.OnFltInexactResultDebugException(ref de);
                                if (this.Settings.PauseOnFltInexactResult)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_INVALID_OPERATION:
                                continueStatus = this.OnFltInvalidOperationDebugException(ref de);
                                if (this.Settings.PauseOnFltInvalidOperation)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_OVERFLOW:
                                continueStatus = this.OnFltOverflowDebugException(ref de);
                                if (this.Settings.PauseOnFltOverflow)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_STACK_CHECK:
                                continueStatus = this.OnFltStackCheckDebugException(ref de);
                                if (this.Settings.PauseOnFltStackCheck)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.FLT_UNDERFLOW:
                                continueStatus = this.OnFltUnderflowDebugException(ref de);
                                if (this.Settings.PauseOnFltUnderflow)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.GUARD_PAGE:
                                continueStatus = this.OnGuardPageDebugException(ref de);
                                if (this.Settings.PauseOnGuardPage)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.ILLEGAL_INSTRUCTION:
                                continueStatus = this.OnIllegalInstructionDebugException(ref de);
                                if (this.Settings.PauseOnIllegalInstruction)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.IN_PAGE_ERROR:
                                continueStatus = this.OnInPageErrorDebugException(ref de);
                                if (this.Settings.PauseOnInPageError)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.INT_DIVIDE_BY_ZERO:
                                continueStatus = this.OnIntDivideByZeroDebugException(ref de);
                                if (this.Settings.PauseOnIntDivideByZero)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.INT_OVERFLOW:
                                continueStatus = this.OnIntOverflowDebugException(ref de);
                                if (this.Settings.PauseOnIntOVerflow)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.INVALID_DISPOSITION:
                                continueStatus = this.OnInvalidDispositionDebugException(ref de);
                                if (this.Settings.PauseOnInvalidDisposition)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.NONCONTINUABLE_EXCEPTION:
                                continueStatus = this.OnNoncontinuableExceptionDebugException(ref de);
                                if (this.Settings.PauseOnNoncontinuableException)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.PRIV_INSTRUCTION:
                                continueStatus = this.OnPrivInstructionDebugException(ref de);
                                if (this.Settings.PauseOnPrivInstruction)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            case (uint)WinApi.ExceptionType.STACK_OVERFLOW:
                                continueStatus = this.OnStackOverflowDebugException(ref de);
                                if (this.Settings.PauseOnStackOverflow)
                                {
                                    pauseDebugger = true;
                                }

                                break;

                            default:
                                continueStatus = this.OnUnhandledDebugException(ref de);
                                if (this.Settings.PauseOnUnhandledDebugException)
                                {
                                    pauseDebugger = true;
                                }

                                break;
                        }

                        // Only break on second exceptions once the first breakpoint has been encountered.
                        if (this.PauseOnSecondChanceException && !isFirstBreakpointPass)
                        {
                            pauseDebugger = true;
                        }

                        break;

                    case (uint)WinApi.DebugEventType.CREATE_THREAD_DEBUG_EVENT:
                        continueStatus = this.OnCreateThreadDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.CREATE_PROCESS_DEBUG_EVENT:
                        this.debugThreadInitSuccess = true;
                        this.debugThreadInitComplete = true;
                        continueStatus = this.OnCreateProcessDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.EXIT_THREAD_DEBUG_EVENT:
                        if (this.stepOverOperationInProgress)
                        {
                            this.stepOverOperationInProgress = false;
                        }

                        continueStatus = this.OnExitThreadDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.EXIT_PROCESS_DEBUG_EVENT:
                        continueStatus = this.OnExitProcessDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.LOAD_DLL_DEBUG_EVENT:
                        continueStatus = this.OnLoadDllDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.UNLOAD_DLL_DEBUG_EVENT:
                        continueStatus = this.OnUnloadDllDebugEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.OUTPUT_DEBUG_STRING_EVENT:
                        continueStatus = this.OnOutputDebugStringEvent(ref de);
                        break;

                    case (uint)WinApi.DebugEventType.RIP_EVENT:
                        continueStatus = this.OnRipEvent(ref de);
                        break;

                    default:
                        continueStatus = WinApi.DbgCode.EXCEPTION_NOT_HANDLED;
                        break;
                }

                if (pauseDebugger)
                {
                    // Reset the target state information.
                    this.ts.Reset();

                    // Get the thread context.
                    IntPtr threadHandle;
                    WinApi.CONTEXT context = new WinApi.CONTEXT();
                    this.BeginEditThread(de.dwThreadId, out threadHandle, out context);

                    // Save the thread state information.
                    this.ts.ThreadId = de.dwThreadId;
                    this.ts.ThreadHandle = threadHandle;
                    this.ts.Context = context;
                    this.ts.IsReady = true;

                    // Pause the debugger and target.
                    this.pauseDebuggerLock.Reset();
                    this.IsDebuggingPaused = true;
                    this.IsBusy = false;
                    this.pauseDebuggerLock.WaitOne();

                    // Save any changes that have been made to the thread context.
                    threadHandle = this.ts.ThreadHandle;
                    context = this.ts.Context;
                    this.EndEditThread(this.ts.ThreadId, ref threadHandle, ref context);

                    // Flag the debugger as unpaused.
                    this.IsDebuggingPaused = false;

                    // Delete any target state information.
                    this.ts.Reset();
                }

                this.IsBusy = false;
                WinApi.ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continueStatus);
            }

            this.debugThreadInitComplete = true;

            if (!WinApi.DebugActiveProcessStop((uint)this.PID))
            {
                this.Status.Log("Failed to stop debugging. Error: " + Marshal.GetLastWin32Error());
            }

            this.threadMayExit = true;
            return;
        }
Example #2
0
        /// <summary>
        /// Starts the main debug loop, optionally creating a process from the supplied file path.
        /// </summary>
        /// <param name="arguments">An optional set of arguments that dictate how an executable is debugged.</param>
        private void StartDebugLoop(object arguments = null)
        {
            string filePath;
            string parameters;
            if (arguments == null)
            {
                filePath = string.Empty;
                parameters = string.Empty;
            }
            else if (arguments is DebugLoopArguments)
            {
                DebugLoopArguments dla = (DebugLoopArguments)arguments;
                filePath = dla.FilePath;
                parameters = dla.Parameters;
            }
            else
            {
                filePath = string.Empty;
                parameters = string.Empty;
            }

            if (arguments == null)
            {
                if (!this.IsOpen)
                {
                    return;
                }

                if (!WinApi.DebugActiveProcess((uint)this.PID))
                {
#if DEBUG
                    this.Status.Log("Cannot debug. Error: " + Marshal.GetLastWin32Error(), Logger.Level.HIGH);
#endif
                    return;
                }
                else if (!WinApi.DebugSetProcessKillOnExit(false))
                {
#if DEBUG
                    this.Status.Log("Cannot exit cleanly in the future.", Logger.Level.MEDIUM);
#endif
                }
                else
                {
                    this.allowedToDebug = true;
                    this.threadMayExit = false;
                }

                WinApi.ThreadAccess thread_rights =
                    WinApi.ThreadAccess.SET_CONTEXT | WinApi.ThreadAccess.GET_CONTEXT | WinApi.ThreadAccess.SUSPEND_RESUME;
                IntPtr threadHandle = WinApi.OpenThread(thread_rights, false, (uint)this.ThreadID);
                WinApi.CONTEXT cx = new WinApi.CONTEXT();
                cx.ContextFlags = WinApi.CONTEXT_FLAGS.DEBUG_REGISTERS;
                WinApi.GetThreadContext(threadHandle, ref cx);
                cx.ContextFlags = WinApi.CONTEXT_FLAGS.DEBUG_REGISTERS;
                cx.Dr7 =
                    (uint)(Debugger.DRegSettings.reg0w | Debugger.DRegSettings.reg0len4 | Debugger.DRegSettings.reg0set);
                bool stc = WinApi.SetThreadContext(threadHandle, ref cx);
                WinApi.CloseHandle(threadHandle);
                this.SetDebuggerArchitecture();
                this.DebugLoop();
                return;
            }
            else
            {
                if (!SysInteractor.IsInitialized)
                {
                    SysInteractor.Init();
                }

                bool res = false;
                string application = filePath;
                string commandLine = string.Empty;
                if (!string.IsNullOrEmpty(parameters))
                {
                    commandLine = '"' + filePath + "\" " + parameters;
                }

                WinApi.PROCESS_INFORMATION procInfo = new WinApi.PROCESS_INFORMATION();
                WinApi.STARTUPINFO startupInfo = new WinApi.STARTUPINFO();
                WinApi.SECURITY_ATTRIBUTES processSecurity = new WinApi.SECURITY_ATTRIBUTES();
                WinApi.SECURITY_ATTRIBUTES threadSecurity = new WinApi.SECURITY_ATTRIBUTES();
                processSecurity.nLength = Marshal.SizeOf(processSecurity);
                threadSecurity.nLength = Marshal.SizeOf(threadSecurity);

                // Open the process.
                res = WinApi.CreateProcess(
                    application,
                    commandLine,
                    ref processSecurity,
                    ref threadSecurity,
                    false,
                    (uint)WinApi.ProcessCreationFlags.DEBUG_PROCESS,
                    IntPtr.Zero,
                    null,
                    ref startupInfo,
                    out procInfo);
                if (!res)
                {
                    return;
                }

                this.ProcHandle = procInfo.hProcess;
                if (this.ProcHandle != null)
                {
                    try
                    {
                        this.Proc = System.Diagnostics.Process.GetProcessById(procInfo.dwProcessId);
                    }
                    catch (ArgumentException)
                    {
                        WinApi.CloseHandle(this.ProcHandle);
                        return;
                    }

                    if (!WinApi.DebugSetProcessKillOnExit(false))
                    {
#if DEBUG
                        this.Status.Log("Cannot exit cleanly in the future.", Logger.Level.MEDIUM);
#endif
                    }
                    else
                    {
                        this.allowedToDebug = true;
                        this.threadMayExit = false;
                    }

                    this.SetDebuggerArchitecture();
                    this.DebugLoop();

                    return;
                }

                this.Status.Log("Unable to open the target process.", Logger.Level.HIGH);
            }
        }
Example #3
-1
        /// <summary>
        /// Suspend the thread and prepare the thread context to be modified.
        /// </summary>
        /// <param name="threadId">The ID of the thread to be modified.</param>
        /// <param name="threadHandle">A handle of the thread to be modified.</param>
        /// <param name="cx">The context of the thread to be modified.</param>
        protected void BeginEditThread(uint threadId, out IntPtr threadHandle, out WinApi.CONTEXT cx)
        {
            WinApi.ThreadAccess threadRights =
                WinApi.ThreadAccess.SET_CONTEXT |
                WinApi.ThreadAccess.GET_CONTEXT |
                WinApi.ThreadAccess.SUSPEND_RESUME;
            threadHandle = WinApi.OpenThread(threadRights, false, threadId);
            if (threadHandle == null || threadHandle.Equals(IntPtr.Zero))
            {
                string msg =
                    "Unable to obtain a thread handle for TID: " + threadId + ". Error: " +
                    Marshal.GetLastWin32Error();
                WinApi.CloseHandle(threadHandle);
                throw new InvalidOperationException(msg);
            }

            uint result = WinApi.SuspendThread(threadHandle);
            unchecked
            {
                if (result == (uint)(-1))
                {
                    string msg =
                        "Unable to suspend thread, TID: " + threadId + ". Error: " + Marshal.GetLastWin32Error();
                    WinApi.CloseHandle(threadHandle);
                    throw new InvalidOperationException(msg);
                }
            }

            WinApi.CONTEXT context = new WinApi.CONTEXT();
            context.ContextFlags = WinApi.CONTEXT_FLAGS.FULL;
            if (!WinApi.GetThreadContext(threadHandle, ref context))
            {
                string msg =
                    "Unable to get thread context, TID: " + threadId + ". Error: " + Marshal.GetLastWin32Error();
                WinApi.CloseHandle(threadHandle);
                throw new InvalidOperationException(msg);
            }

            cx = context;
        }