关于百度浏览器收藏夹bookmark.db的分析


 最近一段时间一直和浏览器的收藏夹过不去,脑袋一度活跃到晚上睡不着觉,连续了n天,头疼了n久,解决了搜狗,遨游和百度这三款最难

的。这几个也都是历史遗留问题。现在就拿百度的来做个解读吧(因为这是这三款当中相对来说最简单的),也算是一段时期的留念!

首先说明目的,目的就是为了添加百度浏览器收藏夹,那么说起来简单,做起来难。

对于这个问题,首先要想的是,收藏夹到底保存在哪里呢?注册表?文件?

依照国际惯例,一般都是保存在文件中。 当然这可纯是猜!

对于这个问题,有个通用的解决办法,那就是使用大名鼎鼎的  
ProcessMonitor ,对文件和注册表进行监视!

对于注册表就别监视了吧,其实用脚指头想,收藏夹也不可能会放到注册表中(除非是。。。) 

好了废话别多说了,直接上个图,添加个过滤条件,不然信息太多看不过来。
关于百度浏览器收藏夹bookmark.db的分析1 

意思就是说:对进程名为baidubrowser.exe的WriteFile写文件操作的监视  

 
添加完了之后,关闭 
ProcessMonitor 然后打开百度浏览器。然后再开启动ProcessMonitor

 
这个时候自己手工给百度浏览器添加一个收藏夹。下面我们来看监视到的输出。

关于百度浏览器收藏夹bookmark.db的分析2

总共就那么几个文件而且还大部分都是重复。那么怎么快速的来确定到底是哪个文件负责呢?其实很简单了

就是找到这几个文件,然后改名一个,打开浏览器一次看收藏的内容还在不。总共三五个文件,手工比工具快。

现在就很容易定位到bookmark.db其实就是负责收藏夹的文件,而site_icon.db就是负责收藏夹图标的文件。

好勒,那么现在用文本文件打开site_icon.db,一看文件头,纯粹的sqlite明文数据库。这个图标那我相信大部分人都可以会做了吧

再打开bookmark.db用文本文件看看,一看尼玛,神马乱七八糟的。这下真的就是完蛋了,肯定是加密了!

那么接下来,就得思考了,那自然是到底如何加密的?这个看后缀知道是数据库文件(当然有可能是乱起的),不过

按照收藏夹的话,估计真的会是个加密的数据库,那么就得分两种情况来分析了,那就是这个加密的是用的标准的加密方法

还是自己实现的加密方法呢?没办法,只能来验证!

下面我们再找到ProcessMonitor里刚才那条有bookmark.db的记录,查看下属性中的 栈信息,如下图。
关于百度浏览器收藏夹bookmark.db的分析3

有这个栈信息我们可以看到,WriteFile写入bookmark.db文件的流程是:baidubrowser.exe-->.....-->LogicMisc.dll-->Base.dll-->Kernel32.dll-->.......

其中Kernel32.dll我们已经没办法控制了,那是系统的,baidu浏览器不可能开发这个,而系统kernel32.dll之上的最后一个文件是
Base.dll,这个是baidu浏览器自己的文件,那么我们几乎可以断定,这个肯定是数据库操作相关的了,那么就别客气了。

是IDA应该登场的时候了。

IDA载入Base.dll,然后打开扒拉下string,function等信息,大概先浏览下,做到心里大概有个数。如下图:
 关于百度浏览器收藏夹bookmark.db的分析4

从导出函数这里面看,尼玛,这不就是一个自己封装的 sqlite3的库麻。

既然bookmark.db文件加密了,那么到底是标准的sqlite加密的,还是自己实现的加密的,我们不得而知。

那就只有一个最简单的办法来验证,那就是先得到数据库密码,然后把密码放到现成的工具中

看看能不能把bookmark.db给rekey到明文。如果能,那就是标准的sqlite3加密,如果不能,那很可能就是自己实现的加密

如果是后者,那么就只有两种办法了
(
要么扣出Base.dll的加密算法
要么patch下Base.dll方便我们拿来使用[这个应该是用它的矛攻它的盾]
) 

如果是前者,我们就可以使用现成的开源sqlite3的库。

不过都是说起来简单,做起来难。能不能搞定,全靠信念和毅力!

说太多了,不管是前面的还是后面的,都缺少一个必然的条件,那就是先拿到密码才行。

对的,我们说干就干,我们都知道在一般的sqlite数据库操作中,对加密数据苦的操作都是这样子的

