예제 #1
0
        public static void DumpDetected(Vtero vtero, DetectedProc p, long VAStart = 0, long VAEnd = 0xffffffff0000)
        {
            var mods = vtero.ModuleScan(p, VAStart, VAEnd);

            // BUGBUG: TODO: Refactor the threadlocal stuff seems were re-entrant unsafe :(
            //Parallel.ForEach(mods, (detected) =>
            //{
            foreach (var detected in mods)
            {
                var cv_data = vtero.ExtractCVDebug(p, detected.Value, detected.Key);

                if (cv_data != null)
                {
                    var sympath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH");
                    if (string.IsNullOrWhiteSpace(sympath))
                    {
                        sympath = "SRV*http://msdl.microsoft.com/download/symbols";
                    }

                    if (vtero.TryLoadSymbols(p, detected.Value, cv_data, detected.Key, sympath))
                    {
                        vtero.GetKernelDebuggerData(p, detected.Value, cv_data, sympath);
                    }
                }
            }
            //});
        }
예제 #2
0
        public static PageTable AddProcess(DetectedProc dp, Mem mem, bool RedundantKernelEntries = true, int DepthToGo = 4)
        {
            if(Vtero.DiagOutput)
                WriteLine($"PT analysis of {dp}");

            var rv = new PageTable
            {
                Root = new PageTableRoot() { SLAT = dp.vmcs != null ? dp.vmcs.EPTP : 0, CR3 = dp.CR3Value, Entries = new PFN() },
                Failed = new List<HARDWARE_ADDRESS_ENTRY>(),
                DP = dp,
                mem = mem
            };

            if (dp.MemAccess == null || mem != null)
                dp.MemAccess = mem;

            /* Commenting out this block so we defer the table enumeration
            // any output is error/warning output

            var cnt = rv.FillTable(RedundantKernelEntries, DepthToGo);
            rv.EntriesParsed += cnt;

            if (cnt == 0)
            {
                if (dp.vmcs != null)
                    WriteLine($"BAD EPTP/DirectoryTable Base {dp.vmcs.EPTP:X12}, try a different candidate or this dump may lack a hypervisor. Recommend attempt PT walk W/O SLAT");
                else
                    WriteLine($"Decoding failed for {dp.CR3Value:X12}");
                //WriteLine($"Physical walk w/o SLAT yielded {cnt} entries");
            }
            */
            dp.PT = rv;
            return rv;
        }
예제 #3
0
 public VirtualScanner(DetectedProc Ctx, Mem backingBlocks, bool DoHeaderScan = false) : this()
 {
     DPContext     = Ctx;
     BackingBlocks = backingBlocks;
     BackingStream = new PhysicalMemoryStream(backingBlocks, Ctx);
     HeaderScan    = DoHeaderScan;
 }
예제 #4
0
        public static void DumpDetected(Vtero vtero, DetectedProc p, long VAStart = 0, long VAEnd = 0xffffffff0000)
        {
            var mods = vtero.ModuleScan(p, 3, VAStart, VAEnd);

            //Parallel.ForEach(mods, (detected) =>
            //{
            foreach (var detected in p.Sections)
            {
                var cv_data = vtero.ExtractCVDebug(p, detected.Value);

                if (cv_data != null)
                {
                    var sympath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH");
                    if (string.IsNullOrWhiteSpace(sympath))
                    {
                        sympath = "SRV*http://msdl.microsoft.com/download/symbols";
                    }

                    // TODO: fix this or not?
                    //if(Vtero.TryLoadSymbols(p.ID.GetHashCode(), cv_data, detected.Key))
                    //    vtero.KernelProc = p;
                }
            }
            //});
        }
예제 #5
0
        public static PageTable AddProcess(DetectedProc dp, Mem mem)
        {
            long Address = 0;
            int AddressIndex = 0;

            // dump Page table high to low
            var va = new VIRTUAL_ADDRESS(long.MaxValue - 0xfff);

            var rv = new PageTable
            {
                Failed = new List<HARDWARE_ADDRESS_ENTRY>(),
                DP = dp,
                mem = mem
            };

            // TODO: encode VA's for self/recursive physical addr's
            if (dp.PageTableType == PTType.Windows)
            {
                Address = MagicNumbers.Windows_SelfAsVA;
                AddressIndex = MagicNumbers.Windows_SelfPtr;
            }

            // any output is error/warning output

            var cnt = rv.FillTable(new VIRTUAL_ADDRESS(Address), AddressIndex, dp.CR3Value);
            Debug.WriteLine($"extracted {cnt} PTE from process {dp.vmcs.EPTP:X16}:{dp.CR3Value:X16}");

            dp.PT = rv;
            return rv;
        }
예제 #6
0
        public int CompareTo(object obj)
        {
            int vi = 0;

            if (obj is DetectedProc)
            {
                DetectedProc dp = obj as DetectedProc;
                if (vmcs != null || dp.vmcs != null)
                {
                    if (vmcs == null && dp.vmcs == null)
                    {
                        return(FileOffset.CompareTo(dp.FileOffset));
                    }
                    else if (vmcs != null && dp.vmcs == null)
                    {
                        return(1);
                    }
                    else if (vmcs == null && dp.vmcs != null)
                    {
                        return(-1);
                    }
                    else
                    {
                        vi = vmcs.Offset.CompareTo(dp.vmcs.Offset);
                    }
                }
                return(vi + FileOffset.CompareTo(dp.FileOffset));
            }
            return(int.MinValue);
        }
예제 #7
0
        public Dumper(Vtero vtero, string outDir, DetectedProc dp, MemRangeArgs args)
        {
            Vtero = vtero;
            DP = dp;
            OutDir = outDir;

            SelectedRegions = args.Regions;
        }
예제 #8
0
        public VirtualScanner(DetectedProc Ctx, Mem backingBlocks) : this()
        {
            DPContext = Ctx;
            BackingBlocks = backingBlocks;
            BackingStream = new PhysicalMemoryStream(backingBlocks, Ctx);

            //mn ,n m,MemoryBank = new ConcurrentDictionary<int, Mem>();
            //for(int i=0; i< Environment.ProcessorCount; i++)
                //MemoryBank[i] = new Mem(BackingBlocks);
        }
예제 #9
0
        public VirtualScanner(DetectedProc Ctx, Mem backingBlocks) : this()
        {
            DPContext     = Ctx;
            BackingBlocks = backingBlocks;
            BackingStream = new PhysicalMemoryStream(backingBlocks, Ctx);

            //mn ,n m,MemoryBank = new ConcurrentDictionary<int, Mem>();
            //for(int i=0; i< Environment.ProcessorCount; i++)
            //MemoryBank[i] = new Mem(BackingBlocks);
        }
