上篇介绍了如何通过嗅探MojoIPC抓包小程序的HTTPS数据。

本篇逆向微信客户端本地数据库相关事宜。

本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18423518

微信PC客户端有两种主要的数据存储类型,一种是基于sqlcipher,另一种是基于protobuf。除了这两种外还有别的,不在本篇内容。

它们是对应两个主要的类,StorageBaseConfigInfoStorage。StorageBase使用sqlcipher作为存储手段,ConfigInfoStorage则使用protobuf存储KeyValue。

StorageBase是一个单表操作的封装类,它包含了数据库名跟表名等信息。它封装了打开,查询等底层操作。它的StorageBase::init方法完成了打开数据库以及必要的设置,包括CipherAndKey的设置。逆向分析到现在,我才发现微信是有用混肴的代码段来做代码保护,这个段位于WeChatWin.dll的末尾。StorageBase::init调用DBFactory::openDBbyName方法完成全部打开工作。这个DBFactory::openDBbyName方法,它的日志信息全部字符串都经过混肴处理,显然是不想让人知道。并且DBFactory::openDBbyName的主执行体逻辑被编辑在混肴代码段。混肴代码的目的,不单是让人变白痴,更加重要是让逆向的工具变白痴,包括调用器。微信使用的混肴,有个特点,就是满天的call指令。只要你清楚call指令只是jmp&push的等价物,就明白它的恶心了。调用器的调用栈帧功能,只能用于分析ebp, eip这种中规中举的调用,混肴的call根本不在于call&ret,如果你认为它会在call的下一指令,ret回来执行,你可能等不到它执行。包括逆向工具的代码分析功能也同样被打成白痴。call等同jmp并push eip。这时的eip不是为了ret,而为了开辟esp,并将eip作为后面这个栈位置的内容的解码因子。或者这个栈位置的内容后面是被直接替换而丢弃的。不单代码混肴,连栈结构都被混肴。

所以碰到混肴保护的代码,Mother Mary comes to me Speaking words of wisdom let it be。虽然我假设,微信可能在这里将数据库的KEY,还在KEY的计算方法保护了起来。我承认我还停留在8年那个安卓版的魔法MD5(imei+uin)。想必PC的计算方法是Foo(myPCInfo, uin),存在于客户端代码某处。既然它们都用混肴代码保护起来了,就 so i listened to Mother Mary,let it be。正当我是这么在想的时候,一处AccountService::setDBKey却赫然在目。唉?不对吧。于是我赶紧windbg跟踪。咦?这参数里面不就有我的数据库的KEY吗?前面我还在说,微信煞有介事地用混肴代码将sqlcipher打开数据库的一连串操作,包括KEY设定,通通都保护起来。现在却明目张胆地露出来。这是在打我脸,还是在打它自个的脸。这戏到底在唱的是哪一出,我完全看不懂。它拼命地将那里遮起来不让别人知道,但用来遮住那里的东西却有一张照片是裸露那里的。这是在玩彩蛋。直到看了它们的技术post才明白,”安全性。基于不怕被破解,但也不能任何人都能破解的原则“,https://cloud.tencent.com/developer/article/1005575。这词令有点耳熟,好像在哪里听过类似的格式的短句。微信开发团队为大家指明了方向,欢迎来破解,就怕你不会。(原来它们的数据库还有一个正名WCDB, https://cloud.tencent.com/developer/article/2406614。我却一直将它当sqlcipher在处理。WCDB是用在移动终端的,PC端的应该不是。)虽然市面上关于这个的破解已经写到烂大街,只要在github上搜wecaht Db crack关键词,就有一大堆的repos。我就简单介绍我的分析,还有方法,为观众多一种角度。AccountService有三个成员变量,DBKey,RSA公钥,RSA私钥。它们都是std::string类型。并且有已知固定的长度。最lucky的是,它们之间的相对位置经历了这么多年还有版本都没有变化过。搜查的步骤,先通过RSA私钥字符串的地址,再将地址值结合字符串的长度值找到RSA私钥成员变量的位置,然后相对偏移后得到DBKey成员变量的位置。就如我们熟悉的几何定理三点定面一样,锁定位置。只要三条指令,就可以用windbg实现目标。

