Physical to Virtual and Physical to Hypervisor Guest Virtual memory dump class Convienent generic interfaces for extracting preferred types * Type has to be a value/struct type and is expected to be 64 bits width * TODO: Adjust for other size structs & values stradling page boundries
Inheritance: IDisposable
Beispiel #1
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;
        }
Beispiel #2
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;
        }
Beispiel #3
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);
        }
Beispiel #4
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;
        }
Beispiel #5
0
        public void DumpASToFile(List<DetectedProc> ToDump)
        {
            using (var memAxs = new Mem(MemFile, null, DetectedDesc))
            {
                // in all likelyhood this is the kernel
                var tdp = (from p in ToDump
                           where p.AddressSpaceID == 1
                           orderby p.CR3Value ascending
                           select p).Take(1).First();

                // as a test let's find the process with the most to dump
                /*var tdp = (from p in ToDump
                               where p.AddressSpaceID == 1
                               orderby p.PT.RootPageTable.PFNCount descending
                               select p).Take(1).First();
                               */

                var pml4 = tdp.PT.RootPageTable;

                WriteLine($"Test dumping {tdp}, {pml4.PFNCount} entries scanned.");

                var MemRanges = pml4.SubTables.SelectMany(x => x.Value.SubTables).SelectMany(y => y.Value.SubTables).SelectMany(z => z.Value.SubTables);

    //            WriteLine($"MemRanges = {MemRanges.Count()} available.");

                
                var saveLoc = Path.Combine(Path.GetDirectoryName(MemFile), Path.GetFileName(MemFile) + ".");

                long[] block = new long[0x200]; // 0x200 * 8 = 4k
                byte[] bpage = new byte[0x1000];

                unsafe
                {
                    fixed (void * lp = block, bp = bpage)
                    {
                        foreach (var pte in MemRanges)
                        {
                            if (VerboseOutput)
                                WriteLine($"VA: {pte.Key:X16}  \t PFN: {pte.Value.PTE}");

                            if (pte.Value.PTE.LargePage)
                            {
                                using (var lsavefile = File.OpenWrite(saveLoc + pte.Key.Address.ToString("X") + ".bin"))
                                    // 0x200 * 4kb = 2MB
                                    for (int i = 0; i < 0x200; i++)
                                    {
                                        try { memAxs.GetPageForPhysAddr(pte.Value.PTE, ref block); } catch (Exception ex) { }
                                        pte.Value.PTE.PTE += (i * 0x1000);
                                        if (block == null)
                                            continue;

                                        Buffer.MemoryCopy(lp, bp, 4096, 4096);
                                        lsavefile.Write(bpage, 0, 4096);
                                    }

                            }
                            else
                            {
                                try { memAxs.GetPageForPhysAddr(pte.Value.PTE, ref block); } catch (Exception ex) { }
                                if (block == null)
                                    continue;

                                using (var savefile = File.OpenWrite(saveLoc + pte.Key.Address.ToString("X") + ".bin"))
                                {
                                    Buffer.MemoryCopy(lp, bp, 4096, 4096);
                                    savefile.Write(bpage, 0, 4096);
                                }
                            }
                        }
                    }
                }
            }
        }
Beispiel #6
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;
        }
