用Qt写软件系列一:QCacheViewer(浏览器缓存查看器)

介绍

     Cache技术广泛应用于计算机行业的软硬件领域。该技术既是人们对新技术探讨的结果,也是对当前软硬件计算能力的一种妥协。在浏览器中使用cache技术,可以大幅度提高web页面的响应速度,降低数据传输延迟,提高web用户的体验。因此,客户端在浏览网页的过程中,会在本地缓存许多文件。随着使用时间增长,本地缓存的文件日渐增多。对于用户来说,查看本地主机当前的缓存文件数目和种类成为一种迫切的需要。

    作为主项目的一部分功能,我们需要完成这样一个浏览器缓存查看器。在网上偶然看到了一款这样的软件:IECacheViewer。这款软件功能恰到好处,正是我们所需要的。奈何该网站上并未公布其实现方式,因此只好以该软件界面作为模板,自动动手一一实现其功能。寻寻觅觅良久之后,终于发现了两种实现方式:(1)调用windows系统提供的API。这些API使用简单,只需要循环调用即可获取Cache信息。但缺点是,该方法只能扫描当前系统中存在的cache文件信息。(2)解析index.dat文件。index.dat文件采用增量记录方法,所有在系统中曾经存在过的cache文件,在index.dat文件中都有记录。关于index.dat文件是什么,在参考资料中可以得到详尽的答案。我们将在方法二中详细剖析index.dat的结构。

方法一、调用系统API 

1. 相关的API:

 1 HANDLE FindFirstUrlCacheEntry(
 2   __in          LPCTSTR lpszUrlSearchPattern,
 3   __out         LPINTERNET_CACHE_ENTRY_INFO lpFirstCacheEntryInfo,
 4   __in_out      LPDWORD lpcbCacheEntryInfo
 5 ); 
 6 
 7 BOOLAPI FindNextUrlCacheEntry(
 8   __in          HANDLE hEnumHandle,
 9   __out         LPINTERNET_CACHE_ENTRY_INFO lpNextCacheEntryInfo,
10   __in_out      LPDWORD lpcbCacheEntryInfo
11 );
12 
13 BOOLAPI FindCloseUrlCache(
14   __in          HANDLE hEnumHandle
15 );
16 
17 typedef struct _INTERNET_CACHE_ENTRY_INFO  { 
18  DWORD dwStructSize; 
19  LPTSTR lpszSourceUrlName; 
20  LPTSTR lpszLocalFileName;  
21  DWORD CacheEntryType; 
22  DWORD dwUseCount;  
23  DWORD dwHitRate;  
24  DWORD dwSizeLow;  
25  DWORD dwSizeHigh;  
26  FILETIME LastModifiedTime;  
27  FILETIME ExpireTime;  
28  FILETIME LastAccessTime;  
29  FILETIME LastSyncTime;  
30  LPBYTE lpHeaderInfo;  
31  DWORD dwHeaderInfoSize; 
32  LPTSTR lpszFileExtension;  
33  union {    DWORD dwReserved;    DWORD dwExemptDelta;  };
34 } INTERNET_CACHE_ENTRY_INFO, *LPINTERNET_CACHE_ENTRY_INFO;

    FindFirstUrlCacheEntry()函数开始枚举Cache信息。其返回一个句柄,该句柄用于所有后续的FindNextUrlCacheEntry()调用。FindCloseUrlCache()函数用户关闭句柄,结束枚举过程。利用上述的三个函数,循环调用并将Cache信息保存在INTERNET_CACHE_ENTRY_INFO结构体中。INTERNET_CACHE_ENTRY_INFO结构体包含了当前Cache文件的详细信息,如文件大小、命中次数、访问时间、修改时间、同步时间等。这样,就可以完成IE Cache信息的提取了。

方法二、 解析index.dat文件

1. 文件结构

    如果解析PE文件一样,在解析index.dat文件之前,我们需要知道index.dat文件的组织结构。网上并没有找到index.dat文件的结构说明,只能依着搜到的几个结构体定义来查看index.dat的结构了。大致示意图如下:

    一个index.dat文件以small header开始,该small header占0x250个字节,其结构定义如下:

    其中最重要的字段是dwHashTableOffset,该字段是DWORD型,在32位机器上占4个字节。dwHashTableOffset保存了index.dat文件中的第一个hash section的地址。nDirCount和DirArray字段分别表示子目录个数和子目录名称数组。通常对于Cache来说,所有的缓存文件都放在一个目录中,这两个字段作用不大。而对于Cookie来说,Cookies文件可能分布于多个子目录中。跟在Small header后面的是full header。其具体作用不详,定义如下:

    再来看Hash Section部分。每个hash section都有一个头部,占16个字节。其定义如下:

hash头部的dwSig字段占4字节,是由“HASH”这个四个字母的ASCII码填充的。nBlocks字段表明本哈希节占用多少个块,块单位为0x80字节。dwNext字段指出下一个hash 头部的开始地址,以index.dat文件的起始地址为基准。nOrder则是当前哈希节的编号。紧随头部的便是hash itmes了。一个hash item占8字节,前4字节是哈希值,后4字节是Cache记录在index.dat文件中的偏移,也是以index.dat文件的起始地址为基准

2. 分析实例

    下面以我的机器上的index.dat文件为例进行实例分析:

 

    根据第一个哈希表的偏移地址(0x4000),跳到0x4000处,如下:

    可以看到,hash头部第一个字段为:48, 41, 53, 48.为"HASH"四个字母。紧接着的四个字节值为0x20,单位为块,每块大小为128字节。值得注意的是,由于我使用的是小端机(little endian:大端高位在前,小端低位在前),因此需要转换一下。第三个四字节值为0x11000,是下一个hash section的头部地址。第四个四字节值为0,表明当前hash section的编号为0。我们再接着看0x4010位置的值。根据上述的结构定义可知,第一个四字节是哈希值,不用管它。接下来的0x1BA00才是最重要,它指明了hash条目在文件中的偏移位置。注意相对的偏移基准。我们再跳到0x1BA00位置:

    这是一个URL类型。在index.dat文件中,hash条目有多种类型,在参考资料中有说明,这里不再赘述。不过,我们应当重点看看hash条目的定义结构:

    按着字段大小一一提取即可。到这里,完成了一次cache信息的提取。我们接着要做的,是查看下一个hash section。因此,再跳到0x11000处:

    当前编号为1,下一个hash section 在0x23000处。再跳到0x23000看看:

    果然,此时下一个hash section 的地址为0,表明这是最后一个section了。当前编号为2.由此可知,这个index.dat文件中只有3个section。所有的hash条目都可以依此提取出来。值得注意的是hash section中存在着空洞。如遇到两个字段都为3或者1,表明这是一个空洞。如下图所示,继续查看,仍然有hash条目存在。当遇到两个字节都是0xDEADBEEF,说明后面不再有hash条目了。

预览效果

参考资料

  1. Windows 中 Cookie、Internet Temp Files、History、Temp Directory 具体路径(2000、Xp、Vista、Win7)
  2. 很好的文章:index.dat的分析(也详细介绍了cookie)
  3. A few words about the cache / history on Internet Explorer 10
  4. Index.Dat Files and Primary I.E. Folders
  5. Understanding Microsoft Internet Explorer Cache
  6. Reading the Internet Explorer Cache
  7. Exploring the URL Cache
  8. Internet Explorer History File Format

代码

    View it on github.

posted @ 2014-02-13 17:55  24K纯开源  阅读(3170)  评论(1编辑  收藏  举报