Last active
April 17, 2025 19:17
-
-
Save hLunaaa/e3730f175d572258baf0049ae37f5fec to your computer and use it in GitHub Desktop.
vm cpu detection via cpuid and rdtsc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <thread> | |
static constexpr u32 dynamic_cycles = 10, | |
standard_sleep = 500, | |
vm_cycle_ratio = 100, | |
cycle_ratio = 75; | |
// -- rdtsc -- | |
// https://github.com/hfiref0x/VBoxHardenedLoader | |
// https://docs.microsoft.com/en-us/cpp/intrinsics/rdtsc | |
// https://www.aldeid.com/wiki/X86-assembly/Instructions/rdtsc | |
// -- cpuid -- | |
// https://cs.fit.edu/~mmahoney/cse3101/cpuid.asm.txt | |
// https://en.wikipedia.org/wiki/CPUID#Calling_CPUID | |
// https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex | |
// -- additional resources -- | |
// http://ref.x86asm.net/coder32.html | |
// https://en.wikipedia.org/wiki/X86_calling_conventions#stdcall | |
// msvc intrin.h wraps 0f31 with __rdtsc | |
// reads time-stamp counters or rdtsc for uptime | |
u64 rdts_count() | |
{ | |
__asm | |
{ | |
rdtsc ; call 0f31 | |
shl eax, 20h ; rax fix | |
or edx, eax ; bitor | |
} | |
} | |
// we compare to see if static rdtsc delta exceeds | |
// i would lambda the inline asm but msvc wont allow | |
u32 rdtsc_static_delta() | |
{ | |
__asm | |
{ | |
rdtsc ; call 0f31 | |
xor ecx, ecx ; mov evx, 0 | |
mov ecx, eax ; store low | |
rdtsc ; repeat | |
sub eax, ecx ; calculate delta | |
} | |
} | |
// we compare to see if static rdtsc delta exceeds | |
// this time calling cpuid with eax = 0 to trigger | |
u32 rdtsc_vm_static_delta() | |
{ | |
__asm | |
{ | |
rdtsc ; call 0f31 | |
xor ecx, ecx ; mov evx, 0 | |
mov ecx, eax ; store low | |
xor eax, eax ; eax = 0 | |
cpuid ; highest function parameter | |
rdtsc ; repeat | |
sub eax, ecx ; calculate delta | |
} | |
} | |
// we compute the rdtsc detla dynamically and compare | |
// with known values to detect the system hypervisor | |
u32 rdtsc_dynamic_delta() { | |
u64 mean_delta; | |
for (auto i = 0; i < dynamic_cycles; i++) | |
{ | |
mean_delta += static_cast <u64> (rdtsc_static_delta() * 0.1); | |
this_thread::sleep_for(chrono::milliseconds(standard_sleep)); | |
} | |
return mean_delta >= dynamic_cycles * cycle_ratio; | |
} | |
// we compute the rdtsc detla dynamically and compare | |
// with known values to detect the system hypervisor | |
u32 rdtsc_vm_dynamic_delta() | |
{ | |
u64 mean_delta; | |
for (auto i = 0; i < dynamic_cycles; i++) | |
{ | |
mean_delta += static_cast <u64> (rdtsc_vm_static_delta() * 0.1); | |
this_thread::sleep_for(chrono::milliseconds(standard_sleep)); | |
} | |
return mean_delta >= dynamic_cycles * vm_cycle_ratio; | |
} | |
// msvc cpuid.h wraps 0fa2 via __get_cpuid() | |
// checks flag on bit=31 for hv presence in system | |
u32 cpuid_hypervisor() | |
{ | |
__asm | |
{ | |
mov eax, 1h ; eax = 1 features | |
cpuid ; call 0fa2 | |
shr ecx, 1fh ; hv flag in bit = 31 | |
mov eax, ecx ; ret via eax | |
and eax, 1h ; cmp | |
} | |
} | |
u32 main() | |
{ | |
auto log_event = [](string_view label, u32 condition) { cout | |
<< "* " << label << " ~ " << (condition ? "abnormal" : "normal") << endl; }; | |
log_event("rdts_count", rdts_count() == 0); | |
log_event("cpuid_hypervisor", cpuid_hypervisor()); | |
log_event("rdtsc_dynamic_delta", rdtsc_dynamic_delta()); | |
log_event("rdtsc_vm_dynamic_delta", rdtsc_vm_dynamic_delta()); | |
log_event("rdtsc_static_delta", rdtsc_static_delta() >= 0xfff); | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment