/// <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; }
/// <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); }