Корректный ли это способ хука NtQueryPerformanceCounter, чтобы возвращать rdtsc напрямую?

Тема в разделе "WASM.NT.KERNEL", создана пользователем zky02, 24 май 2025.

  1. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28
    Привет! Это правильный способ заменить NtQueryPerformanceCounter на RDTSC? Спасибо.

    Код (Text):
    1. NTSTATUS HookedNtQueryPerformanceCounter3(
    2.     PLARGE_INTEGER PerformanceCounter,
    3.     PLARGE_INTEGER PerformanceFrequency)
    4. {
    5.     static bool initialized = false;
    6.  
    7.     if (!initialized) {
    8.         // Однократное исправление SharedUserData
    9.         __try {
    10.             // Сбросить флаг Qpc bias
    11.             *(BYTE*)(&SharedUserData->QpcData) = *(BYTE*)(&SharedUserData->QpcData) & 0xFFFE;
    12.  
    13.             // Установить новую частоту
    14.             *(LONGLONG*)(&SharedUserData->QpcFrequency) = rdtscfreq;
    15.  
    16.             // Очистить данные Qpc bias/virtualization
    17.             *(BYTE*)((BYTE*)SharedUserData + 0x3c7) = 0;
    18.             *(LONGLONG*)((BYTE*)SharedUserData + 0x3b8) = 0;
    19.  
    20.             initialized = true;
    21.         }
    22.         __except (EXCEPTION_EXECUTE_HANDLER) {
    23.             NOTHING;
    24.         }
    25.     }
    26.  
    27.     if (!PerformanceCounter)
    28.         return STATUS_ACCESS_VIOLATION;
    29.  
    30.     PerformanceCounter->QuadPart = __rdtsc();
    31.  
    32.     if (PerformanceFrequency)
    33.         PerformanceFrequency->QuadPart = rdtscfreq;
    34.  
    35.     return STATUS_SUCCESS;
    36. }
     
  2. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    392
    модить SharedUserData надо?
     
  3. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28
    Я так думаю, потому что qpc нельзя масштабировать с помощью rdtsc
     
  4. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28
    Я нашёл, что работает только этот метод — напрямую использовать rdtsc у меня никогда не получалось, так как я не знаю, что именно управляет частотой 10 МГц

    Код (Text):
    1. static long long tsc_to_nanoseconds(unsigned long long tsc_count)
    2. {
    3.     long long scaled_ns = (tsc_count / rdtscfreq) * 10000000LL;
    4.  
    5.  
    6.     unsigned long long remainder = tsc_count % rdtscfreq;
    7.     scaled_ns += (remainder * 10000000LL) / rdtscfreq;
    8.  
    9.     return scaled_ns;
    10. }  
    11.  
    12. PerformanceCounter->QuadPart = tsc_to_nanoseconds(__rdtsc());
    13. if (PerformanceFrequency)
    14.      PerformanceFrequency->QuadPart = 10000000LL;
    --- Сообщение объединено, 26 май 2025 ---
    upload_2025-5-26_1-22-9.png
    преуспевать
     
  5. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    392
    Код (C++):
    1. NTSTATUS HookedNtQueryPerformanceCounter(
    2.     PLARGE_INTEGER PerformanceCounter,
    3.     PLARGE_INTEGER PerformanceFrequency)
    4. {
    5.     if (!PerformanceCounter)
    6.         return STATUS_ACCESS_VIOLATION;
    7.  
    8.     // Get current TSC value
    9.     UINT64 tsc = __rdtsc();
    10.  
    11.     // Convert TSC to QPC units (10MHz base)
    12.     // This maintains compatibility with existing code
    13.     PerformanceCounter->QuadPart = (tsc * 10000000ULL) / rdtscfreq;
    14.  
    15.     if (PerformanceFrequency)
    16.         PerformanceFrequency->QuadPart = 10000000ULL; // 10 MHz standard
    17.  
    18.     return STATUS_SUCCESS;
    19. }
    --- Сообщение объединено, 26 май 2025 ---
    Intelligent QPC Hook with Auto-Calibration
    Код (C++):
    1. class SmartQPCHook {
    2. private:
    3.     static volatile bool initialized;
    4.     static UINT64 tsc_frequency;
    5.     static UINT64 qpc_baseline;
    6.     static UINT64 tsc_baseline;
    7.     static double scale_factor;
    8.    
    9.     static void calibrate_once() {
    10.         if (initialized) return;
    11.        
    12.         // Get real QPC values for calibration
    13.         LARGE_INTEGER real_qpc1, real_qpc2, freq;
    14.         UINT64 tsc1, tsc2;
    15.        
    16.         // Sample multiple times for accuracy
    17.         tsc1 = __rdtsc();
    18.         QueryPerformanceCounter(&real_qpc1);
    19.        
    20.         Sleep(10); // Short delay
    21.        
    22.         tsc2 = __rdtsc();
    23.         QueryPerformanceCounter(&real_qpc2);
    24.         QueryPerformanceFrequency(&freq);
    25.        
    26.         // Calculate precise scaling
    27.         UINT64 tsc_delta = tsc2 - tsc1;
    28.         UINT64 qpc_delta = real_qpc2.QuadPart - real_qpc1.QuadPart;
    29.        
    30.         scale_factor = (double)qpc_delta / tsc_delta;
    31.         tsc_baseline = tsc1;
    32.         qpc_baseline = real_qpc1.QuadPart;
    33.         tsc_frequency = freq.QuadPart;
    34.        
    35.         _InterlockedExchange8((char*)&initialized, 1);
    36.     }
    37.  
    38. public:
    39.     static NTSTATUS NTAPI HookedNtQueryPerformanceCounter(
    40.         PLARGE_INTEGER PerformanceCounter,
    41.         PLARGE_INTEGER PerformanceFrequency)
    42.     {
    43.         if (!PerformanceCounter)
    44.             return STATUS_ACCESS_VIOLATION;
    45.            
    46.         if (!initialized) {
    47.             calibrate_once();
    48.         }
    49.        
    50.         // Convert TSC to QPC using calibrated scaling
    51.         UINT64 current_tsc = __rdtsc();
    52.         UINT64 tsc_offset = current_tsc - tsc_baseline;
    53.        
    54.         PerformanceCounter->QuadPart = qpc_baseline +
    55.             (UINT64)(tsc_offset * scale_factor);
    56.        
    57.         if (PerformanceFrequency)
    58.             PerformanceFrequency->QuadPart = tsc_frequency;
    59.            
    60.         return STATUS_SUCCESS;
    61.     }
    62. };
    63.  
    64. // Static member definitions
    65. volatile bool SmartQPCHook::initialized = false;
    66. UINT64 SmartQPCHook::tsc_frequency = 0;
    67. UINT64 SmartQPCHook::qpc_baseline = 0;
    68. UINT64 SmartQPCHook::tsc_baseline = 0;
    69. double SmartQPCHook::scale_factor = 0.0;
    70.  
    Even Smarter: Runtime Adaptive Solution

    Код (C++):
    1. static NTSTATUS NTAPI AdaptiveQPCHook(
    2.     PLARGE_INTEGER PerformanceCounter,
    3.     PLARGE_INTEGER PerformanceFrequency)
    4. {
    5.     if (!PerformanceCounter)
    6.         return STATUS_ACCESS_VIOLATION;
    7.    
    8.     static thread_local bool tls_calibrated = false;
    9.     static thread_local UINT64 tls_scale_num = 0;
    10.     static thread_local UINT64 tls_scale_den = 0;
    11.     static thread_local UINT64 tls_qpc_freq = 0;
    12.    
    13.     // Per-thread calibration for maximum accuracy
    14.     if (!tls_calibrated) {
    15.         LARGE_INTEGER freq, qpc1, qpc2;
    16.         UINT64 tsc1, tsc2;
    17.        
    18.         // Quick calibration
    19.         QueryPerformanceFrequency(&freq);
    20.        
    21.         tsc1 = __rdtsc();
    22.         QueryPerformanceCounter(&qpc1);
    23.        
    24.         // Micro-delay using TSC
    25.         UINT64 target = tsc1 + 1000000; // ~1ms on modern CPUs
    26.         while (__rdtsc() < target);
    27.        
    28.         tsc2 = __rdtsc();
    29.         QueryPerformanceCounter(&qpc2);
    30.        
    31.         // Calculate integer scaling to avoid floating point
    32.         UINT64 tsc_delta = tsc2 - tsc1;
    33.         UINT64 qpc_delta = qpc2.QuadPart - qpc1.QuadPart;
    34.        
    35.         tls_scale_num = qpc_delta;
    36.         tls_scale_den = tsc_delta;
    37.         tls_qpc_freq = freq.QuadPart;
    38.        
    39.         tls_calibrated = true;
    40.     }
    41.    
    42.     // Fast TSC->QPC conversion using integer math
    43.     static UINT64 base_tsc = __rdtsc();
    44.     UINT64 current_tsc = __rdtsc();
    45.     UINT64 tsc_elapsed = current_tsc - base_tsc;
    46.    
    47.     // Scale TSC to QPC units
    48.     PerformanceCounter->QuadPart = (tsc_elapsed * tls_scale_num) / tls_scale_den;
    49.    
    50.     if (PerformanceFrequency)
    51.         PerformanceFrequency->QuadPart = tls_qpc_freq;
    52.        
    53.     return STATUS_SUCCESS;
    54. }
    55.  
    Ultra-Smart: VDSO-Style Fast Path
    Код (C++):
    1.  
    2. // Leverage existing system calibration
    3. static NTSTATUS NTAPI VDSOStyleQPCHook(
    4.     PLARGE_INTEGER PerformanceCounter,
    5.     PLARGE_INTEGER PerformanceFrequency)
    6. {
    7.     if (!PerformanceCounter)
    8.         return STATUS_ACCESS_VIOLATION;
    9.    
    10.     // Read system's own TSC calibration data
    11.     static UINT64 cached_mult = 0;
    12.     static UINT32 cached_shift = 0;
    13.     static UINT64 cached_freq = 0;
    14.    
    15.     if (!cached_mult) {
    16.         // Extract from SharedUserData if accessible
    17.         auto* sud = (KUSER_SHARED_DATA*)0x7FFE0000;
    18.         if (sud && sud->QpcFrequency.QuadPart) {
    19.             cached_freq = sud->QpcFrequency.QuadPart;
    20.            
    21.             // Use system's TSC scaling if available
    22.             if (sud->QpcData.QpcMultiplier) {
    23.                 cached_mult = sud->QpcData.QpcMultiplier;
    24.                 cached_shift = sud->QpcData.QpcShift;
    25.             } else {
    26.                 // Fallback: calculate our own
    27.                 cached_mult = (cached_freq << 32) / __rdtsc();
    28.                 cached_shift = 32;
    29.             }
    30.         }
    31.     }
    32.    
    33.     if (cached_mult) {
    34.         // Use system-compatible scaling
    35.         UINT64 tsc = __rdtsc();
    36.         PerformanceCounter->QuadPart = (tsc * cached_mult) >> cached_shift;
    37.     } else {
    38.         // Emergency fallback
    39.         PerformanceCounter->QuadPart = __rdtsc();
    40.     }
    41.    
    42.     if (PerformanceFrequency)
    43.         PerformanceFrequency->QuadPart = cached_freq;
    44.        
    45.     return STATUS_SUCCESS;
    46. }
     
  6. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28

    большое спасибо Моя цель заключалась в том, чтобы пропатчить 10МГц и использовать его напрямую. Для этого мне нужно было найти патч KeQueryPerformanceCounter внутри HalpPerformanceCounter.QueryCounter, чтобы он возвращал rdtsc, затем пропатчить структуру HAL - исправить каждые 10МГц внутри KeQueryPerformanceCounter по смещению 0xc0, чтобы он возвращал вашу реальную частоту. Получить её оттуда, а затем перехватить NtQueryPerformanceCounter, чтобы он возвращал rdtsc с частотой, полученной из смещения 0xc0.
    --- Сообщение объединено, 26 май 2025 ---
    Код (Text):
    1. PVOID FindHalpPerformanceCounter() {
    2.  
    3.     UNICODE_STRING routineName = RTL_CONSTANT_STRING(L"KeQueryPerformanceCounter");
    4.     PVOID keQueryPerformanceCounter = MmGetSystemRoutineAddress(&routineName);
    5.  
    6.     if (!keQueryPerformanceCounter) {
    7.         return nullptr;
    8.     }
    9.  
    10.    
    11. // Template from your disassembly: mov rdi, qword ptr [nt!HalpPerformanceCounter]
    12. // Offset instruction 0x12: 48 8B 3D ?? ?? ?? ?? (REX.W mov rdi, [rip+offset])
    13.  
    14.     PUCHAR scanAddress = (PUCHAR)keQueryPerformanceCounter;
    15.  
    16.     for (ULONG i = 0; i < 0x100; i++) {
    17.         if (scanAddress[i] == 0x48 && scanAddress[i + 1] == 0x8B && scanAddress[i + 2] == 0x3D) {
    18.      
    19.             LONG relativeOffset = *(PLONG)(&scanAddress[i + 3]);
    20.             PVOID halpPerformanceCounterAddress = (PVOID)(&scanAddress[i + 7] + relativeOffset);
    21.  
    22.             return *(PVOID*)halpPerformanceCounterAddress;
    23.         }
    24.     }
    25.  
    26.     return nullptr;
    27. }
    28.  
    29. [code]UINT64 GetKernelQPCFrequency()
    30. {
    31.     static PVOID halpCounter = FindHalpPerformanceCounter();
    32.     if (!halpCounter)
    33.         return 0;
    34.     PUCHAR counterStruct = (PUCHAR)halpCounter;
    35.     UINT64 frequency = *(UINT64*)(counterStruct + 0xC0);
    36.     DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL,
    37.                "HalpPerformanceCounter: %p, Frequency: %llu\n",
    38.                halpCounter, frequency);
    39.     return frequency;
    40. }

    upload_2025-5-26_22-20-23.png
    --- Сообщение объединено, 27 май 2025 ---
    Код (Text):
    1. NTSTATUS HookedNtQueryPerformanceCounter(
    2.     PLARGE_INTEGER PerformanceCounter,
    3.     PLARGE_INTEGER PerformanceFrequency)
    4. {
    5.    
    6.     if (!PerformanceCounter)
    7.         return STATUS_ACCESS_VIOLATION;
    8.  
    9.  
    10.     static UINT64 cached_mult = 0;
    11.     static UINT32 cached_shift = 0;
    12.     static UINT64 cached_tsc_freq = 0;
    13.     static UINT64 cached_qpc_freq = 0;
    14.  
    15.    
    16.     if (!cached_mult) {
    17.         // Получаем частоту оригинального QPC (10 МГц)
    18.         auto* sud = (KUSER_SHARED_DATA*)0xFFFFF78000000000;
    19.         if (sud && sud->QpcFrequency) {
    20.             // Сохраняем исходную частоту QPC до изменения
    21.             cached_qpc_freq = 10000000;
    22.  
    23.             // Получаем частоту TSC от ядра
    24.             cached_tsc_freq = GetKernelTSCFrequency();
    25.  
    26.             if (cached_tsc_freq > 0) {
    27.                 cached_shift = 32;
    28.                 // Вычисляем множитель для преобразования значений
    29.                 cached_mult = (cached_tsc_freq << cached_shift) / cached_qpc_freq;
    30.             }
    31.         }
    32.     }
    33.  
    34.     // Получаем оригинальное значение QPC из ядра
    35.     LARGE_INTEGER original_qpc;
    36.     NTSTATUS status = OriginalNtQueryPerformanceCounter(&original_qpc, NULL);
    37.     if (!NT_SUCCESS(status)) {
    38.         return status;
    39.     }
    40.  
    41.     // Преобразуем значение QPC (в 10 МГц) в эквивалентное значение на частоте TSC
    42.     PerformanceCounter->QuadPart = (original_qpc.QuadPart * cached_mult) >> cached_shift;
    43.  
    44.  
    45.     if (PerformanceFrequency)
    46.         PerformanceFrequency->QuadPart = cached_tsc_freq;
    47.  
    48.     return STATUS_SUCCESS;
    49. }
     
  7. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28
    Код (Text):
    1. RDTSC: 104576556070602, QPC: 25113090688, FREQ: 10000000
    2. RDTSC: 104577051659995, QPC: 25114327194, FREQ: 10000000
    3. RDTSC: 104577482537159, QPC: 25115402236, FREQ: 10000000
    4. RDTSC: 104577918714364, QPC: 25116490501, FREQ: 10000000
    5. RDTSC: 104578358818373, QPC: 25117588566, FREQ: 10000000
    6. RDTSC: 104578797081227, QPC: 25118682036, FREQ: 10000000
    7. RDTSC: 104579235100407, QPC: 25119774899, FREQ: 10000000
    8. RDTSC: 104579675170783, QPC: 25120872878, FREQ: 10000000
    9. RDTSC: 104580111324371, QPC: 25121961084, FREQ: 10000000
    10. RDTSC: 104580549362612, QPC: 25123053994, FREQ: 10000000   104580549362612 - 104576556070602 = 3993292010  25123053994     - 25113090688     =    9963310  RDTSC / QPC = 3993292010 / 9963310 ≈ 400.799
    --- Сообщение объединено, 27 май 2025 ---
    преуспевать

    upload_2025-5-27_7-46-29.png
     
  8. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    392
    Share source code :)
     
  9. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28

    Код (Text):
    1. static NTSTATUS QPCHook(
    2.  
    3.     PLARGE_INTEGER PerformanceCounter,
    4.     PLARGE_INTEGER PerformanceFrequency)
    5. {
    6.     if (!PerformanceCounter)
    7.         return STATUS_ACCESS_VIOLATION;
    8.  
    9.     static bool tls_calibrated = false;
    10.     static UINT64 tls_tsc_freq = 0;
    11.  
    12.     if (!tls_calibrated) {
    13.  
    14.         *(USHORT*)&SharedUserData->QpcData = (*(USHORT*)&SharedUserData->QpcData | 0x0001) & ~(0x0002 | 0x0080);
    15.         *(volatile ULONGLONG*)(&SharedUserData->QpcBias) = 0;
    16.  
    17.  
    18.         tls_tsc_freq = GetKernelTSCFrequency();
    19.  
    20.         *(LONGLONG*)(&SharedUserData->QpcFrequency) = tls_tsc_freq;
    21.  
    22.         tls_calibrated = true;
    23.     }
    24.  
    25.  
    26.     UINT64 current_tsc = __rdtsc();
    27.  
    28.  
    29.     PerformanceCounter->QuadPart = current_tsc;
    30.  
    31.     if (PerformanceFrequency)
    32.         PerformanceFrequency->QuadPart = tls_tsc_freq;
    33.  
    34.     return STATUS_SUCCESS;
    35. }
    36.  
    Код (Text):
    1. RDTSC: 226281083690684, QPC: 226281083691523, FREQ: 4008003775
    2.  
    3. RDTSC: 226281501712621, QPC: 226281501715577, FREQ: 4008003775
    4. RDTSC: 226281938115703, QPC: 226281938119206, FREQ: 4008003775
    5. RDTSC: 226282378197316, QPC: 226282378200047, FREQ: 4008003775
    6. RDTSC: 226282816344965, QPC: 226282816347556, FREQ: 4008003775
    7. RDTSC: 226283252826076, QPC: 226283252829052, FREQ: 4008003775
    8. RDTSC: 226283690934045, QPC: 226283690936975, FREQ: 4008003775
    9. RDTSC: 226284129232575, QPC: 226284129235396, FREQ: 4008003775
    10. RDTSC: 226284567444364, QPC: 226284567482848, FREQ: 4008003775
    11. RDTSC: 226285005410383, QPC: 226285005413512, FREQ: 4008003775
    Значения QPC отличаются от RDTSC менее чем на 1000 тактов, но я не знаю, как уменьшить это расхождение ещё больше
     
    Последнее редактирование: 29 май 2025
  10. zky02

    zky02 New Member

    Публикаций:
    0
    Регистрация:
    16 янв 2024
    Сообщения:
    28
    upload_2025-5-30_2-28-12.png совершенство
     
  11. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    392
    Research нравится это.