一、查资料
网上没找到SDK可以分析,关于微信安卓协议的文章也比较少,比较有用的是<微信交互协议和加密模式研究>,这篇论文里介绍了微信使用RSA2048与AES-CBC-128结合的加密算法以及使用protobuf编码格式传输数据;<微信协议简单调研笔记>帖子里提到微信使用长短链接结合的网络通讯方式以及基于sync key的消息同步机制;<基于TLS1.3的微信安全通信协议mmtls介绍>详细讲解了类似于https中TLS作用的mmtls协议;<微信安卓客户端逆向分析>通过举例拦截聊天记录详细演示了安卓微信客户端分析的过程.
二、准备工作
工具除了安卓反编译常用打包解包软件以及查看java代码的软件,还可以用XSearch方便在大量smali汇编文件中快速搜索字符串,Wireshark用于抓包,Android Studio动态调试smali汇编代码,IDA静态分析so文件,WinHex用于编辑二进制文件.
微信底层使用自家开源的跨平台通讯库mars,该库包含xlog模块,详尽记录了微信几乎所有主要函数调用流程,开启log可以极大地方便动态分析,研究mars库也有助于理解微信与服务器交互流程.
由于mmtls无法中间人攻击,所以抓包无法获取短链接HTTP通讯的明文数据;考虑到兼容性微信允许在不使用mmtls的情况下通讯,所以关闭mmtls有助于协议分析.
由于长链接含有包头不利于分析,考虑到稳定性微信允许在不使用长链接的情况下通讯,所以禁用长链接有利于协议分析.
三、二次打包客户端
微信允许非官方签名的客户端运行,但是会校验签名并上报异常数据.最近因使用非官方客户端封号的风控策略越来越严格,运行二次打包客户端时要做好被封号准备,或者使用XP插件Hook代码,或者patch掉获取软件签名的代码或者禁掉上传异常数据的封包,总之这不是本文的重点.如果反编译工具直接打包失败,可以只重新编译dex文件,然后替换到原来的apk中.
从mars库的Xlog文档中可以知道setConsoleLogOpen接口负责开启控制台log,在反汇编代码中搜索这句代码的调用"->setConsoleLogOpen",找到XLogSetup.smali文件直接修改Lcom/tencent/mars/xlog/Xlog;->setConsoleLogOpen的调用参数即开启log.搜索getLogLevel最终可以在Lcom/tencent/mm/sdk/platformtools/下面找到输出Log等级的定义,从6改为0即可打印所有等级的log.logcat里可以通过"MicroMsg""mars"两个tag来分别过滤java层和native层的log.
运行开启Log的客户端,过滤tag为"mmtls"的日志,可以找到"Java_com_tencent_mars_mm_MMLogic_setMmtlsCtrlInfo"函数打印的log:
从函数名可以猜出这是java调用jni控制开启mmtls的接口,在反汇编代码中搜索";->setMmtlsCtrlInfo"找到调用的代码,修改参数为0关闭mmtls.
从mars库中可以看出,长链接使用mars/stn/src/longlink.cc文件的LongLink::__RunConnect函数连接服务器,解压apk搜索字符串"longlink.cc"可知mars库编译出的文件为libwechatnetwork.so,在二进制文件中结合IDA patch掉该函数返回值可以禁用长链接;从mars文档也可以看出上层需要调用mars::stn::MakesureLonglinkConnected();启用长链接,在smali代码中搜索调用";->makesureLongLinkConnected"的代码注释掉也可关闭长链接.
四、抓包
使用安卓模拟器或用手机连接电脑开启的wifi,运行二次打包处理的客户端,使用Wireshark工具即可抓到微信短链接的HTTP协议封包了.比如登录包可以抓到使用POST方法向/cgi-bin/micromsg-bin/manualauth 发送了1183字节长度的数据,数据是被加密的:
<微信安卓客户端逆向分析>文章中提到数据是被libMMProtocalJni.so这个库加密的,使用IDA查看该库的jni接口:
可以看到"Java_com_tencent_mm_protocal_MMProtocalJni_pack"很可能是封包加密的接口,在smali反汇编代码中搜索调用该接口的代码"MMProtocalJni;->pack"如下:
根据log tag"RemoteReq"以及"reqToBuf using protobuf ok"可以猜测这里就是protobuf明文加密封包的地方.接下来可以使用AS在smali这句代码上下断点观察参数与返回值,如果配置调试环境有困难,可以在smali代码中插log将参数与返回值打印并保存下来,方便后面分析.其中第二个参数类型是PByteArray,这是自定义的类型,需要打印的字节数组为该对象的value成员变量;使用Log.d在控制台打印时默认有4000字节的长度限制,超过的部分无法输出,插入log时注意将长log拆分多行输出.