用Qt写软件系列二:QCookieViewer(浏览器Cookie查看器)
预备
继上篇《浏览器缓存查看器QCacheViewer》之后,本篇开始QCookieViewer的编写。Cookie技术作为网站收集用户隐私信息、分析用户偏好的一种手段,广泛应用于各大网站。对于网站的精准营销、使用反馈、数据挖掘等具有不可估量的作用。Cookie按照创建者的不同,分成两类:服务端创建的Cookie和客户端浏览器创建的Cookies。那么,作为用户想要查看当前主机的Cookies文件该怎么办呢?最简单的办法是:直接到Windows目录下去找!Cookies文件是以ASCII码字符的形式保存的,因此可以直接用记事本打开查看。然而,由于Cookies文件是以Unix风格换行的,格式非常难看。QCookieViewer为Cookies提供了一个界面友好的查看工具。
这款软件还是部分借鉴于IECookiesViewer。因此,我们还是先看看这款软件的界面:
可以看到,该软件主界面分成上下两栏。上面一栏是当前所有Cookies文件的列表,下面一栏是选中的Cookies文件中的Cookie项。上面一栏的各项信息可以通过解析index.dat文件得到,这个解析过程在上一篇中就已经说到;下面一栏的内容则需要通过解析Cookie文件来得到。上面我们已经知道,Cookies文件中的每一行都是以unix换行符分割的。因此,解析Cookie文件是一个非常简单的过程。然而,我们显然注意到在下面一栏的最右侧有一个Created In列。仅仅靠解析Cookie文件,是无法得到这样的信息的。怎样完成这个功能,下面将有详细叙述。
关键技术
- 为什么不遍历Cookie文件夹?
在上一篇中我们说过,仅仅靠遍历Cache文件夹中的文件来获取Cache文件清单是不可行的。因为那只能获得文件名、文件大小等基本信息,我们需要的不仅仅是这些。另外,使用Windows系统提供的API的话,也具有一定的局限性。通过解析index.dat文件,我们获取更为详尽的信息。不但能够得到当前主机存在的Cookies文件信息,还可以查看到该主机曾经存在过的Cookies文件。因此,我们仍然采用了解析index.dat文件的方法。
-
index.dat文件的位置
- 对于Windows XP/2000而言, Cookies文件保存在:C:/Documents and Settings/Administrator/Cookies/
- 对于Windows Vista/7而言,Cookies文件保存在:C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Cookies/(low/)。该目录会根据权限的不同而不同。
-
内存文件映射
- index.dat文件采用增量记录方式。因此,index.dat文件会随着使用时间的增加而不断增大。为了提高文件IO速度,我们采用了Windows系统的内存文件映射功能,将整个index.dat文件映射到内存中进行操作。代码如下:
CookieHelper::CookieHelper(void)
{
// Need to be fixed
const char* fileName = "C:\Documents and Settings\Administrator\Cookies\index.dat";
// create a kernel file object
m_hFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY, NULL);
if (m_hFile == INVALID_HANDLE_VALUE)
{
MessageBoxA(NULL, "Error", "Can't open the index.dat file.", MB_OKCANCEL);
return;
}
// create a kernel file mapping object
m_hMapping = CreateFileMappingA(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (m_hMapping == NULL)
{
MessageBoxA(NULL, "Error", "Can't create file mapping object.", MB_OKCANCEL);
CloseHandle(m_hFile);
m_hFile = NULL;
return ;
}
m_startAddr = (LPSTR)MapViewOfFile(m_hMapping, FILE_MAP_READ, 0, 0, 0);
if (m_startAddr == NULL)
{
MessageBoxA(NULL, "Error", "Can't mappping the index.dat file.", MB_OKCANCEL);
CloseHandle(m_hFile);
m_hFile = NULL;
CloseHandle(m_hMapping);
m_hMapping = NULL;
return;
}
}
我们将index.dat文件映射到内存中使用完之后,须得及时关闭前面得到的内存句柄。否则可能导致资源泄漏。
-
解析index.dat文件
- 解析index.dat文件的过程自不必说了,在上一篇中我们已经详细阐述过了。唯一需要注意的是,解析得到的字段和上一篇中的有所出入。
-
Cookie文件的格式
- Cookies文件内容以ASCII码字符保存,其格式也不算复杂。在一个Cookie文件中,可能存在多条Cookie记录。每条Cookie记录都包含9个字段,如下所示:
- 每个字段自成一行,以unix换行分隔符分割。每一条Cookie记录又以星号(*)进行分割。这些字段的具体含义不必再赘述了。值得注意的是,这里的时间转换需要注意顺序。在参考资料4中,作者把时间的高地位写反了,导致转换得到的时间错的离谱。另外需要注意的一个字段是Optional flags。这个字段到底包含哪些options,并没有详细的文档说明。
-
关于Created In列
- 如何确定Cookies文件的Creator,起初并没有一个很好的思路。反复查看了每条Cookie记录中Optional flags字段,并比照IECookiesView工具中Created In列之后,我们发现了一个特定的规律:当Optional flags字段出现的值为1024,1536, 9216, 9728, 2147484672(不完全统计)时,IECookieView显示该Cookie由Server创建;当值为1600,1088(不完全统计)时,IECookieView显示该Cookie由Client创建。由此,我们得到一条统计规律:当optional flags值能被0x100整除时,该cookie由server端创建;否则该Cookie是由client端创建的。至于具体的规则如何,由于并没有找到说明文档,不敢妄下结论。
界面设计
由于尚未开始研究Qt的CSS技术,无暇顾及界面的美化工作。界面显示的是Windows XP经典主题,因此看起来较为朴素简陋。
代码
代码全部托管于GitHub,README有更详细的说明。
参考资料
- NirSoft
- Forensic Analysis of Internet Explorer Activity Files.pdf
- 《index.dat文件结构解析》,吴清,吴顺祥.
- Cookie文件说明及IE的Cookie文件格式
- SQL中利用DMV进行数据库性能分析
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(1)--基础环境搭建
- 独家!万达网科大裁员后将转型AI 朱战备或接班曲德君
- Git分支管理的策略梳理
- 数据场景分析 线上线下商家到底谁能干过谁?
- 张钦坤:云计算、开放平台与服务商版权责任
- biztalk 2010 dev版安装小记
- 微信小程序如何获取组件实际高度
- flex4/flash builder中动态加载Module并与之交互的正确方式
- Google发布会看图的人工智能,让它来评评你的照片拍得好不好
- Git日常操作命令梳理
- Git忽略规则.gitignore梳理
- 深入浅出事件流处理NEsper(二)
- 微信推出“微信使用小助手”,中老年人也能轻松玩转微信
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 动态计算图
- 给库加上酷炫的小徽章 & ava、codecov、travis 示例
- 张量的结构操作
- GitHub Actions 指南
- 面试进阶-数据库中的锁
- (译)针对 Kubernetes 工作负载的策略工具
- 又被逼着优化代码,这次我干掉了出入参 Log日志
- 想去看机会?这10道最高频的手撕代码题都会了吗?
- 你知道Python中的4种变量作用域是哪些吗?
- 图解 Python 浅拷贝与深拷贝
- 打卡群刷题总结0716——不同路径
- 原理 + 代码|手把手教你用Python实现智能推荐算法
- 机器学习必刷题-基础概念篇(1):为什么用AUC做评价指标?
- 机器学习必刷题-手撕推导篇(3):FM与softmax
- Python面试必刷题系列(4)