AddProcess() public static method

public static AddProcess ( DetectedProc dp, Mem mem, bool RedundantKernelEntries = true, int DepthToGo = 4 ) : PageTable
dp DetectedProc
mem Mem
RedundantKernelEntries bool
DepthToGo int
return PageTable
Example #1
0
        public void DumpProc(string Folder, bool IncludeData = false, bool KernelSpace = true, bool OnlyExec = true)
        {
            //// TODO: BOILER PLATE check perf of using callbacks
            PageTable.AddProcess(this, new Mem(MemAccess));
            var cnt = PT.FillPageQueue(false, KernelSpace);

            Folder = Folder + Path.DirectorySeparatorChar.ToString();
            Directory.CreateDirectory(Folder);

            long ContigSizeState = 0, curr = 0;

            // single threaded worked best so far
            //Parallel.For(0, cnt, (i, loopState) => x
            foreach (var range in PT.FillPageQueue(false, KernelSpace))
            {
                curr++;
                if (Vtero.VerboseLevel > 1)
                {
                    //var curr = cnt - PT.PageQueue.Count;
                    //var done = Convert.ToDouble(curr) / Convert.ToDouble(cnt) * 100.0;
                    Console.CursorLeft = 0;
                    Console.Write($"{curr} scanned");
                }
                if (range.PTE.Valid)
                {
                    // skip data as requested
                    if (!IncludeData && range.PTE.NoExecute)
                    {
                        continue;
                    }

                    Vtero.WriteRange(range.VA, range, Folder, ref ContigSizeState, MemAccess);
                }
            }
        }
Example #2
0
        public int FillPageQueue(bool OnlyLarge = false)
        {
            PageQueue = new ConcurrentQueue <PFN>();
            VIRTUAL_ADDRESS VA;

            VA.Address = 0;

            if (DP.PT == null)
            {
                PageTable.AddProcess(DP, DP.MemAccess);
            }

            Parallel.ForEach(DP.TopPageTablePage, (kvp) =>
                             //foreach (var kvp in DP.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)
                };

                foreach (var DirectoryPointerOffset in DP.PT.ExtractNextLevel(pfn, true, 3))
                {
                    if (DirectoryPointerOffset == null)
                    {
                        continue;
                    }
                    foreach (var DirectoryOffset in DP.PT.ExtractNextLevel(DirectoryPointerOffset, KernelSpace, 2))
                    {
                        if (DirectoryOffset == null)
                        {
                            continue;
                        }
                        // if we have a large page we add it now
                        if (DirectoryOffset.PTE.LargePage)
                        {
                            PageQueue.Enqueue(DirectoryOffset);
                        }
                        // otherwise were scanning lower level entries
                        else if (!OnlyLarge)
                        {
                            foreach (var TableOffset in DP.PT.ExtractNextLevel(DirectoryOffset, KernelSpace, 1))
                            {
                                if (TableOffset == null)
                                {
                                    continue;
                                }

                                PageQueue.Enqueue(TableOffset);
                            }
                        }
                    }
                }
                //}
            });
            return(PageQueue.Count());
        }
