admin 管理员组

文章数量: 887017

一、前言

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文件长度0x4C04
0x00000010 - 0x00000029pf文件名CONHOST.EXE
0x00000064 - 0x00000067预加载位置0x3870
0x0000006C - 0x0000006F预加载大小0x0EB0
0x00000080 - 0x00000087 最后一次运行时间(FILETIME型)0x01D5B4D9 0x811686FB
0x00000098 - 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/download/duke56/12043965

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

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

#include <stdio.h>
#include <locale.h>
#include <windows.h>

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)

本文标签: 隐私 文件 目录 程序 系统