indexdat文件剖析.docx
《indexdat文件剖析.docx》由会员分享,可在线阅读,更多相关《indexdat文件剖析.docx(19页珍藏版)》请在冰豆网上搜索。
indexdat文件剖析
index.dat文件剖析
一. 前言
注重上网隐私和安全的人在每次上网后都会清除上网痕迹——“删除cookies”、“删除掉上网的临时缓存文件”以及“删除上网历史”。
你觉得这样,所有的一切都会被擦除掉了。
但是如果有人告诉你:
这是不够的,系统中还有一些地方保存了你的上网信息,你是不是感到很恐慌?
——这就是系统中的index.dat文件。
Windows系统中会存在三个index.dat文件。
它们分别用来保存IE上网的cookies、临时文件和上网历史的索引信息(现在知道为什么这些文件名字是index.dat了吧)。
根据Windows系统版本不同,这些文件在系统中的位置也是不尽相同的。
在Windows95/98/Me/NT中,index.dat一般会存放在下面的位置中:
C:
/Windows/Cookies/index.dat
C:
/Windows/History/History.IE5/index.dat
C:
/Windows/TemporaryInternetFiles/Content.IE5/index.dat
而在Window2000/XP系统中,index.dat一般会存在于下面的位置中:
C:
/DocumentsandSettings//Cookies/index.dat
C:
/DocumentsandSettings//LocalSettings/History/History.IE5/index.dat
C:
/DocumentsandSettings//LocalSettings
/TemporaryInternetFiles/Content.IE5/index.dat
这些index.dat文件是系统、隐藏的文件,它们不随IE浏览器中的cookies值、临时文件和历史记录的清除而删除——这就是它的可怕之处。
下面来详细描述index.dat文件的结构。
二. Index.dat文件结构
Index.dat文件分为两部分,头部分和条目(Entry)部分。
所谓头部分,顾名思义就是文件开始部分。
它记录着这个文件的总的信息,如文件文件格式版本、大小、子文件夹等等。
每个index.dat文件仅有一个头部分。
其余的部分都是条目部分。
Index.dat中的各种类型的条目数据结构不同,不过每个条目的前8个字节结构相同,系统就是用这两个DWORD字段来区分条目类型的。
下面我们来具体分析一下各个部分:
1. 头部分
index.dat的头部大小是固定的,为16K。
其开始592个字节(0x250)为小(SMALL)的头部分。
紧接着的空间是3948个DWORD,它用来作为分配MAP。
数据结构如下:
structCacheDir
{
DWORDnFileCount;
CHARsDirName[8];
};
typedefstruct_MEMMAP_HEADER_SMALL
{
TCHARFileSignature[28];//”ClientUrlCacheMMFVer5.2”
DWORDFileSize;//index.dat文件的大小
DWORDdwHashTableOffset;//第一个哈希表的偏移
DWORDNumUrlInternalEntries;
DWORDNumUrlEntriesAlloced;
//DWORDdwGarbage;//无效数据,只在/Zp8编译使用
LONGLONGCacheLimit;
LONGLONGCacheSize;
LONGLONGExemptUsage;
DWORDnDirCount;//子目录个数
CacheDirDirArray[32];//子目录名称
DWORDdwHeaderData[33];
}MEMMAP_HEADER_SMALL;
typedefstruct_MEMMAP_HEADER:
_MEMMAP_HEADER_SMALL
{
DWORDAllocationBitMap[3948];
}MEMMAP_HEADER,*LPMEMMAP_HEADER;
2. 各种条目结构
上文说过每个条目都是以同样结构的2个DWORD开始的,这个结构如下:
typedefstructFILEMAP_ENTRY
{
DWORDdwSig;//条目标识
DWORDnBlocks;//条目占用多少个快(128字节)
}*LPFILEMAP_ENTRY;
dwSig用来标识各种类型的标识。
表示字
值
说明
SIG_FREE
0xbadf00d
本条目空闲,只有此类条目没有nBlocks成员。
SIG_ALLOC
0xdeadbeef
已分配
SIG_URL
'LRU'
URL值
SIG_REDIR
'RDER'
REDIR
SIG_LEAK
'KAEL'
LEAK
SIG_GLIST
'GLST'
GLIST
SIG_HASH
'HSAH'
哈希表
关于各种条目的结构我们下面会详细说明。
nBlocks用来描述此条目所占用的块数。
注意index.dat中的块大小为128字节。
2.1哈希表条目
现在开始说明各种类型的条目。
为什么先要说哈希表呢?
这是因为index.dat使用一个哈希表链来作为目录,从而能够快速找到指定名称的条目。
Index.dat文件中每个哈希表大小都不能超过一个内存分页,即不能超过4K大小。
每个哈希表部分是由下面的结构开始的,同时系统也是利用了这个结构,将index.dat中所有的哈希表部分链接起来的。
structHASH_FILEMAP_ENTRY:
FILEMAP_ENTRY
{
DWORDdwNext;//下一个哈希表偏移(0表示为最后一个)
//偏移以index.dat文件第0字节为基地址。
DWORDnBlock;//本哈希表的序列号。
从0,1,2…….
};
紧接着这个结构就是一个哈希表,每个哈希表的关键是哈希函数,下面是这个哈希表的哈希函数:
PRIVATEDWORDHashKey(LPCSTRlpsz)
{
union
{
DWORDdw;
BYTEc[4];
}
Hash,Hash2;
conststaticBYTEbTranslate[256]=
{
1,14,110,25,97,174,132,119,138,170,125,118,27,233,140,51,
87,197,177,107,234,169,56,68,30,7,173,73,188,40,36,65,
49,213,104,190,57,211,148,223,48,115,15,2,67,186,210,28,
12,181,103,70,22,58,75,78,183,167,238,157,124,147,172,144,
176,161,141,86,60,66,128,83,156,241,79,46,168,198,41,254,
178,85,253,237,250,154,133,88,35,206,95,116,252,192,54,221,
102,218,255,240,82,106,158,201,61,3,89,9,42,155,159,93,
166,80,50,34,175,195,100,99,26,150,16,145,4,33,8,189,
121,64,77,72,208,245,130,122,143,55,105,134,29,164,185,194,
193,239,101,242,5,171,126,11,74,59,137,228,108,191,232,139,
6,24,81,20,127,17,91,92,251,151,225,207,21,98,113,112,
84,226,18,214,199,187,13,32,94,220,224,212,247,204,196,43,
249,236,45,244,111,182,153,136,129,90,217,202,19,165,231,71,
230,142,96,227,62,179,246,114,162,53,160,215,205,180,47,109,
44,38,31,149,135,0,216,52,63,23,37,69,39,117,146,184,
163,200,222,235,248,243,219,10,152,131,123,229,203,76,120,209
};
//Seedthehashvaluesbasedonthefirstcharacter.
Hash.c[0]=bTranslate[*lpsz];
Hash.c[1]=bTranslate[(*lpsz+1)&255];
Hash.c[2]=bTranslate[(*lpsz+2)&255];
Hash.c[3]=bTranslate[(*lpsz+3)&255];
while(*++lpsz)
{
//AllowURLsdifferingonlybytrailingslashtocollide.
if(lpsz[0]=='/'&&lpsz[1]==0)
break;
Hash2.c[0]=Hash.c[0]^*lpsz;
Hash2.c[1]=Hash.c[1]^*lpsz;
Hash2.c[2]=Hash.c[2]^*lpsz;
Hash2.c[3]=Hash.c[3]^*lpsz;
Hash.c[0]=bTranslate[Hash2.c[0]];
Hash.c[1]=bTranslate[Hash2.c[1]];
Hash.c[2]=bTranslate[Hash2.c[2]];
Hash.c[3]=bTranslate[Hash2.c[3]];
}
returnHash.dw;
}
经过这个函数产生的值,根据其低6位就是最终的数组行号(即相当于模64)。
由于解决冲突的方法是:
对同一个哈希地址提供7个位置空间。
于是呈现在我们眼前是实际上就是一个横向7列、纵向64行的表结构:
位置0
位置1
位置2
…
位置6
哈希地址0
1
…
…
63
从这样的表结构中,我们知道这个哈希表以64为模。
每个表允许7个相同值,它们按顺序排列在一起。
所以每个哈希表结构可以索引448(64×7)个条目。
下面就是每个元素的结构:
structHASH_ITEM
{
DWORDdwHash;//哈希值,注意最后6位为0
DWORDdwOffset;//指向的实体中的记录部分的偏移
//偏移以index.dat文件第0字节为基地址。
};
我们注意到了:
数组元素的哈希值的低6为0。
于是系统也是利用了这个特征,将这6位数用作了每个元素的格式表示:
#defineHASH_BIT_NOTURL0x0001//位0
#defineHASH_BIT_LOCK0x0002//位1
#defineHASH_BIT_REDIR0x0004//位2
#defineHASH_BIT_HASGRP0x0008//位3
#defineHASH_BIT_MULTGRP0x0010//位4
#defineHASH_BIT_RESERVED0x0020//位5
//上面的哈希值组合
#defineHASH_UNLOCKED0//URL条目,没被锁定
#defineHASH_FREE1//空闲项,以前曾被使用过
#defineHASH_LOCKED2//URL条目,已锁定
#defineHASH_END3//空闲项,没被使用过
#defineHASH_UNLOCKED_SLASH4//URLentry,notlocked,trailingslashredir
#defineHASH_REDIR5//redirectentry
#defineHASH_LOCKED_SLASH6//URLentry,locked,trailingslashredir
#defineHASH_FLAG_MASK7//illegal,usedtomaskouthashflags
2.2URL条目
URL条目是使用的最多的条目。
它的结构和LEAK条目的结构相同,如下:
structIE5_URL_FILEMAP_ENTRY:
FILEMAP_ENTRY
{
LONGLONGLastModifiedTime;//最后修改时间
LONGLONGLastAccessedTime;//最后访问时间
DWORDdostExpireTime;//到期时间
DWORDdostPostCheckTime;
DWORDdwFileSize;//硬盘缓存中的文件的大小
DWORDdwRedirHashItemOffset;//askDanpoZ
DWORDdwGroupOffset;
union
{
DWORDdwExemptDelta;//forSIG_URL
DWORDdwNextLeak;//forSIG_LEAK
};
DWORDCopySize;//好像总是0x60
DWORDUrlNameOffset;//URL名称偏移。
基地址是本URL条目的开始地址
BYTEDirIndex;//属于的子文件夹索引
BYTEbSyncState;//automaticsyncmodestate
BYTEbVerCreate;//建立本ENTRY的CACHE的版本
BYTEbVerUpdate;//升级本ENTRY的CACHE的版本
DWORDInternalFileNameOffset;//硬盘上文件名(不包括目录)字符串的偏移,
//基地址是本URL条目的开始地址。
DWORDCacheEntryType;//缓存类型
DWORDHeaderInfoOffset;//从WEB服务器中取本文件时的返回的HTTP头部信息
DWORDHeaderInfoSize;//和大小(注意包括最后的回车换行的)
DWORDFileExtensionOffset;//shouldbeWORD
DWORDdostLastSyncTime;
DWORDNumAccessed;//存取次数(点击率)
DWORDNumReferences;//引用次数
DWORDdostFileCreationTime;//好像是ULONG?
};
2.4REDIR结构:
structREDIR_FILEMAP_ENTRY:
FILEMAP_ENTRY
{
DWORDdwItemOffset;//offsettohashtableitemofdestinationURL
DWORDdwHashValue;//destinationURLhashvalue(BUGBUG:
collisions?
)
charszUrl[4];//originalURL,canoccupymorebytes
};
2.5GLIST结构:
structLIST_FILEMAP_ENTRY:
FILEMAP_ENTRY
{
DWORDdwNext;//offsettonextelementinlist
DWORDnBlock;//sequencenumberforthisblock
};
三. 显示系统缓存信息
上面就是一个完整的index.dat文件的结构,利用这些结构我们就可以写出一个完整显示系统缓存信息的程序。
这项非常琐碎的工作,于是微软专门提供了一个函数库——WinInet。
利用这个库中的函数,程序员可以相当方便地取出系统中缓存中的信息。
关于WinInet库的使用方法网络上有很多文章,大家可以参阅。
1. ExploringtheURLCache(
2. ReadingtheInternetExplorerCache (
四. 工作原理
上面我们分析了index.dat文件的结构,那么系统在什么时候读写这个文件的信息呢?
1. COOKIES存取
在用户用IE浏览器上网时,当开始输入一个网址后,IE会根据输入的网址、用户名等信息组成一个字符串,将这个字符串作为参数到哈希函数中产生一个哈希值,然后查找具体的URL实体。
如果能够找到,那么IE就会具体分析此URL实体指定的COOKIES.TXT文件,看是否已经过期,若已经过期则删除;否则将在IE生成的HTTP请求报文中加上一个cookies:
××××××(×××就是.txt文件中的信息)这样的请求头部。
在IE浏览器收到的HTTP响应报文中若响应头部中包含有Set-cookies:
×××××信息时,此时IE就会将这个COOKIES值保存在一个.txt文件中,并在index.dat文件中建立一个索引值。
2. 临时的缓存文件存取
临时缓存文件是一种客户端缓存技术,它有利于节省网络带宽资源并能加快浏览速度。
每次使用IE浏览器上网时,IE会发送一个请求报文要求传输一个文件(比如.htm文件、.jpg文件、.css文件等等)。
WEB服务器响应请求,将所要求的文件传输给IE.。
IE在显示这个文件的同时,会将它放到缓存目录中,并在Index.dat文件中添加索引。
等下次,IE要求传输相同的文件时,IE便会在index.dat中找到这个文件的记录了(当然,如果根本没有传输下载过,index.dat中是不会找到这个记录的)。
IE先检查这个文件是否已经过期了(WEB服务器会在响应某些文件请求时,在HTTP响应报文中添加一个响应头部Age:
×××××来明确表示这个文件在客户机上保存的时间)。
如果没有过期,IE便会直接利用这个缓冲文件而不会发送HTTP请求报文的。
如果没有明确的过期时间或者已经过期来,IE便会在发送的HTTP请求报文中加上一条请求头部If_modified-since:
××××。
而WEB服务器发现所要求的文件并没有改变,它便会发送一个304NotModified报文,而不再传输文件了。
3.历史记录
历史记录只是用来保存曾经浏览过的网页的网址。
它并不保存其他的一些信息。
也不和发送/接受HTTP协议有关。
所以比较简单。
五. 举例说明
理论说了很多,下面来举一个例子。
通过这个例子我们看看系统是这样使用使用index.dat来索引缓存的以及系统是怎样使用缓存的。
1. 环境
一台装有WEB浏览器的客户机,一台IP地址为90.0.0.6的IIS5的WEB服务器。
服务器有一个名为test.asp的网页。
test.asp包含一张图,并会设置一个cookies。
2. 第一次调用网页
过程如下图所示:
具体的HTTP报文如下:
请求报文
回应报文
GET/test.aspHTTP/1.1
Accept:
image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-
powerpoint,application/msword,*/*
Accept-Language:
en
Accept-Encoding:
gzip,deflate
User-Agent:
Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1)
Host:
90.0.0.6
Connection:
Keep-Alive
HTTP/1.1200OK
Server:
Microsoft-IIS/5.0
Date:
Thu,26Oct200606:
43:
45GMT
X-Powered-By:
ASP.NET
Content-Length:
903
Content-Type:
text/html
Set-Cookie:
name=xiaoming;expires=Wed,30-May-200716:
00:
00GMT;path=/
Set-Cookie:
ASPSESSIONIDASARBACA=NOMPFILDEICPMBJBKCDGKGDC;path=/
Cache-control:
private
GET/img/1.gifHTTP/1.1
Accept:
*/*
Referer:
http:
//90.0.0.6/test.asp
Accept-Language:
en
Accept-Encoding:
gzip,deflate
User-Agent:
Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1)
Host:
90.0.0.6
Connection:
Keep-Alive
Cookie:
name=xiaoming;ASPSESSIONIDASARBACA=NOMPFILDEICPMBJBKCDGKGDC
HTTP/1.1200OK
Server:
Microsoft-IIS/5.0
X-Powered-By:
ASP.NET
Date:
Thu,26Oct200606:
43:
45GMT
Content-Type:
image/gif
Accept-Ranges:
bytes
Last-Modified:
Sun,15Oct200615:
54:
58GMT
ETag:
"075bc4372f0c61:
19f8"
Content-Length:
66806
我们再来看一下,index.dat文件有什么变化呢?
1)临时缓存