예제 #10
0
        /// <summary>
        /// Naturally the Generic checker is fairly chatty but at least you can use it
        /// to find unknowns, we could use some more tunable values here to help select the
        /// best match, I currently use the value with the lowest diff, which can be correct
        ///
        /// This will find a self pointer in the first memory run for a non-sparse memory dump.
        ///
        /// The calling code is expected to adjust offset around RUN gaps.
        ///
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Generic(int x, long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            //long bestShift = long.MaxValue, bestDiff = long.MaxValue;
            //var bestOffset = long.MaxValue;
            var i = 0x1ff;

            if (((block[x] & 0xff) == 0x63) || (block[x] & 0xfdf) == 0x847)
            {
                do
                {
                    if (((block[x + i] & 0xff) == 0x63 || (block[x + i] & 0xff) == 0x67))
                    {
                        // we disqualify entries that have these bits configured
                        // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                        //
                        if ((block[x + i] & 0x7FFF000000000480) == 0)
                        {
                            var shifted = (block[x + i] & 0xFFFFFFFFF000);

                            if (shifted == offset)
                            {
                                var diff = offset - shifted;
                                // BUGBUG: Need to K-Means this or something cluster values to help detection of processes in sparse format
                                // this could be better
                                var dp = new DetectedProc {
                                    CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.GENERIC, TrueOffset = TrueOffset
                                };
                                for (int p = 0; p < 0x200; p++)
                                {
                                    if (block[x + p] != 0)
                                    {
                                        dp.TopPageTablePage.Add(p, block[x + p]);
                                    }
                                }
                                DetectedProcesses.TryAdd(offset, dp);
                                if (Vtero.DiagOutput)
                                {
                                    WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                                }
                                Candidate = true;
                            }
                        }
                    }
                    i--;
                } while (i > 0xFF);
            }
            // maybe some kernels keep more than 1/2 system memory
            // wouldn't that be a bit greedy though!?
            return(Candidate);
        }
예제 #11
0
 public void Dispose(bool disposing)
 {
     if (!disposedValue && disposing)
     {
         if (mem != null)
         {
             ((IDisposable)mem).Dispose();
         }
         if (DP != null)
         {
             ((IDisposable)DP).Dispose();
         }
     }
     mem           = null;
     DP            = null;
     disposedValue = true;
 }
예제 #12
0
        public static PageTable AddProcess(DetectedProc dp, Mem mem, bool OnlyUserSpace = false)
        {
            long Address      = 0;
            int  AddressIndex = 0;

            // dump Page table high to low
            var va = new VIRTUAL_ADDRESS(long.MaxValue - 0xfff);

            var rv = new PageTable
            {
                Failed = new List <HARDWARE_ADDRESS_ENTRY>(),
                DP     = dp,
                mem    = mem
            };

            // TODO: encode VA's for self/recursive physical addr's
            if (dp.PageTableType == PTType.Windows)
            {
                Address      = MagicNumbers.Windows_SelfAsVA;
                AddressIndex = MagicNumbers.Windows_SelfPtr;
            }

            // any output is error/warning output

            var cnt = rv.FillTable(new VIRTUAL_ADDRESS(Address), AddressIndex, dp.CR3Value, OnlyUserSpace);

            if (cnt == 0)
            {
                if (dp.vmcs != null)
                {
                    WriteLine($"BAD EPTP/DirectoryTable Base {dp.vmcs.EPTP:X16}, try a different candidate or this dump may lack a hypervisor. Attempting PT walk W/O SLAT");
                }
                else
                {
                    WriteLine($"Decoding failed for {dp.CR3Value:X16}");
                }

                /*cnt = rv.FillTable(new VIRTUAL_ADDRESS(Address), AddressIndex, dp.CR3Value, OnlyUserSpace);
                 * WriteLine($"Physical walk w/o SLAT yielded {cnt} entries");*/
            }

            dp.PT = rv;
            return(rv);
        }
예제 #13
0
        public static PageTable AddProcess(DetectedProc dp, Mem mem, bool RedundantKernelEntries = true)
        {
            if (Vtero.DiagOutput)
            {
                WriteLine($"PT analysis of {dp}");
            }

            var rv = new PageTable
            {
                Root = new PageTableRoot()
                {
                    SLAT = dp.vmcs != null ? dp.vmcs.EPTP : 0, CR3 = dp.CR3Value, Entries = new PFN()
                },
                Failed = new List <HARDWARE_ADDRESS_ENTRY>(),
                DP     = dp,
                mem    = mem
            };

            if (dp.MemAccess == null || mem != null)
            {
                dp.MemAccess = mem;
            }

            /* Commenting out this block so we defer the table enumeration
             * // any output is error/warning output
             *
             * var cnt = rv.FillTable(RedundantKernelEntries, DepthToGo);
             * rv.EntriesParsed += cnt;
             *
             * if (cnt == 0)
             * {
             *  if (dp.vmcs != null)
             *      WriteLine($"BAD EPTP/DirectoryTable Base {dp.vmcs.EPTP:X12}, try a different candidate or this dump may lack a hypervisor. Recommend attempt PT walk W/O SLAT");
             *  else
             *      WriteLine($"Decoding failed for {dp.CR3Value:X12}");
             *  //WriteLine($"Physical walk w/o SLAT yielded {cnt} entries");
             * }
             */
            dp.PT = rv;
            return(rv);
        }
예제 #14
0
        /// <summary>
        /// In some deployments Hyper-V was found to use a configuration as such
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool HV(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[0x1fe] & 0xFFFFFFFFF000);
            var diff    = offset - shifted;

            // detect mode 2, 2 seems good for most purposes and is more portable
            // maybe 0x3 is sufficient
            if (shifted != 0 && ((block[0] & 0xfff) == 0x063) && ((block[0x1fe] & 0xff) == 0x63 || (block[0x1fe] & 0xff) == 0x67) && block[0x1ff] == 0)
            {
                // we disqualify entries that have these bits configured
                // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                //
                if (((ulong)block[0x1fe] & 0xFFFF000000000480) == 0)
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc {
                            CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.HyperV
                        };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                            {
                                dp.TopPageTablePage.Add(p, block[p]);
                            }
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                        {
                            WriteLine(dp.ToString());
                        }
                        Candidate = true;
                    }
                }
            }
            return(Candidate);
        }
예제 #15
0
        public static PageTable AddProcess(DetectedProc dp, Mem mem, bool OnlyUserSpace = false)
        {
            long Address = 0;
            int AddressIndex = 0;

            // dump Page table high to low
            var va = new VIRTUAL_ADDRESS(long.MaxValue - 0xfff);

            var rv = new PageTable
            {
                Failed = new List<HARDWARE_ADDRESS_ENTRY>(),
                DP = dp,
                mem = mem
            };

            // TODO: encode VA's for self/recursive physical addr's
            if (dp.PageTableType == PTType.Windows)
            {
                Address = MagicNumbers.Windows_SelfAsVA;
                AddressIndex = MagicNumbers.Windows_SelfPtr;
            }

            // any output is error/warning output

            var cnt = rv.FillTable(new VIRTUAL_ADDRESS(Address), AddressIndex, dp.CR3Value, OnlyUserSpace);

            if (cnt == 0)
            {
                if (dp.vmcs != null)
                    WriteLine($"BAD EPTP/DirectoryTable Base {dp.vmcs.EPTP:X16}, try a different candidate or this dump may lack a hypervisor. Attempting PT walk W/O SLAT");
                else
                    WriteLine($"Decoding failed for {dp.CR3Value:X16}");
                /*cnt = rv.FillTable(new VIRTUAL_ADDRESS(Address), AddressIndex, dp.CR3Value, OnlyUserSpace);
                WriteLine($"Physical walk w/o SLAT yielded {cnt} entries");*/
            }

            dp.PT = rv;
            return rv;
        }
예제 #16
0
        public static void DumpDetected(Vtero vtero, DetectedProc p, long VAStart = 0, long VAEnd = 0xffffffff0000)
        {
            var mods = vtero.ModuleScan(p, VAStart, VAEnd);

            //Parallel.ForEach(mods, (detected) =>
            //{
            foreach (var detected in p.Sections)
            {
                var cv_data = vtero.ExtractCVDebug(p, detected);

                if (cv_data != null)
                {
                    var sympath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH");
                    if (string.IsNullOrWhiteSpace(sympath))
                        sympath = "SRV*http://msdl.microsoft.com/download/symbols";

                    if(vtero.TryLoadSymbols(cv_data, detected.VA.Address, sympath))
                        vtero.KernelProc = p;
                }
            }
            //});
        }
