一、前言

1、本文说明

如果喜欢打开XX软件看XX视频等,看了多少次,什么时候看的,都会被记录下来,用软件来查看一下,全部的隐私都没有了。

家里的小孩玩的啥游戏,玩了多少次,也都可以看得一清二楚。

查看*.pf格式的软件有:WinPrefetchView、LastActivityView等。

本文带你深入了解pf格式文件所隐藏的内容,并用C/C++编写了个小软件,实现了隐私读取和分析。

顺带讲一下如何清除该隐私.

2、pf 文件简介

在Windows XP及其以后的操作系统中,增加了预读取功能(也可以理解为“预先装载”),该功能可以提高系统的性能,加快系统的启动、文件读取的速度,这些预读文件保存在%systemroot%\Prefetch目录中,以*.pf为扩展名,这些*.pf文件包括了载入文件的详细信息和载入顺序。

每一个应用程序,包括Windows XP的启动过程,都会在PrefetCh目录下留下相应的预读取文件,预读取文件描述了应用程序或启动时各个模块的装载顺序,其命名方式是以应用程序的可执行文件的名字为基础,加上一个“-”和描述执行文件完整路径的十六进制值,再加上文件扩展名.pf,例如QQ.EX-0065A2A1.pf。每当用户启动一个程序,会自动在Prefetch目录中对应的*.pf文件中留下一条记录。不过,Windows XP启动的预读取文件总是同一个名称,即NTOSBOOT-B00DFAAD.PF,其中包含着启动时载入文件的记录。

当下一次启动系统或运行某个程序时,Windows会参考相应的*.pf文件,将其中记录的所有文件载入内存,而不是象以往一项一项依指令逐个载入文件。另外,Windows会利用启动程序或程序的*.pf文件制订一个最优化的磁盘分配方案,这个方案的相关信息存储在Lyaout.ini文件中。

二、关闭预加载功能、保护隐私

注册表项位置:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters

EnablePrefetcher键值:

0代表完全不预读,即为取消预读功能 设置为"1",系统将只预读应用程序; 设置为"2",系统将只预读Windows系统文件; 设置为"3",系统将预读Windows系统文件和应用程序(默认值,有的系统版本默认为1)

修改注册表后,再删除:C:\Windows\Prefetch(C:\为系统盘)下的所有*.pf格式文件

注册表路径太长了,放引用里换行了,单独拿出来:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters

三、pf 文件格式分析

图一、使用WinHex打开的pf文件头部信息

x86系列的CPU都是 Little-Endian 的字节序。所要获取的值得倒着看!

如图一,文件的长度(第一行的C - F位置):04 4C 00 00,其值是:00 00 4C 04。

1、头部信息详解(对图一进行分析)

pf文件头部信息分析

偏移位作用值0x00000000 - 0x0000000B暂定为固定信息(暂时不知道有何用处)0x0000000C - 0x0000000F文件长度0x4C040x00000010 - 0x00000029pf文件名CONHOST.EXE0x00000064 - 0x00000067预加载位置0x38700x0000006C - 0x0000006F预加载大小0x0EB00x00000080 - 0x00000087 最后一次运行时间(FILETIME型)0x01D5B4D9 0x811686FB0x00000098 - 0x0000009B文件运行次数0x22

2、用C/C++定义的结构体

typedef struct pfFILEHEAD

{

unsigned char unknown_1[0x0C];

unsigned int End; //文件长度

wchar_t FileName[0x14]; //文件名

unsigned char unknown_2[0x2C];

unsigned int Start; //预加载位置

unsigned int SizeOff; //大小

unsigned char unknown_3[0x14];

FILETIME Ctime; //最后一次运行时间

unsigned char unknown_4[0x10];

unsigned int RunCount; //运行次数

} FILEHEAD;//定义的头部信息结构体

3、预加载信息

图二、0x2D28 预加载信息位置

预加载信息是由头部信息里的0x00000064位置记录着的,记录路径用的是宽字符(wchar_t类型)存储的,用记事本等软件打开是乱码。

可用WinHex来打开查看。

找到相应的位置后,可以看到“\DEVICE\HARDDISKVOLUME”开头的路径(Dos驱动路径)

4、其它

pf文件内容本身并不包含指定是那个运行程序的预加载,想要得到是那个程序运行的信息,可以在搜索NT路径时对比文件名。

pf文件命名有一定的规律性,这里不用获取文件名方式,主要是考虑到“离线”分析,文件名是可以改的。

四、C/C++语言编程

打包的工程里包含了转换成NT路径的源代码:https://download.csdn.net/download/duke56/12043965

打包了VC6.0 和 VS2008工程,方便下载打开直接编译。

这里为了文章的简洁,去掉了转换成NT路径的源代码,工程里的程序运行结果请看图三。

#include

#include

#include

typedef struct pfFILEHEAD

{

unsigned char unknown_1[0x0C];

unsigned int End; //文件长度

wchar_t FileName[0x14]; //文件名

unsigned char unknown_2[0x2C];

unsigned int Start; //预加载位置

unsigned int SizeOff; //大小

unsigned char unknown_3[0x14];

FILETIME Ctime; //最后一次运行时间

unsigned char unknown_4[0x10];

unsigned int RunCount; //运行次数

} FILEHEAD;//定义的头部信息结构体

int main(void)

{

char FilePath[] = "C:\\Windows\\Prefetch\\CONHOST.EXE-1F3E9D7E.pf";//要分析的文件,自行修改

FILEHEAD FileInfo;//文件头部结构体

unsigned int len = 0;

unsigned int status = 0;

setlocale(LC_ALL, "chs");

FILE *stream = fopen(FilePath,"r");

if ( !stream )

{

printf("打开pf文件失败:%s\n",FilePath);

return -1;

}

memset(&FileInfo,0,sizeof(FILEHEAD));

status = fread(&FileInfo,sizeof(FILEHEAD),1,stream);//读取头部信息

if ( !status )

{

wprintf(L"读取pf文件头部信息失败\n");

return -2;

}

FILE *SaveFile = fopen("Info.txt","w+");//输出信息保存文件

wprintf(L"文件名称:%s\n",FileInfo.FileName);

wprintf(L"文件长度:%X\n",FileInfo.End);

wprintf(L"加载位置:%X\n",FileInfo.Start);

wprintf(L"加载大小:%X\n",FileInfo.SizeOff);

SYSTEMTIME stUTC, stLocal; // 保存文件的UTC时间和本地时间

FileTimeToSystemTime(&FileInfo.Ctime, &stUTC);

SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);

wprintf(L"修改时间:%u-%u-%u %u:%u:%u:%u 星期:%d\n",

stLocal.wYear,stLocal.wMonth,stLocal.wDay,

stLocal.wHour,stLocal.wMinute,stLocal.wSecond,

stLocal.wMilliseconds,stLocal.wDayOfWeek);

wprintf(L"运行次数:%d\n\n",FileInfo.RunCount);

if ( SaveFile )

{

fwprintf(SaveFile,L"文件名称:%s\n",FileInfo.FileName);

fwprintf(SaveFile,L"文件长度:%X\n",FileInfo.End);

fwprintf(SaveFile,L"加载位置:%X\n",FileInfo.Start);

fwprintf(SaveFile,L"加载大小:%X\n",FileInfo.SizeOff);

fwprintf(SaveFile,L"修改时间:%u-%u-%u %u:%u:%u:%u 星期:%d\n",

stLocal.wYear,stLocal.wMonth,stLocal.wDay,

stLocal.wHour,stLocal.wMinute,stLocal.wSecond,

stLocal.wMilliseconds,stLocal.wDayOfWeek);

fwprintf(SaveFile,L"运行次数:%d\n\n",FileInfo.RunCount);

}

wchar_t * SearchPath = (wchar_t *)malloc( FileInfo.SizeOff );//申请保存检索文件驱动信息

memset(SearchPath,0,FileInfo.SizeOff);

fseek(stream,FileInfo.Start,SEEK_SET);//移动文件指针到信息位置

fread(SearchPath,FileInfo.SizeOff,1,stream);//读取信息内容

unsigned int index = 0;//检索路径位置

unsigned Offset = 0;

for ( int count = 0; Offset < FileInfo.SizeOff && (SearchPath + index)[0] == L'\\'; ++count ) //'

{

len = wcslen(SearchPath + index);

Offset += len * sizeof(wchar_t);

wprintf(L"索引位置:%d\n",count);

wprintf(L"Dos驱动路径:%s\n",SearchPath + index);

wprintf(L"=========================================\n");

if ( SaveFile )

{

fwprintf(SaveFile,L"索引位置:%d\n",count);

fwprintf(SaveFile,L"Dos驱动路径:%s\n",SearchPath + index);

fwprintf(SaveFile,L"=========================================\n");

}

index += wcslen(SearchPath + index) + 1;//获得下一个路径位置

}

free(SearchPath);

fclose(stream);

fclose(SaveFile);

return 0;

}

图三、完整程序运行截图

passwd:0x01D5B4D9 0x811686FB

(包括中间的空格,直接从0x复制到FB)