Example #3
0
        public List <ScanResult> YaraScan(string RulesFile, bool IncludeData = false, bool KernelSpace = false)
        {
            var rv = new List <ScanResult>();

            using (var ctx = new YaraContext())
            {
                Rules rules = null;
                try
                {
                    // Rules and Compiler objects must be disposed.
                    using (var compiler = new Compiler())
                    {
                        compiler.AddRuleFile(RulesFile);
                        rules = compiler.GetRules();
                    }

                    PageTable.AddProcess(this, MemAccess);
                    //var cnt = PT.FillPageQueue(false, KernelSpace);
                    var curr = 0;
                    YaraTotalScanned = 0;
                    // single threaded worked best so far
                    //Parallel.For(0, cnt, (i, loopState) => x
                    foreach (var range in PT.FillPageQueue(false, KernelSpace, true, false))
                    //for (int i = 0; i < cnt; i++)
                    {
                        curr++;
                        if (Vtero.VerboseLevel > 1)
                        {
                            //var curr = cnt - PT.PageQueue.Count;
                            //var done = Convert.ToDouble(curr) / Convert.ToDouble(cnt) * 100.0;
                            Console.CursorLeft = 0;
                            Console.Write($"{curr} scanned");
                        }
                        if (range.PTE.Valid)
                        {
                            // skip data as requested
                            if (!IncludeData && range.PTE.NoExecute)
                            {
                                continue;
                            }

                            // Scanner and ScanResults do not need to be disposed.
                            var scanner = new libyaraNET.Scanner();
                            unsafe
                            {
                                long[] block   = null;
                                bool   GotData = false;

                                if (range.PTE.LargePage)
                                {
                                    block = new long[0x40000];
                                }
                                else
                                {
                                    block = new long[0x200];
                                }

                                MemAccess.GetPageForPhysAddr(range.PTE, ref block, ref GotData);
                                if (GotData)
                                {
                                    fixed(void *lp = block)
                                    {
                                        var res = scanner.ScanMemory((byte *)lp, block.Length, rules, ScanFlags.None);

                                        rv.AddRange(res);
                                        YaraTotalScanned += block.Length;
                                    }
                                }
                            }
                        }
                    }
                }
                finally
                {
                    // Rules and Compiler objects must be disposed.
                    if (rules != null)
                    {
                        rules.Dispose();
                    }
                }
            }
            YaraOutput = rv;
            return(YaraOutput);
        }
Example #4
0
        /// <summary>
        /// Currently we scan hard for only kernel regions (2MB pages + ExEC)
        /// If there are kernel modules named the OnlyModule it may cause us to ignore the real one in   that case
        /// you can still scan for * by passing null or empty string
        /// </summary>
        /// <param name="OnlyModule">Stop when the first module named this is found</param>
        public VirtualScanner ScanAndLoadModules(string OnlyModule = "ntkrnlmp.pdb", bool OnlyLarge = true, bool IncludeKernelSpace = true, bool OnlyValid = true, bool IncludeData = false, bool DoExtraHeaderScan = true)
        {
            const int LARGE_PAGE_SIZE = 1024 * 1024 * 2;
            var       curr            = 0;

            PageTable.AddProcess(this, new Mem(MemAccess));
            //var cnt = PT.FillPageQueue(OnlyLarge, IncludeKernelSpace);

            var KVS = new VirtualScanner(this, new Mem(MemAccess), DoExtraHeaderScan);

            // single threaded worked best so far
            //Parallel.For(0, cnt, (i, loopState) => x
            foreach (var range in PT.FillPageQueue(OnlyLarge, IncludeKernelSpace, OnlyValid, IncludeData))
            //for (int i = 0; i < cnt; i++)
            {
                curr++;
                bool stop = false;
                if (Vtero.VerboseLevel > 1)
                {
                    //var curr = cnt - PT.PageQueue.Count;
                    //var done = Convert.ToDouble(curr) / Convert.ToDouble(cnt) * 100.0;
                    Console.CursorLeft = 0;
                    Console.Write($"{curr} scanned");
                }
                if (range.PTE.Valid && !range.PTE.NoExecute)
                {
                    foreach (var artifact in KVS.Run(range.VA.Address, range.VA.Address + (range.PTE.LargePage ? LARGE_PAGE_SIZE : MagicNumbers.PAGE_SIZE), range))
                    {
                        var ms = new MemSection()
                        {
                            IsExec = true, Module = artifact, VA = new VIRTUAL_ADDRESS(artifact.VA), Source = range
                        };
                        var extracted = ExtractCVDebug(ms);
                        if (extracted == null)
                        {
                            if (Vtero.VerboseLevel > 1)
                            {
                                WriteColor(ConsoleColor.Yellow, $"failed debug info for PE @address {range.VA.Address:X}, extracted headers: {artifact}");
                            }
                            continue;
                        }

                        if (!string.IsNullOrWhiteSpace(OnlyModule) && OnlyModule != ms.Name)
                        {
                            continue;
                        }

                        if (!Sections.ContainsKey(artifact.VA))
                        {
                            Sections.TryAdd(artifact.VA, ms);
                        }

                        // we can clobber this guy all the time I guess since everything is stateless in Sym and managed
                        // entirely by the handle ID really which is local to our GUID so....
                        sym = Vtero.TryLoadSymbols(ID.GetHashCode(), ms.DebugDetails, ms.VA.Address);
                        if (Vtero.VerboseOutput)
                        {
                            WriteColor((sym != null) ? ConsoleColor.Green : ConsoleColor.Yellow, $" symbol loaded = [{sym != null}] PDB [{ms.DebugDetails.PDBFullPath}] @ {range.VA.Address:X}, {ms.Name}");
                            if (Vtero.VerboseLevel > 1)
                            {
                                WriteColor((sym != null) ? ConsoleColor.Green : ConsoleColor.Yellow, $"headers: { artifact} ");
                            }
                        }

                        if (!string.IsNullOrWhiteSpace(OnlyModule))
                        {
                            if (!string.IsNullOrWhiteSpace(ms.Name) && ms.Name == OnlyModule)
                            {
                                stop = true;
                                //loopState.Stop();
                                break;
                            }
                        }
                        //if (loopState.IsStopped)
                        //return;
                        if (stop)
                        {
                            break;
                        }
                    }
                }

                //if (loopState.IsStopped)
                //    return;e
                //});
                if (stop)
                {
                    break;
                }
            }
            return(KVS);
        }
