Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
vm cpu detection via cpuid and rdtsc
#include <iostream>
#include <thread>
constexpr std::uint32_t
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
const std::uint64_t rdts_count() noexcept {
__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 is a whore
const std::uint32_t rdtsc_static_delta() noexcept {
__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
const std::uint32_t rdtsc_vm_static_delta() noexcept {
__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
const std::uint32_t rdtsc_dynamic_delta() noexcept {
static std::uint64_t mean_delta;
for (auto i = 0; i < dynamic_cycles; i++) {
mean_delta += static_cast <std::uint64_t> (rdtsc_static_delta() * 0.1),
std::this_thread::sleep_for(std::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
const std::uint32_t rdtsc_vm_dynamic_delta() noexcept {
static std::uint64_t mean_delta;
for (auto i = 0; i < dynamic_cycles; i++) {
mean_delta += static_cast <std::uint64_t> (rdtsc_vm_static_delta() * 0.1),
std::this_thread::sleep_for(std::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
const std::uint32_t cpuid_hypervisor() noexcept {
__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
}
}
std::uint32_t main() {
const auto log_event = [](const std::string_view label, const std::uint32_t condition) { std::cout
<< "* " << label << " ~ " << (condition ? "abnormal" : "normal") << std::endl; };
log_event("rdts_count", !rdts_count());
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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment