Example #1
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 #2
0
        long FillTable(VIRTUAL_ADDRESS VA, int PageIndex, long CR3, bool OnlyUserSpace = false)
        {
            var entries   = 0L;
            var PageTable = new Dictionary <VIRTUAL_ADDRESS, PFN>();

            // We can just pick up the top level page to speed things up
            // we've already visited this page so were not going to waste time looking up the VA->PA
            //var page = new long[512];
            //mem.GetPageFromFileOffset(FileOffset, ref page);

            // clear out the VA for the other indexes since were looking at the top level
            VA.Address = 0;

            foreach (var kvp in DP.TopPageTablePage)
            {
                // Only extract user portion, kernel will be mostly redundant
                if (OnlyUserSpace && kvp.Key >= 256)
                {
                    continue;
                }

                // were at the top level (4th)
                VA.PML4 = kvp.Key;

                var pfn = new PFN(kvp.Value, VA.Address, CR3, DP.vmcs == null ? 0 : DP.vmcs.EPTP);
                PageTable.Add(VA, pfn);
                entries++;
            }

            // simulated top entry
            RootPageTable = new PFN(DP.TopPageTablePage[PageIndex], VA.Address, CR3, DP.vmcs == null ? 0 : DP.vmcs.EPTP)
            {
                SubTables = PageTable
            };

            // descend the remaining levels
            // if we find nothing, we can be sure the value were using for EPTP or CR3 is bogus
            var new_entries = InlineExtract(RootPageTable, 3);

            if (new_entries == 0)
            {
                return(0);
            }

            entries += new_entries;
            // a hint for the full count of entries extracted
            RootPageTable.PFNCount = entries;

            return(entries);
        }
Example #3
0
        /// <summary>
        /// An Inline extraction for the page table hierarchy.
        /// Why not let the compiler do it?  I have code clones here?
        ///
        /// I guess so, but we can see/deal with the subtle differences at each level here as we implement them.
        /// e.g. some levels have LargePage bits and we may also lay over other CPU modes here like 32 in 64 etc..
        /// </summary>
        /// <param name="top"></param>
        /// <param name="Level"></param>
        /// <returns></returns>
        long InlineExtract(PFN top, int Level)
        {
            if (Level == 0)
            {
                return(0);
            }

            var entries = 0L;

            var VA = new VIRTUAL_ADDRESS(top.VA);
            //WriteLine($"4: Scanning {top.PageTable:X16}");

            var hPA = HARDWARE_ADDRESS_ENTRY.MinAddr;

            var SLAT = top.SLAT;
            var CR3  = top.PageTable;

            // pull level 4 entries attach level 3
            foreach (var top_sub in top.SubTables)
            {
                // scan each page for the level 4 entry
                var PTE = top_sub.Value.PTE;

                // we don't need to | in the PML4 AO (address offset) since were pulling down the whole page not just the one value
                // and were going to brute force our way through the entire table so this was just confusing things.
                var l3HW_Addr = PTE.NextTableAddress;   // | top_sub.Key.PML4;

                // if we have an EPTP use it and request resolution of the HW_Addr
                if (SLAT != 0)
                {
                    var hl3HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;

                    try { hl3HW_Addr = mem.VirtualToPhysical(SLAT, l3HW_Addr); } catch (Exception) { if (Vtero.DiagOutput)
                                                                                                     {
                                                                                                         WriteLine($"level3: Failed lookup {l3HW_Addr:X16}");
                                                                                                     }
                    }

                    l3HW_Addr = hl3HW_Addr;
                }
                if (SLAT != 0 && (l3HW_Addr == long.MaxValue || l3HW_Addr == long.MaxValue - 1))
                {
                    continue;
                }

                // copy VA since were going to be making changes
                var s3va = new VIRTUAL_ADDRESS(top_sub.Key.Address);
                //WriteLine($"3: Scanning {s3va.Address:X16}");

                top_sub.Value.hostPTE = l3HW_Addr; // cache translated value
                var lvl3_page = new long[512];

                // extract the l3 page for each PTEEntry we had in l4
                try { mem.GetPageForPhysAddr(l3HW_Addr, ref lvl3_page); } catch (Exception) { if (Vtero.DiagOutput)
                                                                                              {
                                                                                                  WriteLine($"level3: Failed lookup {l3HW_Addr:X16}");
                                                                                              }
                }

                if (lvl3_page == null)
                {
                    continue;
                }

                for (uint i3 = 0; i3 < 512; i3++)
                {
                    if (lvl3_page[i3] == 0)
                    {
                        continue;
                    }

                    var l3PTE = new HARDWARE_ADDRESS_ENTRY(lvl3_page[i3]);

                    // adjust VA to match extracted page entries
                    s3va.DirectoryPointerOffset = i3;

                    // save 'PFN' entry into sub-table I should really revisit all these names
                    var l3PFN = new PFN(l3PTE, s3va.Address, CR3, SLAT);
                    top_sub.Value.SubTables.Add(s3va, l3PFN);
                    entries++;

                    /// TODO: Double check if this is a real bit...
                    /// I added it to help weed out some failure cases
                    if (!l3PTE.LargePage)
                    {
                        // get the page that the current l3PFN describes
                        var l2HW_Addr = l3PTE.NextTableAddress;
                        if (SLAT != 0)
                        {
                            var hl2HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                            try { hl2HW_Addr = mem.VirtualToPhysical(SLAT, l2HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput)
                                                                                                                {
                                                                                                                    WriteLine($"level2: Unable to V2P {l3PTE}");
                                                                                                                }
                            }
                            l2HW_Addr = hl2HW_Addr;
                        }
                        // TODO: more error handling of exceptions & bad returns
                        // TODO: support software PTE types
                        if (l2HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                        {
                            continue;
                        }

                        l3PFN.hostPTE = l2HW_Addr;
                        var lvl2_page = new long[512];

                        try { mem.GetPageForPhysAddr(l2HW_Addr, ref lvl2_page); } catch (Exception ex) { if (Vtero.DiagOutput)
                                                                                                         {
                                                                                                             WriteLine($"level2: Failed lookup {l2HW_Addr:X16}");
                                                                                                         }
                        }

                        if (lvl2_page == null)
                        {
                            continue;
                        }

                        // copy VA
                        var s2va = new VIRTUAL_ADDRESS(s3va.Address);
                        //WriteLine($"2: Scanning {s2va.Address:X16}");

                        // extract PTE's for each set entry
                        for (uint i2 = 0; i2 < 512; i2++)
                        {
                            if (lvl2_page[i2] == 0)
                            {
                                continue;
                            }

                            var l2PTE = new HARDWARE_ADDRESS_ENTRY(lvl2_page[i2]);
                            s2va.DirectoryOffset = i2;

                            var l2PFN = new PFN(l2PTE, s2va.Address, CR3, SLAT)
                            {
                                Type = PFNType.Data
                            };
                            l3PFN.SubTables.Add(s2va, l2PFN);
                            entries++;

                            if (!l2PTE.LargePage)
                            {
                                var l1HW_Addr = l2PTE.NextTableAddress;
                                if (SLAT != 0)
                                {
                                    var hl1HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                                    try { hl1HW_Addr = mem.VirtualToPhysical(SLAT, l1HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput)
                                                                                                                        {
                                                                                                                            WriteLine($"level1: Unable to V2P {l2PTE}");
                                                                                                                        }
                                    }

                                    l1HW_Addr = hl1HW_Addr;
                                }
                                if (l1HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                                {
                                    continue;
                                }

                                l2PFN.hostPTE = l1HW_Addr;

                                var lvl1_page = new long[512];

                                try { mem.GetPageForPhysAddr(l1HW_Addr, ref lvl1_page); } catch (Exception ex) { if (Vtero.DiagOutput)
                                                                                                                 {
                                                                                                                     WriteLine($"level1: Failed lookup {l1HW_Addr:X16}");
                                                                                                                 }
                                }

                                if (lvl1_page == null)
                                {
                                    continue;
                                }

                                var s1va = new VIRTUAL_ADDRESS(s2va.Address);
                                //WriteLine($"1: Scanning {s1va.Address:X16}");

                                for (uint i1 = 0; i1 < 512; i1++)
                                {
                                    if (lvl1_page[i1] == 0)
                                    {
                                        continue;
                                    }

                                    var l1PTE = new HARDWARE_ADDRESS_ENTRY(lvl1_page[i1]);
                                    s1va.TableOffset = i1;

                                    var l1PFN = new PFN(l1PTE, s1va.Address, CR3, SLAT)
                                    {
                                        Type = PFNType.Data
                                    };
                                    l2PFN.SubTables.Add(s1va, l1PFN);
                                    entries++;
                                }
                            }
                        }
                    }
                }
            }
            //top.PFNCount += entries;
            return(entries);
        }
Example #4
0
        public IEnumerable<PFN> ExtractNextLevel(PFN PageContext, bool RedundantKernelSpaces, int Level = 4)
        {
            if (PageContext == null) yield break;

            RedundantKernelSpaces = true;

            var SLAT = Root.SLAT;
            var CR3 = Root.CR3;
            var top = Root.Entries;

            VIRTUAL_ADDRESS SubVA = PageContext.VA;
            HARDWARE_ADDRESS_ENTRY PA = PageContext.PTE;

            // get the page that the current PFN describes
            var HW_Addr = PA.NextTableAddress;
            if (SLAT != 0)
            {
                var hHW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                try { hHW_Addr = mem.VirtualToPhysical(SLAT, HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput) WriteLine($"level{Level}: Unable to V2P {HW_Addr}"); }
                HW_Addr = hHW_Addr;

                if (HW_Addr == long.MaxValue || HW_Addr == long.MaxValue - 1)
                    yield break;
            }

            if (PageContext.PTE.LargePage && Level <= 1)
            {
                // cyclic 
                PageContext.SubTables.Add(PageContext.VA, PageContext);
                yield break;
            }

            long[] page = new long[512];
            bool ReadData = false;
            // copy VA since were going to be making changes

            var valueRead = mem.GetPageForPhysAddr(HW_Addr, ref page, ref ReadData);

            if (!ReadData || page == null)
                yield break;

            var dupVA = new VIRTUAL_ADDRESS(SubVA.Address);

            for (int i = 0; i < 512; i++)
            {
                if (!RedundantKernelSpaces && i >= MagicNumbers.KERNEL_PT_INDEX_START_USUALLY)
                    continue;

                if (page[i] == 0)
                    continue;

                switch (Level)
                {
                    case 4:
                        dupVA.PML4 = i;
                        break;
                    case 3:
                        dupVA.DirectoryPointerOffset = i;
                        break;
                    case 2:
                        dupVA.DirectoryOffset = i;
                        break;
                    case 1:
                        dupVA.TableOffset = i;
                        break;
                    default:
                        break;
                }

                var pfn = new PFN
                {
                    VA = new VIRTUAL_ADDRESS(dupVA.Address),
                    PTE = new HARDWARE_ADDRESS_ENTRY(page[i])
                };
                    
                PageContext.SubTables.Add(
                        pfn.VA,
                        pfn);

                EntriesParsed++;
                yield return pfn;
            }
            yield break;
        }
Example #5
0
        long FillTable(VIRTUAL_ADDRESS VA, int PageIndex, long CR3, bool OnlyUserSpace = false)
        {
            var entries = 0L;
            var PageTable = new Dictionary<VIRTUAL_ADDRESS, PFN>();
            // We can just pick up the top level page to speed things up 
            // we've already visited this page so were not going to waste time looking up the VA->PA
            //var page = new long[512];
            //mem.GetPageFromFileOffset(FileOffset, ref page);

            // clear out the VA for the other indexes since were looking at the top level
            VA.Address = 0;

            foreach (var kvp in DP.TopPageTablePage)
            {
                // Only extract user portion, kernel will be mostly redundant
                if(OnlyUserSpace && kvp.Key >= 256)
                    continue;

                // were at the top level (4th)
                VA.PML4 = kvp.Key;

                var pfn = new PFN(kvp.Value, VA.Address, CR3, DP.vmcs == null ? 0 : DP.vmcs.EPTP);
                PageTable.Add(VA, pfn);
                entries++;
            }

            // simulated top entry
            RootPageTable = new PFN(DP.TopPageTablePage[PageIndex], VA.Address, CR3, DP.vmcs == null ? 0 : DP.vmcs.EPTP)
            {
                SubTables = PageTable
            };

            // descend the remaining levels
            // if we find nothing, we can be sure the value were using for EPTP or CR3 is bogus
            var new_entries = InlineExtract(RootPageTable, 3);
            if (new_entries == 0)
                return 0;

            entries += new_entries;
            // a hint for the full count of entries extracted
            RootPageTable.PFNCount = entries;
            
            return entries;
        }
Example #6
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;

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

            // large page read
            if (entry != null && entry.PTE.LargePage)
            {
                block = new byte[MagicNumbers.LARGE_PAGE_SIZE];
                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 byte[MagicNumbers.PAGE_SIZE];
                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) != MagicNumbers.PAGE_SIZE)
                {
                    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 byte[MagicNumbers.PAGE_SIZE]; // 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   += MagicNumbers.PAGE_SIZE;

                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);
        }