예제 #17
0
        /// <summary>
        /// TODO: NetBSD needs some analysis
        /// Will add more later, this check is a bit noisy, consider it alpha
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool NetBSD(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[255] & 0xFFFFFFFFF000);
            var diff    = offset - shifted;


            if (((block[511] & 0xf3) == 0x63) && ((0x63 == (block[320] & 0xf3)) || (0x63 == (block[256] & 0xf3))))
            {
                if (((block[255] & 0xf3) == 0x63) && (0 == (block[255] & 0x7FFF000000000000)))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc {
                            CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.NetBSD
                        };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                            {
                                dp.TopPageTablePage.Add(p, block[p]);
                            }
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                        {
                            WriteLine(dp.ToString());
                        }
                        Candidate = true;
                    }
                }
            }
            return(Candidate);
        }
예제 #18
0
        /// <summary>
        /// The FreeBSD check for process detection is good
        /// Consider it release quality ;)
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool FreeBSD(int bo, long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[bo + 0x100] & 0xFFFFFFFFF000);
            var diff    = offset - shifted;

            if (((block[bo] & 0xff) == 0x67) && (0x67 == (block[bo + 0xff] & 0xff)))
            {
                if (((block[bo + 0x100] & 0xff) == 0x63) && (0 == (block[bo + 0x100] & 0x7FFF000000000000)))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc {
                            CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.FreeBSD, TrueOffset = TrueOffset
                        };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[bo + p] != 0)
                            {
                                dp.TopPageTablePage.Add(p, block[bo + p]);
                            }
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                        {
                            WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                        }
                        Candidate = true;
                    }
                }
            }
            return(Candidate);
        }
예제 #19
0
        /// <summary>
        /// The FreeBSD check for process detection is good
        /// Consider it release quality ;) 
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool FreeBSD(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[0x100] & 0xFFFFFFFFF000);
            var diff = offset - shifted;

            if (((block[0] & 0xff) == 0x67) && (0x67 == (block[0xff] & 0xff)))
            {
                if (((block[0x100] & 0xff) == 0x63) && (0 == (block[0x100] & 0x7FFF000000000000)))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.FreeBSD, TrueOffset = TrueOffset };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                                dp.TopPageTablePage.Add(p, block[p]);
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                            WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                        Candidate = true;
                    }
                }
            }
            return Candidate;
        }
예제 #20
0
        /// <summary>
        /// The LinuxS check is a single pass state preserving scanner
        /// 
        /// This was created using kernel 3.19 as a baseline.  More to follow.
        /// 
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool LinuxS(long offset)
        {
            var Candidate = false;
            var group = -1;

            // The main observation on kern319 is the given set below of must-have offsets that are identical and 0x7f8 which is unique per process
            // Next is the behavior that uses entries in 2 directions from top down and bottom up 
            // i.e. 0x7f0 0x0 are the next expected values.
            // All others would be unset in the top level / base page
            //
            // Kernel should have only the magnificent entries
            // memcmp 0 ranges 8-7f0, 800-880, 888-c88, c98-e88, e90-ea0, ea8-ff0
            // after first (likely kernel) page table found, use it's lower 1/2 to validate other detected page tables
            // Linux was found (so far) to have a consistent kernel view.
            var kern319 = new Dictionary<int, bool> { [0x7f8] = false, [0x880] = true, [0xc90] = true, [0xe88] = true, [0xea0] = true, [0xff0] = true, [0xff8] = true };

            var Profiles = new List<Dictionary<int, bool>>();

            if (((block[0xFF] & 0xfff) == 0x067) &&
               ((block[0x110] & 0xfff) == 0x067) &&
               ((block[0x192] & 0xfff) == 0x067) &&
               ((block[0x1d1] & 0xfff) == 0x067) &&
               ((block[0x1d4] & 0xfff) == 0x067) &&
               ((block[0x1fe] & 0xfff) == 0x067) &&
               ((block[0x1ff] & 0xfff) == 0x067) 

               // this is the largest block of 0's 
               // just do this one to qualify
               //IsZero(block, 8, 0xe0)
               )

            if (
                    /*IsZero(block, 8,     0xE0) &&
                IsZero(block, 0x100, 0x10) &&*/
                IsZero(block, 0x111, 0x80) &&
                IsZero(block, 0x193, 0x3e) &&
                IsZero(block, 0x1D2, 0x02) &&
                IsZero(block, 0x1D5, 0x29))
            {
                // before we catalog this entry, check to see if we can put it in a group
                for (int i = 0; i < LinuxSFirstPages.Count(); i++)
                    if (EqualBytesLongUnrolled(block, LinuxSFirstPages[i], 0x100))
                        group = i;

                // if we haven't found anything yet, setup first page
                if (LinuxSFirstPage == null)
                {
                    LinuxSFirstPage = block;
                    LinuxSFirstPages.Add(block);
                    group = 0;
                }

                // load DP 
                var dp = new DetectedProc { CR3Value = offset, FileOffset = offset, Diff = 0, Mode = 2, Group = group, PageTableType = PTType.LinuxS, TrueOffset = TrueOffset };
                    for (int p = 0; p < 0x200; p++)
                    if (block[p] != 0)
                        dp.TopPageTablePage.Add(p, block[p]);

                if (Vtero.VerboseOutput)
                    WriteColor(ConsoleColor.Cyan, dp.ToString());

                DetectedProcesses.TryAdd(offset, dp);
                Candidate = true;
            }
            return Candidate;
        }
예제 #21
0
 public PhysicalMemoryStream(Mem blockStorage, DetectedProc proc)
 {
     MemBlockStorage = blockStorage;
     Proc            = proc;
 }
예제 #22
0
 public PhysicalMemoryStream(Mem blockStorage, DetectedProc proc)
 {
     MemBlockStorage = blockStorage;
     Proc = proc;
 }
예제 #23
0
        // TODO: MOVE below to DetectedProc class

        public CODEVIEW_HEADER ExtractCVDebug(DetectedProc dp, MemSection sec)
        {
             uint SizeData=0, RawData=0, PointerToRawData=0;

            Extract Ext = sec.Module;
            long VA = sec.VA.Address;

            if (dp.MemAccess == null)
                dp.MemAccess = new Mem(MemAccess);

            var _va = VA + Ext.DebugDirPos;
            var block = dp.VGetBlock(_va);
            var TimeDate2 = BitConverter.ToUInt32(block, ((int) Ext.DebugDirPos & 0xfff) + 4);

            if(TimeDate2 != Ext.TimeStamp & Vtero.VerboseOutput)
            {
                WriteColor(ConsoleColor.Yellow, "Unable to lock on to CV data.");
                return null; 
            }

            if(Vtero.VerboseOutput)
                WriteColor(ConsoleColor.Green, $"Locked on to CV Debug info.  Time2 = {TimeDate2:X} Time1 = {Ext.TimeStamp:X}");

            var max_offset = (int)(_va & 0xfff) + 28;
            if (max_offset > 0x1000)
            {
                if (Vtero.VerboseOutput)
                    WriteColor(ConsoleColor.Yellow, "CV block seems too straddle into next block (too large)"); return null;
            }
            SizeData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 16);
            RawData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 20);
            PointerToRawData = BitConverter.ToUInt32(block, (int)(_va & 0xfff) + 24);

            _va = VA + RawData;

            var bytes = new byte[16];

            block = dp.VGetBlock(_va);

            // first 4 bytes
            var sig = block[((int)_va & 0xfff)];
            
            Array.ConstrainedCopy(block, (((int) _va & 0xfff) + 4), bytes, 0, 16);
            var gid = new Guid(bytes);

            // after GUID
            var age = block[((int)_va & 0xfff) + 20];

            // char* at end
            var str = Encoding.Default.GetString(block, (((int)_va & 0xfff) + 24), 32).Trim();

            if (Vtero.VerboseOutput)
            {
                WriteLine($"Size = {SizeData} \t Raw = {RawData} \t Pointer {PointerToRawData}");
                WriteLine($"Str {str} : GUID : {gid} : AGE {age}");
            }

            var cv = new CODEVIEW_HEADER { VSize = (int) Ext.SizeOfImage, TimeDateStamp = TimeDate2, byteGuid = bytes, Age = age, aGuid = gid, Sig = sig, PdbName = str };

            sec.DebugDetails = cv;

            return cv;
        }
예제 #24
0
        /// <summary>
        /// The LinuxS check is a single pass state preserving scanner
        ///
        /// This was created using kernel 3.19 as a baseline.  More to follow.
        ///
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool LinuxS(long offset)
        {
            var Candidate = false;
            var group     = -1;

            // The main observation on kern319 is the given set below of must-have offsets that are identical and 0x7f8 which is unique per process
            // Next is the behavior that uses entries in 2 directions from top down and bottom up
            // i.e. 0x7f0 0x0 are the next expected values.
            // All others would be unset in the top level / base page
            //
            // Kernel should have only the magnificent entries
            // memcmp 0 ranges 8-7f0, 800-880, 888-c88, c98-e88, e90-ea0, ea8-ff0
            // after first (likely kernel) page table found, use it's lower 1/2 to validate other detected page tables
            // Linux was found (so far) to have a consistent kernel view.
            var kern319 = new Dictionary <int, bool> {
                [0x7f8] = false, [0x880] = true, [0xc90] = true, [0xe88] = true, [0xea0] = true, [0xff0] = true, [0xff8] = true
            };

            var Profiles = new List <Dictionary <int, bool> >();

            if (((block[0xFF] & 0xfff) == 0x067) &&
                ((block[0x110] & 0xfff) == 0x067) &&
                ((block[0x192] & 0xfff) == 0x067) &&
                ((block[0x1d1] & 0xfff) == 0x067) &&
                ((block[0x1d4] & 0xfff) == 0x067) &&
                ((block[0x1fe] & 0xfff) == 0x067) &&
                ((block[0x1ff] & 0xfff) == 0x067) &&

                // this is the largest block of 0's
                // just do this one to qualify
                IsZero(block, 8, 0xe0)
                )

            /*
             * if (IsZero(block, 8,     0xE0) &&
             *  IsZero(block, 0x100, 0x10) &&
             *  IsZero(block, 0x111, 0x80) &&
             *  IsZero(block, 0x193, 0x3e) &&
             *  IsZero(block, 0x1D2, 0x02) &&
             *  IsZero(block, 0x1D5, 0x29))
             */
            {
                // before we catalog this entry, check to see if we can put it in a group
                for (int i = 0; i < LinuxSFirstPages.Count(); i++)
                {
                    if (EqualBytesLongUnrolled(block, LinuxSFirstPages[i], 0x100))
                    {
                        group = i;
                    }
                }

                // if we haven't found anything yet, setup first page
                if (LinuxSFirstPage == null)
                {
                    LinuxSFirstPage = block;
                    LinuxSFirstPages.Add(block);
                    group = 0;
                }

                // load DP
                var dp = new DetectedProc {
                    CR3Value = offset, FileOffset = offset, Diff = 0, Mode = 2, Group = group, PageTableType = PTType.LinuxS
                };
                for (int p = 0; p < 0x200; p++)
                {
                    if (block[p] != 0)
                    {
                        dp.TopPageTablePage.Add(p, block[p]);
                    }
                }

                if (Vtero.VerboseOutput)
                {
                    WriteLine(dp.ToString());
                }

                DetectedProcesses.TryAdd(offset, dp);
                Candidate = true;
            }
            return(Candidate);
        }
예제 #25
0
        /// <summary>
        /// This is the same check as the earlier process detection code from CSW and DefCon
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Windows(long offset)
        {
            var Candidate = false;

            // pre randomized kernel 10.16 anniversario edition
            const int SELF_PTR = 0x1ed;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[SELF_PTR] & 0xFFFFFFFFF000);
            var diff = offset - shifted;

            // detect mode 2, 2 seems good for most purposes and is more portable
            // maybe 0x3 is sufficient
            if (((block[0] & 0xfdf) == 0x847) && ((block[SELF_PTR] & 0xff) == 0x63 || (block[SELF_PTR] & 0xff) == 0x67))
            {
                // we disqualify entries that have these bits configured
                //111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                if ((block[0x1ed] & 0x7FFF000000000480) == 0)
                {
#if MODE_1
                    if (!SetDiff)
                    {
                        FirstDiff = diff;
                        SetDiff = true;
                    }
#endif
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.Windows, TrueOffset = TrueOffset };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                                dp.TopPageTablePage.Add(p, block[p]);
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                            WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                        Candidate = true;
                    }
                }
            }
            // mode 1 is implemented to hit on very few supported bits
            // developing a version close to this that will work for Linux
#region MODE 1 IS PRETTY LOOSE
#if MODE_1
            else
                /// detect MODE 1, we can probably get away with even just testing & 1, the valid bit
                //if (((block[0] & 3) == 3) && (block[0x1ed] & 3) == 3)		
                if ((block[0] & 1) == 1 && (block[0xf68 / 8] & 1) == 1)
            {
                // a possible kernel first PFN? should look somewhat valid... 
                if (!SetDiff)
                {
                    // I guess we could be attacked here too, the system kernel could be modified/hooked/bootkit enough 
                    // we'll see if we need to analyze this in the long run
                    // the idea of mode 1 is a very low bit-scan, but we also do not want to mess up FirstDiff
                    // these root entries are valid for all win64's for PTE/hyper/session space etc.
                    if ((block[0xf78 / 8] & 1) == 1 && (block[0xf80 / 8] & 1) == 1 && (block[0xff8 / 8] & 1) == 1 && (block[0xff0 / 8] == 0))
                    {
                        // W/O this we may see some false positives 
                        // however can remove if you feel aggressive
                        if (diff < FileSize && (offset > shifted ? (diff + shifted == offset) : (diff + offset == shifted)))
                        {
                            FirstDiff = diff;
                            SetDiff = true;
                        }
                    }
                }

                if (SetDiff &&
                    !(FirstDiff != diff) &&
                     (shifted < (FileSize + diff)
                     //|| shifted != 0
                     ))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 1, PageTableType = PTType.Windows };

                        DetectedProcesses.TryAdd(offset, dp);
                        WriteColor(dp);

                        Candidate = true;
                    }
                }
            }
#endif
#endregion
            return Candidate;
        }
예제 #26
0
        public long GetSymAddress(DetectedProc dp, string SymName)
        {
            var AddrName = SymName + "Address";
            if (dp.SymbolStore.ContainsKey(AddrName))
                return dp.SymbolStore[AddrName];

            DebugHelp.SYMBOL_INFO symInfo = new DebugHelp.SYMBOL_INFO();

            symInfo.SizeOfStruct = 0x58;
            symInfo.MaxNameLen = 1024;

            var rv = DebugHelp.SymFromName(hCurrentProcess, SymName, ref symInfo);
            if (!rv)
            {
                WriteColor(ConsoleColor.Red, $"GetSymValue: {new Win32Exception(Marshal.GetLastWin32Error()).Message }.");
                return MagicNumbers.BAD_VALUE_READ;
            }

            dp.SymbolStore.Add(AddrName, symInfo.Address);

            return symInfo.Address;
        }
