From 41e717dd633fa894caa5d4f31a8eb415ae0f15ae Mon Sep 17 00:00:00 2001 From: Requiem Date: Fri, 1 May 2026 06:20:12 +0200 Subject: [PATCH] feat: stealthy ASLR and compile-time based entropy --- src/vmaware.hpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 348da173..1608779b 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -5416,6 +5416,20 @@ struct VM { bool hypervisor_detected = false; bool bypass_detected = false; + #define VMAWARE_STR2(x) #x + #define VMAWARE_STR(x) VMAWARE_STR2(x) + + const u32 ct_seed = []() constexpr -> u32 { + constexpr char s[] = __DATE__ " " __TIME__ " " __FILE__ " " VMAWARE_STR(__LINE__); + u32 h = 2166136261u; + for (char c : s) { + if (!c) break; + h ^= static_cast(c); + h *= 16777619u; + } + return h; + }(); + // search for the physical sibling of CPU 0, then pick a random CPU excluding it to avoid SMT locks auto get_target_mask = []() -> DWORD_PTR { const HANDLE current_process = reinterpret_cast(-1LL); @@ -5460,10 +5474,36 @@ struct VM { // this will affect latency if cache lines from trigger_thread and counter_thread are separated // however, we do a ratio based detection, so this wont affect the detection accuracy because the cache latency affects both samples if (n) { - std::mt19937 gen(std::random_device{}()); + // std::random_device{}() uses RDRAND/RDSEED which can be intercepted by hypervisors + // we use our own compile-time seed that cannot be taken by examining PE/Linux binary properties and would need static/dynamic analysis + // this changes per build and per process session due to hardware ASLR + std::uintptr_t seed = 0; + seed ^= static_cast(ct_seed); + seed ^= reinterpret_cast(¤t_process); + seed ^= reinterpret_cast(&procMask) << 1; + seed ^= reinterpret_cast(&sysMask) << 2; + seed ^= reinterpret_cast(&len) << 3; + seed ^= reinterpret_cast(&stackBuf[0]) << 4; + seed ^= reinterpret_cast(&heapBuf) << 5; + seed ^= reinterpret_cast(&buf) << 6; + + seed ^= seed >> 33; + seed *= 0xff51afd7ed558ccdULL; + seed ^= seed >> 33; + seed *= 0xc4ceb9fe1a85ec53ULL; + seed ^= seed >> 33; + + std::seed_seq seq{ + static_cast(seed), + static_cast(seed >> 32), + static_cast(seed ^ 0x9e3779b9u), + ct_seed + }; + + std::mt19937 gen(seq); return 1ull << idxs[std::uniform_int_distribution(0, n - 1)(gen)]; } - return 1ull; // fallback + return 1ull; }; // we dont use cpu::cpuid on purpose @@ -5670,11 +5710,39 @@ struct VM { SetThreadPriorityBoost(current_thread, TRUE); // disable dynamic boosts // so that hypervisor can't predict how many samples we will collect - std::mt19937 gen(std::random_device{}()); + // stack-only / ASLR-derived component (no APIs, no rdtsc) + std::uintptr_t seed = 0; + seed ^= static_cast(ct_seed); + + std::uint64_t local1 = 0; + std::uint64_t local2 = 0; + std::uint64_t local3 = 0; + + seed ^= reinterpret_cast(&seed); + seed ^= reinterpret_cast(&local1) << 1; + seed ^= reinterpret_cast(&local2) << 2; + seed ^= reinterpret_cast(&local3) << 3; + + // splitmix64 + seed ^= seed >> 33; + seed *= 0xff51afd7ed558ccdULL; + seed ^= seed >> 33; + seed *= 0xc4ceb9fe1a85ec53ULL; + seed ^= seed >> 33; + + std::seed_seq seq{ + static_cast(seed), + static_cast(seed >> 32), + static_cast(seed ^ 0x9e3779b9u), + ct_seed + }; + + std::mt19937 gen(seq); std::uniform_int_distribution batch_dist(30000, 70000); const size_t BATCH_SIZE = batch_dist(gen); i32 dummy_res[4]{}; size_t valid = 0; // end of setup phase + SleepEx(0, FALSE); // try to get fresh quantum before starting warm-up phase, give time to kernel to set up priorities std::vector vm_samples(BATCH_SIZE), ref_samples(BATCH_SIZE); // pre page-fault MMU, wwe wont warm-up cpuid samples for the P-states intentionally