public GetPageForPhysAddr ( |
||
PAddr | byte address an address contained in the block | |
block | long | array to be filled |
리턴 | long |
/// <summary> /// /// </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 long Run(long Start = 0, long Stop = 0xFFFFffffFFFF) { DetectedFragments = new ConcurrentDictionary <long, VAScanType>(); // convert index to an address // then add start to it long i = Start; var block = new long[0x200]; // 0x200 * 8 = 4k while (i < Stop) { foreach (var scanner in CheckMethods) { HARDWARE_ADDRESS_ENTRY locPhys = HARDWARE_ADDRESS_ENTRY.MinAddr; if (DPContext.vmcs != null) { //locPhys = MemoryBank[j].VirtualToPhysical(DPContext.vmcs.EPTP, DPContext.CR3Value, i); locPhys = BackingBlocks.VirtualToPhysical(DPContext.vmcs.EPTP, DPContext.CR3Value, i); } else { //locPhys = MemoryBank[j].VirtualToPhysical(DPContext.CR3Value, i); locPhys = BackingBlocks.VirtualToPhysical(DPContext.CR3Value, i); } var Curr = i; i += 0x1000; if (HARDWARE_ADDRESS_ENTRY.IsBadEntry(locPhys)) { continue; } bool GotData = false; BackingBlocks.GetPageForPhysAddr(locPhys, ref block, ref GotData, false); if (!GotData) { continue; } var scan_detect = scanner(Curr, block); if (scan_detect != VAScanType.UNDETERMINED) { DetectedFragments.TryAdd(Curr, scan_detect); if (Vtero.VerboseOutput) { Console.WriteLine($"Detected PE @ VA {Curr:X}"); } } } } return(DetectedFragments.Count()); }
public override int Read(byte[] buffer, int offset, int count) { int CurrOff = 0; // figure out how many pages we need int PageCount = count / 4096; if ((count & 0xfff) != 0) { PageCount++; } int rv = PageCount; if (offset != 0) { throw new NotImplementedException("Sub-Page reads not supported, use BufferedStream to even out your access pattern."); } while (PageCount > 0) { // block may be set to null by the GetPageForPhysAddr call, so we need to remake it every time through... var lblock = new long[0x200]; // 0x200 * 8 = 4k PageCount--; //fixed (void* lp = lblock, bp = buffer) //{ try { if (MemBlockStorage.GetPageForPhysAddr(CurrPage.PTE, ref lblock) == MagicNumbers.BAD_VALUE_READ) { continue; } Buffer.BlockCopy(lblock, CurrOff / 4, buffer, CurrOff, 4096); //Buffer.MemoryCopy((byte*)lp + CurrOff, (byte*)bp + CurrOff, 4096, 4096); } finally { CurrOff += 0x1000; } //} } return((rv - PageCount) * 0x1000); }
public override int Read(byte[] buffer, int offset, int count) { bool GoodRead = false; int CurrOff = 0; // figure out how many pages we need int PageCount = count / MagicNumbers.PAGE_SIZE; if ((count & 0xfff) != 0) { PageCount++; } int rv = PageCount; if (offset != 0) { throw new NotImplementedException("Sub-Page reads not supported, use BufferedStream to even out your access pattern."); } var lblock = new long[0x200]; // 0x200 * 8 = 4k while (PageCount > 0) { PageCount--; MemBlockStorage.GetPageForPhysAddr(CurrPage.PTE, ref lblock, ref GoodRead); if (!GoodRead) { continue; } Buffer.BlockCopy(lblock, CurrOff / 4, buffer, CurrOff, MagicNumbers.PAGE_SIZE); CurrOff += MagicNumbers.PAGE_SIZE; } return((rv - PageCount) * MagicNumbers.PAGE_SIZE); }
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); } } } } } } }
/// <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); }
// 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; //} //} }
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); } } } } } } }