예제 #27
0
        /// <summary>
        /// Only scanning for core kernel modules
        /// </summary>
        /// <param name="dp"></param>
        /// <param name="StartingVA"></param>
        /// <param name="EndingVA"></param>
        /// <returns>Array of modules</returns>
        public ConcurrentDictionary<long, Extract> ModuleScan(DetectedProc dp, long StartingVA = 0, long EndingVA = 0xFFFFFFFFF000)
        {
            if (dp.PT == null)
                PageTable.AddProcess(dp, new Mem(MemAccess));

            var cnt = dp.PT.FillPageQueue(true);

            KVS = new VirtualScanner(dp, new Mem(MemAccess));
            KVS.ScanMode = VAScanType.PE_FAST;

            if (VerboseLevel > 0)
            {
                WriteColor(ConsoleColor.Cyan, "Scanning VA for Kernel... ");
                ForegroundColor = ConsoleColor.Green;
            }

            Parallel.For(0, cnt, i =>
            {
                PFN range;

                var curr = cnt - dp.PT.PageQueue.Count();
                CursorLeft = 0;
                var done = (int)(Convert.ToDouble(curr) / Convert.ToDouble(cnt) * 100.0) + 0.5;

                if (VerboseLevel > 0)
                    Write($"{done} % done");

                if (dp.PT.PageQueue.TryDequeue(out range))
                    if (range.PTE.Valid)
                        KVS.Run(range.VA.Address, range.VA.Address + (range.PTE.LargePage ? (1024 * 1024 * 2) : 0x1000));
            });
            if (VerboseLevel > 0)
                WriteLine("Done comprehensive VA scan");

            foreach (var detected in KVS.Artifacts)
                dp.Sections.Add(new MemSection() { IsExec = true, Module = detected.Value, VA = new VIRTUAL_ADDRESS(detected.Key) });

            return KVS.Artifacts;
        }
예제 #28
0
 public void AddProcessPageTable(DetectedProc tdp, Mem memAxs)
 {
     PageTable.AddProcess(tdp, memAxs, true);
 }
예제 #29
0
 public VirtualScanner(DetectedProc Ctx, Mem backingBlocks) : this()
 {
     DPContext     = Ctx;
     BackingBlocks = backingBlocks;
     BackingStream = new PhysicalMemoryStream(backingBlocks, Ctx);
 }
예제 #30
0
        public void ReScanNextLevel(DetectedProc tdp, bool DisplayOutput = false)
        {
            bool validInput, ignoreSlat;
            int levels;
            do
            {
                WriteColor(ConsoleColor.White, "How many levels to process? (1-4)");
                var selection = ReadLine();
                validInput = int.TryParse(selection, out levels);
                if (!validInput)
                    WriteLine("invalid response.");

            } while (!validInput);

            do
            {
                WriteColor(ConsoleColor.White, "Ignore SLAT? (True|False)");
                var selection = ReadLine();
                validInput = bool.TryParse(selection, out ignoreSlat);
                if (!validInput)
                    WriteLine("invalid response.");

            } while (!validInput);

            if (ignoreSlat)
            {
                tdp.vmcs = null;
                tdp.PT.Root.SLAT = 0;
            }

            tdp.PT.FillTable(true, levels);
            if(DisplayOutput)
            {
                var MemRanges = tdp.PT.Root.Entries.SubTables.SelectMany(x => x.Value.SubTables).SelectMany(y => y.Value.SubTables).SelectMany(z => z.Value.SubTables).ToList();
                foreach (var mr in MemRanges)
                    WriteColor(ConsoleColor.Cyan, $" {mr.Key} {mr.Value.PTE}");
            }
        }
예제 #31
0
        /// <summary>
        /// Naturally the Generic checker is fairly chatty but at least you can use it
        /// to find unknowns, we could use some more tunable values here to help select the
        /// best match, I currently use the value with the lowest diff, which can be correct
        /// 
        /// This will find a self pointer in the first memory run for a non-sparse memory dump.
        ///
        /// The calling code is expected to adjust offset around RUN gaps.
        ///
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Generic(long offset)
        {
            var Candidate = false;
            //var offset = CurrWindowBase + CurrMapBase;
            //long bestShift = long.MaxValue, bestDiff = long.MaxValue;
            //var bestOffset = long.MaxValue;
            var i = 0x1ff;

            if (((block[0] & 0xff) == 0x63) || (block[0] & 0xfdf) == 0x847)
            {
                do
                {
                    if (((block[i] & 0xff) == 0x63 || (block[i] & 0xff) == 0x67))
                    {
                        // we disqualify entries that have these bits configured
                        // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                        // 
                        if ((block[i] & 0x7FFF000000000480) == 0)
                        {
                            var shifted = (block[i] & 0xFFFFFFFFF000);

                            if (shifted == offset)
                            {
                                var diff = offset - shifted;
                                // BUGBUG: Need to K-Means this or something cluster values to help detection of processes in sparse format
                                // this could be better 
                                var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.GENERIC, TrueOffset = TrueOffset };
                                for (int p = 0; p < 0x200; p++)
                                {
                                    if (block[p] != 0)
                                        dp.TopPageTablePage.Add(p, block[p]);
                                }
                                DetectedProcesses.TryAdd(offset, dp);
                                if (Vtero.VerboseOutput)
                                    WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                                Candidate = true;
                            }
                        }
                    }
                    i--;
                } while (i > 0xFF);
            }
            // maybe some kernels keep more than 1/2 system memory 
            // wouldn't that be a bit greedy though!?
            return Candidate;
        }
예제 #32
0
        /// <summary>
        /// This is the same check as the earlier process detection code from CSW and DefCon
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Windows(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[0x1ed] & 0xFFFFFFFFF000);
            var diff    = offset - shifted;

            // detect mode 2, 2 seems good for most purposes and is more portable
            // maybe 0x3 is sufficient
            if (((block[0] & 0xfdf) == 0x847) && ((block[0x1ed] & 0xff) == 0x63 || (block[0x1ed] & 0xff) == 0x67))
            {
                // we disqualify entries that have these bits configured
                //111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                if ((block[0x1ed] & 0x7FFF000000000480) == 0)
                {
#if MODE_1
                    if (!SetDiff)
                    {
                        FirstDiff = diff;
                        SetDiff   = true;
                    }
#endif
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc {
                            CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.Windows
                        };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                            {
                                dp.TopPageTablePage.Add(p, block[p]);
                            }
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                        {
                            WriteLine(dp.ToString());
                        }
                        Candidate = true;
                    }
                }
            }
            // mode 1 is implemented to hit on very few supported bits
            // developing a version close to this that will work for Linux
            #region MODE 1 IS PRETTY LOOSE
#if MODE_1
            else
            /// detect MODE 1, we can probably get away with even just testing & 1, the valid bit
            //if (((block[0] & 3) == 3) && (block[0x1ed] & 3) == 3)
            if ((block[0] & 1) == 1 && (block[0xf68 / 8] & 1) == 1)
            {
                // a possible kernel first PFN? should look somewhat valid...
                if (!SetDiff)
                {
                    // I guess we could be attacked here too, the system kernel could be modified/hooked/bootkit enough
                    // we'll see if we need to analyze this in the long run
                    // the idea of mode 1 is a very low bit-scan, but we also do not want to mess up FirstDiff
                    // these root entries are valid for all win64's for PTE/hyper/session space etc.
                    if ((block[0xf78 / 8] & 1) == 1 && (block[0xf80 / 8] & 1) == 1 && (block[0xff8 / 8] & 1) == 1 && (block[0xff0 / 8] == 0))
                    {
                        // W/O this we may see some false positives
                        // however can remove if you feel aggressive
                        if (diff < FileSize && (offset > shifted ? (diff + shifted == offset) : (diff + offset == shifted)))
                        {
                            FirstDiff = diff;
                            SetDiff   = true;
                        }
                    }
                }

                if (SetDiff &&
                    !(FirstDiff != diff) &&
                    (shifted < (FileSize + diff)
                     //|| shifted != 0
                    ))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc {
                            CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 1, PageTableType = PTType.Windows
                        };

                        DetectedProcesses.TryAdd(offset, dp);
                        WriteLine(dp);

                        Candidate = true;
                    }
                }
            }
#endif
            #endregion
            return(Candidate);
        }
예제 #33
0
        /// <summary>
        /// In some deployments Hyper-V was found to use a configuration as such
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool HV(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[0x1fe] & 0xFFFFFFFFF000);
            var diff = offset - shifted;

            // detect mode 2, 2 seems good for most purposes and is more portable
            // maybe 0x3 is sufficient
            if (shifted != 0 && ((block[0] & 0xfff) == 0x063) && ((block[0x1fe] & 0xff) == 0x63 || (block[0x1fe] & 0xff) == 0x67) && block[0x1ff] == 0)
            {
                // we disqualify entries that have these bits configured
                // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                // 
                if (((ulong)block[0x1fe] & 0xFFFF000000000480) == 0)
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.HyperV, TrueOffset = TrueOffset };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                                dp.TopPageTablePage.Add(p, block[p]);
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                            WriteColor(ConsoleColor.Cyan, ConsoleColor.Black, dp.ToString());
                        Candidate = true;
                    }
                }
            }
            return Candidate;
        }
예제 #34
0
        /// <summary>
        /// Naturally the Generic checker is fairly chatty but at least you can use it
        /// to find unknowns, we could use some more tuneables here to help select the
        /// best match, I currently use the value with the lowest diff, which can be correct
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Generic(long offset)
        {
            var Candidate = false;
            //var offset = CurrWindowBase + CurrMapBase;
            long bestShift = long.MaxValue, bestDiff = long.MaxValue;
            var  bestOffset = long.MaxValue;
            var  i          = 0x1ff;

            do
            {
                if (((block[0] & 0xff) == 0x63) && block[0x1ff] == 0)
                {
                    if (((block[i] & 0xff) == 0x63 || (block[i] & 0xff) == 0x67))
                    {
                        // we disqualify entries that have these bits configured
                        // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                        //
                        if ((block[i] & 0x7FFF000000000480) == 0)
                        {
                            var shifted = (block[i] & 0xFFFFFFFFF000);

                            if (shifted != 0 && shifted < FileSize)
                            {
                                var diff = offset - shifted;

                                if (diff < bestDiff)
                                {
                                    bestShift  = shifted;
                                    bestDiff   = diff;
                                    bestOffset = offset;
                                }
                                if (!DetectedProcesses.ContainsKey(offset))
                                {
                                    var dp = new DetectedProc {
                                        CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.GENERIC
                                    };
                                    for (int p = 0; p < 0x200; p++)
                                    {
                                        if (block[p] != 0)
                                        {
                                            dp.TopPageTablePage.Add(p, block[p]);
                                        }
                                    }

                                    DetectedProcesses.TryAdd(offset, dp);
                                    if (Vtero.VerboseOutput)
                                    {
                                        WriteLine(dp.ToString());
                                    }
                                    Candidate = true;
                                }
                            }
                        }
                    }
                }
                i--;
                // maybe some kernels keep more than 1/2 system memory
                // wouldn't that be a bit greedy though!?
            } while (i > 0xFF);
            return(Candidate);
        }
예제 #35
0
        /// <summary>
        /// TODO: Make better for all types
        /// </summary>
        /// <param name="dp"></param>
        /// <param name="SymName"></param>
        /// <returns>Currently a single byte for the address resolved from the Name</returns>
        public long GetSymValueLong(DetectedProc dp, string SymName)
        {
            long value = 0;

            if (dp.SymbolStore.ContainsKey(SymName))
                return dp.SymbolStore[SymName];

            value = dp.GetLongValue(GetSymAddress(dp, SymName));
            dp.SymbolStore.Add(SymName, value);

            return value;
        }
예제 #36
0
        /*   OpenBSD /src/sys/arch/amd64/include/pmap.h
            #define L4_SLOT_PTE		255
            #define L4_SLOT_KERN		256
            #define L4_SLOT_KERNBASE	511
            #define L4_SLOT_DIRECT		510
        */
        /// <summary>
        /// Slightly better check then NetBSD so I guess consider it beta!
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool OpenBSD(long offset)
        {
            var Candidate = false;

            //var offset = CurrWindowBase + CurrMapBase;
            var shifted = (block[255] & 0xFFFFFFFFF000);
            var diff = offset - shifted;

            if (((block[510] & 0xf3) == 0x63) && (0x63 == (block[256] & 0xf3)) && (0x63 == (block[254] & 0xf3)))
            {
                if (((block[255] & 0xf3) == 0x63) && (0 == (block[255] & 0x7FFF000000000000)))
                {
                    if (!DetectedProcesses.ContainsKey(offset))
                    {
                        var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.OpenBSD };
                        for (int p = 0; p < 0x200; p++)
                        {
                            if (block[p] != 0)
                                dp.TopPageTablePage.Add(p, block[p]);
                        }

                        DetectedProcesses.TryAdd(offset, dp);
                        if (Vtero.VerboseOutput)
                            WriteLine(dp.ToString());
                        Candidate = true;
                    }
                }
            }
            return Candidate;
        }
