QueryPerformanceCounter Timing
A timing-based anti-analysis check that uses the high-resolution performance counter to detect single-stepping or breakpoint-induced execution delays.
QueryPerformanceCounter (QPC) returns a monotonic, high-resolution timestamp
from a hardware or hypervisor-backed counter. Malware brackets a short block of
code with two QPC reads and measures the elapsed ticks. Under normal execution
the delta is tiny; when an analyst single-steps the block or trips a software
breakpoint, the delta explodes, revealing the debugger.
Unlike flag-based checks such as IsDebuggerPresent, a timing check leaves no
artifact to patch in memory — it observes a side effect of analysis itself.
How it works
The sample records the counter, runs a few instructions, records it again, and compares the difference against a threshold. A human stepping through, or a debugger servicing exceptions, inflates the measured interval by orders of magnitude.
#include <windows.h>
LARGE_INTEGER t1, t2;
QueryPerformanceCounter(&t1);
// ... small block of work the analyst might single-step ...
QueryPerformanceCounter(&t2);
if ((t2.QuadPart - t1.QuadPart) > THRESHOLD) {
// Execution was too slow — likely being debugged.
ExitProcess(0);
}The same idea appears with rdtsc, GetTickCount, and timeGetTime; QPC is
favored because it is high-resolution and stable across the cores a hypervisor
exposes.
Detection & analysis
When reverse engineering a sample that uses this check:
- Static analysis: flag paired imports of
QueryPerformanceCounter(andQueryPerformanceFrequency) where the two results feed a subtraction and a comparison branch. Look for the same pattern around decryption or unpacking stubs. - Dynamic analysis: hook
QueryPerformanceCounterand return monotonically increasing values with small, consistent deltas so timed blocks always appear fast. ScyllaHide's timing patches and time-warp plugins automate this. - Detection rule hint: in YARA, match the imports
QueryPerformanceCounterplusQueryPerformanceFrequencyco-occurring with a conditionalExitProcessor jump; in behavioral logs, alert on two QPC calls separated by very few instructions followed by an early exit.