x86

s-a 0 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
* theRes
s-d wechatwin L2000000 theRes 0 0 0 377 37f
* theRes2
da poi(theRes2 - 18)
* check if "-----BEGIN PUBLIC KEY-----"
db poi(theRes2 - a8) Lpoi(theRes2 - a4)

x64

s-a 0 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
* theRes
s-q wechatwin L2000000 theRes 0 377 37f
* theRes2
da poi(theRes2 - 20)
* check if "-----BEGIN PUBLIC KEY-----"
db poi(theRes2 - f8) Lpoi(theRes2 - f0) 

补充一下,windbg没有像gdb那样,可以赋值变量,但可以用alias代替。将theRes跟theRes2别名成结果地址, 或者手动替换指令中的theRes跟theRes2。另外一次最多只能搜索地址空间0x10000000,因些在第一个地址段找不到,请用下面命令扫描地址空间的全部用户空间。

s-a 0 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 10000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 20000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 30000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 40000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 50000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 60000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"
s-a 70000000 L10000000 "-----BEGIN RSA PRIVATE KEY-----"

我也跟跟风,写一个https://github.com/bbqz007/CrackMicroMsgDBKey关于如何用windbg看密钥。

  

找到DBKey后,当然就想知道计算Key的代码。开始我以为会在混肴代码段,但在发现AccountService::setDBKey后,再去跟踪才真相大白。DBKey由服务器返回,计算不在客户端,而在服务器。

有需要的请自行探究,与Auth相关的类。

加密解密两因素,一是Key,二是Cipher。多年没碰微信数据库,我也忘了cipher的设定。随便找个最新的sqlcipher来用,key对了还是死活打不开数据库。因为每个sqlcipher版本默认的cipher不同,或者分发软件的发行者编译的选项不同,默认的cipher不同。cipher的设置必须也要匹配。我们可以直接通过微信直接查询它打开的数据库。一共有kdf_iter,cipher_page_size, cipher_use_hmac, cipher_plaintext_header_size, cipher_hmac_algorithm,cipher_kdf_algorithm六项。

微信将sqlcipher的访问封装成一个单表操作的类。StorageBase。它包含了数据库名,表名,还有最重要的数据库句柄。毕竟还是sqlite3。我们只要找到api表就可以使用所有c接口了。上图的示例就是通过api表的c接口访问StorageBase打开的数据库句柄。即使StorageBase虽然将打开数据库的流程通通用混肴代码保护起来。

得到capi表后,sqlite3_exec可以操作数据库,如上图演示,sqlite3_prapare可以跟踪sql,如下图演示。

我已经在我的KTL工具ver0.9.1gitee仓库)添加了patch,方便有需要的人,只要在AlgoDataTool.cpp设置你的破解出来的DBKey,就可以浏览你的微信数据库。

数据库文件目录在”我的文档“下,”WeChat Files\wxid_????????\Msg"。如果想知道当前登陆的wxid,可以查看”WeChat Files\config\AccInfo.dat",字符串类型数组中编号4的数值,而编号10则是昵称。如何查看,就是接下来要介绍的另一种数据库类型,我同样也在KTL添加了patch,提供对应查看工具。在本篇,数据库是一个广泛的,包括各种格式的数据文件。比如,类mongodb同样可以用plaintext的方式作为底层存储。一种格式的文件也可以通过mysql存储引擎接口做成自定义存储引擎被mysql使用。

另一种数据库基于protobuf,类型名称为ConfigInfoStorage。它的主要数据成员是micromsg::KeyValueSetting,这是由proto文件生成的类。虽然没有KeyValueSetting的proto文件,但是由逆向内容可以分析根结构。

