Chinaunix首页 | 论坛 | 博客
  • 博客访问: 566496
  • 博文数量: 190
  • 博客积分: 10937
  • 博客等级: 上将
  • 技术积分: 2205
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-07 11:28
文章分类

全部博文(190)

文章存档

2012年(1)

2011年(27)

2010年(20)

2009年(142)

我的朋友

分类: WINDOWS

2009-05-18 16:15:14

参考工程代码
一.        前言
 
注重上网隐私和安全的人在每次上网后都会清除上网痕迹——“删除cookies”、“删除掉上网的临时缓存文件”以及“删除上网历史”。你觉得这样,所有的一切都会被擦除掉了。但是如果有人告诉你:这是不够的,系统中还有一些地方保存了你的上网信息,你是不是感到很恐慌?——这就是系统中的index.dat文件。
 
Windows系统中会存在三个index.dat文件。它们分别用来保存IE上网的cookies、临时文件和上网历史的索引信息(现在知道为什么这些文件名字是index.dat了吧J)。根据Windows系统版本不同,这些文件在系统中的位置也是不尽相同的。
 
在Windows 95/98/Me/ NT中,index.dat一般会存放在下面的位置中:
C:\Windows\Cookies\index.dat
C:\Windows\History\History.IE5\index.dat
C:\Windows\Temporary Internet Files\Content.IE5\index.dat
而在Window2000/XP系统中,index.dat一般会存在于下面的位置中:
C:\Documents and Settings\\Cookies\index.dat
C:\Documents and Settings\\Local Settings\History\History.IE5\index.dat
C:\Documents and Settings\\Local Settings
\Temporary Internet Files\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。数据结构如下:
 
struct CacheDir
{
   DWORD nFileCount;
   CHAR sDirName[8];
};
 
typedef struct _MEMMAP_HEADER_SMALL
{
TCHAR    FileSignature[28]; //”Client UrlCache MMF Ver 5.2”
    DWORD    FileSize;         //index.dat文件的大小
    DWORD    dwHashTableOffset; //第一个哈希表的偏移
    DWORD    NumUrlInternalEntries;
    DWORD    NumUrlEntriesAlloced;
  // DWORD    dwGarbage; // 无效数据,只在/Zp8编译使用
    LONGLONG CacheLimit;
    LONGLONG CacheSize;
    LONGLONG ExemptUsage;
    DWORD    nDirCount;     //子目录个数
    CacheDir DirArray[32];     //子目录名称
    DWORD    dwHeaderData[33];
} MEMMAP_HEADER_SMALL;
 
typedef struct _MEMMAP_HEADER : _MEMMAP_HEADER_SMALL
{
    DWORD AllocationBitMap[3948];
} MEMMAP_HEADER, *LPMEMMAP_HEADER;
 
2. 各种条目结构
 
上文说过每个条目都是以同样结构的2个DWORD开始的,这个结构如下:
 
 
typedef struct FILEMAP_ENTRY
{
    DWORD dwSig; //条目标识
    DWORD nBlocks; //条目占用多少个快(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中所有的哈希表部分链接起来的。
 
 
struct HASH_FILEMAP_ENTRY : FILEMAP_ENTRY
{
DWORD dwNext; // 下一个哈希表偏移(0表示为最后一个)
                  //偏移以index.dat文件第0字节为基地址。
    DWORD nBlock; // 本哈希表的序列号。从012…….
};
 
紧接着这个结构就是一个哈希表,每个哈希表的关键是哈希函数,下面是这个哈希表的哈希函数:
 
PRIVATE DWORD HashKey (LPCSTR lpsz)
{
    union
    {
        DWORD dw;
        BYTE c[4];
    }
    Hash, Hash2;
       
    const static BYTE bTranslate[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
    };
 
    // Seed the hash values based on the first character.
    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)
    {
        // Allow URLs differing only by trailing slash to collide.
        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]];
    }
    return Hash.dw;
}
经过这个函数产生的值,根据其低6位就是最终的数组行号(即相当于模64)。
 
由于解决冲突的方法是:对同一个哈希地址提供7个位置空间。于是呈现在我们眼前是实际上就是一个横向7列、纵向64行的表结构:
 
 
位置0
位置1
位置2
位置6
哈希地址0
 
 
 
 
 
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
 
 
 
 
 
从这样的表结构中,我们知道这个哈希表以64为模。每个表允许7个相同值,它们按顺序排列在一起。所以每个哈希表结构可以索引448(64×7)个条目。
 
下面就是每个元素的结构:
 
struct HASH_ITEM
{
 DWORD dwHash; //哈希值,注意最后6位为0
DWORD dwOffset; //指向的实体中的记录部分的偏移
                 //偏移以index.dat文件第0字节为基地址。
};
 
我们注意到了:数组元素的哈希值的低6为0。于是系统也是利用了这个特征,将这6位数用作了每个元素的格式表示:
 
#define HASH_BIT_NOTURL   0x0001  // 0
#define HASH_BIT_LOCK      0x0002  //1
#define HASH_BIT_REDIR     0x0004  //2
#define HASH_BIT_HASGRP   0x0008  //3
#define HASH_BIT_MULTGRP 0x0010  //4
#define HASH_BIT_RESERVED 0x0020  //5
 
// 上面的哈希值组合
#define HASH_UNLOCKED      0 // URL条目,没被锁定
#define HASH_FREE            1 // 空闲项,以前曾被使用过
#define HASH_LOCKED         2 // URL条目, 已锁定
#define HASH_END             3 // 空闲项,没被使用过
#define HASH_UNLOCKED_SLASH 4 // URL entry, not locked, trailing slash redir
#define HASH_REDIR           5 // redirect entry
#define HASH_LOCKED_SLASH   6 // URL entry, locked, trailing slash redir
#define HASH_FLAG_MASK       7 // illegal, used to mask out hash flags
 
