From dbc1b4439e08043a39c63e42834c0e3e49936db3 Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Thu, 10 Apr 2025 06:58:01 +0530 Subject: [PATCH 1/7] feat: spoof rdtsc timings Previously, RDTSC in the VM always returned a constant value, which broke any non deterministic timing-based operations, or caused detections in heuristics of malware and ANTI-VM tools. This patch introduces a spoofed rdtsc_fake counter that tracks and adjusts timing deltas to simulate realistic TSC increments. Can be extended to simulate rdtsc timings based on CPU clock speed. --- src/common/utils/time.hpp | 22 ++++++++++++++++++++++ src/windows-emulator/windows_emulator.cpp | 22 +++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index b887e789..e2d2e5c6 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -3,6 +3,10 @@ #include #include "../platform/platform.hpp" +#if defined(_MSC_VER) +#include +#pragma intrinsic(__rdtsc) +#endif constexpr auto HUNDRED_NANOSECONDS_IN_ONE_SECOND = 10000000LL; constexpr auto EPOCH_DIFFERENCE_1601_TO_1970_SECONDS = 11644473600LL; @@ -29,6 +33,24 @@ namespace utils { return std::chrono::steady_clock::now(); } + + // Returnds the current timestamp counter value. RDTSC on x86/x64, or just time since epoch for ARM + /// TODO: find better solution for ARM and Figure out better CPU base frequency heuristics + virtual uint64_t timestamp_counter() + { +#if defined(_MSC_VER) +#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86) + return __rdtsc(); // 64-bit with MSVC intrinsic +#endif + +#elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) // If we are using clang or gcc + unsigned int lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +#endif + return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()) * + 3.8; // should be base cpu frequency here; + } }; class tick_clock : public clock diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e87f7044..d127d569 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -448,9 +448,25 @@ void windows_emulator::setup_hooks() }); this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { - const auto instructions = this->executed_instructions_; - this->emu().reg(x64_register::rax, instructions & 0xFFFFFFFF); - this->emu().reg(x64_register::rdx, (instructions >> 32) & 0xFFFFFFFF); + uint64_t ticks = this->clock_.get()->timestamp_counter(); + static uint64_t fake_ticks = ticks; + static uint64_t prev_ticks = 0; + + if (prev_ticks != 0) + { + if (ticks > prev_ticks) + { + fake_ticks += (ticks - prev_ticks); + } + } + if (fake_ticks > ticks) + { + fake_ticks = ticks; + } + prev_ticks = ticks; + + this->emu().reg(x64_register::rax, fake_ticks & 0xFFFFFFFF); + this->emu().reg(x64_register::rdx, (fake_ticks >> 32) & 0xFFFFFFFF); return instruction_hook_continuation::skip_instruction; }); From 0271e39474ab69fb3ce174fd673155144f32f59f Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 00:40:38 +0530 Subject: [PATCH 2/7] refactor(rdtsc): clean up tick logic, fix intrinsics, and resolve x86 compiler issues - fix `time.hpp` compiler warnings (errors) and use proper intrinsic for gcc - simplify tick calculation logic - fix: exclude intrinsics include for non x86 builds and fix style - fix: get() on clock_ unique ptr --- src/common/utils/time.hpp | 10 +++++----- src/windows-emulator/windows_emulator.cpp | 14 ++++---------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index e2d2e5c6..25236fe0 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -6,6 +6,8 @@ #if defined(_MSC_VER) #include #pragma intrinsic(__rdtsc) +#elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) +#include #endif constexpr auto HUNDRED_NANOSECONDS_IN_ONE_SECOND = 10000000LL; @@ -44,12 +46,10 @@ namespace utils #endif #elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) // If we are using clang or gcc - unsigned int lo, hi; - __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); - return ((uint64_t)hi << 32) | lo; + return __rdtsc(); // 64-bit with clang/gcc intrinsic #endif - return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()) * - 3.8; // should be base cpu frequency here; + int64_t count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + return static_cast((count * 38LL) / 10LL); } }; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index d127d569..4db7c843 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -448,21 +448,15 @@ void windows_emulator::setup_hooks() }); this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { - uint64_t ticks = this->clock_.get()->timestamp_counter(); + uint64_t ticks = this->clock_->timestamp_counter(); static uint64_t fake_ticks = ticks; static uint64_t prev_ticks = 0; - if (prev_ticks != 0) + if (ticks > prev_ticks) { - if (ticks > prev_ticks) - { - fake_ticks += (ticks - prev_ticks); - } - } - if (fake_ticks > ticks) - { - fake_ticks = ticks; + fake_ticks += (ticks - prev_ticks); } + fake_ticks = std::min(fake_ticks, ticks); prev_ticks = ticks; this->emu().reg(x64_register::rax, fake_ticks & 0xFFFFFFFF); From 3bb599d35617d1c580e07a01d0fd1097b68a858a Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 02:21:22 +0530 Subject: [PATCH 3/7] refactor: better conditional compilation on time.hpp --- src/common/utils/time.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index 25236fe0..07774107 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -4,9 +4,11 @@ #include "../platform/platform.hpp" #if defined(_MSC_VER) +#define ARCH_x86 #include #pragma intrinsic(__rdtsc) #elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) +#define ARCH_x86 #include #endif @@ -40,14 +42,10 @@ namespace utils /// TODO: find better solution for ARM and Figure out better CPU base frequency heuristics virtual uint64_t timestamp_counter() { -#if defined(_MSC_VER) -#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86) - return __rdtsc(); // 64-bit with MSVC intrinsic -#endif +#if defined(ARCH_x86) + return __rdtsc(); +#endif // We are using x86, regardless of compiler the instrinsic is the same -#elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) // If we are using clang or gcc - return __rdtsc(); // 64-bit with clang/gcc intrinsic -#endif int64_t count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); return static_cast((count * 38LL) / 10LL); } From 55f29caf0f13c5da0053e467d844ec0a8a05b8c1 Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 02:26:28 +0530 Subject: [PATCH 4/7] Revert "refactor: better conditional compilation on time.hpp" This reverts commit 3bb599d35617d1c580e07a01d0fd1097b68a858a. --- src/common/utils/time.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index 07774107..25236fe0 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -4,11 +4,9 @@ #include "../platform/platform.hpp" #if defined(_MSC_VER) -#define ARCH_x86 #include #pragma intrinsic(__rdtsc) #elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) -#define ARCH_x86 #include #endif @@ -42,10 +40,14 @@ namespace utils /// TODO: find better solution for ARM and Figure out better CPU base frequency heuristics virtual uint64_t timestamp_counter() { -#if defined(ARCH_x86) - return __rdtsc(); -#endif // We are using x86, regardless of compiler the instrinsic is the same +#if defined(_MSC_VER) +#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86) + return __rdtsc(); // 64-bit with MSVC intrinsic +#endif +#elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) // If we are using clang or gcc + return __rdtsc(); // 64-bit with clang/gcc intrinsic +#endif int64_t count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); return static_cast((count * 38LL) / 10LL); } From daeefb4a7f989ad7eb4de60ac0de464376a1c800 Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 11:42:36 +0530 Subject: [PATCH 5/7] refactor(rdtsc): clean up code overall Change type of chrono return to be auto Co-authored-by: Maurice Heumann simplify conditional compile and add #else to prevent clang-tidy breaking CI Co-authored-by: Maurice Heumann --- src/common/utils/time.hpp | 15 ++++++--------- src/windows-emulator/windows_emulator.cpp | 14 ++------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index 25236fe0..255045fc 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -40,16 +40,13 @@ namespace utils /// TODO: find better solution for ARM and Figure out better CPU base frequency heuristics virtual uint64_t timestamp_counter() { -#if defined(_MSC_VER) -#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86) - return __rdtsc(); // 64-bit with MSVC intrinsic -#endif - -#elif defined(__x86_64__) || defined(__i386__) || defined(__amd64__) // If we are using clang or gcc - return __rdtsc(); // 64-bit with clang/gcc intrinsic -#endif - int64_t count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); +#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) || \ + defined(__amd64__) + return __rdtsc(); // any x86 system will have this instrinsic +#else + const auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); return static_cast((count * 38LL) / 10LL); +#endif } }; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 4db7c843..4adbb7ab 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -449,18 +449,8 @@ void windows_emulator::setup_hooks() this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { uint64_t ticks = this->clock_->timestamp_counter(); - static uint64_t fake_ticks = ticks; - static uint64_t prev_ticks = 0; - - if (ticks > prev_ticks) - { - fake_ticks += (ticks - prev_ticks); - } - fake_ticks = std::min(fake_ticks, ticks); - prev_ticks = ticks; - - this->emu().reg(x64_register::rax, fake_ticks & 0xFFFFFFFF); - this->emu().reg(x64_register::rdx, (fake_ticks >> 32) & 0xFFFFFFFF); + this->emu().reg(x64_register::rax, ticks & 0xFFFFFFFF); + this->emu().reg(x64_register::rdx, (ticks >> 32) & 0xFFFFFFFF); return instruction_hook_continuation::skip_instruction; }); From 640cd500c36e0d9bccba0767a4b16c1ac65c73c4 Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 12:12:31 +0530 Subject: [PATCH 6/7] fix typo on time.hpp Co-authored-by: Maurice Heumann --- src/common/utils/time.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index 255045fc..fdc3d89f 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -36,7 +36,7 @@ namespace utils return std::chrono::steady_clock::now(); } - // Returnds the current timestamp counter value. RDTSC on x86/x64, or just time since epoch for ARM + // Returns the current timestamp counter value. RDTSC on x86/x64, or just time since epoch for ARM /// TODO: find better solution for ARM and Figure out better CPU base frequency heuristics virtual uint64_t timestamp_counter() { From ea7f6a68c819b3d0310eb2e9a51456745681455b Mon Sep 17 00:00:00 2001 From: Soham Nandy Date: Fri, 11 Apr 2025 12:12:56 +0530 Subject: [PATCH 7/7] Use auto for timestamp_counter tick type Co-authored-by: Maurice Heumann --- src/windows-emulator/windows_emulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 4adbb7ab..8bdb30bb 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -448,7 +448,7 @@ void windows_emulator::setup_hooks() }); this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { - uint64_t ticks = this->clock_->timestamp_counter(); + const auto ticks = this->clock_->timestamp_counter(); this->emu().reg(x64_register::rax, ticks & 0xFFFFFFFF); this->emu().reg(x64_register::rdx, (ticks >> 32) & 0xFFFFFFFF); return instruction_hook_continuation::skip_instruction;