Beispiel #7
0
        /// <summary>
        /// This routine is fairly expensive, maybe unnessisary as well but it demo's walking the page table + EPT.
        /// You can connect an address space dumper really easially
        /// </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 void ExtrtactAddressSpaces(IOrderedEnumerable<VMCS> MemSpace = null, ConcurrentBag<DetectedProc> Procs = null, PTType pTypes = PTType.UNCONFIGURED)
        {
            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; //.Where(xw => xw.All(xz => xz.EPTP == 0x1138601E))

            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();
            int tot = pcnt * vmcnt;
            int 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;
            Parallel.ForEach(memSpace, (space) =>
            //foreach (var space in memSpace)
            {
                using (var memAxs = new Mem(MemFile))
                {
                    var sx = 0;
                    //foreach (var proc in p)
                    Parallel.ForEach(p, (proc) =>
                    { 
                        try
                        {
                            proc.vmcs = space;
                            var pt = PageTable.AddProcess(proc, memAxs);
                            if (pt != null && VerboseOutput)
                            {
                                var currKern = from ptes in proc.TopPageTablePage
                                                       where ptes.Key > 255 && MagicNumbers.Each.All(ppx => ppx != ptes.Key)
                                                       select ptes.Value;

                                var interSection = currKern.Intersect(AlikelyKernelSet);

                                var corralated = interSection.Count() * 1.00 / AlikelyKernelSet.Count();
                                WriteLine($"PT Entries [{proc.PT.RootPageTable.PFNCount}] Type [{proc.PageTableType}] GroupCorrelation [{corralated:P3}] PID [{proc.vmcs.EPTP:X}:{proc.CR3Value:X}]");

                                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.");
                        }
                        catch (MemoryRunMismatchException mrun)
                        {
                            WriteLine($"Error in accessing memory for PFN {mrun.PageRunNumber:X16}");
                        }
                        catch (PageNotFoundException pnf)
                        {
                            WriteLine($"Error in selecting page, see {pnf}");
                        }
                        catch(Exception ex)
                        {
                            WriteLine($"Error in memspace extraction: {ex.ToString()}");
                        }

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


                    });
                    //}
                }
            //}
            });
        }
Beispiel #8
0
        // TODO: Figure out if MemoryCopy or BlockCopy ...
         

        public string WriteRange(VIRTUAL_ADDRESS KEY, PFN VALUE, string BaseFileName, Mem PhysMemReader = null, bool SinglePFNStore = false, bool DumpNULL = false)
        {
            if (SinglePFNStore && SISmap == null)
                SISmap = new WAHBitArray();

            if(SinglePFNStore)
            {
                if (SISmap.Get((int)VALUE.PTE.PFN))
                    return string.Empty;

                SISmap.Set((int)VALUE.PTE.PFN, true);
            }

            bool canAppend = false;
            var saveLoc = BaseFileName + KEY.Address.ToString("X") + ".bin";
            var lastLoc = BaseFileName + (KEY.Address - ContigSize).ToString("X") + ".bin";

            if (File.Exists(lastLoc))
            {
                canAppend = true;
                ContigSize += 0x1000;
                saveLoc = lastLoc;
            }
            else
                ContigSize = 0x1000;

            //unsafe
            //{
                var block = new long[0x200]; // 0x200 * 8 = 4k
                var bpage = new byte[0x1000];

                //fixed (void* lp = block, bp = bpage)
                //{

                    if (DiagOutput)
                        WriteColor(VALUE.PTE.Valid ? ConsoleColor.Cyan : ConsoleColor.Red,  $"VA: {KEY:X12}  \t PFN: {VALUE.PTE}");

                    // if we have invalid (software managed) page table entries
                    // the data may be present, or a prototype or actually in swap.
                    // for the moment were only going to dump hardware managed data
                    // or feel free to patch this up ;)
                    if (!VALUE.PTE.Valid)
                        return string.Empty;

                    if (VALUE.PTE.LargePage)
                    {
                        bool GoodRead = false;
                        using (var lsavefile = File.OpenWrite(saveLoc))
                        {
                            // 0x200 * 4kb = 2MB
                            // TODO: Large pages properly?
                            // TODO: PageCache is still broken in some cases... disable for now here
                            for (int i = 0; i < 0x200; i++)
                            {
                                PhysMemReader.GetPageForPhysAddr(VALUE.PTE, ref block, ref GoodRead); 
                                VALUE.PTE.PTE += 0x1000;
                                if(!GoodRead)
                                    block = new long[0x200];

                                Buffer.BlockCopy(block, 0, bpage, 0, 4096);
                                //Buffer.MemoryCopy(lp, bp, 4096, 4096);
                                lsavefile.Write(bpage, 0, 4096);
                                //lsavefile.Write(bpage, 0, 4096);

                            }
                            return lastLoc;
                        }
                    }
                    else
                    {
                        try { PhysMemReader.GetPageForPhysAddr(VALUE.PTE, ref block); } catch (Exception ex) { }

                        if (block != null)
                        {
                            if (DumpNULL || !UnsafeHelp.IsZero(block))
                            {
                                Buffer.BlockCopy(block, 0, bpage, 0, 4096);
                               //Buffer.MemoryCopy(lp, bp, 4096, 4096);
                                
                                using (var savefile = (canAppend ? File.Open(lastLoc, FileMode.Append, FileAccess.Write, FileShare.ReadWrite) : File.OpenWrite(saveLoc)))
                                    savefile.Write(bpage, 0, 4096);

                                    //savefile.Write(bpage, 0, 4096);
                                return lastLoc;
                            }
                        }
                    }
                    ContigSize = 0;
                    return string.Empty;
                //}
            //}
        }
Beispiel #9
0
 public void AddProcessPageTable(DetectedProc tdp, Mem memAxs)
 {
     PageTable.AddProcess(tdp, memAxs, true);
 }
Beispiel #10
0
        /// <summary>
        /// Scan and return Extract objects which represent detected PE's
        ///
        /// TODO:simplify/rewrite this
        /// </summary>
        /// <param name="Start"></param>
        /// <param name="Stop">We just truncate VA's at 48 bit's</param>
        /// <returns>count of new detections since last Run</returns>
        public List <Extract> Run(long Start = 0, long Stop = 0xFFFFffffFFFF, PFN entry = null, ParallelLoopState pState = null, Mem Instance = null)
        {
            bool GotData = false;
            var  memAxss = Instance == null ? BackingBlocks : Instance;
            long i = Start, Curr = 0;

            long[] block;
            var    rv = new List <Extract>();

            // large page read
            if (entry != null && entry.PTE.LargePage)
            {
                block = new long[0x40000];
                memAxss.GetPageForPhysAddr(entry.PTE, ref block, ref GotData);
                if (GotData)
                {
                    rv = FastPE(Start, block);
                }

                return(rv);
            }
            else
            // use supplied page sized physical entry
            if (entry != null && Stop - Start == MagicNumbers.PAGE_SIZE)
            {
                block = new long[0x200];
                memAxss.GetPageForPhysAddr(entry.PTE, ref block, ref GotData);
                if (GotData)
                {
                    rv = FastPE(Start, block);
                }

                // we only header scan when asked and if the page read is 1 from an alignment
                if (!HeaderScan)
                {
                    return(rv);
                }
                if ((Start & 0xF000) != 0x1000)
                {
                    return(rv);
                }
                // if were doing a header scan back up i so we do the previous page
                i -= 0x1000;
                // back up Stop also so we just scan this current page one time
                Stop -= 0x1000;
            }
            // just use the virtual addresses and attempt to locate phys from page walk
            // this is a really slow way to enumerate memory
            // convert index to an address
            // then add start to it
            block = new long[0x200]; // 0x200 * 8 = 4k
            while (i < Stop)
            {
                if (pState != null && pState.IsStopped)
                {
                    return(rv);
                }

                HARDWARE_ADDRESS_ENTRY locPhys = HARDWARE_ADDRESS_ENTRY.MinAddr;
                if (DPContext.vmcs != null)
                {
                    locPhys = memAxss.VirtualToPhysical(DPContext.vmcs.EPTP, DPContext.CR3Value, i);
                }
                else
                {
                    locPhys = memAxss.VirtualToPhysical(DPContext.CR3Value, i);
                }

                Curr = i;
                i   += 0x1000;

                if (HARDWARE_ADDRESS_ENTRY.IsBadEntry(locPhys) || !locPhys.Valid)
                {
                    continue;
                }

                memAxss.GetPageForPhysAddr(locPhys, ref block, ref GotData);
                if (!GotData)
                {
                    continue;
                }

                var new_pe = FastPE(Curr, block);
                rv.AddRange(new_pe);
                if (Vtero.VerboseOutput && new_pe.Count > 0)
                {
                    Console.WriteLine($"Detected PE @ VA {Curr:X}");
                }
            }
            return(rv);
        }
 public PhysicalMemoryStream(Mem blockStorage, DetectedProc proc)
 {
     MemBlockStorage = blockStorage;
     Proc            = proc;
 }
 public PhysicalMemoryStream(Mem blockStorage, DetectedProc proc)
 {
     MemBlockStorage = blockStorage;
     Proc = proc;
 }
Beispiel #13
0
        public static Mem InitMem(String mFile, AMemoryRunDetector Detector, uint[] BitmapArray = null) //: this()
        {
            
            var thiz = new Mem();

            thiz.StartOfMemory = Detector != null ? Detector.StartOfMem : 0;

            if (Detector != null)
            {
                thiz.StartOfMemory = Detector.StartOfMem;
                thiz.MD = Detector;
            }
#if USE_BITMAP
            // maybe there's a bit map we can use from a DMP file
            if (BitmapArray != null)
                pfnTableIdx = new WAHBitArray(WAHBitArray.TYPE.Bitarray, BitmapArray);
            else
                pfnTableIdx = new WAHBitArray();

            // 32bit's of pages should be plenty?
            pfnTableIdx.Length = (int) (MapViewSize / 0x1000);
#endif

            if (File.Exists(mFile))
            {
                thiz.MemoryDump = mFile;
                thiz.FileSize = new FileInfo(mFile).Length;

                if (Detector != null)
                    thiz.MD = Detector;
            }

            thiz.SetupStreams();

            return thiz;
        }
Beispiel #14
0
        public Mem(Mem parent) : this()
        {
            MD = parent.MD;

            StartOfMemory = parent.StartOfMemory;
            MemoryDump = parent.MemoryDump;
            FileSize = parent.FileSize;

            SetupStreams();
        }