if (SQLITE_OK == sqlite3_open_v2("aaaa.db", &db,SQLITE_OPEN_READWRITE, NULL))
{
char *key = "xxxxyyyzzz***";
sqlite3_key(db,key,strlen(key)); 


既然是这样子的话,Base.dll都有这些导出函数,那么我们来对open和key下上断点,如果open出现的是bookmark.db的路径,那么下面

key断下来出来的密码,就一定会是bookmark.db的数据库密码。

open断三个 分别为:sqlite3_open   sqlite3_open16   sqlite3_open_v2
key断1个  为sqlite3_key (其实还有个sqlite3_key_v2但是这个导出里面没有,我们更省心)。

下来挂接本地调试器,设置好baidubrowser.exe的启动。然后开始运行,到了第一个断点如下图

 关于百度浏览器收藏夹bookmark.db的分析5

好吧,sqlite3_open16的第一个参数是一个WCHAR*的类型
那么我们set lvar type修改下sqlite3_oepn16的第一个参数a1为LPCWSTR方便显示 。

F9继续运行,就到了sqlite3_key的断点的地方了,如下图
关于百度浏览器收藏夹bookmark.db的分析6 

我们把a1的地址 g到hex view之后,发现这个参数a1就是密码  是一个char*的类型

同样的道理我们把sqlite3_key的第一个参数a1 给 set lvar type修改为LPCSTR方便显示。

那么我们剩下来做的,就是F9 关注着sqlite3_open16的第一个参数是bookmark.db的时候,然后再按一次F9就会到

sqlite3_key  这个时候的第一个参数,就肯定是bookmark.db的密码。上图。

关于百度浏览器收藏夹bookmark.db的分析7

这里抓图故意没抓全,防止被人拿来主义。我这里写这个的目的只是为了自己留念,还有起到抛砖引玉的作用对小伙伴们

木有装x的意思。

废话不多说了,继续进行后面的,既然拿到密码了,我们到现成的sqlite3的工具里去实验一下,嘿嘿

真是不错,天公做美,还真给sqlite3_rekey(db,NULL,0);出明文来了

那就不客气了,拖到SQLite Expert Professional 3里面快去看个究竟。费了这么半天劲,真实不容易啊。

不过等等先,工具是能解开,那我自己去代码能rekey出来吗?说干就干,于是到sqlite3的官网上下载份最新的代码

然后自己写好代码,但是总是在sqlite3_key上编译不过去,tmd,网上一搜,原来sqlite3的免费开源的只是留了加密解密的接口

但是内容,没实现,实现加密内容的要卖2000多美刀。。。这个蛋疼。

于是网上接着搜,最后找到了wxsqlite3,这个开源了,并且评价还很高。于是就扣下来,最后改来改去是最终终于能解bookmark.db了。

然后就是这个数据库的明文到底是什么东西,我要迫不及待的看看了。

关于百度浏览器收藏夹bookmark.db的分析8

我草,这是什么鬼毛,与收藏夹有个毛关系,也没看到title   url什么的。难道费了这么大的劲,被狠狠的坑了???

不行,得一个一个字段用16进制看,当看到data字段的时候 又喜又忧,上图

关于百度浏览器收藏夹bookmark.db的分析9

喜的是这果然是收藏夹的数据库
忧的是这尼吗data的内容是个什么东西啊

于是对比了很多份data,终于摸索出规律来了
 =====================================================

12
固定的一个字节
3B
后面内容的总长度
0A
url开头的标志
29
下面的url的utf8编码的长度
68 74 74 70 73 3A 2F 2F 77 77 77 2E 62 61 69 64 75 2E 63 6F 6D 2F 3F 74 6E 3D 31 38 30 32 39 31 30 32 5F 6F 65 6D 5F 64 67
https://www.baidu.com/?tn=18029102_oem_dg的utf8编码
1A
title开头的标志
0C
下面的title的utf8编码的长度
E7 99 BE E5 BA A6 E4 B8 80 E4 B8 8B
百度一下 的utf8编码
32 00
两个固定的字节结尾
=======================================================
但是这里关于长度的地方不准,是以0x80的长度为分界线
>= 0x80的 后面的长度会多一个字节,并且前面的长度值也会改变

后面的字节实际上是     实际长度/0x80的商
前面的字节实际上是    商*0x80 - 0x80

这里就不详细描述了,看图

 关于百度浏览器收藏夹bookmark.db的分析10

计算出来的完全一样,这个就放上吧。

char *data(const char *url,const char *title)
{
char *lpszUtf8_url = ToUTF8(url);
char *lpszUtf8_title = ToUTF8(title);

int len_url = strlen(lpszUtf8_url);
int len_title = strlen(lpszUtf8_title);
unsigned char szUrl_len[3] = {0};
int  szUrl_YU = 0;

unsigned char szTitle_len[3] = {0};
int  szTitle_YU = 0;

int total = 0;
unsigned char szTotal_len[3] = {0};
int szTotal_YU = 0;

int all = 0;
char *lpszResult = NULL;

//有url总数  计算出值
if (len_url < 0x80)
{
szUrl_len[0] = len_url;
}
else
{
szUrl_YU = len_url / 0x80;
szUrl_len[1] = szUrl_YU;
szUrl_len[0] = len_url - szUrl_YU*0x80 + 0x80;
}
//有title总数  计算出值
if (len_title < 0x80)
{
szTitle_len[0] = len_title;
}
else
{
szTitle_YU = len_title / 0x80;
szTitle_len[1] = szTitle_YU;
szTitle_len[0] = len_title - szTitle_YU*0x80 + 0x80;
}

total =  len_url + len_title + strlen(szUrl_len) + strlen(szTitle_len) +4;
if (total < 0x80)
{
szTotal_len[0] = total;
}
else
{
szTotal_YU = total / 0x80;
szTotal_len[1] = szTotal_YU ;
szTotal_len[0] = total - szTotal_YU*0x80 + 0x80;
}

all = total + strlen(szTotal_len) + 2;
lpszResult = (char*)malloc(all);
memset(lpszResult,0,all);

sprintf(lpszResult,"%c%s%c%s%s%c%s%s%c%c",0x12,szTotal_len,0xA,szUrl_len,lpszUtf8_url,0x1A,szTitle_len,lpszUtf8_title,0x32,0);
return lpszResult;
}

int main()
{
char *lpsztest = data("https://www.baidu.com/?tn=18029102_oem_dg","百度一下");
free(lpsztest);
return 1;
} 

好了到这里,所有的难点就已经解决了。

上图为证

关于百度浏览器收藏夹bookmark.db的分析11 
到这里bookmark.db就分析完毕了~~

总结一下:这年头研究什么都很难了。

不过只要坚持,搞定也是早晚的事情,加油~! 

CopyRight @2018, Www.LiuLanQiCode.Com, Inc.All Rights Reserved. QQ:8560851 转载请标明来源,否则木有小jj

鲁ICP备18034788号-1

鲁公网安备 37078302000299号