flat assembler
Message board for the users of flat assembler.
Index
> High Level Languages > System time acceleration after modifying QPC |
| Author |
|
|
AsmGuru62 18 Nov 2025, 23:55
Nice research, but I think you can get the same value (no patching needed) using this function, designed for HLL:
https://learn.microsoft.com/en-us/cpp/intrinsics/rdtsc?view=msvc-170 |
|||
|
|
SoHigh200 20 Nov 2025, 01:07
AsmGuru62 wrote: Nice research, but I think you can get the same value (no patching needed) using this function, designed for HLL: After extensive investigation and multiple implementation attempts, I need to inform you that i cannot achieve both raw Time Stamp Counter access through QueryPerformanceCounter and accurate system clock progression simultaneously within the Windows kernel architecture. This conclusion is based on concrete technical barriers rather than implementation challenges, and I want to provide you with a complete explanation of what i discovered and the options available moving forward. my research goal was to modify QueryPerformanceCounter to return raw processor cycle counts at the actual TSC frequency while maintaining normal system time progression. i successfully implemented the first part by patching the ntdll shared library section to return raw TSC values directly from the RDTSC instruction. However, this modification creates a frequency mismatch with the kernel's timing calibration parameters, causing the system clock to advance approximately four hundred times faster than real time. i attempted several approaches to resolve this time acceleration issue. The first approach involved directly modifying the kernel's SharedUserData calibration parameters to account for the raw TSC frequency. While i successfully computed mathematically correct calibration values using the Windows-provided RtlGenerateQpcToIncrementConstants function, writing these values to SharedUserData caused the system clock to freeze completely. This occurred because the kernel maintains baseline performance counter values synchronized with the previous normalized frequency regime, creating an irreconcilable mismatch when we changed only the calibration parameters. The second approach attempted to hook the kernel's KiUpdateSystemTime function to substitute corrected calibration parameters during timer interrupt processing. This implementation encountered critical failures related to executable memory allocation for the hook trampoline, resulting in system crashes with access violation exceptions. Even with corrected executable memory allocation, the complexity of maintaining synchronization between all timing subsystem components during the transition from normalized to raw counter values proved architecturally problematic. The third approach proposed hooking KeQueryPerformanceCounter to provide context-aware return values, scaling raw TSC to normalized frequency for kernel timer interrupts while returning raw values for user-mode applications. However, this function is protected by Control Flow Guard, a kernel security feature that prevents modification of critical system functions to protect against exploitation. This represents a fundamental architectural barrier that cannot be circumvented without disabling core security features. The technical constraints i encountered reflect deliberate design decisions by Microsoft to protect system timing integrity. The Windows kernel implements multiple layers of security and consistency checks specifically designed to prevent tampering with timing infrastructure, as accurate timekeeping is fundamental to scheduler operation, file system integrity, security event logging, and numerous other critical system functions. Given these architectural limitations my only option is accept the time acceleration and move on |
|||
|
|
bitshifter 20 Nov 2025, 01:56
Measuring time on multi core systems is not simple.
Agner Fog has nice low level performance timing code for many systems. Maybe the answer can be found here. https://agner.org/optimize/testp.zip |
|||
|
|
revolution 20 Nov 2025, 06:03
SoHigh200 wrote: ... return raw processor cycle counts at the actual TSC frequency ... For almost all CPUs manufactured today the TSC runs at a fixed frequency, and is in no way related the the CPU cycle counts. But each CPU is different and future CPUs might use it differently. |
|||
|
|
AsmGuru62 20 Nov 2025, 13:54
To measure (or research) performance that same function QueryPerformanceCounter can be used.
All what is needed is to make a long loop where the only difference is the principle (or a way) of coding. Here is an example: Code: ; --------------------------------------------------------------------------- ; PROGRAM ENTRY POINT ; --------------------------------------------------------------------------- align 16 start: mov ebx, ParamTest_PushMem call ParamTest_Main mov ebx, ParamTest_PushReg call ParamTest_Main int3 ; ; Here: ; ST0 = relative time taken by 'ParamTest_PushReg' ; ST1 = relative time taken by 'ParamTest_PushMem' ; nop nop nop invoke ExitProcess, 0 And the rest of functions are next: Code: ; --------------------------------------------------------------------------- ; FILE: ParamTest.Asm ; DATE: November 20, 2025 ; --------------------------------------------------------------------------- align 16 proc ParamTest_PushMem uses ecx, param1:DWORD, param2:DWORD, param3:DWORD ; --------------------------------------------------------------------------- invoke MulDiv, [param1], [param2], [param3] ret endp align 16 proc ParamTest_PushReg uses ecx, param1:DWORD, param2:DWORD, param3:DWORD ; --------------------------------------------------------------------------- mov eax, [param1] mov ecx, [param2] mov edx, [param3] invoke MulDiv, eax, ecx, edx ret endp align 16 proc ParamTest_Main ; --------------------------------------------------------------------------- ; INPUT: ; ebx = pointer to a function to test ; --------------------------------------------------------------------------- local low_int64:DWORD local high_int64:DWORD ; ; Get the counter before code being tested ; lea esi, [low_int64] invoke QueryPerformanceCounter, esi fild qword [esi] ; ; Call the code being tested in a long loop ; mov ecx, 0x10000000 @@: stdcall ebx, 100, 25, 4 loop @r ; ; Get the counter after code being tested ; invoke QueryPerformanceCounter, esi fild qword [esi] ; ; Subtract two counter values ; fsubrp ; ; ST0 = difference between counter values. ; Just look at it in debugger later on. ; ret endp |
|||
|
|
SoHigh200 21 Nov 2025, 21:46
AsmGuru62 wrote: ![]() |
|||
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.