2.条目2 URL
 
URL条目是使用的最多的条目。它的结构和LEAK条目的结构相同,如下:
 
struct IE5_URL_FILEMAP_ENTRY : FILEMAP_ENTRY
{
    LONGLONG LastModifiedTime;       //最后修改时间
    LONGLONG LastAccessedTime;      //最后访问时间
    DWORD    dostExpireTime;         //到期时间
    DWORD    dostPostCheckTime;
 
    DWORD    dwFileSize;              //硬盘缓存中的文件的大小
    DWORD    dwRedirHashItemOffset; // ask DanpoZ
    DWORD    dwGroupOffset;
    union
    {
        DWORD dwExemptDelta;   // for SIG_URL
        DWORD dwNextLeak;      // for SIG_LEAK
    };
   
    DWORD    CopySize;         // 好像总是0x60
    DWORD    UrlNameOffset;   // URL名称偏移。基地址是本URL条目的开始地址
    BYTE     DirIndex;           // 属于的子文件夹索引
    BYTE     bSyncState;        // automatic sync mode state
    BYTE     bVerCreate;        // 建立本ENTRYCACHE的版本
    BYTE     bVerUpdate;        // 升级本ENTRYCACHE的版本
       
DWORD    InternalFileNameOffset; //硬盘上文件名(不包括目录)字符串的偏移,
                                     //基地址是本URL条目的开始地址。
    DWORD    CacheEntryType;        //缓存类型
    DWORD    HeaderInfoOffset; //WEB服务器中取本文件时的返回的HTTP头部信息
    DWORD    HeaderInfoSize; //和大小(注意包括最后的回车换行的)
    DWORD    FileExtensionOffset;    // should be WORD
    DWORD    dostLastSyncTime;      
    DWORD    NumAccessed;            // 存取次数(点击率)
    DWORD    NumReferences;          // 引用次数
    DWORD    dostFileCreationTime;   // 好像是ULONG
};
 
2.结构:4 REDIR
 
struct REDIR_FILEMAP_ENTRY : FILEMAP_ENTRY
{
    DWORD dwItemOffset; // offset to hash table item of destination URL
    DWORD dwHashValue;   // destination URL hash value (BUGBUG: collisions?)
    char szUrl[4];      // original URL, can occupy more bytes
};
 
2.结构:5 GLIST
 
struct LIST_FILEMAP_ENTRY : FILEMAP_ENTRY
{
    DWORD dwNext; // offset to next element in list
    DWORD nBlock; // sequence number for this block
};
 
三.        显示系统缓存信息
 
上面就是一个完整的index.dat文件的结构,利用这些结构我们就可以写出一个完整显示系统缓存信息的程序。这项非常琐碎的工作,于是微软专门提供了一个函数库——WinInet。利用这个库中的函数,程序员可以相当方便地取出系统中缓存中的信息。
 
关于WinInet库的使用方法网络上有很多文章,大家可以参阅。
 
1. ()Exploring the URL Cache 
2. () 
 
四.        工作原理
 
上面我们分析了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服务器发现所要求的文件并没有改变,它便会发送一个304 Not Modified报文,而不再传输文件了。
 
3. 历史记录
 
历史记录只是用来保存曾经浏览过的网页的网址。它并不保存其他的一些信息。也不和发送/接受HTTP协议有关。所以比较简单。
 
五.             举例说明
 
理论说了很多,下面来举一个例子。通过这个例子我们看看系统是这样使用使用index.dat来索引缓存的以及系统是怎样使用缓存的。
 
1. 环境
 
一台装有WEB浏览器的客户机,一台IP地址为90.0.0.6的IIS5的WEB服务器。服务器有一个名为test.asp的网页。test.asp包含一张图,并会设置一个cookies。
 
2. 第一次调用网页
 
过程如下图所示:
具体的HTTP报文如下:
 
请求报文
回应报文
GET /test.asp HTTP/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; MSIE 6.0; Windows NT 5.1; SV1)
Host: 90.0.0.6
Connection: Keep-Alive
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 26 Oct 2006 06:43:45 GMT
X-Powered-By: ASP.NET
Content-Length: 903
Content-Type: text/html
Set-Cookie: name=xiaoming; expires=Wed, 30-May-2007 16:00:00 GMT; path=/
Set-Cookie: ASPSESSIONIDASARBACA=NOMPFILDEICPMBJBKCDGKGDC; path=/
Cache-control: private
GET /img/1.gif HTTP/1.1
Accept: */*
Referer:
Accept-Language: en
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 90.0.0.6
Connection: Keep-Alive
Cookie: name=xiaoming; ASPSESSIONIDASARBACA=NOMPFILDEICPMBJBKCDGKGDC
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
X-Powered-By: ASP.NET
Date: Thu, 26 Oct 2006 06:43:45 GMT
Content-Type: image/gif
Accept-Ranges: bytes
Last-Modified: Sun, 15 Oct 2006 15:54:58 GMT
ETag: "075bc4372f0c61:19f8"
Content-Length: 66806
 
我们再来看一下,index.dat文件有什么变化呢?
1)临时缓存文件
 
首先我们计算1.gif文件的HASH值。URL名称为: ,经过上文的HashKey计算得出结果:0x127F5346。于是我们在第一个HASH表的0X5000 + 8 ×7 × (0x127F5346 & 0x3F)= 0x5150 开始查找:
 
 
00005150h: 01 00 00 00 00 9F 03 00 01 00 00 00 00 FD 03 00 ; .....?......?.
00005160h: 40 53 7F 12 80 66 00 00 40 E7 8F A7 80 F2 01 00 ; @S.
阅读(850) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~