根级结构主要有5个成员,它们都是数组,每个数组元素皆为一个key-value对。key是整形。知道总的框架结构,在没有proto文件情况下,也可以对protobuf进行大概的分析。虽然没有proto定义文件,但仍然可以用protoc工具解码,只是不知道成员的名称,所有名称都是整形的位置号。但是有了上面的根级结构就可以开展分析。根1号位是32位整形的value数组,每个value都有一个名称对应的编号。数组每个元素是一个intkey-value的proto,所以元素的1号位是intkey,2号位是value。后面的数组以同样的方式。根2号位是buffer类型的数组,这里的buffer有些是经序列化的protobuf。可以认为是对象类型的数组。根3号位是字符串数组,所有字符串的value都在这个数组。根4号位是64位的整形数组。根5号位是浮点形数组。

protoc工具不能在没有proto文件的情况下,解码成JSON格式,只能用TextFormat。但是这个TextFormat是真的独特,似DICT或JSON,但又不同。不能方便使用python或json浏览器进行分析。所以我用我的KTL添加了一个功能,可以将protoc工具解码出来的TextFormat转换成JSON,并提供可视视图。有了转换后的JSON,可以粘贴到任意你喜欢的可视工具进行分析,最简单的就是使用chrome浏览器的devtools,粘贴到console执行。

数据库文件目录在”我的文档“下,”WeChat Files\config\“。其中AccInfo.dat对应AccoutService类,aconfig.dat对应AccoutStorageMgr类。

本篇相继介绍了微信如何使用sqlcipher,AccoutService类,基于protobuf的key-value数据库,ConfigInfoStorage类。数据库存储在我们的电脑磁盘,而类运行在我们的内存。通过扫描这些东西,就可以搜集个人信息。AccoutService类还包含了绑定的手机号。又例如,单纯扫描磁盘,不扫描微信进程,不扫描sqlcipher数据库。也可以得到当前登陆的微信号,这个微信号使用了哪些小程序,这些小程序是哪些知名的小程序应用,是哪种类型的小程序应用,这个微信号有着一些使用习惯喜好以及需求,等等。(每个小程序有一个唯一的AppID,还有绑定的公众号)。配合扫描微信进程的DBKey,就可以直接窥探更加多内容。

在我的KTL工具ver0.9.1gitee仓库)添加了两个patch,patch.sqlcipher查看sqlcipher数据库,patch.protobuf查看protobuf数据(文件)。

另外直得一提。wechatwin.dll就像一个Library,静态编译进了不计其数的开源库。sqlcipher也是其中之一。我们也可以直接wechatwin.dll。

本篇到这里,下一篇再见。

逆向WeChat(七,查找sqlcipher的DBKey,查看protobuf文件)

逆向WeChat(六,通过嗅探mojo抓包小程序https,打开小程序devtool)

逆向WeChat(五,mmmojo, wmpfmojo)

逆向通达信 x 逆向微信 x 逆向Qt (趣味逆向,你未曾见过的signal-slot用法)

逆向WeChat(四,mars, 网络模块)

逆向WeChat(三, EventCenter, 所有功能模块的事件中心)

逆向WeChat (二, WeUIEngine, UI引擎)

逆向wechat(一, 计划热身)

我还有逆向通达信系列

我还有一个K线技术工具项目KTL可以用C++14进行公式,QT,数据分析等开发。你的代码JustInTime运行。

