微信协议篇

一、查资料
        网上没找到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:

1
I/mars::mmext(12496): [com_tencent_mars_mm_MMLogic_Java2C.cc, Java_com_tencent_mars_mm_MMLogic_setMmtlsCtrlInfo, 299]:j_use_mmtls=1
       从函数名可以猜出这是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拆分多行输出.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31
#参数1:logtag,参数2:需要打印的bytes
.method public static logX(Ljava/lang/String;[B)V
    .locals 8
    .prologue
    if-eqz p1, :cond_1
    #如果参数p1是PByteArray,要取其成员变量value
    #iget-object v1, p1, Lcom/tencent/mm/pointers/PByteArray;->value:[B
    move-object v1, p1
    #使用平台自带的将bytes转成string的函数,每个版本混淆函数名略有不同
    invoke-static {v1}, Lcom/tencent/mm/sdk/platformtools/bh;->bp([B)Ljava/lang/String;
    move-result-object v1
    invoke-virtual {v1}, Ljava/lang/String;->length()I
    move-result v2
    const v4, 0x0
    #超过4000字节长度的log,分行输出
    const v3, 0xfa0
    :goto_0
    if-ge v4, v2, :cond_1
    move v5, v4
    add-int/2addr v5, v3
    if-le v5, v2, :cond_0
    move v5, v2
    :cond_0
    invoke-virtual {v1, v4, v5}, Ljava/lang/String;->substring(II)Ljava/lang/String;
    move-result-object v6
    invoke-static {p0, v6}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    move v4, v5
    goto :goto_0
    :cond_1
    return-void
.end method

作者:IT随笔
来源:CSDN
原文:https://blog.csdn.net/qq_21051503/article/details/79746742
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(协议)