Beispiel #1
0
        public void ClearEvents() {
            // const uint DBG_EXCEPTION_NOT_HANDLED = 0x80010001;
            // const uint EXCEPTION_SINGLE_STEP = 0x80000004;
            const int dbgContinue = 0x00010002; // Seems to work better than DBG_EXCEPTION_NOT_HANDLED

            while (true) {
                Win32Imports.DebugEvent evt;
                if (!Win32Imports.WaitForDebugEvent(out evt, 0)) {
                    break;
                }
                CurrentInfo.EventCount++;
                Win32Imports.ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, dbgContinue);//DBG_EXCEPTION_NOT_HANDLED);
            }
        }
Beispiel #2
0
        public bool ResumeBreak(bool trace = true) {
            //Console.WriteLine("ResumeBreak");
            //for (var i = 0; i < 10000; i++) {
            var done = false;
            var goNextBreakPoint = false;
            var continueCode = Win32Imports.DbgContinue;
            while (!done)
            {
                Win32Imports.DebugEvent evt;
                if (!Win32Imports.WaitForDebugEvent(out evt, 0)) {
                //if (!handleDebugEvent(out evt, out continueCode)) {
                        //Console.WriteLine("WaitForDebugEvent failed");
                        //throw new Win32Exception();
                        done = true;
                }
                else {
                    CurrentInfo.EventCount++;

                    // Multiple if's for easier debugging at this moment
                    switch (evt.dwDebugEventCode) {
                        case Win32Imports.DebugEventType.LoadDllDebugEvent:
                            //Console.WriteLine($"resumed load dll event: {evt.dwThreadId}");
                            break;
                        case Win32Imports.DebugEventType.UnloadDllDebugEvent:
                            //Console.WriteLine($"resumed unload dll event: {evt.dwThreadId}");
                            break;
                        case Win32Imports.DebugEventType.ExceptionDebugEvent:
                            var exceptionAddress = (ulong) evt.Exception.ExceptionRecord.ExceptionAddress.ToInt64(); 

                            //Console.WriteLine($"first addr: {breakAddress:X} vs {address:X}");
                            var context = new Win32Imports.ContextX64();
                            var breakAddress = getRip((uint) evt.dwThreadId, ref context, GetRipAction.ActionGetContext);
                            var code = evt.Exception.ExceptionRecord.ExceptionCode;
                            //Console.WriteLine($"code: {code}, events: {eventCount}, thread: {evt.dwThreadId}, addr: {breakAddress2:X} vs {address:X}");

                            if (BreakPoints.ContainsKey(breakAddress) && BreakPoints[breakAddress].IsActive) {
                                LoggerInstance.WriteLine($"match at {breakAddress:X}, trace: {trace}");

                                setTrace((uint)evt.dwThreadId);
                                UninstallBreakPoint(breakAddress);
                                _lastBreakAddress = breakAddress;

                                CurrentInfo.LastContext = context;
                                CurrentInfo.LastContextReady = true;
                                // trace
                                //setTrace((uint) evt.dwThreadId, false);
                                if (BreakPoints[breakAddress].Description.Equals(CloseHandleDescription)) {
                                    LoggerInstance.WriteLine("CloseHandle hit");
                                    LoggerInstance.WriteLine("Registers:" + AssemblyUtil.FormatContext(context));
                                } else {
                                }
                                done = BreakPointCallBack(this, evt.dwThreadId, context, trace).StepOver;
                                goNextBreakPoint = done;
                                //} else if (!CheckBreakPointActive()) {
                            }
                            else {
                                // if we have seen it before
                                var shouldTrace = !BreakPoints.ContainsKey(breakAddress) ||
                                    !(BreakPoints.ContainsKey(breakAddress) && !BreakPoints[breakAddress].ShouldEnable) ||
                                    !(BreakPoints.ContainsKey(breakAddress) && !BreakPoints[breakAddress].IsActive);
                                // no breakpoint active, so we are tracing
                                if (trace && shouldTrace) {
                                    LoggerInstance.WriteLine($"tracing thread {evt.dwThreadId} at 0x{breakAddress:X}");
                                    var ret = BreakPointCallBack(this, evt.dwThreadId, context, true);
                                    done = ret.StepOver;
                                    goNextBreakPoint = done;
                                    if (ret.Ignore) {
                                        LoggerInstance.WriteLine("continuing with exception handlers");
                                        continueCode = Win32Imports.DbgExceptionNotHandled;
                                    }
                                }
                                else {
                                    LoggerInstance.WriteLine("continuing with exception handlers");
                                    continueCode = Win32Imports.DbgExceptionNotHandled;
                                }
                            }

                            Instruction instr = null;
                            string asm = "N/A";
                            string asm2 = "N/A";
                            try {
                                instr = AssemblyUtil.Disassemble(CurrentProcess, exceptionAddress);
                                asm = AssemblyUtil.FormatInstruction(AssemblyUtil.Disassemble(CurrentProcess, breakAddress));
                                asm2 = AssemblyUtil.FormatInstruction(AssemblyUtil.Disassemble(CurrentProcess, exceptionAddress));
                            }
                            catch (Exception)
                            {
                                // ignored
                            }

                            string msg;

                            switch (code) {
                                case Win32Imports.ExceptionCodeStatus.ExceptionSingleStep:
                                    asm = AssemblyUtil.FormatInstruction(AssemblyUtil.Disassemble(CurrentProcess, breakAddress));
                                    LoggerInstance.WriteLine($"single step at {breakAddress:X}, evtCount: {CurrentInfo.EventCount}, asm: {asm}");
                                    continueCode = HasBreakPoint(breakAddress) ? Win32Imports.DbgContinue : Win32Imports.DbgExceptionNotHandled;
                                    break;
                                case Win32Imports.ExceptionCodeStatus.ExceptionBreakpoint:        
                                    asm = AssemblyUtil.FormatInstruction(instr);
                                    //if (instr.Mnemonic.Equals("INT") && instr.Operands.Equals("3")) {
                                    if (instr != null && instr.Mnemonic == ud_mnemonic_code.UD_Iint3) {
                                        LoggerInstance.WriteLine($"int3 breakpoint at: {exceptionAddress:X}, evtCount: {CurrentInfo.EventCount}, asm: {asm}");
                                        LoggerInstance.WriteLine("overwriting with NOP");
                                        DebugProcessUtils.WriteByte(CurrentProcess, exceptionAddress, AssemblyUtil.Nop);
                                        continueCode = Win32Imports.DbgContinue;
                                    } else {
                                        msg = $"breakpoint, chance: { evt.Exception.dwFirstChance}";
                                        msg += $", at: 0x{breakAddress:X}, exc at: 0x{exceptionAddress:X}, asm: {asm}, exc asm: {asm2}";
                                        LoggerInstance.WriteLine(msg);
                                    }
                                    break;
                                case Win32Imports.ExceptionCodeStatus.ExceptionInvalidHandle:
                                    msg = $"invalid handle, chance: { evt.Exception.dwFirstChance}";
                                    msg += $", at: 0x{breakAddress:X}, exc at: 0x{exceptionAddress:X}, asm: {asm}, exc asm: {asm2}";
                                    LoggerInstance.WriteLine(msg);
                                    LoggerInstance.WriteLine(msg);
                                    AssemblyUtil.LogStackTrace(_importResolver, LoggerInstance, CurrentProcess, context.Rsp);
                                    continueCode = Win32Imports.DbgExceptionNotHandled;
                                    break;
                                case Win32Imports.ExceptionCodeStatus.ExceptionInvalidOperation:
                                    msg = $"invalid operation, chance: { evt.Exception.dwFirstChance}";
                                    msg += $", at: 0x{breakAddress:X}, exc at: 0x{exceptionAddress:X}, asm: {asm}, exc asm: {asm2}";
                                    // anti-anti-debug measure
                                    if (instr != null && instr.Mnemonic == ud_mnemonic_code.UD_Iud2) {
                                        LoggerInstance.WriteLine("overwriting UD2 with NOP");
                                        DebugProcessUtils.WriteBytes(CurrentProcess, exceptionAddress, new[] { AssemblyUtil.Nop, AssemblyUtil.Nop });
                                    }
                                    // anti-anti-debug measure
                                    var instr2 = AssemblyUtil.Disassemble(CurrentProcess, exceptionAddress - 1);
                                    if (instr2.Mnemonic == ud_mnemonic_code.UD_Iint && instr2.Operands[0].Value == 0x2D) {
                                        ulong rip = context.Rip - 1;
                                        setRip((uint) evt.dwThreadId, false, rip);
                                        LoggerInstance.WriteLine("INT2D encountered, subtracting 1 from Rip");
                                        continueCode = Win32Imports.DbgContinue;
                                    } else {
                                        continueCode = Win32Imports.DbgExceptionNotHandled;
                                    }
                                    LoggerInstance.WriteLine(msg);                                    
                                    break;
                                case Win32Imports.ExceptionCodeStatus.ExceptionAccessViolation:
                                    msg = $"access violation: {code:X}, chance: { evt.Exception.dwFirstChance}";
                                    msg += $", at: 0x{breakAddress:X}, exc at: 0x{exceptionAddress:X}, asm: {asm}, exc asm: {asm2}";
                                    LoggerInstance.WriteLine(msg);
                                    break;
                                case 0:
                                    LoggerInstance.WriteLine($"event 0 at: {breakAddress:X}");
                                    break;
                                default:
                                    msg = $"unknown code: {code:X}, chance: { evt.Exception.dwFirstChance}";
                                    msg += $", at: 0x{breakAddress:X}, exc at: 0x{exceptionAddress:X}, asm: {asm}, exc asm: {asm2}";
                                    LoggerInstance.WriteLine(msg);
                                    break;
                            }
                            break;
                        case Win32Imports.DebugEventType.CreateProcessDebugEvent:
                            //Console.WriteLine($"resumed create process event for thread {evt.dwThreadId}");
                            break;
                        case Win32Imports.DebugEventType.CreateThreadDebugEvent:
                            //Console.WriteLine($"resumed create thread event for thread {evt.dwThreadId}");
                            break;
                        case Win32Imports.DebugEventType.ExitThreadDebugEvent:
                            //Console.WriteLine($"resumed exit thread event for thread {evt.dwThreadId}");
                            break;
                        case Win32Imports.DebugEventType.ExitProcessDebugEvent:
                            Console.WriteLine($"resumed exit process event for thread {evt.dwThreadId}");
                            break;
                        default:
                            Console.WriteLine($"resumed debug event for thread: {evt.dwThreadId} {evt.dwDebugEventCode}");
                            break;
                    }

                    
                    //LoggerInstance.WriteLine($"debug event of type {evt.dwDebugEventCode}");

                    if (!Win32Imports.ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, continueCode)) {
                        throw new Win32Exception();
                    }
                    //ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
                    //setBreakPoint((uint) evt.dwThreadId, address, false);
                }
            }

            //Console.WriteLine("End ResumeBreak");
            //return events;
            return goNextBreakPoint;
        }