Example #5
0
        /// <summary>
        /// Currently we scan hard for only kernel regions (2MB pages + ExEC)
        /// If there are kernel modules named the OnlyModule it may cause us to ignore the real one in that case
        /// you can still scan for * by passing null or empty string
        /// </summary>
        /// <param name="OnlyModule">Stop when the first module named this is found</param>
        public VirtualScanner ScanAndLoadModules(string OnlyModule = "ntkrnlmp")
        {
            PageTable.AddProcess(this, new Mem(MemAccess));
            var cnt = PT.FillPageQueue(true);

            var KVS = new VirtualScanner(this, new Mem(MemAccess));

            KVS.ScanMode = VAScanType.PE_FAST;

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



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

                if (PT.PageQueue.TryDequeue(out range) && range.PTE.Valid)
                {
                    var found = KVS.Run(range.VA.Address, range.VA.Address + (range.PTE.LargePage ? (1024 * 1024 * 2) : 0x1000), loopState);
                    // Attempt load
                    foreach (var artifact in found)
                    {
                        var ms = new MemSection()
                        {
                            IsExec = true, Module = artifact.Value, VA = new VIRTUAL_ADDRESS(artifact.Key)
                        };
                        var extracted = ExtractCVDebug(ms);
                        if (extracted == null)
                        {
                            continue;
                        }

                        if (!string.IsNullOrWhiteSpace(OnlyModule) && OnlyModule != ms.Name)
                        {
                            continue;
                        }

                        if (!Sections.ContainsKey(artifact.Key))
                        {
                            Sections.TryAdd(artifact.Key, ms);
                        }

                        // we can clobber this guy all the time I guess since everything is stateless in Sym and managed
                        // entirely by the handle ID really which is local to our GUID so....
                        sym = Vtero.TryLoadSymbols(ID.GetHashCode(), ms.DebugDetails, ms.VA.Address);
                        if (Vtero.VerboseOutput)
                        {
                            WriteColor(ConsoleColor.Green, $"symbol loaded [{sym != null}] from file [{ms.DebugDetails.PDBFullPath}]");
                        }

                        if (!string.IsNullOrWhiteSpace(OnlyModule))
                        {
                            if (!string.IsNullOrWhiteSpace(ms.Name) && ms.Name == OnlyModule)
                            {
                                loopState.Stop();
                                return;
                            }
                        }
                        if (loopState.IsStopped)
                        {
                            return;
                        }
                    }
                }

                if (loopState.IsStopped)
                {
                    return;
                }
            });
            return(KVS);
        }
