所有的数据库文件都是经过AES加密的,AES的密钥是32位,而且所有数据库文件共用一个密钥,我们需要找到那个AES密钥才能进行解密,然后才能对数据库文件进行操作。
在API断下之后怎么去找数据库的密码呢?可以根据AES的密钥长度为32位这个线索,32也就是十六进制的20,时刻注意20这个数字!
另外,在解密数据库的call中至少需要两个参数,一个是AES的密钥,另外一个是需要解密的数据库文件的路径。
还有一种方法是在内存中搜索数据库文件的名字,然后下访问断点。这种方案也是可行的。
如果出现了这个错误,需要修改一下设置
将StrongOD和OD本身取消忽略所有异常,这个错误是因为多线程访问冲突引起的。
在CreateFileW的返回地址下断,直接F9运行,CreateFileW这个API我们是不需要看的
CreateFileW断点断下来,那么现在应该怎么跟呢?肯定不能一直往下单步,虽然单步也能达到目标。
直接找到第四个返回地址
这个函数传入了三个参数,虽然三个参数都没有什么价值。但是这个call稍微往下拉,你会发现一个字符串
这个函数的作用应该就是用来提示错误的,一般比较大的工程都会将错误提示信息写成一个函数,报错的时候会提示哪一个模块的哪一个cpp的哪一行出错了,以便最快定位到错误点。
再往上看会发现一个je,用来跳过这个错误
根据这个错误提示的内容,我们现在可以百分百的确定打开数据库的操作已经完成!
这里是我们遇见的第一个函数,看参数就知道不是我们想要的了,跳过继续往下
第二个函数将数据库名和一个保存零的指针入栈,也跳过
第三个函数就很可疑了,这个call将三个参数压入堆栈,其中eax是一个结构体,里面保存一个地址和0x20这个数字,AES的密钥正好是32位的,也就是十六进制的0x20。
数据窗口跟随,前两行0x20个字节就是数据库的密钥了
各个参数含义如下:
这份代码原作者是谁我已经不记得了反正被拷来拷去拷了很多次了
运行程序
最后生成的dec_ChatMsg.db就是解密出来的文件,对比一下解密前后的文件
解密前
解密后看到这个MAGIC头,不用验证我就知道已经解密成功了。接下来还是验证一下结果
用Navicat新建一个SQLite连接,
选择解密后的数据库
可以看到所有的表数据已经出现了。解密完成
找到了密钥之后就结束了吗?这个密钥目前是写死的,如果变化的话,我们又要重新找,然后再次输入。所以我们需要动态获取到数据库密钥。想要动态获取数据库密钥,就必须定位到数据库密钥的基址。步骤如下:
直接在CE中搜索之前找到的密钥
接着依次搜索这两个地址,找到了一个绿色的基址
动态获取数据库密钥的代码如下:
如果我们直接拿到密码,然后对数据库进行解密,再查询好友信息,这种方法当然也是可以的。但是拿到的数据并不是实时的。
如果我们拿到这个数据库的句柄,就能实时的去查询好友的详细信息了,而且也不需要进行解密和获取数据库密码的操作了。
接着来到CreateFileW的返回地址处,点击K查看调用堆栈
经过排查,这个地址的call最像我们需要的找的call,在这个call的地址下断,点击F9运行
程序断下,此时ecx指向数据库文件的路径
edx指向一个空的缓冲区,那么这个就非常像我们要找的call
单步步过这个call,发现缓冲区里写入了一个地址,那么就可以确定这个就是我们要找的call,只要我们HOOK这个地址,那么就能拿到所有的数据库文件的句柄了。而数据库的名称就在堆栈里,可以自己去找到偏移然后获取数据。
至于代码,等我研究下怎么调用SQlite再告诉你们,最后附上用代码解密数据库的工程。