Example #7
0
        // TODO: Remove this call, only seen called by legacy stuff
        public long FillTable(bool RedundantKernelSpaces, int depth = 4)
        {
            var entries    = 0L;
            var PageTables = new Dictionary <VIRTUAL_ADDRESS, PFN>();

            KernelSpace = RedundantKernelSpaces;
            // clear out the VA for the other indexes since were looking at the top level
            VIRTUAL_ADDRESS VA;

            VA.Address = 0;

            // making use of the cached top level
            foreach (var kvp in DP.TopPageTablePage)
            {
                // Only extract user portion, kernel will be mostly redundant
                if (!RedundantKernelSpaces && kvp.Key >= (MagicNumbers.KERNEL_PT_INDEX_START_USUALLY - 1))
                {
                    continue;
                }

                // 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
                if (MemorizeTables)
                {
                    PageTables.Add(VA, pfn);
                }

                // We will only do one level if were not buffering
                if (depth > 1)
                {
                    foreach (var DirectoryPointerOffset in ExtractNextLevel(pfn, 3))
                    {
                        if (DirectoryPointerOffset == null)
                        {
                            continue;
                        }
                        if (depth > 2 /* && !DirectoryPointerOffset.PTE.LargePage */)
                        {
                            foreach (var DirectoryOffset in ExtractNextLevel(DirectoryPointerOffset, 2))
                            {
                                if (DirectoryOffset == null)
                                {
                                    continue;
                                }

                                if (depth > 3 /* && !DirectoryOffset.PTE.LargePage && EnvLimits.MAX_PageTableEntriesToScan > entries */)
                                {
                                    foreach (var TableOffset in ExtractNextLevel(DirectoryOffset, 1))
                                    {
                                        if (TableOffset == null)
                                        {
                                            continue;
                                        }
                                        entries++;
                                    }
                                }
                                entries++;
                            }
                        }
                        entries++;
                    }
                }
                entries++;
            }

            if (MemorizeTables)
            {
                Root.Entries = new PFN()
                {
                    SubTables = PageTables
                }
            }
            ;

            // InlineExtract may be faster but it's memory requirement is higher which was a problem
            // when analyzing 64GB+ dumps (yes InVtero.net handles very big memory)++
#if FALSE
            // descend the remaining levelsPageTableEntries
            // if we find nothing, we can be sure the value were using for EPTP or CR3 is bogus
            var new_entries = InlineExtract(Root);
            if (new_entries == 0)
            {
                return(0);
            }

            entries += new_entries;
#endif

            EntriesParsed += entries;
            DepthParsed    = depth;
            // a hint for the full count of entries extracted
            Root.Count = entries;

            return(entries);
        }
