Пример #1
0
        public static string FormatContextReflection(Win32Imports.ContextX64 context)
        {
            var registers = "";

            foreach (var field in typeof(Win32Imports.ContextX64).GetFields(BindingFlags.Instance |
                                                                            BindingFlags.NonPublic |
                                                                            BindingFlags.Public))
            {
                var    reg = field.Name.ToUpper();
                string value;
                try {
                    value = field.GetValue(context).ToString();
                }
                catch {
                    value = "?";
                }
                ulong n;
                if (UInt64.TryParse(value, out n))
                {
                    value      = FormatValue(UInt64.Parse(value));
                    registers += $" {reg}={value}";
                }
            }
            return(registers);
        }
Пример #2
0
        public static string FormatContextDiffReflection(Win32Imports.ContextX64 context, Win32Imports.ContextX64 oldContext, DecodedInst oldInstruction)
        {
            var registers = "";

            // log only changed registers and operands
            foreach (var field in typeof(Win32Imports.ContextX64).GetFields(BindingFlags.Instance |
                                                                            BindingFlags.NonPublic |
                                                                            BindingFlags.Public))
            {
                // log registers that changed
                var reg = field.Name.ToUpper();
                if (reg.Equals("RIP"))
                {
                    continue;
                }
                string oldValue;
                try {
                    oldValue = field.GetValue(oldContext).ToString();
                } catch {
                    oldValue = "?";
                }
                string value;
                try {
                    value = field.GetValue(context).ToString();
                } catch {
                    value = "?";
                }
                if (!oldValue.Equals(value))
                {
                    oldValue   = FormatValue(UInt64.Parse(oldValue));
                    value      = FormatValue(UInt64.Parse(value));
                    registers += $" {reg}={oldValue}->{value}";
                }
                else
                {
                    // log operand registers
                    var ops   = oldInstruction.Operands;
                    var reg32 = Regex.Replace(reg, "^R", "E");
                    var reg16 = Regex.Replace(reg, "^R", "");
                    int n;
                    if (ops.Contains(reg) || ops.Contains(reg32) || (!Int32.TryParse(reg16, out n) && ops.Contains(reg16)))
                    {
                        value      = FormatValue(UInt64.Parse(value));
                        registers += $" {reg}={value}";
                    }
                }
            }
            return(registers);
        }
Пример #3
0
        public List<ThreadData> GetContexts() {

            // Attach to the process we provided the thread as an argument
#if RestartEachTime
#if UseDebugger
            if (!Win32Imports.DebugActiveProcess(CurrentProcess.Id)) {
                throw new Win32Exception();
            }

            if (!Win32Imports.DebugSetProcessKillOnExit(false)) {
                throw new Win32Exception();
            }
#endif
#endif

            var retval = new List<ThreadData>();

            //CONTEXT_X64 context = new CONTEXT_X64();
            Win32Imports.ContextX64 context = new Win32Imports.ContextX64();

            foreach (ProcessThread thread in CurrentProcess.Threads) {
                uint iThreadId = (uint)thread.Id;

                getRip(iThreadId, ref context, GetRipAction.ActionGetContext);
                //Console.WriteLine($"Rip: {Rip}");
                retval.Add(new ThreadData() {
                    ThreadId = iThreadId,
                    Rip = context.Rip
                });

                //Console.WriteLine($"thread id: {iThreadId}");
                //Console.WriteLine($"RIP: {context.Rip}");
            }

#if RestartEachTime
#if UseDebugger
            if (!Win32Imports.DebugActiveProcessStop(CurrentProcess.Id))
            {
                throw new Win32Exception();
            }
#endif
#endif
            return retval;
        }
