/// <summary> /// The VMCS scan is based on the LINK pointer, abort code and CR3 register /// We later isolate the EPTP based on constraints for that pointer /// </summary> /// <param name="xoffset"></param> /// <returns>true if the page being scanned is a candidate</returns> public bool VMCS(long xoffset) { var RevID = (REVISION_ID)(block[0] & 0xffffffff); var Acode = (VMCS_ABORT)((block[0] >> 32) & 0x7fffffff); var KnownAbortCode = false; var KnownRevision = false; var Candidate = false; var LinkCount = 0; var Neg1 = -1; if (ScanForVMCSset == null) throw new NullReferenceException("Entered VMCS callback w/o having found any VMCS, this is a second pass Func"); // this might be a bit micro-opt-pointless ;) KnownRevision = typeof(REVISION_ID).GetEnumValues().Cast<REVISION_ID>().Any(x => x == RevID); KnownAbortCode = typeof(VMCS_ABORT).GetEnumValues().Cast<VMCS_ABORT>().Any(x => x == Acode); // TODO: Relax link pointer check. Possible when VMCS is shadow, then the link pointer is configured, retest this detection/nesting etc.. // Find a 64bit value for link ptr for (int l = 0; l < block.Length; l++) { if (block[l] == Neg1) LinkCount++; // too many if (LinkCount > 32) return false; } // Currently, we expect to have 1 Link pointer at least if (LinkCount == 0 || !KnownAbortCode) return false; // curr width of line to screen Candidate = false; Parallel.For(0, ScanForVMCSset.Length, (v) => { var ScanFor = ScanForVMCSset[v]; for (int check = 1; check < block.Length; check++) { if (block[check] == ScanFor.CR3Value && Candidate == false) { var OutputList = new List<long>(); StringBuilder sb = null, sbRED = null; byte[] shorted = null; var curr_width = 0; if (Vtero.VerboseOutput) { sb = new StringBuilder(); // reverse endianness for easy reading in hex dumps/editors shorted = BitConverter.GetBytes(block[check]); Array.Reverse(shorted, 0, 8); var Converted = BitConverter.ToUInt64(shorted, 0); sbRED = new StringBuilder(); sbRED.Append($"Hypervisor: VMCS revision field: {RevID} [{((uint)RevID):X8}] abort indicator: {Acode} [{((int)Acode):X8}]{Environment.NewLine}"); sbRED.Append($"Hypervisor: {ScanFor.PageTableType} CR3 found [{ScanFor.CR3Value:X16})] byte-swapped: [{Converted:X16}] @ PAGE/File Offset = [{xoffset:X16}]"); } for (int i = 0; i < block.Length; i++) { var value = block[i]; var eptp = new EPTP(value); // any good minimum size? 64kb? if (block[i] > 0 && block[i] < FileSize && eptp.IsFullyValidated() // && EPTP.IsValid(eptp.aEPTP) && EPTP.IsValid2(eptp.aEPTP) && EPTP.IsValidEntry(eptp.aEPTP) && !OutputList.Contains(block[i])) { Candidate = true; OutputList.Add(block[i]); if (Vtero.VerboseOutput) { var linefrag = $"[{i}][{block[i]:X16}] "; if (curr_width + linefrag.Length > MAX_LINE_WIDTH) { sb.Append(Environment.NewLine); curr_width = 0; } sb.Append(linefrag); curr_width += linefrag.Length; } } } if (Candidate && Vtero.VerboseOutput) { WColor(ConsoleColor.Red, ConsoleColor.Black, sbRED.ToString().PadRight(WindowWidth)); WColor(ConsoleColor.DarkGreen, ConsoleColor.Black, sb.ToString().PadRight(WindowWidth)); } // most VMWare I've scanned comes are using this layout // we know VMWare well so ignore any other potential candidates // TODO: Constantly Verify assumption's if (RevID == REVISION_ID.VMWARE_NESTED && OutputList.Contains(block[14])) { var vmcsFound = new VMCS { dp = ScanFor, EPTP = block[14], gCR3 = ScanFor.CR3Value, Offset = xoffset }; HVLayer.Add(vmcsFound); } else foreach (var entry in OutputList) HVLayer.Add(new VMCS { dp = ScanFor, EPTP = entry, gCR3 = ScanFor.CR3Value, Offset = xoffset }); } } }); return Candidate; }
/// <summary> /// The VMCS scan is based on the LINK pointer, abort code and CR3 register /// We later isolate the EPTP based on constraints for that pointer /// </summary> /// <param name="xoffset"></param> /// <returns>true if the page being scanned is a candidate</returns> public bool VMCS(long xoffset) { var RevID = (REVISION_ID)(block[0] & 0xffffffff); var Acode = (VMCS_ABORT)((block[0] >> 32) & 0x7fffffff); var KnownAbortCode = false; var KnownRevision = false; var Candidate = false; var LinkCount = 0; var Neg1 = -1; if(VMCSScanSet == null) throw new NullReferenceException("Entered VMCS callback w/o having found any VMCS, this is a second pass Func") ; // this might be a bit micro-opt-pointless ;) //Parallel.Invoke(() => //{ KnownRevision = typeof(REVISION_ID).GetEnumValues().Cast<REVISION_ID>().Any(x => x == RevID); //}, () => //{ KnownAbortCode = typeof(VMCS_ABORT).GetEnumValues().Cast<VMCS_ABORT>().Any(x => x == Acode); //}); // TODO: Link pointer may not always be needed, evaluate removing this constraint // Find a 64bit value for link ptr for (int l = 0; l < block.Length; l++) { if (block[l] == Neg1) LinkCount++; // too many if (LinkCount > 32) return false; } // Currently, we expect to have 1 Link pointer at least if (LinkCount == 0 || !KnownAbortCode) return false; // curr width of line to screen Candidate = false; Parallel.For(0, VMCSScanSet.Length, (v) => { var vmcs_entry = VMCSScanSet[v]; for (int check = 1; check < block.Length; check++) { if (block[check] == vmcs_entry.CR3Value && Candidate == false) { var OutputList = new List<long>(); StringBuilder sb = null, sbRED = null; byte[] shorted = null; var curr_width = 0; if (Vtero.VerboseOutput) { sb = new StringBuilder(); // reverse endianess for easy reading in hex dumps/editors shorted = BitConverter.GetBytes(block[check]); Array.Reverse(shorted, 0, 8); var Converted = BitConverter.ToUInt64(shorted, 0); sbRED = new StringBuilder(); sbRED.Append($"Hypervisor: VMCS revision field: {RevID} [{((uint)RevID):X8}] abort indicator: {Acode} [{((int)Acode):X8}]{Environment.NewLine}"); sbRED.Append($"Hypervisor: {vmcs_entry.PageTableType} CR3 found [{vmcs_entry.CR3Value:X16})] byte-swapped: [{Converted:X16}] @ PAGE/File Offset = [{xoffset:X16}]"); } for (int i = 0; i < block.Length; i++) { var eptp = new EPTP(block[i]); // any good minimum size? 64kb? if (block[i] > 0 && block[i] < FileSize && eptp.IsFullyValidated() && !OutputList.Contains(block[i])) { Candidate = true; OutputList.Add(block[i]); if (Vtero.VerboseOutput) { var linefrag = $"[{i}][{block[i]:X16}] "; if (curr_width + linefrag.Length > MAX_LINE_WIDTH) { sb.Append(Environment.NewLine); curr_width = 0; } sb.Append(linefrag); curr_width += linefrag.Length; } } } if (Candidate && Vtero.VerboseOutput) { ForegroundColor = ConsoleColor.Red; WriteLine(sbRED.ToString()); ForegroundColor = ConsoleColor.DarkGreen; WriteLine(sb.ToString()); } VMCS vmcsFound = null; // most VMWare I've scanned comes are using this layout if (RevID == REVISION_ID.VMWARE_NESTED && OutputList.Contains(block[14])) vmcsFound = new VMCS { dp = vmcs_entry, EPTP = block[14], gCR3 = vmcs_entry.CR3Value }; else if (OutputList.Count() == 1) vmcsFound = new net.VMCS { dp = vmcs_entry, EPTP = OutputList[0], gCR3 = vmcs_entry.CR3Value }; if (vmcsFound != null) HVLayer.Add(vmcsFound); } } }); return Candidate; }
/// <summary> /// The VMCS scan is based on the LINK pointer, abort code and CR3 register /// We later isolate the EPTP based on constraints for that pointer /// </summary> /// <param name="xoffset"></param> /// <returns>true if the page being scanned is a candidate</returns> public bool VMCS(long xoffset) { var RevID = (REVISION_ID)(block[0] & 0xffffffff); var Acode = (VMCS_ABORT)((block[0] >> 32) & 0x7fffffff); var KnownAbortCode = false; var KnownRevision = false; var Candidate = false; var LinkCount = 0; var Neg1 = -1; if (VMCSScanSet == null) { throw new NullReferenceException("Entered VMCS callback w/o having found any VMCS, this is a second pass Func"); } // this might be a bit micro-opt-pointless ;) //Parallel.Invoke(() => //{ KnownRevision = typeof(REVISION_ID).GetEnumValues().Cast <REVISION_ID>().Any(x => x == RevID); //}, () => //{ KnownAbortCode = typeof(VMCS_ABORT).GetEnumValues().Cast <VMCS_ABORT>().Any(x => x == Acode); //}); // TODO: Link pointer may not always be needed, evaluate removing this constraint // Find a 64bit value for link ptr for (int l = 0; l < block.Length; l++) { if (block[l] == Neg1) { LinkCount++; } // too many if (LinkCount > 32) { return(false); } } // Currently, we expect to have 1 Link pointer at least if (LinkCount == 0 || !KnownAbortCode) { return(false); } // curr width of line to screen Candidate = false; Parallel.For(0, VMCSScanSet.Length, (v) => { var vmcs_entry = VMCSScanSet[v]; for (int check = 1; check < block.Length; check++) { if (block[check] == vmcs_entry.CR3Value && Candidate == false) { var OutputList = new List <long>(); StringBuilder sb = null, sbRED = null; byte[] shorted = null; var curr_width = 0; if (Vtero.VerboseOutput) { sb = new StringBuilder(); // reverse endianess for easy reading in hex dumps/editors shorted = BitConverter.GetBytes(block[check]); Array.Reverse(shorted, 0, 8); var Converted = BitConverter.ToUInt64(shorted, 0); sbRED = new StringBuilder(); sbRED.Append($"Hypervisor: VMCS revision field: {RevID} [{((uint)RevID):X8}] abort indicator: {Acode} [{((int)Acode):X8}]{Environment.NewLine}"); sbRED.Append($"Hypervisor: {vmcs_entry.PageTableType} CR3 found [{vmcs_entry.CR3Value:X16})] byte-swapped: [{Converted:X16}] @ PAGE/File Offset = [{xoffset:X16}]"); } for (int i = 0; i < block.Length; i++) { var eptp = new EPTP(block[i]); // any good minimum size? 64kb? if (block[i] > 0 && block[i] < FileSize && eptp.IsFullyValidated() && !OutputList.Contains(block[i])) { Candidate = true; OutputList.Add(block[i]); if (Vtero.VerboseOutput) { var linefrag = $"[{i}][{block[i]:X16}] "; if (curr_width + linefrag.Length > MAX_LINE_WIDTH) { sb.Append(Environment.NewLine); curr_width = 0; } sb.Append(linefrag); curr_width += linefrag.Length; } } } if (Candidate && Vtero.VerboseOutput) { ForegroundColor = ConsoleColor.Red; WriteLine(sbRED.ToString()); ForegroundColor = ConsoleColor.DarkGreen; WriteLine(sb.ToString()); } VMCS vmcsFound = null; // most VMWare I've scanned comes are using this layout if (RevID == REVISION_ID.VMWARE_NESTED && OutputList.Contains(block[14])) { vmcsFound = new VMCS { dp = vmcs_entry, EPTP = block[14], gCR3 = vmcs_entry.CR3Value } } ; else if (OutputList.Count() == 1) { vmcsFound = new net.VMCS { dp = vmcs_entry, EPTP = OutputList[0], gCR3 = vmcs_entry.CR3Value } } ; if (vmcsFound != null) { HVLayer.Add(vmcsFound); } } } }); return(Candidate); }
/// <summary> /// The VMCS scan is based on the LINK pointer, abort code and CR3 register /// We later isolate the EPTP based on constraints for that pointer /// </summary> /// <param name="xoffset"></param> /// <returns>true if the page being scanned is a candidate</returns> public bool VMCS(int bo, long xoffset) { var RevID = (REVISION_ID)(block[bo + 0] & 0xffffffff); var Acode = (VMCS_ABORT)((block[bo + 0] >> 32) & 0x7fffffff); var KnownAbortCode = false; var KnownRevision = false; var Candidate = false; var LinkCount = 0; var Neg1 = -1; if (ScanForVMCSset == null) { throw new NullReferenceException("Entered VMCS callback w/o having found any VMCS, this is a second pass Func"); } // this might be a bit micro-opt-pointless ;) KnownRevision = typeof(REVISION_ID).GetEnumValues().Cast <REVISION_ID>().Any(x => x == RevID); KnownAbortCode = typeof(VMCS_ABORT).GetEnumValues().Cast <VMCS_ABORT>().Any(x => x == Acode); // TODO: Relax link pointer check. Possible when VMCS is shadow, then the link pointer is configured, retest this detection/nesting etc.. // Find a 64bit value for link ptr for (int l = 0; l < block.Length; l++) { if (block[bo + l] == Neg1) { LinkCount++; } // too many if (LinkCount > 32) { return(false); } } // Currently, we expect to have 1 Link pointer at least if (LinkCount == 0 || !KnownAbortCode) { return(false); } // curr width of line to screen Candidate = false; Parallel.For(0, ScanForVMCSset.Length, (v) => { var ScanFor = ScanForVMCSset[v]; for (int check = 1; check < block.Length; check++) { if (block[bo + check] == ScanFor.CR3Value && Candidate == false) { var OutputList = new List <long>(); StringBuilder sb = null, sbRED = null; byte[] shorted = null; var curr_width = 0; if (Vtero.VerboseOutput) { sb = new StringBuilder(); // reverse endianness for easy reading in hex dumps/editors shorted = BitConverter.GetBytes(block[bo + check]); Array.Reverse(shorted, 0, 8); var Converted = BitConverter.ToUInt64(shorted, 0); sbRED = new StringBuilder(); sbRED.Append($"Hypervisor: VMCS revision field: {RevID} [{((uint)RevID):X8}] abort indicator: {Acode} [{((int)Acode):X8}]{Environment.NewLine}"); sbRED.Append($"Hypervisor: {ScanFor.PageTableType} CR3 found [{ScanFor.CR3Value:X16})] byte-swapped: [{Converted:X16}] @ PAGE/File Offset = [{xoffset:X16}]"); } for (int i = 0; i < block.Length; i++) { var value = block[bo + i]; var eptp = new EPTP(value); // any good minimum size? 64kb? if (block[bo + i] > 0 && block[bo + i] < FileSize && eptp.IsFullyValidated() // && EPTP.IsValid(eptp.aEPTP) && EPTP.IsValid2(eptp.aEPTP) && EPTP.IsValidEntry(eptp.aEPTP) && !OutputList.Contains(block[bo + i])) { Candidate = true; OutputList.Add(block[bo + i]); if (Vtero.VerboseOutput) { var linefrag = $"[{i}][{block[bo + i]:X16}] "; if (curr_width + linefrag.Length > MAX_LINE_WIDTH) { sb.Append(Environment.NewLine); curr_width = 0; } sb.Append(linefrag); curr_width += linefrag.Length; } } } if (Candidate && Vtero.VerboseOutput) { WColor(ConsoleColor.Red, ConsoleColor.Black, sbRED.ToString().PadRight(WindowWidth)); WColor(ConsoleColor.DarkGreen, ConsoleColor.Black, sb.ToString().PadRight(WindowWidth)); } // most VMWare I've scanned comes are using this layout // we know VMWare well so ignore any other potential candidates // TODO: Constantly Verify assumption's if (RevID == REVISION_ID.VMWARE_NESTED && OutputList.Contains(block[bo + 14])) { var vmcsFound = new VMCS { dp = ScanFor, EPTP = block[bo + 14], gCR3 = ScanFor.CR3Value, Offset = xoffset }; HVLayer.Add(vmcsFound); } else { foreach (var entry in OutputList) { HVLayer.Add(new VMCS { dp = ScanFor, EPTP = entry, gCR3 = ScanFor.CR3Value, Offset = xoffset }); } } } } }); return(Candidate); }