介紹
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條目了。
預覽效果
參考資料
- Windows 中 Cookie、Internet Temp Files、History、Temp Directory 具體路徑(2000、Xp、Vista、Win7)
- 很好的文章:index.dat的分析(也詳細介紹了cookie)
- A few words about the cache / history on Internet Explorer 10
- Index.Dat Files and Primary I.E. Folders
- Understanding Microsoft Internet Explorer Cache
- Reading the Internet Explorer Cache
- Exploring the URL Cache
- Internet Explorer History File Format
代碼
View it on github.