Exemple #1
0
        public static void MemMain(Process process, ImportResolver ir, bool setPageExecuteReadWrite = false)
        {
            // getting minimum & maximum address

            SystemInfo sysInfo;

            GetSystemInfo(out sysInfo);

            var procMinAddress = sysInfo.minimumApplicationAddress;
            var procMaxAddress = sysInfo.maximumApplicationAddress;

            // saving the values as long ints so I won't have to do a lot of casts later
            var procMinAddressL = (ulong)procMinAddress;
            var procMaxAddressL = (ulong)procMaxAddress;

            // opening the process with desired access level
            // IntPtr processHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryRead, false, process.Id);
            var processHandle = OpenProcess(ProcessAccessFlags.All, false, process.Id);

            if ((ulong)processHandle == 0)
            {
                throw new Win32Exception();
            }

            var sw = new StreamWriter(Specifics.RawRegionsDumpFileName);

            // this will store any information we get from VirtualQueryEx()

            var   bytesRead      = new IntPtr(0); // number of bytes read with ReadProcessMemory
            ulong totalBytesRead = 0;

            // expect 4 gig
            var progressTotal = new BigInteger(1024 * 1024 * 1024);

            progressTotal *= 4;
            BigInteger lastProgress = 0;

            Console.WriteLine("start scanning");
            while (procMinAddressL < procMaxAddressL)
            {
                // 28 = sizeof(MEMORY_BASIC_INFORMATION)
                MemoryBasicInformation memBasicInfo;
                if (
                    (ulong)
                    VirtualQueryEx(processHandle, procMinAddress, out memBasicInfo,
                                   new IntPtr(Marshal.SizeOf(typeof(MemoryBasicInformation)))) == 0)
                {
                    throw new Win32Exception();
                }

                if (setPageExecuteReadWrite)
                {
                    AllocationProtectEnum oldProtection;
                    if (
                        !VirtualProtectEx(processHandle, memBasicInfo.BaseAddress,
                                          new UIntPtr((ulong)memBasicInfo.RegionSize),
                                          AllocationProtectEnum.PageExecuteReadwrite, out oldProtection))
                    {
                        //throw new Win32Exception();
                    }
                }

                var regionStartModule = ir.LookupAddress((ulong)memBasicInfo.BaseAddress);
                var regionEndModule   =
                    ir.LookupAddress((ulong)memBasicInfo.BaseAddress + (ulong)memBasicInfo.RegionSize);

                var isAccessible = memBasicInfo.Protect.HasFlag(AllocationProtectEnum.PageReadwrite) ||
                                   memBasicInfo.Protect.HasFlag(AllocationProtectEnum.PageExecuteReadwrite);

                if (isAccessible && memBasicInfo.State.HasFlag(StateEnum.MemCommit))
                {
                    var buffer = new byte[(ulong)memBasicInfo.RegionSize];

                    // read everything in the buffer above
                    var success = "";
                    if (
                        !ReadProcessMemory(processHandle, memBasicInfo.BaseAddress, buffer, memBasicInfo.RegionSize,
                                           ref bytesRead))
                    {
                        success = "false";
                    }
                    else
                    {
                        totalBytesRead += (ulong)bytesRead;
                    }

                    var regionStart = memBasicInfo.BaseAddress.ToString("X");
                    var regionEnd   = ((ulong)memBasicInfo.BaseAddress + (ulong)memBasicInfo.RegionSize).ToString("X");
                    sw.WriteLine(
                        $"region 0x{regionStart}({regionStartModule})-0x{regionEnd}({regionEndModule}): size {memBasicInfo.RegionSize}: {success}");
                    // then output this in the file

                    /*for (int i = 0; i < mem_basic_info.RegionSize; i++) {
                     *  //sw.WriteLine("0x{0} : {1}", (mem_basic_info.BaseAddress + i).ToString("X"), (char)buffer[i]);
                     * }*/
                }
                else
                {
                    var regionStart = memBasicInfo.BaseAddress.ToString("X");
                    var regionEnd   = ((ulong)memBasicInfo.BaseAddress + (ulong)memBasicInfo.RegionSize).ToString("X");
                    sw.WriteLine(
                        $"NOT READ region 0x{regionStart}({regionStartModule})-0x{regionEnd}({regionEndModule}): size {memBasicInfo.RegionSize}");
                }

                // move to the next memory chunk
                procMinAddressL += (ulong)memBasicInfo.RegionSize;
                procMinAddress   = new IntPtr((long)procMinAddressL);

                var progress = new BigInteger(totalBytesRead) * 100 / progressTotal;
                if (progress != lastProgress)
                {
                    Console.WriteLine($"scanning memory: estimated {progress}%, totalSize: ");
                }
                lastProgress = progress;
            }
            Console.WriteLine($"end scanning. total MB: {totalBytesRead/1024/1024}");

            sw.Close();
        }
Exemple #2
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
            });
        }
Exemple #3
0
        // see also StackWalk64, but I'm not sure I can use that, because I don't have a function table
        public static void LogStackTrace(ImportResolver ir, Logger log, Process process, ulong stackPointer)
        {
            int size    = 4096;
            var mem     = DebugProcessUtils.ReadBytes(process, stackPointer, 4096);
            var ptrSize = Marshal.SizeOf(typeof(IntPtr));

            for (var offset = 0; offset + ptrSize < size; offset += 1)
            {
                ulong ptr = (ulong)BitConverter.ToInt64(mem, offset);
                if (ptr == 0)
                {
                    continue;
                }
                Tuple <string, ulong> ret = null;
                try {
                    ret = ir.LookupAddress(ptr);
                }
                catch (Exception)
                {
                    // ignored
                }
                string module   = "lookup-failed";
                ulong  relative = 0;
                if (ret != null)
                {
                    module = ret.Item1;
                    var functionAddress = ret.Item2;
                    relative = ptr - functionAddress;
                }

                byte[] ptrMem = null;
                try {
                    ptrMem = DebugProcessUtils.ReadBytes(process, ptr, ptrSize);
                }
                catch (Exception)
                {
                    // ignored
                }
                ulong data = 0;
                if (ptrMem != null)
                {
                    data = (ulong)BitConverter.ToInt64(ptrMem, 0);
                }
                for (ulong potentialCallOffset = 0; potentialCallOffset <= 6; potentialCallOffset++)
                {
                    try {
                        var callLocation = ptr - potentialCallOffset;
                        var instr        = Disassemble(process, callLocation);
                        var asm          = FormatInstruction(instr);
                        if (instr.Mnemonic == ud_mnemonic_code.UD_Icall || potentialCallOffset == 0)
                        {
                            log.WriteLine($"stack call {offset}-{potentialCallOffset}: {module}+0x{relative:X} 0x{ptr:X}: asm 0x{data:X} {asm}");
                        }
                    } catch (Exception) {
                        if (potentialCallOffset == 0)
                        {
                            log.WriteLine($"stack trace {offset}-{potentialCallOffset}: {module}+0x{relative:X} 0x{ptr:X}: asm 0x{data:X} exception");
                        }
                    }
                }
            }
        }