Beispiel #3
0
        public static void TraceIt(Process process, ulong patchSite, Logger logger, bool debug, Action <Process, ulong, Logger> installTracer)
        {
            if (debug)
            {
                if (!Win32Imports.DebugActiveProcess(process.Id))
                {
                    throw new Win32Exception();
                }

                if (!Win32Imports.DebugSetProcessKillOnExit(false))
                {
                    throw new Win32Exception();
                }
            }
            foreach (ProcessThread thread in process.Threads)
            {
                var threadId = thread.Id;
                var context  = new Win32Imports.ContextX64();
                ContextManager.getRip((uint)threadId, ref context, ContextManager.GetRipAction.ActionSuspend);
            }

            Console.WriteLine("installing tracer");
            installTracer(process, patchSite, logger);

            var mainThread = 0;

            foreach (ProcessThread thread in process.Threads)
            {
                var threadId     = thread.Id;
                var context      = new Win32Imports.ContextX64();
                var breakAddress = ContextManager.getRip((uint)threadId, ref context, ContextManager.GetRipAction.ActionGetContext);
                var diff         = new BigInteger(breakAddress) - new BigInteger(patchSite);
                diff = diff < 0 ? -diff : diff;
                if (diff < 1000)
                {
                    mainThread = threadId;
                    logger.WriteLine($"thread {threadId} setting Rip to patch site: {patchSite:X}");
                    ContextManager.setRip((uint)threadId, false, patchSite);
                    if (debug)
                    {
                        ContextManager.setTrace((uint)threadId, false);
                    }
                }
                ContextManager.getRip((uint)threadId, ref context, ContextManager.GetRipAction.ActionResume);
            }

            /*if (!Win32Imports.DebugBreakProcess(process.Id)) {
             *  throw new Win32Exception();
             * }*/

            if (debug)
            {
                Dictionary <int, OldState> oldThreadState = new Dictionary <int, OldState>();
                try {
                    while (true)
                    {
                        Win32Imports.DebugEvent evt;
                        if (Win32Imports.WaitForDebugEvent(out evt, -1))
                        {
                            Console.WriteLine($"debug event {evt.dwDebugEventCode}");
                            var continueCode = Win32Imports.DbgContinue;
                            if (evt.dwDebugEventCode == Win32Imports.DebugEventType.ExceptionDebugEvent && evt.dwThreadId == mainThread)
                            {
                                var exceptionAddress = (ulong)evt.Exception.ExceptionRecord.ExceptionAddress.ToInt64();
                                var context          = new Win32Imports.ContextX64();
                                var breakAddress     = ContextManager.getRip((uint)evt.dwThreadId, ref context, ContextManager.GetRipAction.ActionGetContext);
                                var code             = evt.Exception.ExceptionRecord.ExceptionCode;
                                Console.WriteLine($"thread {evt.dwThreadId} break at 0x{exceptionAddress:X} code {code}, 0x{breakAddress:X}");
                                ContextManager.setTrace((uint)evt.dwThreadId);

                                var instr      = AssemblyUtil.Disassemble(process, exceptionAddress);
                                var asm        = AssemblyUtil.FormatInstruction(instr);
                                var strContext = oldThreadState.ContainsKey(evt.dwThreadId) ?
                                                 AssemblyUtil.FormatContextDiff(context, oldThreadState[evt.dwThreadId].Context, oldThreadState[evt.dwThreadId].Instruction) :
                                                 AssemblyUtil.FormatContext(context);
                                logger.WriteLine($"thread {evt.dwThreadId} break at 0x{exceptionAddress:X}, 0x{breakAddress:X} code {code}: {asm}, regs-1: {strContext}");

                                oldThreadState[evt.dwThreadId] = new OldState {
                                    Context     = context,
                                    Instruction = instr
                                };

                                if (code == Win32Imports.ExceptionCodeStatus.ExceptionAccessViolation)
                                {
                                    continueCode = Win32Imports.DbgExceptionNotHandled;
                                }
                            }

                            if (!Win32Imports.ContinueDebugEvent(evt.dwProcessId, evt.dwThreadId, continueCode))
                            {
                                throw new Win32Exception();
                            }
                        }
                    }
                }
                finally {
                    if (!Win32Imports.DebugActiveProcessStop(process.Id))
                    {
                        throw new Win32Exception();
                    }
                }
            }
        }