Example #6
0
        //[ProtoIgnore]
        //public List<PFN> PageQueue;
        //TODO: this should really take a PFN with various bit's set we can test with a .Match
        //TODO: fix all callers of this to use a callback also
        public IEnumerable <PFN> FillPageQueue(bool OnlyLarge = false, bool RedundantKernelSpaces = false, bool OnlyValid = true, bool OnlyExec = true)
        {
            KernelSpace = RedundantKernelSpaces;
            //PageQueue = new List<PFN>();
            VIRTUAL_ADDRESS VA;

            VA.Address = 0;

            if (DP.PT == null)
            {
                PageTable.AddProcess(DP, DP.MemAccess);
            }

            //Parallel.ForEach(DP.TopPageTablePage, (kvp) =>
            foreach (var kvp in DP.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)
                };

                // do redundant check here
                if (!RedundantKernelSpaces && (kvp.Key >= MagicNumbers.KERNEL_PT_INDEX_START_USUALLY))
                {
                    continue;
                }

                if (OnlyExec && pfn.PTE.NoExecute)
                {
                    continue;
                }

                foreach (var DirectoryPointerOffset in DP.PT.ExtractNextLevel(pfn, 3))
                {
                    if (DirectoryPointerOffset == null)
                    {
                        continue;
                    }
                    if (OnlyExec && DirectoryPointerOffset.PTE.NoExecute)
                    {
                        continue;
                    }

                    foreach (var DirectoryOffset in DP.PT.ExtractNextLevel(DirectoryPointerOffset, 2))
                    {
                        if (DirectoryOffset == null)
                        {
                            continue;
                        }
                        // if we have a large page we add it now
                        if (DirectoryOffset.PTE.LargePage || (OnlyValid && !DirectoryOffset.PTE.Valid))
                        {
                            if (OnlyExec && DirectoryOffset.PTE.NoExecute)
                            {
                                continue;
                            }

                            yield return(DirectoryOffset);

                            continue;
                        }
                        // otherwise were scanning lower level entries
                        // unless we are only large page scanning.
                        else if (!OnlyLarge)
                        {
                            foreach (var TableOffset in DP.PT.ExtractNextLevel(DirectoryOffset, 1))
                            {
                                if (OnlyExec && TableOffset.PTE.NoExecute)
                                {
                                    continue;
                                }

                                if (TableOffset == null || (OnlyValid && !TableOffset.PTE.Valid))
                                {
                                    continue;
                                }

                                yield return(TableOffset);
                            }
                        }
                    }
                }
            }
            //});
            yield break;
        }
