Привет! Это правильный способ заменить NtQueryPerformanceCounter на RDTSC? Спасибо. Код (Text): NTSTATUS HookedNtQueryPerformanceCounter3( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { static bool initialized = false; if (!initialized) { // Однократное исправление SharedUserData __try { // Сбросить флаг Qpc bias *(BYTE*)(&SharedUserData->QpcData) = *(BYTE*)(&SharedUserData->QpcData) & 0xFFFE; // Установить новую частоту *(LONGLONG*)(&SharedUserData->QpcFrequency) = rdtscfreq; // Очистить данные Qpc bias/virtualization *(BYTE*)((BYTE*)SharedUserData + 0x3c7) = 0; *(LONGLONG*)((BYTE*)SharedUserData + 0x3b8) = 0; initialized = true; } __except (EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; PerformanceCounter->QuadPart = __rdtsc(); if (PerformanceFrequency) PerformanceFrequency->QuadPart = rdtscfreq; return STATUS_SUCCESS; }
Я нашёл, что работает только этот метод — напрямую использовать rdtsc у меня никогда не получалось, так как я не знаю, что именно управляет частотой 10 МГц Код (Text): static long long tsc_to_nanoseconds(unsigned long long tsc_count) { long long scaled_ns = (tsc_count / rdtscfreq) * 10000000LL; unsigned long long remainder = tsc_count % rdtscfreq; scaled_ns += (remainder * 10000000LL) / rdtscfreq; return scaled_ns; } PerformanceCounter->QuadPart = tsc_to_nanoseconds(__rdtsc()); if (PerformanceFrequency) PerformanceFrequency->QuadPart = 10000000LL; --- Сообщение объединено, 26 май 2025 --- преуспевать
Код (C++): NTSTATUS HookedNtQueryPerformanceCounter( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; // Get current TSC value UINT64 tsc = __rdtsc(); // Convert TSC to QPC units (10MHz base) // This maintains compatibility with existing code PerformanceCounter->QuadPart = (tsc * 10000000ULL) / rdtscfreq; if (PerformanceFrequency) PerformanceFrequency->QuadPart = 10000000ULL; // 10 MHz standard return STATUS_SUCCESS; } --- Сообщение объединено, 26 май 2025 --- Intelligent QPC Hook with Auto-Calibration Код (C++): class SmartQPCHook { private: static volatile bool initialized; static UINT64 tsc_frequency; static UINT64 qpc_baseline; static UINT64 tsc_baseline; static double scale_factor; static void calibrate_once() { if (initialized) return; // Get real QPC values for calibration LARGE_INTEGER real_qpc1, real_qpc2, freq; UINT64 tsc1, tsc2; // Sample multiple times for accuracy tsc1 = __rdtsc(); QueryPerformanceCounter(&real_qpc1); Sleep(10); // Short delay tsc2 = __rdtsc(); QueryPerformanceCounter(&real_qpc2); QueryPerformanceFrequency(&freq); // Calculate precise scaling UINT64 tsc_delta = tsc2 - tsc1; UINT64 qpc_delta = real_qpc2.QuadPart - real_qpc1.QuadPart; scale_factor = (double)qpc_delta / tsc_delta; tsc_baseline = tsc1; qpc_baseline = real_qpc1.QuadPart; tsc_frequency = freq.QuadPart; _InterlockedExchange8((char*)&initialized, 1); } public: static NTSTATUS NTAPI HookedNtQueryPerformanceCounter( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; if (!initialized) { calibrate_once(); } // Convert TSC to QPC using calibrated scaling UINT64 current_tsc = __rdtsc(); UINT64 tsc_offset = current_tsc - tsc_baseline; PerformanceCounter->QuadPart = qpc_baseline + (UINT64)(tsc_offset * scale_factor); if (PerformanceFrequency) PerformanceFrequency->QuadPart = tsc_frequency; return STATUS_SUCCESS; } }; // Static member definitions volatile bool SmartQPCHook::initialized = false; UINT64 SmartQPCHook::tsc_frequency = 0; UINT64 SmartQPCHook::qpc_baseline = 0; UINT64 SmartQPCHook::tsc_baseline = 0; double SmartQPCHook::scale_factor = 0.0; Even Smarter: Runtime Adaptive Solution Код (C++): static NTSTATUS NTAPI AdaptiveQPCHook( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; static thread_local bool tls_calibrated = false; static thread_local UINT64 tls_scale_num = 0; static thread_local UINT64 tls_scale_den = 0; static thread_local UINT64 tls_qpc_freq = 0; // Per-thread calibration for maximum accuracy if (!tls_calibrated) { LARGE_INTEGER freq, qpc1, qpc2; UINT64 tsc1, tsc2; // Quick calibration QueryPerformanceFrequency(&freq); tsc1 = __rdtsc(); QueryPerformanceCounter(&qpc1); // Micro-delay using TSC UINT64 target = tsc1 + 1000000; // ~1ms on modern CPUs while (__rdtsc() < target); tsc2 = __rdtsc(); QueryPerformanceCounter(&qpc2); // Calculate integer scaling to avoid floating point UINT64 tsc_delta = tsc2 - tsc1; UINT64 qpc_delta = qpc2.QuadPart - qpc1.QuadPart; tls_scale_num = qpc_delta; tls_scale_den = tsc_delta; tls_qpc_freq = freq.QuadPart; tls_calibrated = true; } // Fast TSC->QPC conversion using integer math static UINT64 base_tsc = __rdtsc(); UINT64 current_tsc = __rdtsc(); UINT64 tsc_elapsed = current_tsc - base_tsc; // Scale TSC to QPC units PerformanceCounter->QuadPart = (tsc_elapsed * tls_scale_num) / tls_scale_den; if (PerformanceFrequency) PerformanceFrequency->QuadPart = tls_qpc_freq; return STATUS_SUCCESS; } Ultra-Smart: VDSO-Style Fast Path Код (C++): // Leverage existing system calibration static NTSTATUS NTAPI VDSOStyleQPCHook( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; // Read system's own TSC calibration data static UINT64 cached_mult = 0; static UINT32 cached_shift = 0; static UINT64 cached_freq = 0; if (!cached_mult) { // Extract from SharedUserData if accessible auto* sud = (KUSER_SHARED_DATA*)0x7FFE0000; if (sud && sud->QpcFrequency.QuadPart) { cached_freq = sud->QpcFrequency.QuadPart; // Use system's TSC scaling if available if (sud->QpcData.QpcMultiplier) { cached_mult = sud->QpcData.QpcMultiplier; cached_shift = sud->QpcData.QpcShift; } else { // Fallback: calculate our own cached_mult = (cached_freq << 32) / __rdtsc(); cached_shift = 32; } } } if (cached_mult) { // Use system-compatible scaling UINT64 tsc = __rdtsc(); PerformanceCounter->QuadPart = (tsc * cached_mult) >> cached_shift; } else { // Emergency fallback PerformanceCounter->QuadPart = __rdtsc(); } if (PerformanceFrequency) PerformanceFrequency->QuadPart = cached_freq; return STATUS_SUCCESS; }
большое спасибо Моя цель заключалась в том, чтобы пропатчить 10МГц и использовать его напрямую. Для этого мне нужно было найти патч KeQueryPerformanceCounter внутри HalpPerformanceCounter.QueryCounter, чтобы он возвращал rdtsc, затем пропатчить структуру HAL - исправить каждые 10МГц внутри KeQueryPerformanceCounter по смещению 0xc0, чтобы он возвращал вашу реальную частоту. Получить её оттуда, а затем перехватить NtQueryPerformanceCounter, чтобы он возвращал rdtsc с частотой, полученной из смещения 0xc0. --- Сообщение объединено, 26 май 2025 --- Код (Text): PVOID FindHalpPerformanceCounter() { UNICODE_STRING routineName = RTL_CONSTANT_STRING(L"KeQueryPerformanceCounter"); PVOID keQueryPerformanceCounter = MmGetSystemRoutineAddress(&routineName); if (!keQueryPerformanceCounter) { return nullptr; } // Template from your disassembly: mov rdi, qword ptr [nt!HalpPerformanceCounter] // Offset instruction 0x12: 48 8B 3D ?? ?? ?? ?? (REX.W mov rdi, [rip+offset]) PUCHAR scanAddress = (PUCHAR)keQueryPerformanceCounter; for (ULONG i = 0; i < 0x100; i++) { if (scanAddress[i] == 0x48 && scanAddress[i + 1] == 0x8B && scanAddress[i + 2] == 0x3D) { LONG relativeOffset = *(PLONG)(&scanAddress[i + 3]); PVOID halpPerformanceCounterAddress = (PVOID)(&scanAddress[i + 7] + relativeOffset); return *(PVOID*)halpPerformanceCounterAddress; } } return nullptr; } [code]UINT64 GetKernelQPCFrequency() { static PVOID halpCounter = FindHalpPerformanceCounter(); if (!halpCounter) return 0; PUCHAR counterStruct = (PUCHAR)halpCounter; UINT64 frequency = *(UINT64*)(counterStruct + 0xC0); DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "HalpPerformanceCounter: %p, Frequency: %llu\n", halpCounter, frequency); return frequency; } --- Сообщение объединено, 27 май 2025 --- Код (Text): NTSTATUS HookedNtQueryPerformanceCounter( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; static UINT64 cached_mult = 0; static UINT32 cached_shift = 0; static UINT64 cached_tsc_freq = 0; static UINT64 cached_qpc_freq = 0; if (!cached_mult) { // Получаем частоту оригинального QPC (10 МГц) auto* sud = (KUSER_SHARED_DATA*)0xFFFFF78000000000; if (sud && sud->QpcFrequency) { // Сохраняем исходную частоту QPC до изменения cached_qpc_freq = 10000000; // Получаем частоту TSC от ядра cached_tsc_freq = GetKernelTSCFrequency(); if (cached_tsc_freq > 0) { cached_shift = 32; // Вычисляем множитель для преобразования значений cached_mult = (cached_tsc_freq << cached_shift) / cached_qpc_freq; } } } // Получаем оригинальное значение QPC из ядра LARGE_INTEGER original_qpc; NTSTATUS status = OriginalNtQueryPerformanceCounter(&original_qpc, NULL); if (!NT_SUCCESS(status)) { return status; } // Преобразуем значение QPC (в 10 МГц) в эквивалентное значение на частоте TSC PerformanceCounter->QuadPart = (original_qpc.QuadPart * cached_mult) >> cached_shift; if (PerformanceFrequency) PerformanceFrequency->QuadPart = cached_tsc_freq; return STATUS_SUCCESS; }
Код (Text): RDTSC: 104576556070602, QPC: 25113090688, FREQ: 10000000 RDTSC: 104577051659995, QPC: 25114327194, FREQ: 10000000 RDTSC: 104577482537159, QPC: 25115402236, FREQ: 10000000 RDTSC: 104577918714364, QPC: 25116490501, FREQ: 10000000 RDTSC: 104578358818373, QPC: 25117588566, FREQ: 10000000 RDTSC: 104578797081227, QPC: 25118682036, FREQ: 10000000 RDTSC: 104579235100407, QPC: 25119774899, FREQ: 10000000 RDTSC: 104579675170783, QPC: 25120872878, FREQ: 10000000 RDTSC: 104580111324371, QPC: 25121961084, FREQ: 10000000 RDTSC: 104580549362612, QPC: 25123053994, FREQ: 10000000 104580549362612 - 104576556070602 = 3993292010 25123053994 - 25113090688 = 9963310 RDTSC / QPC = 3993292010 / 9963310 ≈ 400.799 --- Сообщение объединено, 27 май 2025 --- преуспевать
Код (Text): static NTSTATUS QPCHook( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency) { if (!PerformanceCounter) return STATUS_ACCESS_VIOLATION; static bool tls_calibrated = false; static UINT64 tls_tsc_freq = 0; if (!tls_calibrated) { *(USHORT*)&SharedUserData->QpcData = (*(USHORT*)&SharedUserData->QpcData | 0x0001) & ~(0x0002 | 0x0080); *(volatile ULONGLONG*)(&SharedUserData->QpcBias) = 0; tls_tsc_freq = GetKernelTSCFrequency(); *(LONGLONG*)(&SharedUserData->QpcFrequency) = tls_tsc_freq; tls_calibrated = true; } UINT64 current_tsc = __rdtsc(); PerformanceCounter->QuadPart = current_tsc; if (PerformanceFrequency) PerformanceFrequency->QuadPart = tls_tsc_freq; return STATUS_SUCCESS; } Код (Text): RDTSC: 226281083690684, QPC: 226281083691523, FREQ: 4008003775 RDTSC: 226281501712621, QPC: 226281501715577, FREQ: 4008003775 RDTSC: 226281938115703, QPC: 226281938119206, FREQ: 4008003775 RDTSC: 226282378197316, QPC: 226282378200047, FREQ: 4008003775 RDTSC: 226282816344965, QPC: 226282816347556, FREQ: 4008003775 RDTSC: 226283252826076, QPC: 226283252829052, FREQ: 4008003775 RDTSC: 226283690934045, QPC: 226283690936975, FREQ: 4008003775 RDTSC: 226284129232575, QPC: 226284129235396, FREQ: 4008003775 RDTSC: 226284567444364, QPC: 226284567482848, FREQ: 4008003775 RDTSC: 226285005410383, QPC: 226285005413512, FREQ: 4008003775 Значения QPC отличаются от RDTSC менее чем на 1000 тактов, но я не знаю, как уменьшить это расхождение ещё больше