예제 #37
0
        public dynamic[] WalkProcList(DetectedProc dp)
        {
            bool GotData = false;
            // TODO: Build out symbol system / auto registration into DLR for DIA2
            // expected kernel hardcoded


            var pdbFile = (from kern in dp.Sections
                           where kern.DebugDetails != null &&
                           !string.IsNullOrWhiteSpace(kern.DebugDetails.PDBFullPath) && 
                           kern.DebugDetails.PDBFullPath.ToLower().Contains("ntkrnlmp")
                           select kern.DebugDetails.PDBFullPath).FirstOrDefault();

            if (string.IsNullOrWhiteSpace(pdbFile))
                return null;

            // this is for DIA API SDK... 
            // TODO: Perf analysis of switching over to xStruct... however it's expando objects
            // are a lot slower than using the dictionary
            SymForKernel = Sym.Initalize(pdbFile);
            long[] memRead = null;

            var PsHeadAddr = GetSymValueLong(dp, "PsActiveProcessHead");


            // TODO: update this to be used instead of legacy .Dictionary kludge ;)
            //var rv = SymForKernel.xStructInfo(pdbFile, "_EPROCESS");
            // figure out OFFSET_OF the process LIST_ENTRY
            // MemberInfo returned is Byte Position, Length
            var aplinks = SymForKernel.StructMemberInfo(pdbFile, "_EPROCESS", "ActiveProcessLinks.Flink");
            var offset_of = aplinks.Item1;
            var sym_dtb = SymForKernel.StructMemberInfo(pdbFile, "_EPROCESS", "Pcb.DirectoryTableBase");
            var sym_ImagePathPtr = SymForKernel.StructMemberInfo(pdbFile, "_EPROCESS", "SeAuditProcessCreationInfo.ImageFileName");
            var sym_procID = SymForKernel.StructMemberInfo(pdbFile, "_EPROCESS", "UniqueProcessId");
            var sym_vadRoot = SymForKernel.StructMemberInfo(pdbFile, "_EPROCESS", "VadRoot");

            // adjust the first link through 
            //var flink = dp.GetLongValue(PsHeadAddr);

            var typeDefs = from typeDef in SymForKernel.StructInfo
                            where typeDef.Key.StartsWith("_EPROCESS")
                            select typeDef;

            var flink = PsHeadAddr;
            do 
            {
                // walk the offset back to the head of the _EPROCESS
                // this needs to adjsut since we get the entire block here based to the page not offset 
                memRead = dp.GetVirtualLong((flink - offset_of), ref GotData);
                if (!GotData)
                    break;

                // memRead is a long array so we have to divide the length by 8
                var EprocCR3 = memRead[sym_dtb.Item1 / 8];
                var ProcessID = memRead[sym_procID.Item1 / 8];
                var VadRootPtr = memRead[sym_vadRoot.Item1 / 8];

                // ImagePath here is a pointer to a struct, get ptr
                // +0x10 in this unicode string object
                var ImagePathPtr = memRead[sym_ImagePathPtr.Item1 / 8];
                var ImagePathArr = dp.GetVirtualByte(ImagePathPtr+0x10);
                var ImagePath = Encoding.Unicode.GetString(ImagePathArr);
                var pathTrim = ImagePath.Split('\x0');
                ImagePath = pathTrim[0];

                dynamic lproc = new ExpandoObject();
                var dproc = (IDictionary<string, object>)lproc;

                var staticDict = new Dictionary<string, object>();
                lproc.Dictionary = staticDict;

                foreach (var def in typeDefs)
                {
                    // custom types are not fitted this way
                    // we just recuse into basic types
                    if (def.Value.Item2 > 8)
                        continue;

                    // TODO: expand on this dynamic object stuff
                    var defName = def.Key.Substring("_EPROCESS".Length + 1); //.Replace('.', '_');

                    switch (def.Value.Item2)
                    {
                        case 4:
                            var ival = (int)(memRead[def.Value.Item1 / 8] & 0xffffffffff);
                            dproc.Add(defName, ival);
                            staticDict.Add(defName, ival);
                            break;
                        case 2:
                            var sval = (short)(memRead[def.Value.Item1 / 8] & 0xffffff);
                            dproc.Add(defName, sval);
                            staticDict.Add(defName, sval);
                            break;
                        case 1:
                            var bval = (byte)(memRead[def.Value.Item1 / 8] & 0xff);
                            dproc.Add(defName, bval);
                            staticDict.Add(defName, bval);
                            break;
                        default:
                            var lval = memRead[def.Value.Item1 / 8];
                            dproc.Add(defName, lval);
                            staticDict.Add(defName, lval);
                            break;
                    }
                } 

                lproc.ImagePath = ImagePath;

                dp.LogicalProcessList.Add(lproc);

                // move flink to next list entry
                flink = memRead[offset_of / 8];

            } while (PsHeadAddr != flink);
            return dp.LogicalProcessList.ToArray();
        }
예제 #38
0
        /// <summary>
        /// Naturally the Generic checker is fairly chatty but at least you can use it
        /// to find unknowns, we could use some more tuneables here to help select the
        /// best match, I currently use the value with the lowest diff, which can be correct
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public bool Generic(long offset)
        {
            var Candidate = false;
            //var offset = CurrWindowBase + CurrMapBase;
            long bestShift = long.MaxValue, bestDiff = long.MaxValue;
            var bestOffset = long.MaxValue;
            var i = 0x1ff;

            do
            {
                if (((block[0] & 0xff) == 0x63) && block[0x1ff] == 0)
                {
                    if (((block[i] & 0xff) == 0x63 || (block[i] & 0xff) == 0x67))
                    {
                        // we disqualify entries that have these bits configured
                        // 111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0100 1000 0000
                        // 
                        if ((block[i] & 0x7FFF000000000480) == 0)
                        {
                            var shifted = (block[i] & 0xFFFFFFFFF000);

                            if (shifted != 0 && shifted < FileSize)
                            {
                                var diff = offset - shifted;

                                if (diff < bestDiff)
                                {
                                    bestShift = shifted;
                                    bestDiff = diff;
                                    bestOffset = offset;
                                }
                                if (!DetectedProcesses.ContainsKey(offset))
                                {
                                    var dp = new DetectedProc { CR3Value = shifted, FileOffset = offset, Diff = diff, Mode = 2, PageTableType = PTType.GENERIC };
                                    for (int p = 0; p < 0x200; p++)
                                    {
                                        if (block[p] != 0)
                                            dp.TopPageTablePage.Add(p, block[p]);
                                    }

                                    DetectedProcesses.TryAdd(offset, dp);
                                    if (Vtero.VerboseOutput)
                                        WriteLine(dp.ToString());
                                    Candidate = true;
                                }
                            }
                        }
                    }
                }
                i--;
                // maybe some kernels keep more than 1/2 system memory 
                // wouldn't that be a bit greedy though!?
            } while (i > 0xFF); 
            return Candidate;
        }
예제 #39
0
        public static void DumpIt(Vtero vtero, ConfigOptions co, DumpOptions dmpo)
        {
            var Version = vtero.Version;

            Mem.InitMem(co.FileName, vtero.MRD);

            // Extract Address Spaces verifies the linkages between
            // process<->CR3<->EPTP(if there is one)
            // and that they are functional

            var vetted = vtero.ExtrtactAddressSpaces(null, null, Version);

            // leaving this in as an example maybe? ;)

            //WriteLine("enter a group ID: ");
            //input = ReadLine();
            //int Grp = int.Parse(input);
            //WriteLine("enter a process ID: ");
            //input = ReadLine();
            //long procID = long.Parse(input, NumberStyles.HexNumber);
            //var proc = (from procz in vtero.ASGroups[Grp]
            //            where procz.CR3Value == procID
            //            select procz).First();
            //int i = 1;
            //DetectedProc dp = proc;
            //while(dp == null)
            //    dp = vtero.GetKernelRangeFromGroup(i++);


            // Scan for kernel
            // NT kernel may be in 0xFFFFF80000000 to 0xFFFFF8800000 range
            long         KernVAStart  = 0xF80000000000;
            long         KernVAEnd    = KernVAStart + (0x8000000000 - 0x1000);
            string       input        = string.Empty;
            var          Detections   = new Dictionary <long, Extract>();
            DetectedProc LikelyKernel = null;
            bool         Decoded      = false;

            // were doing this in nested loops to brute force our way past any errors
            // but only need the first set of detections per group

            foreach (var grpz in vtero.ASGroups)
            {
                foreach (var vm in vtero.VMCSs.Values)
                {
                    WriteColor(ConsoleColor.White, $"Group ID: {grpz.Key}");
                    foreach (var p in grpz.Value)
                    {
                        WriteLine($"Proc: {p.CR3Value:X}");
                        Detections = Detections.Concat(
                            vtero.ModuleScan(p, 3, KernVAStart, KernVAEnd).Where(x => !Detections.ContainsKey(x.Key)))
                                     .ToDictionary(x => x.Key, x => x.Value);

                        if (Detections.Count() > 0)
                        {
                            LikelyKernel = p;

                            if (vm.EPTP == 0)
                            {
                                p.vmcs = null;
                            }
                            else
                            {
                                p.vmcs = vm;
                            }

                            // scan for kernel
                            foreach (var detected in Detections)
                            {
                                WriteColor(ConsoleColor.Green, $"Attempting to parse detected PE module loaded @ {detected.Key:X}");
                                WriteColor(ConsoleColor.Cyan, detected.Value.ToString());

                                if (detected.Value.ToString().Contains("POOLCODE"))
                                {
                                    WriteColor(ConsoleColor.White, "Likely Kernel analyzing for CV data");

                                    /*
                                     * var cv_data = vtero.ExtractCVDebug(LikelyKernel, detected.Value, detected.Key);
                                     *
                                     * if (cv_data != null)
                                     * {
                                     *  var sympath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH");
                                     *  if (string.IsNullOrWhiteSpace(sympath))
                                     *      sympath = "SRV*http://msdl.microsoft.com/download/symbols";
                                     *
                                     *  if (Vtero.TryLoadSymbols(cv_data, detected.Key, sympath))
                                     *      Decoded = vtero.GetKernelDebuggerData(LikelyKernel, detected.Value, cv_data, sympath);
                                     * }
                                     */
                                }
                            }
                        }
                        if (Decoded)
                        {
                            break;
                        }
                    }
                    if (Decoded)
                    {
                        break;
                    }
                }
                if (Decoded)
                {
                    break;
                }
            }
            ForegroundColor = ConsoleColor.Green;
            WriteLine($"{Environment.NewLine}Final analysis completed, address spaces extracted. {QuickOptions.Timer.Elapsed} {QuickOptions.FormatRate(vtero.FileSize * 3, QuickOptions.Timer.Elapsed)}");

            // do a test dump
            // extract & dump could be done at the same time

            if (!dmpo.ListOnly)
            {
                vtero.DumpASToFile();
            }

            //if (Vtero.VerboseOutput)
            //vtero.DumpFailList();

            return;
        }