Example #8
0
        /// <summary>
        /// An Inline extraction for the page table hierarchy.
        /// Why not let the compiler do it?  I have code clones here?
        /// 
        /// I guess so, but we can see/deal with the subtle differences at each level here as we implement them.
        /// e.g. some levels have LargePage bits and we may also lay over other CPU modes here like 32 in 64 etc..
        /// </summary>
        /// <param name="top"></param>
        /// <param name="Level"></param>
        /// <returns></returns>
        long InlineExtract(PFN top, int Level)
        {
            if (Level == 0)
                return 0;

            var entries = 0L;

            var VA = new VIRTUAL_ADDRESS(top.VA);
            //WriteLine($"4: Scanning {top.PageTable:X16}");

            var hPA = HARDWARE_ADDRESS_ENTRY.MinAddr;

            var SLAT = top.SLAT;
            var CR3 = top.PageTable;

            // pull level 4 entries attach level 3
            foreach (var top_sub in top.SubTables)
            {
                // scan each page for the level 4 entry
                var PTE = top_sub.Value.PTE;

                // we don't need to | in the PML4 AO (address offset) since were pulling down the whole page not just the one value
                // and were going to brute force our way through the entire table so this was just confusing things.
                var l3HW_Addr = PTE.NextTableAddress   ;// | top_sub.Key.PML4;

                // if we have an EPTP use it and request resolution of the HW_Addr
                if (SLAT != 0)
                {
                    var hl3HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;

                    try { hl3HW_Addr = mem.VirtualToPhysical(SLAT, l3HW_Addr); } catch (Exception) { if (Vtero.DiagOutput) WriteLine($"level3: Failed lookup {l3HW_Addr:X16}"); }

                    l3HW_Addr = hl3HW_Addr;
                }
                if (SLAT != 0 && (l3HW_Addr == long.MaxValue || l3HW_Addr == long.MaxValue-1))
                    continue;

                // copy VA since were going to be making changes
                var s3va = new VIRTUAL_ADDRESS(top_sub.Key.Address);
                //WriteLine($"3: Scanning {s3va.Address:X16}");

                top_sub.Value.hostPTE = l3HW_Addr; // cache translated value
                var lvl3_page = new long[512];

                // extract the l3 page for each PTEEntry we had in l4
                try { mem.GetPageForPhysAddr(l3HW_Addr, ref lvl3_page); } catch (Exception) { if (Vtero.DiagOutput) WriteLine($"level3: Failed lookup {l3HW_Addr:X16}"); }

                if (lvl3_page == null)
                    continue;

                for (uint i3 = 0; i3 < 512; i3++)
                {
                    if (lvl3_page[i3] == 0)
                        continue;

                    var l3PTE = new HARDWARE_ADDRESS_ENTRY(lvl3_page[i3]);

                    // adjust VA to match extracted page entries
                    s3va.DirectoryPointerOffset = i3;

                    // save 'PFN' entry into sub-table I should really revisit all these names
                    var l3PFN = new PFN(l3PTE, s3va.Address, CR3, SLAT);
                    top_sub.Value.SubTables.Add(s3va, l3PFN);
                    entries++;

                    /// TODO: Double check if this is a real bit... 
                    /// I added it to help weed out some failure cases
                    if (!l3PTE.LargePage)
                    {
                        // get the page that the current l3PFN describes
                        var l2HW_Addr = l3PTE.NextTableAddress;
                        if (SLAT != 0)
                        {
                            var hl2HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                            try { hl2HW_Addr = mem.VirtualToPhysical(SLAT, l2HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput) WriteLine($"level2: Unable to V2P {l3PTE}"); }
                            l2HW_Addr = hl2HW_Addr;
                        }
                        // TODO: more error handling of exceptions & bad returns
                        // TODO: support software PTE types 
                        if (l2HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                            continue;

                        l3PFN.hostPTE = l2HW_Addr;
                        var lvl2_page = new long[512];

                        try { mem.GetPageForPhysAddr(l2HW_Addr, ref lvl2_page); } catch (Exception ex) { if (Vtero.DiagOutput) WriteLine($"level2: Failed lookup {l2HW_Addr:X16}"); }

                        if (lvl2_page == null)
                            continue;

                        // copy VA 
                        var s2va = new VIRTUAL_ADDRESS(s3va.Address);
                        //WriteLine($"2: Scanning {s2va.Address:X16}");

                        // extract PTE's for each set entry
                        for (uint i2 = 0; i2 < 512; i2++)
                        {
                            if (lvl2_page[i2] == 0)
                                continue;

                            var l2PTE = new HARDWARE_ADDRESS_ENTRY(lvl2_page[i2]);
                            s2va.DirectoryOffset = i2;

                            var l2PFN = new PFN(l2PTE, s2va.Address, CR3, SLAT) { Type = PFNType.Data };
                            l3PFN.SubTables.Add(s2va, l2PFN);
                            entries++;

                            if (!l2PTE.LargePage)
                            {
                                var l1HW_Addr = l2PTE.NextTableAddress;
                                if (SLAT != 0)
                                {
                                    var hl1HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                                    try { hl1HW_Addr = mem.VirtualToPhysical(SLAT, l1HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput) WriteLine($"level1: Unable to V2P {l2PTE}"); }

                                    l1HW_Addr = hl1HW_Addr;
                                }
                                if (l1HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                                    continue;

                                l2PFN.hostPTE = l1HW_Addr;

                                var lvl1_page = new long[512];

                                try { mem.GetPageForPhysAddr(l1HW_Addr, ref lvl1_page); } catch (Exception ex) { if(Vtero.DiagOutput) WriteLine($"level1: Failed lookup {l1HW_Addr:X16}"); }

                                if (lvl1_page == null)
                                    continue;

                                var s1va = new VIRTUAL_ADDRESS(s2va.Address);
                                //WriteLine($"1: Scanning {s1va.Address:X16}");

                                for (uint i1 = 0; i1 < 512; i1++)
                                {
                                    if (lvl1_page[i1] == 0)
                                        continue;

                                    var l1PTE = new HARDWARE_ADDRESS_ENTRY(lvl1_page[i1]);
                                    s1va.TableOffset = i1;

                                    var l1PFN = new PFN(l1PTE, s1va.Address, CR3, SLAT) { Type = PFNType.Data };
                                    l2PFN.SubTables.Add(s1va, l1PFN);
                                    entries++;
                                }
                            }
                        }
                    }
                }
            }
            //top.PFNCount += entries;
            return entries;
        }
Example #9
0
        public IEnumerable <PFN> ExtractNextLevel(PFN PageContext, int Level = 4, bool RedundantKernelSpaces = false)
        {
            if (PageContext == null)
            {
                yield break;
            }

            var SLAT = Root.SLAT;
            var CR3  = Root.CR3;
            var top  = Root.Entries;

            VIRTUAL_ADDRESS        SubVA = PageContext.VA;
            HARDWARE_ADDRESS_ENTRY PA    = PageContext.PTE;

            // get the page that the current PFN describes
            var HW_Addr = PA.NextTableAddress;

            if (SLAT != 0)
            {
                var hHW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                try { hHW_Addr = mem.VirtualToPhysical(SLAT, HW_Addr); } catch (Exception ex) { if (Vtero.DiagOutput)
                                                                                                {
                                                                                                    WriteLine($"level{Level}: Unable to V2P {HW_Addr}");
                                                                                                }
                }
                HW_Addr = hHW_Addr;

                if (HW_Addr == long.MaxValue || HW_Addr == long.MaxValue - 1)
                {
                    yield break;
                }
            }

            if (PageContext.PTE.LargePage && Level <= 1)
            {
                // cyclic
                if (MemorizeTables)
                {
                    PageContext.SubTables.Add(PageContext.VA, PageContext);
                }
                yield break;
            }

            long[] page     = new long[512];
            bool   ReadData = false;
            // copy VA since were going to be making changes

            var valueRead = mem.GetPageForPhysAddr(HW_Addr, ref page, ref ReadData);

            if (!ReadData || page == null)
            {
                yield break;
            }

            // if every entry is exactially the same bail out
            var check1 = page[0];

            if (Array.TrueForAll <long>(page, (entry) => entry == check1))
            {
                yield break;
            }

            var dupVA = new VIRTUAL_ADDRESS(SubVA.Address);

            for (int i = 0; i < 512; i++)
            {
                // kernel indexes are only relevant on the top level
                if (Level == 4 && (!RedundantKernelSpaces && i >= MagicNumbers.KERNEL_PT_INDEX_START_USUALLY))
                {
                    continue;
                }

                if (page[i] == 0)
                {
                    continue;
                }

                switch (Level)
                {
                case 4:
                    dupVA.PML4 = i;
                    break;

                case 3:
                    dupVA.DirectoryPointerOffset = i;
                    break;

                case 2:
                    dupVA.DirectoryOffset = i;
                    break;

                case 1:
                    dupVA.TableOffset = i;
                    break;

                default:
                    break;
                }

                var pfn = new PFN
                {
                    VA  = new VIRTUAL_ADDRESS(dupVA.Address),
                    PTE = new HARDWARE_ADDRESS_ENTRY(page[i])
                };

                if (MemorizeTables)
                {
                    PageContext.SubTables.Add(
                        pfn.VA,
                        pfn);
                }

                EntriesParsed++;
                yield return(pfn);
            }
            yield break;
        }
Example #10
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 #11
0
        long InlineExtract(PFN top, int Level)
        {
            if (Level == 0)
                return 0;

            var entries = 0L;

            var VA = new VIRTUAL_ADDRESS(top.VA);
            var hPA = HARDWARE_ADDRESS_ENTRY.MinAddr;

            var CR3 = top.PageTable;
            var SLAT = top.SLAT;

            // pull level 4 entries attach level 3
            foreach (var top_sub in top.SubTables)
            {
                // scan each page for the level 4 entry
                var PTE = top_sub.Value.PTE;

                var l3HW_Addr = PTE.NextTableAddress | top_sub.Key.PML4;

                // if we have an EPTP use it and request resolution of the HW_Addr
                if (SLAT != 0)
                {
                    var hl3HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                    hl3HW_Addr = mem.VirtualToPhysical(SLAT, l3HW_Addr);
                    l3HW_Addr = hl3HW_Addr;
                }
                if (l3HW_Addr == long.MaxValue)
                    continue;

                // copy VA since were going to be making changes
                var s3va = new VIRTUAL_ADDRESS(top_sub.Key.Address);

                top_sub.Value.hostPTE = l3HW_Addr; // cache translated value
                var lvl3_page = new long[512];

                // extract the l3 page for each PTEEntry we had in l4
                try { mem.GetPageForPhysAddr(l3HW_Addr, ref lvl3_page); } catch (Exception) { WriteLine($"level3: Failed lookup {l3HW_Addr:X16}"); }

                if (lvl3_page == null)
                    continue;

                for (uint i3 = 0; i3 < 512; i3++)
                {
                    if (lvl3_page[i3] == 0)
                        continue;

                    var l3PTE = new HARDWARE_ADDRESS_ENTRY(lvl3_page[i3]);

                    // adjust VA to match extracted page entries
                    s3va.DirectoryPointerOffset = i3;

                    // save 'PFN' entry into sub-table I should really revisit all these names
                    var l3PFN = new PFN(l3PTE, s3va.Address, CR3, SLAT);
                    top_sub.Value.SubTables.Add(s3va, l3PFN);
                    entries++;

                    // get the page that the current l3PFN describes
                    var l2HW_Addr = l3PTE.NextTableAddress;
                    if (SLAT != 0)
                    {
                        var hl2HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                        try { hl2HW_Addr = mem.VirtualToPhysical(SLAT, l2HW_Addr); } catch(Exception ex) { WriteLine($"level2: Unable to V2P {l3PTE}"); }
                        l2HW_Addr = hl2HW_Addr;
                    }
                    // TODO: more error handlng of exceptions & bad return's
                    // TODO: support software PTE types 
                    if (l2HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                        continue;

                    l3PFN.hostPTE = l2HW_Addr;
                    var lvl2_page = new long[512];

                    try { mem.GetPageForPhysAddr(l2HW_Addr, ref lvl2_page); } catch (Exception ex) { WriteLine($"level2: Failed lookup {l2HW_Addr:X16}"); }

                    if (lvl2_page == null)
                        continue;

                    // copy VA 
                    var s2va = new VIRTUAL_ADDRESS(s3va.Address);
                    // extract PTE's for each set entry
                    for (uint i2 = 0; i2 < 512; i2++)
                    {
                        if (lvl2_page[i2] == 0)
                            continue;

                        var l2PTE = new HARDWARE_ADDRESS_ENTRY(lvl2_page[i2]);
                        s2va.DirectoryOffset = i2;

                        var l2PFN = new PFN(l2PTE, s2va.Address, CR3, SLAT);
                        l3PFN.SubTables.Add(s2va, l2PFN);
                        entries++;

                        if (!l2PTE.LargePage)
                        {

                            var l1HW_Addr = l2PTE.NextTableAddress;
                            if (SLAT != 0)
                            {
                                var hl1HW_Addr = HARDWARE_ADDRESS_ENTRY.MaxAddr;
                                try { hl1HW_Addr = mem.VirtualToPhysical(SLAT, l1HW_Addr); } catch (Exception ex) { WriteLine($"level1: Unable to V2P {l2PTE}"); }

                                l1HW_Addr = hl1HW_Addr;
                            }
                            if (l1HW_Addr == HARDWARE_ADDRESS_ENTRY.MaxAddr)
                                continue;

                            l2PFN.hostPTE = l1HW_Addr;

                            var lvl1_page = new long[512];

                            try { mem.GetPageForPhysAddr(l1HW_Addr, ref lvl1_page); } catch (Exception ex) { WriteLine($"level1: Failed lookup {l1HW_Addr:X16}"); }

                            if (lvl1_page == null)
                                continue;

                            var s1va = new VIRTUAL_ADDRESS(s2va.Address);

                            for (uint i1 = 0; i1 < 512; i1++)
                            {
                                if (lvl1_page[i1] == 0)
                                    continue;

                                var l1PTE = new HARDWARE_ADDRESS_ENTRY(lvl1_page[i1]);
                                s1va.TableOffset = i1;

                                var l1PFN = new PFN(l1PTE, s1va.Address, CR3, SLAT);
                                l2PFN.SubTables.Add(s1va, l1PFN);
                                entries++;
                            }
                        }
                    }
                }
            }
            top.PFNCount += entries;
            return entries;
        }
Example #12
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 #13
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;
        }
Example #14
0
        public byte[] HashRange(VIRTUAL_ADDRESS KEY, PFN VALUE)
        {
            var rv = new byte[1];

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

            var tigger = new Tiger();
            tigger.Initialize();


            //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 rv;

            if (VALUE.PTE.LargePage)
            {
                bool GoodRead = false;
                // 0x200 * 4kb = 2MB
                for (int i = 0; i < 0x200; i++)
                {
                    MemAccess.GetPageForPhysAddr(VALUE.PTE, ref block, ref GoodRead);
                    VALUE.PTE.PTE += 0x1000;
                    if (!GoodRead)
                        block = new long[0x200];

                    Buffer.BlockCopy(block, 0, bpage, 0, 4096);
                    rv = tigger.ComputeHash(bpage);
                }
                return rv;
            }
            else
            {
                try { MemAccess.GetPageForPhysAddr(VALUE.PTE, ref block); } catch (Exception ex) { }

                if (block != null)
                {
                    Buffer.BlockCopy(block, 0, bpage, 0, 4096);
                    rv = tigger.ComputeHash(bpage);
                }
            }

            return rv;
        }
Example #15
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;
                //}
            //}
        }
Example #16
0
        // TODO: Move this to Dumper.cs

        /// <summary>
        /// Memory Dump routines
        /// </summary>
        /// <param name="AS_ToDump"></param>
        public void DumpASToFile(IDictionary<int, List<DetectedProc>> AS_ToDump = null)
        {
            var DumpList = AS_ToDump;
            if(DumpList == null)
            {
                DumpList = new Dictionary<int, List <DetectedProc>> ();
                foreach(var g in ASGroups)
                {
                    DumpList[g.Key] = new List<DetectedProc>();

                    var p = from px in g.Value
                            orderby px.CR3Value
                            select px;

                    foreach (var pp in p)
                        DumpList[pp.AddressSpaceID].Add(pp);
                }
            }

            List <KeyValuePair <VIRTUAL_ADDRESS, PFN>> MemRanges = null;
            List<string> DumpedToDisk = new List<string>();
            Stack<PFN> PFNStack = new Stack<PFN>();
            // instance member
            ContigSize = -1;

            ForegroundColor = ConsoleColor.Gray;

            string LastDumped = string.Empty;
            int cntDumped = 0;
            WriteLine($"{Environment.NewLine} Address spaces resolved.  Dump method starting. {Environment.NewLine}");
            //using (var memAxs = new Mem(MemFile, null, DetectedDesc))
            var memAxs = MemAccess;
            {
                memAxs.OverrideBufferLoadInput = true;

TripleBreak:

                int asID=0;
                foreach(var AS in DumpList)
                if(DumpList[AS.Key] != null && DumpList[AS.Key].Count() > 0)
                    if(DumpList[AS.Key].Count() > 1)
                        WriteColor(ConsoleColor.Green, $"[{AS.Key}] Contains {DumpList[AS.Key].Count()} entries EPTP/Kernels shared {DumpList[AS.Key][0]}");
                    else
                        WriteColor(ConsoleColor.Yellow, $"[{AS.Key}] Contains {DumpList[AS.Key].Count()} entries EPTP/Kernels shared {DumpList[AS.Key][0]}");

                bool validInput = false;
                do
                {
                    ForegroundColor = ConsoleColor.White;
                    Write("Select an address space: ");
                    var ASselect = ReadLine();
                    validInput = int.TryParse(ASselect, out asID);
                    if (!validInput)
                        WriteLine("just enter the number that coincides with the address space you want to investigate.");
                    if (!DumpList.ContainsKey(asID))
                        validInput = false;

                } while (!validInput);

                WriteColor(ConsoleColor.Green, $"Loading address space entries based on {DumpList[asID][0]}");

                var ToDump = DumpList[asID];

                // sort for convince
                ToDump.Sort((x, y) => { if (x.CR3Value < y.CR3Value) return -1; else if (x.CR3Value > y.CR3Value) return 1; else return 0; });

                while (true)
                {
DoubleBreak:
                    // prompt user
                    for (int i = 0; i < ToDump.Count; i++)
                    {
                        var vmcs = ToDump[i].vmcs == null ? 0 : ToDump[i].vmcs.EPTP;

                        if (ToDump[i].PT == null)
                            PageTable.AddProcess(ToDump[i], memAxs, true, 1);

                        WriteColor(ConsoleColor.Magenta, $"{i} VMCS:{vmcs:X} Process:{ToDump[i].CR3Value:X} (top level) {ToDump[i].PT.Root.Count} type {ToDump[i].PageTableType} group {ToDump[i].Group}");
                    }

                    validInput = false;
                    int procId = 0;
                    do
                    {
                        ForegroundColor = ConsoleColor.White;
                        Write("Select a process to dump: ");
                        var selection = ReadLine();
                        validInput = int.TryParse(selection, out procId);
                        if (!validInput)
                            WriteLine("just enter the number 0 or 1 or 2 or ... that coincides with the process you want to investigate.");

                    } while (!validInput);

                    WriteColor(ConsoleColor.Gray, $"Selected process {procId} {ToDump[procId]}");
                    var tdp = ToDump[procId];

                    var saveLoc = Path.Combine(Path.GetDirectoryName(MemFile), Path.GetFileName(MemFile) + ".");
                    var table = tdp.PT.Root.Entries;
                    bool fKeepGoing = true;

                    while (fKeepGoing)
                    {
                        WriteColor(ConsoleColor.Gray, $"{Environment.NewLine}Listing ranges for {tdp}, {table.PFNCount} entries scanned.");

                        int parse = -1, level = 4;
                        PFN next_table = new PFN();
                        Dictionary<VIRTUAL_ADDRESS, PFN> TableEntries;
                        Dictionary<VIRTUAL_ADDRESS, PFN> LastTableEntries = null;
                        do
                        {
                            TableEntries = table.SubTables;
                            // If we have 0 entries, ensure there really are none and we did
                            // not optimize out pre-buffering everything
                            if (TableEntries.Count() == 0)
                                foreach (var pfn in tdp.PT.ExtractNextLevel(table, true, level)) ;

                            if (TableEntries.Count() == 0)
                            {
                                WriteColor(ConsoleColor.Yellow, $"Entry {parse}:{table.VA}{table.PTE} contains no in-memory pages addressable to this process.");

                                if(LastTableEntries != null)
                                    TableEntries = LastTableEntries;
                                if (level < 4)
                                    level++;

                                if (PFNStack.Count() > 0)
                                    table = PFNStack.Pop();
                                else
                                {
                                    table = tdp.PT.Root.Entries;
                                    level = 4;
                                    TableEntries = table.SubTables;
                                }
                            }

                            var dict_keys = TableEntries.Keys.ToArray();
                            for (int r = 0; r < TableEntries.Count(); r++)
                            {
                                var dict_Val = TableEntries[dict_keys[r]];
                                
                                WriteColor((level & 1) == 1 ? ConsoleColor.Cyan : ConsoleColor.Green, $"{r} Virtual: {dict_keys[r]} \t Physical: {dict_Val.PTE}");
                            }

                            ForegroundColor = ConsoleColor.White;
                            Write($"command ({level}): ");
                            var userSelect = ReadLine().ToLower();

                            if (string.IsNullOrWhiteSpace(userSelect))
                                parse = -1;
                            else if(char.IsLetter(userSelect[0]))
                                switch(userSelect)
                                {
                                    case "u":
                                        if (PFNStack.Count() > 0)
                                        {
                                            table = PFNStack.Pop();
                                            level++;
                                        }
                                        else {
                                            WriteColor(ConsoleColor.Yellow, "Can not go any higher");
                                            table = tdp.PT.Root.Entries;
                                            level = 4;
                                        }
                                        continue;
                                    case "l":
                                        PrintLastDumped(DumpedToDisk);
                                        continue;
                                    case "x":
                                        Environment.Exit(0);
                                        break;
                                    case "p":
                                        goto DoubleBreak;
                                    case "s":
                                        goto TripleBreak;
                                    case "h":
                                    case "r":
                                        ReScanNextLevel(tdp);
                                        break;
                                    case "d":
                                        ReScanNextLevel(tdp, true);
                                        break;
                                    case "a":
                                        AddProcessPageTable(tdp, memAxs);
                                        break;
                                    default:
                                        REPLhelp();
                                        continue;
                                } 
                            else
                                int.TryParse(userSelect, out parse);

                            // extract the key that the user index is referring to and reassign table

                            if (parse >= 0)
                            {
                                PFNStack.Push(table);
                                try
                                {
                                    next_table = TableEntries[TableEntries.Keys.ToArray()[parse]];
                                }
                                catch (Exception ex) { WriteColor(ConsoleColor.Red, $"Exception accessing page table, try again... {ex.ToString()}"); continue; }
                                table = next_table;
                            }
                            if (parse < 0)
                                break;

                            level--;
                            LastTableEntries = TableEntries;
                        } while (level > 0);


                        WriteColor(ConsoleColor.Gray, $"Writing out data into the same folder as the input: {Path.GetDirectoryName(MemFile)}");


                        if (parse < 0)
                        {
                            switch (level)
                            {
                                case 4:
                                    MemRanges = TableEntries.SelectMany(x => x.Value.SubTables).SelectMany(y => y.Value.SubTables).SelectMany(z => z.Value.SubTables).ToList();
                                    break;
                                case 3:
                                    MemRanges = TableEntries.SelectMany(x => x.Value.SubTables).SelectMany(y => y.Value.SubTables).ToList();
                                    break;
                                case 2:
                                    MemRanges = TableEntries.SelectMany(x => x.Value.SubTables).ToList();
                                    break;
                                case 1:
                                default:
                                    MemRanges = TableEntries.ToList();
                                    break;
                            }

                            foreach (var mr in MemRanges)
                            {
                                LastDumped = WriteRange(mr.Key, mr.Value, saveLoc, memAxs);
                                DumpedToDisk.Add(LastDumped);
                                cntDumped++;
                            }
                        }
                        else
                        {
                            var a_range = new KeyValuePair<VIRTUAL_ADDRESS, PFN>(next_table.VA, next_table);
                            LastDumped = WriteRange(a_range.Key, a_range.Value, saveLoc, memAxs);
                            DumpedToDisk.Add(LastDumped);
                            cntDumped++;
                        }

                        Write($"All done, last written file {LastDumped} of {cntDumped} so far.  KeepGoing? (y)");
                        var answer = ReadKey();
                        if (answer.Key == ConsoleKey.N)
                            fKeepGoing = false;
                    }
                }
            }
        }
Example #17
0
        public long FillTable(bool RedundantKernelSpaces, int depth = 4)
        {
            var entries = 0L;
            var PageTables = new Dictionary<VIRTUAL_ADDRESS, PFN>();

            KernelSpace = RedundantKernelSpaces;
            // clear out the VA for the other indexes since were looking at the top level
            VIRTUAL_ADDRESS VA;
            VA.Address = 0;


            int level = 3;
            foreach (var kvp in DP.TopPageTablePage)
            {
                // Only extract user portion, kernel will be mostly redundant
                if(!RedundantKernelSpaces && kvp.Key >= 255)
                    continue;

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

                // We will only do one level if were not buffering
                if(depth > 1)
                foreach(var DirectoryPointerOffset in ExtractNextLevel(pfn, KernelSpace, level))
                {
                    if (DirectoryPointerOffset == null) continue;
                    if(depth > 2 /* && !DirectoryPointerOffset.PTE.LargePage */)
                    foreach (var DirectoryOffset in ExtractNextLevel(DirectoryPointerOffset, KernelSpace, level-1))
                    {   
                        if (DirectoryOffset == null) continue;

                        if(depth > 3 /* && !DirectoryOffset.PTE.LargePage && EnvLimits.MAX_PageTableEntriesToScan > entries */)
                        foreach (var TableOffset in ExtractNextLevel(DirectoryOffset, KernelSpace, level - 2))
                        {
                            if (TableOffset == null) continue;
                            entries++;
                        }
                        entries++;
                    }
                    entries++;
                }
                entries++;
            }

            Root.Entries = new PFN()
            {
                SubTables = PageTables
            };

            // InlineExtract may be faster but it's memory requirement is higher which was a problem
            // when analyzing 64GB+ dumps (yes InVtero.net handles very big memory)++
#if FALSE
            

            // descend the remaining levelsPageTableEntries
            // if we find nothing, we can be sure the value were using for EPTP or CR3 is bogus
            var new_entries = InlineExtract(Root);
            if (new_entries == 0)
                return 0;

            entries += new_entries;
#endif

            EntriesParsed += entries;
            DepthParsed = depth;
            // a hint for the full count of entries extracted
            Root.Count = entries;
            
            return entries;
        }