上篇介绍了如何通过嗅探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. 2024-07-27:用go语言,给定一个正整数数组,最开始可以对数组中的元素进行增加操作,每个元素最多加1。 然后从修改后的数组中选出一个或多个元素,使得这些元素排序后是连续的。 要求找出最多可以选

    2024-07-27:用go语言,给定一个正整数数组,最开始可以对数组中的元素进行增加操作,每个元素最多加1. 然后从修改后的数组中选出一个或多个元素,使得这些元素排序后是连续的. 要求找出最多可以选 ...

  2. 使用 useState 管理响应式状态

    title: 使用 useState 管理响应式状态 date: 2024/8/1 updated: 2024/8/1 author: cmdragon excerpt: 摘要:本文详细介绍了在Nux ...

  3. windows11系统NVIDIA显卡驱动自动升级导致2070 Super显卡失效 —— 552.22版本自动升级到560.70版本后2070 Super型号显卡停止工作

    操作系统 Windows11,旧版本显卡驱动是552.22,由于安装的是NVIDIA Geforce Experience后显卡驱动自动升级到560.77版本,然后显卡不再工作. 重新安装显卡驱动56 ...

  4. 数字人 —— 虚拟人 —— Inworld AI用生成式AI——生成式游戏NPC

    相关: https://www.ithome.com/0/756/603.htm https://baijiahao.baidu.com/s?id=1774732295233220838 https: ...

  5. 编程语言mojo报错:error: cannot call function that may raise in a context that cannot raise

    代码: from python import Python fn main(): # fn main() raises: # This is equivalent to Python's `impor ...

  6. PyTorch显存机制分析——显存碎片问题

    参考前文: https://www.cnblogs.com/devilmaycry812839668/p/15578068.html ================================= ...

  7. java集合专题之Collection接口

    1.背景 集合是java中非常重要的技术点,也是面试经常问到的技术点.... 2.集合体系 单列集合 双列集合,key value集合 如果出去面试,这体系应该可以背出来,才算合格 3.常用方法 代码 ...

  8. 这应该是全网最全的CSP-S初赛复习吧

    点我到洛谷看 \(Update\ 2024/8/2:\) 加入了在数据结构中增加了"树",做出部分更改. linux基础命令 cd 切换目录 ls 列出目前工作目录所含的文件及子目 ...

  9. 用DolphinScheduler轻松实现Flume数据采集任务自动化!

    转载自天地风雷水火山泽 目的 因为我们的数仓数据源是Kafka,离线数仓需要用Flume采集Kafka中的数据到HDFS中. 在实际项目中,我们不可能一直在Xshell中启动Flume任务,一是因为项 ...

  10. 【客户案例】白鲸开源WhaleStudio助力某证券公司打造全面数据解决方案:探析DataOps平台革新与应用

    背景 近年来随着国际形势的变化,信创产业成为我国国家战略的一部分.一直以来,一直以来,全球 ICT 产业底层标准.架构.产品.生态等要素均由国外公司或机构制定和控制,使我国 ICT 产业乃至广大用户面 ...