예제 #40
0
        public long DumpProc(string Folder, DetectedProc Proc, bool IncludeData = false, bool KernelSpace = true)
        {
            //var entries = PageTable.Flatten(Proc.PT.Root.Entries.SubTables, 4);
            VIRTUAL_ADDRESS VA;
            VA.Address = 0;
            var PageTables = new Dictionary<VIRTUAL_ADDRESS, PFN>();
            int level = 3;
            long entries = 0;


            if (Proc.PT == null)
                PageTable.AddProcess(Proc, MemAccess);

            foreach (var kvp in Proc.TopPageTablePage)
            {
                // were at the top level (4th)
                VA.PML4 = kvp.Key;
                var pfn = new PFN { PTE = kvp.Value, VA = new VIRTUAL_ADDRESS(VA.PML4 << 39) };

                // Top level for page table
                PageTables.Add(VA, pfn);

                foreach (var DirectoryPointerOffset in Proc.PT.ExtractNextLevel(pfn, true, level))
                {
                    if (DirectoryPointerOffset == null) continue;
                    foreach (var DirectoryOffset in Proc.PT.ExtractNextLevel(DirectoryPointerOffset, KernelSpace, level - 1))
                    {
                        if (DirectoryOffset == null) continue;

                        foreach (var TableOffset in Proc.PT.ExtractNextLevel(DirectoryOffset, KernelSpace, level - 2))
                        {
                            if (TableOffset == null) continue;

                            entries++;
                            if (IncludeData == TableOffset.PTE.NoExecute)
                                WriteRange(TableOffset.VA, TableOffset, Folder, MemAccess);
                            if (!TableOffset.PTE.NoExecute)
                            WriteRange(TableOffset.VA, TableOffset, Folder, MemAccess);

                        }
                        entries++;
                        if (IncludeData == DirectoryOffset.PTE.NoExecute)
                            WriteRange(DirectoryOffset.VA, DirectoryOffset, Folder, MemAccess);
                        if (!DirectoryOffset.PTE.NoExecute)
                            WriteRange(DirectoryOffset.VA, DirectoryOffset, Folder, MemAccess);
                    }
                    entries++;
                }

            }
            return entries;
        }
예제 #41
0
 public VirtualScanner(DetectedProc Ctx, Mem backingBlocks, bool DoHeaderScan = false) : this()
 {
     DPContext     = Ctx;
     BackingBlocks = backingBlocks;
     HeaderScan    = DoHeaderScan;
 }
예제 #42
0
        /// <summary>
        /// Prefer symbol loading.
        /// </summary>
        /// <param name="dp"></param>
        /// <param name="ext"></param>
        /// <param name="cv_data"></param>
        /// <param name="SymbolCache"></param>
        /// <returns></returns>
        public bool GetKernelDebuggerData(DetectedProc dp, Extract ext, CODEVIEW_HEADER cv_data, string SymbolCache)
        {
            DebugHelp.SYMBOL_INFO symInfo = new DebugHelp.SYMBOL_INFO();
            bool rv = false;
            bool GotData = false;

            // Locate and extract some data points

            symInfo.SizeOfStruct = 0x58;
            symInfo.MaxNameLen = 1024;
            rv = DebugHelp.SymFromName(hCurrentProcess, "KdpDataBlockEncoded", ref symInfo);
            if(!rv)
            {
                WriteLine($"Symbol Find : {new Win32Exception(Marshal.GetLastWin32Error()).Message }.");
                return rv;
            }

            KernelProc = dp;

            // at this point we should return true if it's encoded or not
            rv = true;
            return rv;
#if FALSE
            I'm leaving this in for now just to show the use of DecodePointer if needed since it could be uswed in a scenerio where symbols fail


            var KdpDataBlockEncoded = dp.GetByteValue(symInfo.Address);
            // Convention is to use *Address for addresses or the simple name is the value it is assumed to be a pointer

            dp.SymbolStore["KdDebuggerDataBlockAddress"] = GetSymAddress(dp, "KdDebuggerDataBlock");

            if (KdpDataBlockEncoded == 0)
                WriteColor(ConsoleColor.Green, $"Kernel KdDebuggerDataBlock @ {dp.SymbolStore["KdDebuggerDataBlockAddress"]:X16} not encoded.");
            else
            {
#if FALSE_NOT_NEEDED_IF_WE_USE_SYMBOLS
                var KdDebuggerDataBlock = dp.VGetBlockLong(dp.KdDebuggerDataBlockAddress, ref GotData);
                if (!GotData)
                    WriteColor(ConsoleColor.Red, "Unable to read debuggerdatablock array");

                // Windbg tells us the diff for loaded modules is 0x48 and active proc is 0x50
                var EncLoadedModuleList = KdDebuggerDataBlock[9];
                var EncActiveProcessList = KdDebuggerDataBlock[0xA];

                var PsLoadedModuleList = (long) DecodePointer((ulong) dp.KdDebuggerDataBlockAddress, (ulong)dp.KiWaitAlways, (ulong)dp.KiWaitNever,(ulong) EncLoadedModuleList);
                var PsActiveProcessHead = (long) DecodePointer((ulong) dp.KdDebuggerDataBlockAddress, (ulong)dp.KiWaitAlways, (ulong)dp.KiWaitNever, (ulong) EncActiveProcessList);

                WriteColor(ConsoleColor.Cyan, $"Decoded LoadedModuleList {PsLoadedModuleList}, ActiveProcessList {PsActiveProcessHead}");
#endif
            }
            return rv;
#endif
        }