Пример #4
0
        // returns true if new breakpoint was set
        public TraceReturn Log(ContextManager cm, Logger logFile, Process process, int threadId, Win32Imports.ContextX64 context, bool trace)
        {
            if (!trace)
            {
                // end trace
                return(new TraceReturn {
                    StepOver = false
                });
            }
            // http://stackoverflow.com/questions/14698350/x86-64-asm-maximum-bytes-for-an-instruction

            var breakAddress = context.Rip;

            var mem      = DebugProcessUtils.ReadBytes(process, breakAddress, AssemblyUtil.MaxInstructionBytes);
            var distance = (long)(breakAddress - cm.LastBreakAddress);

            var decodedInstruction = AssemblyUtil.Disassemble(process, breakAddress);
            var hex = DebugProcessUtils.BytesToHex(mem.Take(decodedInstruction.Length).ToArray());

            var moduleAddressTuple = _importResolver.LookupAddress(breakAddress);
            var module             = moduleAddressTuple.Item1;
            var relativeAddress    = breakAddress - moduleAddressTuple.Item2;

            var hitCounts =
                _oldState.ContainsKey(threadId) ?
                _oldState[threadId].HitCounts :
                new Dictionary <ulong, ulong>();

            var stackDepth = 0;

            if (_oldState.ContainsKey(threadId))
            {
                stackDepth = _oldState[threadId].StackDepth;
            }
            if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Icall)
            {
                stackDepth++;
            }
            else if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Iret)
            {
                stackDepth--;
            }

            if (breakAddress == _importResolver.ResolveRelativeAddress(Specifics.StartAddress))
            {
                // reset trace state when we hit first breakpoint
                // except for oldHitCounts, which will be added back at end of function
                _oldState.Remove(threadId);
            }
            else if (breakAddress != cm.LastBreakAddress)
            {
#if UseDebugger
                // we're not interested in logging threads where breakpoint was not found
                if (!_oldState.ContainsKey(threadId))
                {
                    logFile.WriteLine($"ignoring trace for thread {threadId}");
                    return(new TraceReturn {
                        Ignore = true,
                        StepOver = false
                    });
                }
#endif
            }

            // IMPORTANT: continues the trace
            var   retVal = false;
            ulong lastCallAddressInTraceModule =
                _oldState.ContainsKey(threadId) ?
                _oldState[threadId].LastCallAddressInTraceModule :
                0;
            // clean up breakpoints as soon as they are hit
            cm.DisableBreakPointOnHit(breakAddress);
#if UseDebugger
            if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Icall && !module.Equals(Specifics.TraceModuleName))
            {
                // step over call
                var returnAddress = breakAddress + (ulong)decodedInstruction.Length;
                logFile.WriteLine($"installing return breakpoint at {returnAddress:X}");
                cm.EnableBreakPoint(returnAddress, new ContextManager.BreakPointInfo {
                    Description = "return breakpoint"
                });
                stackDepth--;     // since the RET will not be executed
                retVal = true;
            }
            else
            {
                if (module.Equals(Specifics.TraceModuleName))
                {
                    if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Iret)
                    {
                    }
                    else if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Ijmp)
                    {
                    }
                    else
                    {
                        var cAddress = breakAddress + (ulong)decodedInstruction.Length;
                        logFile.WriteLine($"setting continuation at 0x{cAddress:X} for {decodedInstruction.Mnemonic} of size {decodedInstruction.Length}");
                        cm.EnableBreakPoint(cAddress, new ContextManager.BreakPointInfo {
                            Description = $"for {decodedInstruction.Mnemonic} of size {(ulong) decodedInstruction.Length}"
                        });
                    }

                    /*foreach (var condJump in new string[] {
                     *  "JE", "JZ", "JNE", "JNZ", "JG", "JNLE", "JGE", "JNL", "JL", "JNGE",
                     *  "JLE", "JNG", "JA", "JNBE", "JAE", "JNB", "JB", "JNAE", "JBE", "JNA" }) {
                     *  if (decodedInstruction.Mnemonic.Equals(condJump)) {
                     *      var nextTarget = breakAddress + decodedInstruction.Size;
                     *      var jumpMatch = Regex.Match("0x([a-z0-9]+)", decodedInstruction.Operands);
                     *      if (jumpMatch.Success) {
                     *          var offset = ulong.Parse(jumpMatch.Groups[0].Value, System.Globalization.NumberStyles.AllowHexSpecifier);
                     *          var jumpTarget = (ulong) (new BigInteger(breakAddress) + (long) offset);
                     *          //logFile.WriteLine($"jump calc: offset: {(long) offset}, target: 0x{jumpTarget:X}");
                     *      }
                     *
                     *      //cm.continuationBreakAddress +=
                     *      break;
                     *  }
                     * }*/
                    if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Icall)
                    {
                        // step over instruction
                        lastCallAddressInTraceModule  = breakAddress;
                        lastCallAddressInTraceModule += (ulong)decodedInstruction.Length;
                    }
                    logFile.WriteLine($"setting next trace for {threadId}");
                    ContextManager.setTrace((uint)threadId);
                }
                else
                {
                    if (lastCallAddressInTraceModule == 0)
                    {
                        logFile.WriteLine("In external module, but no call to get back to.");
                    }
                    else if (!cm.BreakPoints.ContainsKey(lastCallAddressInTraceModule))
                    {
                        logFile.WriteLine($"In external module, returning to {lastCallAddressInTraceModule:X}");
                        cm.EnableBreakPoint(lastCallAddressInTraceModule, new ContextManager.BreakPointInfo {
                            Description = $"return from external module: {module}+{relativeAddress}"
                        });
                    }
                }
            }
