Today I learned about KUSER_SHARED_DATA: a kernel-populated shared page that user mode can read directly.
User-mode address
- User mode reads it at fixed address
0x7FFE0000(same on x86 and x64). - It is mapped read-only in user mode.
- Kernel has a different fixed mapping, but from user-mode reversing,
0x7FFE0000is the important one.
What is stored there (high value fields)
This structure contains fast-access global OS data, historically heavy on time-related values:
TickCount/TickCountLowDeprecatedTickCountMultiplierInterruptTimeSystemTimeTimeZoneBias
Why malware cares
Malware often reads KUSER_SHARED_DATA directly for low-overhead timing checks (instead of noisy API calls), for example to:
- kill time checks
- detect sleeps/time acceleration in sandboxes
- spot breakpoint/single-step slowdowns
- implement anti-emulation timing heuristics
Because the address is fixed and reads are cheap, this is a common primitive in packed samples and anti-analysis routines.
Even with -ldflags="-s -w", Go binaries retain the pclntab section which maps PC values to function names. Tools like GoReSym or IDA’s Go helper scripts can recover the full symbol table. “Stripped” means less than you think in Go.
Standard UPX uses the magic bytes UPX! (0x55505821). Swapping them to anything else (e.g. TRTW / 0x54525457) causes upx -d to throw NotPackedException while the binary still unpacks and runs fine at runtime. Four bytes of friction against automated tools.