Example #7
0
        /// <summary>
        /// This routine is fairly expensive, maybe unnecessary as well but it demo's walking the page table + EPT.
        /// You can connect an address space dumper really easily
        /// </summary>
        /// <param name="MemSpace">The list of VMCS/EPTP configurations which will alter the page table use</param>
        /// <param name="Procs">Detected procs to query</param>
        /// <param name="pTypes">Type bitmas to interpreate</param>
        public List <DetectedProc> ExtrtactAddressSpaces(IOrderedEnumerable <VMCS> MemSpace = null, ConcurrentBag <DetectedProc> Procs = null, PTType pTypes = PTType.UNCONFIGURED)
        {
            List <DetectedProc> rvList = new List <DetectedProc>();

            var PT2Scan  = pTypes == PTType.UNCONFIGURED ? (PTType.Windows | PTType.HyperV | PTType.GENERIC) : pTypes;
            var procList = Procs == null ? Processes : Procs;
            //var memSpace = MemSpace == null ? VMCSs.First() : MemSpace.First();

            var memSpace = MemSpace == null?VMCSs.GroupBy(x => x.EPTP).Select(xg => xg.First()) : MemSpace;

            var p = from proc in Processes
                    where (((proc.PageTableType & PT2Scan) == proc.PageTableType))
                    orderby proc.CR3Value ascending
                    select proc;

            int pcnt  = Processes.Count();
            int vmcnt = memSpace.Count();
            var tot   = pcnt * vmcnt;
            var curr  = 0;

            var AlikelyKernelSet = from ptes in p.First().TopPageTablePage
                                   where ptes.Key > 255 && MagicNumbers.Each.All(ppx => ppx != ptes.Key)
                                   select ptes.Value;

            Console.ForegroundColor = ConsoleColor.Yellow;
            WriteLine($"assessing {tot} address spaces");
            ProgressBarz.Progress = 0;

            var VMCSTriage = new Dictionary <VMCS, int>();

            //Parallel.ForEach(memSpace, (space) =>
            foreach (var space in memSpace)
            {
                // we do it this way so that parallelized tasks do not interfere with each other
                // overall it may blow the cache hit ratio but will tune a single task to see the larger/better cache
                // versus multicore, my suspicion is that multi-core is better
                using (var memAxs = new Mem(MemFile, null, DetectedDesc))
                {
                    var sx = 0;
                    foreach (var px in p)
                    //Parallel.ForEach(p, (proc) =>
                    {
                        try
                        {
                            var proc = px.Clone <DetectedProc>();
                            proc.vmcs = space;

                            var pt = PageTable.AddProcess(proc, memAxs, false);
                            if (pt != null && VerboseOutput)
                            {
                                // If we used group detection correlation a valid EPTP should work for every process

                                if (proc.vmcs != null && proc.PT.RootPageTable.PFNCount > proc.TopPageTablePage.Count())
                                {
                                    WriteLine($"Virtualized Process PT Entries [{proc.PT.RootPageTable.PFNCount}] Type [{proc.PageTableType}] PID [{proc.vmcs.EPTP:X}:{proc.CR3Value:X}]");
                                    rvList.Add(proc);
                                }
                                else
                                {
                                    WriteLine($"canceling evaluation of bad EPTP for this group");
                                    foreach (var pxc in Processes)
                                    {
                                        pxc.vmcs = null;
                                    }
                                    break;
                                }

                                sx++;
                                curr++;
                                var progress = Convert.ToInt32((Convert.ToDouble(curr) / Convert.ToDouble(tot) * 100.0) + 0.5);
                                ProgressBarz.RenderConsoleProgress(progress);
                            }
                        }
                        catch (ExtendedPageNotFoundException eptpX)
                        {
                            WriteLine($"Bad EPTP selection;{Environment.NewLine}\tEPTP:{eptpX.RequestedEPTP}{Environment.NewLine}\t CR3:{eptpX.RequestedCR3}{Environment.NewLine} Attempting to skip to next proc.");

                            memAxs.DumpPFNIndex();
                        }
                        catch (MemoryRunMismatchException mrun)
                        {
                            WriteLine($"Error in accessing memory for PFN {mrun.PageRunNumber:X16}");

                            memAxs.DumpPFNIndex();
                        }
                        catch (PageNotFoundException pnf)
                        {
                            WriteLine($"Error in selecting page, see {pnf}");

                            memAxs.DumpPFNIndex();
                        }
                        catch (Exception ex)
                        {
                            WriteLine($"Error in memspace extraction: {ex.ToString()}");

                            memAxs.DumpPFNIndex();
                        }
                        WriteLine($"{sx} VMCS dominated process address spaces and were decoded succsessfully.");
                        //});
                    }
                }
            }
            //});


            using (var memAxs = new Mem(MemFile, null, DetectedDesc))
            {
                var nonVMCSprocs = from px in Processes
                                   where px.vmcs == null
                                   select px;

                foreach (var px in nonVMCSprocs)
                {
                    var pmetal = px.Clone <DetectedProc>();

                    // this is a process on the bare metal
                    var pt = PageTable.AddProcess(pmetal, memAxs, false);
                    WriteLine($"Process {pmetal.CR3Value:X16} Physical walk w/o SLAT yielded {pmetal.PT.RootPageTable.PFNCount} entries");

                    rvList.Add(pmetal);
                }
            }
            return(rvList);
        }