#else
            throw new NotImplementedException();

            /*
             * cm.continuationBreakAddress = breakAddress;
             * //cm.continuationBreakAddress += decodedInstruction.Size;
             * if (decodedInstruction.Mnemonic.Equals("RET")) {
             *  var stackPointer = context.Rsp;
             *  if (!decodedInstruction.Operands.Equals("")) {
             *      var offset = ulong.Parse(decodedInstruction.Operands);
             *      stackPointer += offset;
             *  }
             *  ulong returnAddress = BitConverter.ToUInt64(DebugProcessUtils.ReadBytes(process, stackPointer, 8), 0);
             *  cm.continuationBreakAddress = returnAddress;
             * }*/
#endif

            if (hitCounts.ContainsKey(breakAddress))
            {
                hitCounts[breakAddress]++;
            }
            else
            {
                hitCounts[breakAddress] = 1;
            }

            var registers = _oldState.ContainsKey(threadId) ?
                            AssemblyUtil.FormatContextDiff(context, _oldState[threadId].Context, _oldState[threadId].SdInstruction) :
                            AssemblyUtil.FormatContext(context);
            //logFile.WriteLine(registers);
            var previous  = "";
            var lineBreak = false;
            if (_oldState.ContainsKey(threadId))
            {
                previous = _oldState[threadId].Line;
                if (_oldState[threadId].Instruction.Mnemonic == ud_mnemonic_code.UD_Iret ||
                    _oldState[threadId].Instruction.Mnemonic == ud_mnemonic_code.UD_Icall)
                {
                    lineBreak = true;
                }
            }
            var    asm     = $"{ decodedInstruction.Mnemonic } { decodedInstruction.Operands}";
            double logdist =
                distance == 0 ?
                0.0 :
                distance < 0 ?
                -Math.Log(-distance, 2) :
                Math.Log(distance, 2);

            var pattern = "";
            pattern += Regex.Escape("[");
            pattern += "(?<reg1>[A-Z0-9]{3})";
            pattern += "((?<sign1>[" + Regex.Escape("+") + Regex.Escape("-") + "])(?<reg2>[A-Z0-9]{3})(" + Regex.Escape("*") + "(?<multiplier>[0-9]+))?)?";
            pattern += "((?<sign2>[" + Regex.Escape("+") + Regex.Escape("-") + "])0x(?<offset>[0-9a-f]+))?";
            pattern += Regex.Escape("]");
            var rex = new Regex(pattern);
            // TODO: rewrite offset code to use SharpDisasm structure instead of string parsing
            var        operands   = decodedInstruction.Operands.ToString();
            var        match      = rex.Matches(operands);
            BigInteger memAddress = 0;
            if (match.Count > 0)
            {
                var  reg1             = match[0].Groups[rex.GroupNumberFromName("reg1")].Value;
                var  reg2             = match[0].Groups[rex.GroupNumberFromName("reg2")].Value;
                long sign1            = match[0].Groups[rex.GroupNumberFromName("sign1")].Value.Equals("+") ? 1 : -1;
                long sign2            = match[0].Groups[rex.GroupNumberFromName("sign2")].Value.Equals("+") ? 1 : -1;
                var  multiplierString = match[0].Groups[rex.GroupNumberFromName("multiplier")].Value;
                var  multiplier       = multiplierString.Equals("") ? 1 : long.Parse(multiplierString);

                var   offsetHex = match[0].Groups[rex.GroupNumberFromName("offset")].Value;
                var   reg1Value = (ulong)_fieldMap[reg1].GetValue(context);
                ulong reg2Value = 0;
                if (!reg2.Equals(""))
                {
                    reg2Value = (ulong)_fieldMap[reg2].GetValue(context);
                }
                var offset = offsetHex.Equals("") ? 0 : long.Parse(offsetHex, System.Globalization.NumberStyles.AllowHexSpecifier);
                memAddress = new BigInteger(reg1Value) + sign1 * new BigInteger(reg2Value) * multiplier + sign2 * new BigInteger(offset);
            }
            else if (decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Ipop || decodedInstruction.Mnemonic == ud_mnemonic_code.UD_Ipush)
            {
                memAddress = context.Rsp;
            }

            //var module = DebugProcessUtils.GetModuleByAddress(process, breakAddress);
            var oldLine          = $"d: {logdist,8:#.##}, thread: {threadId,6:D}, mem: {memAddress,16:X} ";
            var moduleAndAddress = $"{module}+0x{relativeAddress:X}:{breakAddress:X}";
            oldLine += $"instr: {hex,30},";
            var hits = hitCounts[breakAddress];
            oldLine += $" {moduleAndAddress,64}(h{hits,2})(s{stackDepth,2}): {asm,-40} ";
            logFile.WriteLine(previous + registers);
            if (lineBreak)
            {
                logFile.WriteLine("");
            }

            _oldState[threadId] = new State {
                Context     = context,
                Instruction = decodedInstruction,
                Line        = oldLine,
                HitCounts   = hitCounts,
                StackDepth  = stackDepth,
                LastCallAddressInTraceModule = lastCallAddressInTraceModule
            };

            return(new TraceReturn {
                StepOver = retVal
            });
        }