逆向WeChat(七)的更多相关文章

  1. XCTF IgniteMe

    一.查壳 结论: 1.用vc++编译的. 2.无壳,毕竟是一分的题 二.点击运行,发现不是爆破,而是找出注册机,汇编功力还在提升中,只能拖入ida来静态调试了 具体的见注释: 二.1点击进入关键函数 ...

  2. 【腾讯Bugly干货分享】移动App入侵与逆向破解技术-iOS篇

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e0acc896e9ebb6865f321 如果您有耐心看完这篇文章,您将懂 ...

  3. Reverse Core 第一部分 代码逆向技术基础

    @date: 2016/10/14 <逆向工程核心原理>笔记 记录书中较重要的知识,方便回顾 ps. 因有一些逆向基础,所以我本来就比较熟悉的知识并未详细记录 第一章 关于逆向工程 目标, ...

  4. 10天学会phpWeChat——第七天:创建一个自适应PC网站+H5移动端的模块

    本教程基于phpWeChat核心框架1.1.0+版本.下载地址:http://s.phpwechat.com/app_38026ed22fc1a91d92b5d2ef93540f20 通过前面六讲的系 ...

  5. QiniuUpload- 一个方便用七牛做图床然后插入markdown的小工具

    最近一段时间有用markdown做笔记,其他都好,但是markdown插入图片挺麻烦的,特别是想截图之后直接插入的时候.需要首先把图片保存了,然后还要上传到一个地方生成链接才能插入.如果有个工具可以直 ...

  6. Mybatis(七) mybatis的逆向工程的配置详解

    还是觉得看书学习有意思~嘿嘿.今天把mybatis给结束掉. --WH 一.什么是逆向工程? 简单点说,就是通过数据库中的单表,自动生成java代码. Mybatis官方提供了逆向工程,可以针对单表自 ...

  7. Android逆向分析(2) APK的打包与安装背后的故事

    前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...

  8. 【从零开始搭建自己的.NET Core Api框架】(七)授权认证进阶篇

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...

  9. Mybatis学习(七)————— mybatis的逆向工程的配置详解

    一.什么是逆向工程? 简单点说,就是通过数据库中的单表,自动生成java代码. Mybatis官方提供了逆向工程,可以针对单表自动生成mybatis代码(mapper.java\mapper.xml\ ...

  10. [工控安全]西门子S7-400 PLC固件逆向分析(一)

    不算前言的前言:拖了这么久,才发现这个专题没有想象中的简单,学习的路径大致是Step7->S7comm->MC7 code->firmware,我会用尽量简短的语言把前两部分讲清楚, ...

随机推荐

  1. app接口测试

    app接口测试 一,app请求服务器端接口和web页面请求服务器端接口有什么区别? 1,大多数项目如果有app的话,而且web端和app端的页面显示结构已经功能都相似,调用的后台接口也是一样的. 2, ...

  2. Jmeter函数助手13-threadGroupName

    threadGroupName函数获取当前线程组的名称.该函数没有参数,直接引用即可. 1. 返回当前线程组的名称

  3. PixiJS源码分析系列:第四章 响应 Pointer 交互事件(上篇)

    响应 Pointer 交互事件(上篇) 上一章我们分析了 sprite 在 canvasRenderer 上的渲染,那么接下来得看看交互上最重要的事件系统了 最简单的 demo 还是用一个最简单的 d ...

  4. 最新SEO自动外链蜘蛛池工具促进百度快速收录使用方法介绍

    此工具集成市面上所有自动外链网站的资源链接,经过合并.去重.筛选.验证 总结出最终的外链资源 ,软件实时更新 本软件将您繁杂的外链推广转为自动化进行,并且加入站群的支持,您只需要将你的站群域名粘贴到软 ...

  5. 【Windows】远程访问设置

    Windows自带了远程访问功能: Win + R 打开运行,输入[mstsc] 连接需要提供主机地址,和用户账号 下面的选项可以保存此连接为文件,下一次连接直接打开文件即可访问 当然设置了以后可能还 ...

  6. Linux共享内存通信的C语言Demo代码

    重点注明: 本文代码来源于: https://blog.csdn.net/github_38294679/article/details/122360026 ===================== ...

  7. golang 指定权限是 0o755 而不是 0755

    在Go语言中,当指定文件权限时,使用前缀 0o 来明确表示八进制数是一种推荐的做法. 这是因为在Go语言中,八进制字面量必须以 0o 或 0O 开头,后跟八进制数字(0-7). 这种语法是从 Go 1 ...

  8. Illegal key size or default parameters 解决方案

    1.背景 在做aes加密时,报错 Illegal key size or default parameters...有的jdk版本报错,有的不报错,原因在于: jdk 或jre\lib\securit ...

  9. 20-canvas之形变

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...

  10. IP报文格式详解

    下图为常见的IP报文格式表: 上面是IP的报文格式,接下来我们先说明各个字段的意义.然后,用Etheral软件转包分析IP的报文格式. 1.版本:ip报文中,版本占了4位,用来表示该协议采用的是那一个 ...