3232 * - License: MIT
3333 *
3434 * MIT License
35- *
35+ *
3636 * Copyright (c) 2026 kernelwernel
3737 *
3838 * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -13179,29 +13179,29 @@ struct VM {
1317913179 return hypervisor_detected;
1318013180 #endif
1318113181 }
13182-
13183-
1318413182 /**
1318513183 * @brief Check whether a hypervisor leaks EFER.SVME into guest context via SVM instruction fault type
13186- * @category Windows, x86
13184+ * @category Windows, x86_64, AMD
1318713185 * @implements VM::SVM_EXCEPTIONS
1318813186 */
1318913187 [[nodiscard]] static bool svm_exceptions() {
13190- #if (x86)
13191- if (!cpu::is_amd()) {
13192- debug("SVM_EXCEPTIONS: AMD CPU not detected, skipping");
13188+ if (!x86 || !cpu::is_amd()) {
13189+ debug("SVM_EXCEPTIONS: neither AMD or x86 detected, skipping");
1319313190 return false;
1319413191 }
1319513192
13196- if (util::hyper_x() == HYPERV_ARTIFACT_VM) {
13193+ const auto hx = util::hyper_x();
13194+ if (hx == HYPERV_ARTIFACT_VM || hx == HYPERV_REAL_VM || hx == HYPERV_ENLIGHTENMENT) {
13195+ debug("SVM_EXCEPTIONS: Hyper-V active, skipping");
1319713196 return false;
1319813197 }
1319913198
1320013199 u32 eax = 0, ebx = 0, ecx = 0, edx = 0;
1320113200 cpu::cpuid(eax, ebx, ecx, edx, 0x80000001);
13202- const bool svmcpuid_visible = (( ecx >> 2) & 1) != 0 ;
13201+ const bool svmcpuid_visible = (ecx >> 2) & 1;
1320313202
1320413203 const HMODULE ntdll = util::get_ntdll();
13204+
1320513205 if (!ntdll) {
1320613206 return false;
1320713207 }
@@ -13222,103 +13222,93 @@ struct VM {
1322213222 util::get_function_address(ntdll, names, funcs, ARRAYSIZE(names));
1322313223
1322413224 const auto nt_allocate_virtual_memory = reinterpret_cast<nt_allocate_virtual_memory_t>(funcs[0]);
13225- const auto nt_protect_virtual_memory = reinterpret_cast<nt_protect_virtual_memory_t>(funcs[1]);
13226- const auto nt_free_virtual_memory = reinterpret_cast<nt_free_virtual_memory_t>(funcs[2]);
13225+ const auto nt_protect_virtual_memory = reinterpret_cast<nt_protect_virtual_memory_t>(funcs[1]);
13226+ const auto nt_free_virtual_memory = reinterpret_cast<nt_free_virtual_memory_t>(funcs[2]);
1322713227 const auto nt_flush_instruction_cache = reinterpret_cast<nt_flush_instruction_cache_t>(funcs[3]);
1322813228
13229- if (!nt_allocate_virtual_memory || !nt_protect_virtual_memory || !nt_free_virtual_memory || !nt_flush_instruction_cache) {
13229+ if (
13230+ (!nt_allocate_virtual_memory) ||
13231+ (!nt_protect_virtual_memory) ||
13232+ (!nt_free_virtual_memory) ||
13233+ (!nt_flush_instruction_cache)
13234+ ) {
1323013235 return false;
1323113236 }
13237+
1323213238
13233- constexpr std::array<std::array<u8, 4>, 5> opcodes{ {
13239+ constexpr u8 opcodes[][4] = {
1323413240 { 0x0F, 0x01, 0xD8, 0xC3 }, // VMRUN
1323513241 { 0x0F, 0x01, 0xDA, 0xC3 }, // VMLOAD
1323613242 { 0x0F, 0x01, 0xDB, 0xC3 }, // VMSAVE
1323713243 { 0x0F, 0x01, 0xDD, 0xC3 }, // CLGI
1323813244 { 0x0F, 0x01, 0xDF, 0xC3 } // INVLPGA
13239- } } ;
13245+ };
1324013246
13241- constexpr SIZE_T opcode_size = 4;
1324213247 const HANDLE current_process = reinterpret_cast<HANDLE>(-1);
13248+ constexpr u32 opcode_size = 4;
1324313249
1324413250 for (const auto& opcode : opcodes) {
1324513251 PVOID base_address = nullptr;
1324613252 SIZE_T region_size = 0x1000;
1324713253
13248- auto free_region = [&]() {
13249- if (base_address) {
13250- SIZE_T free_size = 0;
13251- nt_free_virtual_memory(current_process, &base_address, &free_size, MEM_RELEASE);
13252- base_address = nullptr;
13253- }
13254- };
13255-
1325613254 NTSTATUS status = nt_allocate_virtual_memory(
13257- current_process,
13258- &base_address,
13259- 0,
13260- ®ion_size,
13261- MEM_COMMIT | MEM_RESERVE,
13262- PAGE_EXECUTE_READWRITE
13255+ current_process, &base_address, 0, ®ion_size,
13256+ MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE
1326313257 );
1326413258
1326513259 if (!NT_SUCCESS(status)) {
1326613260 continue;
1326713261 }
1326813262
13269- memcpy(base_address, opcode.data() , opcode_size);
13263+ memcpy(base_address, opcode, opcode_size);
1327013264 nt_flush_instruction_cache(current_process, base_address, opcode_size);
1327113265
1327213266 ULONG old_protect = 0;
1327313267 PVOID protect_address = base_address;
1327413268 SIZE_T protect_size = region_size;
1327513269
1327613270 status = nt_protect_virtual_memory(
13277- current_process,
13278- &protect_address,
13279- &protect_size,
13280- PAGE_EXECUTE_READ,
13281- &old_protect
13271+ current_process, &protect_address, &protect_size,
13272+ PAGE_EXECUTE_READ, &old_protect
1328213273 );
1328313274
13284- if (!NT_SUCCESS(status)) {
13285- free_region();
13286- continue;
13287- }
13288-
13289- nt_flush_instruction_cache(current_process, base_address, opcode_size);
13275+ if (NT_SUCCESS(status)) {
13276+ nt_flush_instruction_cache(current_process, base_address, opcode_size);
1329013277
13291- DWORD exception_status = 0;
13292- bool fault_hit = false;
13278+ DWORD exception_status = 0;
13279+ bool fault_hit = false;
1329313280
13294- __try {
13295- reinterpret_cast<void(*)()>(base_address)();
13296- }
13297- __except (exception_status = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) {
13298- fault_hit = true;
13299- }
13281+ __try {
13282+ const auto execute_svm = reinterpret_cast<void(*)()>(base_address);
13283+ execute_svm();
13284+ }
13285+ __except (exception_status = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) {
13286+ fault_hit = true;
13287+ }
1330013288
13301- free_region();
13289+ SIZE_T free_size = 0;
13290+ nt_free_virtual_memory(current_process, &base_address, &free_size, MEM_RELEASE);
1330213291
13303- if (!fault_hit) {
13304- continue;
13305- }
13292+ if (fault_hit) {
13293+ if (exception_status == EXCEPTION_ILLEGAL_INSTRUCTION) {
13294+ continue;
13295+ }
1330613296
13307- if (exception_status == EXCEPTION_ILLEGAL_INSTRUCTION) {
13308- continue;
13309- }
13297+ if (svmcpuid_visible) {
13298+ debug("SVM_EXCEPTIONS: #GP with SVM CPUID visible, VM detected");
13299+ } else {
13300+ debug("SVM_EXCEPTIONS: #GP with SVM CPUID hidden, VM spoofing CPUID detected");
13301+ core::add(brand_enum::NULL_BRAND, 100);
13302+ }
1331013303
13311- if (svmcpuid_visible) {
13312- debug("SVM_EXCEPTIONS: Detected SVM hypervisor");
13313- }
13314- else {
13315- debug("SVM_EXCEPTIONS: Detected SVM hypervisor hiding CPU capabilities");
13316- core::add(brand_enum::NULL_BRAND, 150);
13304+ return true;
13305+ }
13306+ } else {
13307+ SIZE_T free_size = 0;
13308+ nt_free_virtual_memory(current_process, &base_address, &free_size, MEM_RELEASE);
1331713309 }
13318-
13319- return true;
1332013310 }
13321- #endif
13311+
1332213312 return false;
1332313313 }
1332413314
@@ -14600,9 +14590,9 @@ std::array<VM::core::technique, VM::enum_size + 1> VM::core::technique_table = [
1460014590 #if (WINDOWS)
1460114591 {VM::TRAP, {100, VM::trap}},
1460214592 {VM::KVM_INTERCEPTION, {100, VM::kvm_interception}},
14603- {VM::SVM_EXCEPTIONS, {100, VM::svm_exceptions}},
1460414593 {VM::INTERRUPT_SHADOW, {100, VM::interrupt_shadow}},
1460514594 {VM::EIP_OVERFLOW, {100, VM::eip_overflow}},
14595+ {VM::SVM_EXCEPTIONS, {25, VM::svm_exceptions}},
1460614596 {VM::HYPERVISOR_HOOK, {100, VM::hypervisor_hook}},
1460714597 {VM::SINGLE_STEP, {100, VM::single_step}},
1460814598 {VM::NVRAM, {100, VM::nvram}},
@@ -14714,4 +14704,4 @@ std::array<VM::core::technique, VM::enum_size + 1> VM::core::technique_table = [
1471414704 return table;
1471514705}();
1471614706
14717- #endif // include guard end
14707+ #endif // include guard end
0 commit comments