Пример #5
0
        // remember to set targetAddress before using this function
        public List<ThreadData> TestBreak() {

#if RestartEachTime
#if UseDebugger
            // Attach to the process we provided the thread as an argument
            if (!Win32Imports.DebugActiveProcess(CurrentProcess.Id)) {
                throw new Win32Exception();
            }

            if (!Win32Imports.DebugSetProcessKillOnExit(false)) {
                throw new Win32Exception();
            }
#endif
#endif

        var retval = new List<ThreadData>();
            var context = new Win32Imports.ContextX64();

            //Console.WriteLine("TestBreak");

            if (!CheckBreakPointActive()) {
                //Console.WriteLine("adding breakpoints: " + breakPoints.Keys.Count);

                foreach (var breakPoint in BreakPoints.Keys) {
                    var shouldEnable = BreakPoints[breakPoint].ShouldEnable;
                    //Console.WriteLine($"enumerating breakPoint: 0x{breakPoint}, shouldEnable: {shouldEnable}");
                    if (shouldEnable) {
                        var msg = BreakPoints[breakPoint].Description;
                        Console.WriteLine($"installing continuation breakpoint at {breakPoint:X}: {msg}");
                        LoggerInstance.WriteLine($"installing continuation breakpoint at {breakPoint:X}: {msg}");
                        /*
                        if (!Specifics.useDebugger) {
                            LoggerInstance.WriteLine("Suspending all threads");
                            foreach (ProcessThread thread2 in process.Threads) {
                                getRip((uint)thread2.Id, ref context, ACTION_SUSPEND);
                            }
                        }*/

                        try {
#if UseHardwareBreakPoints
                            foreach (ProcessThread thread in CurrentProcess.Threads) {
                                InstallHardwareBreakPoint((uint) thread.Id, breakPoint);
                            }
#else
                            InstallBreakPoint(breakPoint);
      
#endif
                        }
                        catch (Exception e) {
                            Console.WriteLine($"Exception: {e.Message}");
                            Console.WriteLine(e.StackTrace);
                            LoggerInstance.WriteLine($"Exception: {e.Message}");
                            LoggerInstance.WriteLine(e.StackTrace);
                        }
                    } else {
                        Console.WriteLine("stale breakpoint" + BreakPoints[breakPoint].Description);
                    }
                }
            }

            foreach (ProcessThread thread in CurrentProcess.Threads) {
                uint iThreadId = (uint)thread.Id;

#if UseDebugger
                var traceInterval = Specifics.TraceInterval;
                var waitInterval = Specifics.WaitInterval;

                var sw = new Stopwatch();
                sw.Start();
                // trace program. slows down program a lot
                var done = false;
                foreach (ProcessThread thread2 in CurrentProcess.Threads) {
                    //Console.WriteLine("reinstalling CloseHandle breakpoint");
                    InstallHardwareBreakPoint((uint)thread2.Id,
                        BreakPoints.First(kv => kv.Value.Description.Equals(CloseHandleDescription)).Key);
                }
                while (sw.ElapsedMilliseconds <= traceInterval) {
                    getRip(iThreadId, ref context, GetRipAction.ActionGetContext);
                    var breakAddress = context.Rip;
                    if (BreakPoints.ContainsKey(breakAddress) && BreakPoints[breakAddress].IsActive) {
                        LoggerInstance.WriteLine("setting initial trace");
                        setTrace(iThreadId);
                    }
                    if (ResumeBreak()) {
                        done = true;
                        break;
                    }
                }
                sw.Stop();
                if (!done) {
                    sw = new Stopwatch();
                    sw.Start();
                    // give program time to run without debugging
                    while (sw.ElapsedMilliseconds <= waitInterval) {
                        ResumeBreak(false);
                    }
                    sw.Stop();
                }
#else
                    var sw = new Stopwatch();
                    sw.Start();

                    //getRip(iThreadId, ref context, ACTION_RESUME);

                    while (sw.ElapsedMilliseconds <= Specifics.loopWaitInterval) {
                        foreach (ProcessThread thread2 in CurrentProcess.Threads) {
                            uint iThreadId2 = (uint)thread2.Id;

                            getRip(iThreadId2, ref context, ActionGetContext);

                            var breakAddress = context.Rip;

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

                                setTrace((uint)iThreadId2, true);
                                UninstallBreakPoint(breakAddress);
                                _lastBreakAddress = breakAddress;

                                CurrentInfo.LastContext = context;
                                CurrentInfo.LastContextReady = true;
                                // trace
                                BreakPointCallBack(this, (int)iThreadId2, context, true);
                            }
                        }
                    }

                    //getRip(iThreadId, ref context, ACTION_SUSPEND);

                    sw.Stop();
#endif

            // XXX: ONLY FIRST THREAD
            /*if (Specifics.useDebugger) {
                break;
            }*/
            break;
            }

            /*
            if (!Specifics.useDebugger) {
                foreach (var address in originalCode.Keys) {
                    if (activeBreakPoints[address]) {
                        RemoveBreakPoint(address);
                    }
                }

                if (!Specifics.useDebugger) {
                    LoggerInstance.WriteLine("Resuming all threads");
                    foreach (ProcessThread thread2 in process.Threads) {
                        getRip((uint)thread2.Id, ref context, ACTION_RESUME);
                    }
                }
            }*/

            //ResumeBreak(address);
            //Thread.Sleep(5000);

#if RestartEachTime
#if UseDebugger
            if (!Win32Imports.DebugActiveProcessStop(CurrentProcess.Id)) {
                throw new Win32Exception();
            }
#endif
#endif
            return retval;
        }
Пример #6
0
 public static extern ulong getRip(uint tHandle, ref Win32Imports.ContextX64 context, GetRipAction actions);
Пример #7
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;
        }
Пример #8
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();
                    }
                }
            }
        }