Prefetch文件结构不固定,不同Windows版本间存在显著差异:魔数“SCCA”和版本号(XP为0x11、Win7为0x17、Win10为0x1A)位置固定,但后续字段偏移随版本变化,必须先读取版本号再动态解析,否则会导致时间戳、运行次数等字段误读。

Prefetch文件结构是否固定?
Windows Prefetch文件(.pf)结构在不同系统版本间有明显差异,但核心布局稳定:前4字节是魔数 "SCCA",紧随其后是版本号(XP为0x11、Win7为0x17、Win10 1809+多为0x1A)。不校验版本直接解析会导致字段偏移错乱,比如把Win10的执行计数误读为时间戳。解析前必须先读取偏移0x04处的version字段,并据此选择对应结构体定义。
如何安全读取Unicode路径与文件名
Prefetch中程序路径以UTF-16 LE存储,但长度不固定,且紧跟在可变长的“文件统计数组”之后。常见错误是硬编码路径起始偏移(如从0x100开始),实际需按版本计算:先跳过头部+运行次数+最后一次执行时间+预加载页列表等字段,再根据number_of_filenames和filename_offset_array定位。路径末尾无null终止符,必须严格按filename_length_in_bytes截取,否则会读到后续内存垃圾。
- Win10 v26/27:路径起始偏移通常在0x120–0x180之间,依赖
filename_offset_array[0] - 用
std::wstring接收,避免char*强制转换导致乱码 - 路径含驱动器符号(如
L"C:\WINDOWS\SYSTEM32\SVCHOST.EXE"),注意反斜杠转义
为什么解析出的执行时间总是1601年?
Prefetch使用Windows FILETIME(100纳秒精度,起点为1601-01-01 UTC),而非Unix时间戳。直接将last_run_time字段(8字节LE)当普通整数打印,会显示为0或极小值,对应FILETIME零点。正确做法是调用FileTimeToSystemTime()或手动转为std::chrono::file_clock(C++20)。
- Win7及以后版本存有8个
last_run_time,分别对应最近8次执行,非所有字段都有效(可能全零) - 部分旧版Prefetch(如XP)只存1个时间,且位于不同偏移
- 注意字节序:x86/x64下FILETIME低32位在前,直接
memcpy到ULARGE_INTEGER即可
能否用纯C++标准库完成解析?
可以读取二进制并解析基础字段(魔数、版本、路径长度),但涉及Windows特有类型(FILETIME、SYSTEMTIME)和路径转换时,必须链接kernel32.lib并调用WinAPI。标准库无跨平台FILETIME处理能力,也无原生UTF-16宽字符文件I/O支持(std::wifstream在MinGW上常失效)。最小依赖是#include <windows.h></windows.h>和#include <fstream></fstream>。
立即学习“C++免费学习笔记(深入)”;
- 打开文件必须用
std::ios::binary,否则CR/LF会被误转 - 用
std::ifstream::read()配合reinterpret_cast<char></char>读结构体,避免operator>>格式化读取 - Prefetch文件权限受UAC限制,普通用户进程无法读取
C:WindowsPrefetch*.pf,需提升权限或复制到临时目录


















