首页
论坛
课程
招聘
WhatsApp私信协议实现记录
2022-8-24 15:53 12673

WhatsApp私信协议实现记录

2022-8-24 15:53
12673

WhatsApp私信协议实现记录


      最近看了下WhatsApp (android及pc版本),实现了协议发送私信(模板信息也可以发), 记录下学习过程,技术交流用。



一、软硬件环境:

 

WhatsApp v2.22

IDA 7.5

Frida 14.2.2

Gda3.86

JEB

jadx-gui

unidbg

LineageOs 17.1 (android 10)

小米8

 

二、流水账 

    

        刚开始了解了下WhatsApp,说是消息端对端加密的,信息只能双方解密,服务器都不知道的,初始看了一脸懵,在网上找了下资料:

        

      【翻译】WhatsApp 加密概述(技术白皮书)

        http://www.caotama.com/1993224.html

        WhatsAPP通讯协议端对端加密人工智能

        https://blog.csdn.net/BMW33939/article/details/120322512

        Signal 协议 

        https://blog.csdn.net/yzpbright/article/details/117808556


        不过看这些资料其实有点尴尬,刚开始不知道的时候,看这些也看不懂,各种密钥概念,加密过程直接绕晕了,等开始分析app,能看懂的时候,

        发现也搞完了,回过头来看,确实上面写的(特别是白皮书)都是对的,只是初始不了解的时候理解不了,毕竟上面文章不是实操流程。


        首先看下数据流,确定下网络传输方式,结合Wireshark,通过hook及下断点等方式确定了是TCP:


查了下IP:157.240.199.61香港 Facebook


知道发送点后,再结合JNI函数(根据名称就可以确定重要的模块libwhatsapp.so,libcurve25519.so),逐步确定调用线。

看到上面so的名称,查了下知识点:

Curve25519 是目前最高水平的 Diffie-Hellman 函数,适用于广泛的场景,由 Daniel J. Bernstein 教授设计。

在密码学中,Curve25519 是一个椭圆曲线提供 128 位安全性,

设计用于椭圆曲线 Diffie-Hellman(ECDH)密钥协商方案。它是最快的 ECC 曲线之一,并未被任何已知专利所涵盖。



libcurve25519.so boolean org.whispersystems.curve25519.NativeCurve25519Provider.smokeCheck(int) 0x9d782548 func: 0x78b8406288 0x0  iOffset: 4288

libcurve25519.so byte[] org.whispersystems.curve25519.NativeCurve25519Provider.generatePrivateKey(byte[]) 0x9d782638 func: 0x78b8405a2c 0x0  iOffset: 3a2c

libcurve25519.so byte[] org.whispersystems.curve25519.NativeCurve25519Provider.calculateAgreement(byte[], byte[]) 0x9d7825c0 func: 0x78b8405b68 0x0  iOffset: 3b68



生成密钥:

retval: [object Object]

java.lang.Exception

        at org.whispersystems.curve25519.NativeCurve25519Provider.generatePublicKey(Native Method)

        at org.whispersystems.curve25519.OpportunisticCurve25519Provider.generatePublicKey(:750206)


找到了发送信息的明文("11"):

[MI 10::com.whatsapp]-> byteArray,byte src : [10,2,49,49]        protobuf格式

byteArray,md5str:

11

java.lang.Exception

        at X.1FH.A02(Native Method)

        at com.whatsapp.jobqueue.job.SendE2EMessageJob.writeObject(:271863)

        at java.lang.reflect.Method.invoke(Native Method)



顺着流程,会发现很多加密相关类的调用:

java.security.MessageDigest

javax.crypto.Mac

javax.crypto.Cipher


可以直接hook了看数据流的变化,这个时候对加密模式就有了一定了解:

客户端跟服务器有一个加密方式AES-256-GCM,每个包的加密IV都不同,如果发送的数据包是私信内容的,

那里面的私信内容是第二层的加密(aes-256-cbc),这一层的数据因为key的生成用到了对方的公钥做DH得到,

所以只能接收方才能解密,每条私信内容加密的key也是不同的。


每次打开app都会重新发起TCP连接(已经是用验证码登录的情况,后续的打开app),

这个时候要初始化一对密钥,公钥会在连接建立后的第一个发送包中包含,发给服务器。

这里还会用到其它几种密钥(自己的identity_key,标记登录会话类似抖音session token的key,服务器的公钥),这些key相互组合通过calculateAgreement

及HKDF扩展得到中间数据和密钥,包括用来加密下面的数据,

第一个发送包中包含有手机环境信息:

这个数据校验通过后,就是连接正常建立了,后面就可以发送私信了。

前面提到,私信内容的加密其实又是一种加密模式,这个数据是发送者和接收者交互用的,服务器也解密不了的,它只是转发加密后的数据。

私信内容加密是aes-256-cbc,这里会用到消息密钥(Message Key), 80 个字节的值,用于加密消息内容。

32 个字节用于 AES-256 密钥,32 个字节用于 HMAC-SHA256 密钥,16 个字节用于 IV。

HMAC-SHA256密钥用于计算私信内容aes加密的结果的消息认证码,只取结果的前8字节。


这个消息密钥(Message Key)的计算涉及到一个棘轮变换,每加密一条消息后,就要通过sha256的组合算法计算下一条消息加密用的Message Key了。

私信消息的发送,有个会话的概念,双方建立端对端通信需要建立一个会话,就是构造约定好密钥,建立会话后,双方就可以保存这个相关环境参数,直接按

消息序号就可以根据当前的密钥计算出要加解密的Message Key,用于加解密消息了。就算之后重新打开app,私信内容的加解密也可以继续按之前的会话继续,不用重新建立会话。


所以刚开始分析的时候,为了简单,就是在app会话建立的基础上分析的,这样只用hook拿到当前的消息的Message Key,就可以计算出指定消息序号的Message Key,直接加密信息发送就可以了


然后就开始实现建立会话,这个过程可以参考白皮书:


会话发起人为接收人申请身份公钥(public Identity Key)、已签名的预共享公钥(public Signed Pre Key)和一个一次性预共享密钥(One-Time Pre Key)。

服务器返回所请求的公钥。一次性预共享密钥(One-Time Pre Key)仅使用一次,因此请求完成后将从服务器删除。如果一次性预共享密钥(One-Time Pre Key)被用完且尚未补充,则返回空。

发起人将接收人的身份密钥(Identity Key)存为 Irecipient,将已签名的预共享密钥(Signed Pre Key)存为 Srecipient,将一次性预共享密钥(One-Time Pre Key)存为 Orecipient。

发起者生成一个临时的 Curve25519 密钥对  Einitiator

发起者加载自己的身份密钥(Identity Key)作为 Iinitiator

发起者计算主密钥 master_secret = ECDH ( Iinitiator, Srecipient ) || ECDH ( Einitiator, Irecipient ) || ECDH ( Einitiator, Srecipient )  || ECDH ( Einitiator, Orecipient ) 。如果没有一次性预共享密钥(One-Time Pre Key),最终 ECDH 将被忽略。

发起者使用 HKDF 算法从 master_secret 创建一个根密钥(Root Key)和链密钥(Chain Keys)。


过程是这样,但是这个要实际跟一遍,才能比较了解,涉及到的算法本身不复杂,主要是这些key的变换流程。

对建立会话,初始还要创建2组密钥对(OurBaseKey和ourRatchetKey):


按流程实现后测试,发送信息后对方能收到,但是看不到内容:


查了下,网上有说是发送方换设备了就可能这样,那我这个肯定不属于这个情况。

当时一直没搞定,开始认为是加密算法还原有问题,反复核对了几遍,按照hook的数据及参数加密结果跟实际的完全一致。


反复的核对这种数据,搞得没脾气了,后来就静下心来想了下,要实现这个端对端加密应该怎么做,最后发现一个不确定的点,就是oneTimePreKey

对方没法知道用的是哪个。

这个请求的时候,服务器直接返回了一个对方的一次性预共享密钥,这个接收方是提供了一批存到服务器的,用一个就删除一个,如果会话最后没建立成功,服务器应该

也不会同步给接收方的,并且实际发送建立会话的数据中也没看到有回发这个过去,那接收方要能正确解密,肯定要能知道当前会话用的是哪个一次性预共享密钥,

后来想到应该是有个ID来标识的,当时也确实发现发送建立会话的数据中有几个字段值不确定,但是从返回的接收方key数据和发送的私信数据中没找到这个共同的值

(后来发现其实是数据格式不同)。

一直没解决,就新开了条战线,分析PC版本,希望能找出这个差异点,解决这个问题。



PC上的WhatsApp 7个进程,也是首先找收发数据点,最后确定下面的进程是处理网络数据的,根据命令行参数也可以看出来:

跟踪发现PC上发送是用的websocket,直接下载ssl源码,参考标出函数:



找到了数据收发点:

跟踪的时候发现,接收的数据没有进一步的逻辑处理,有时候就请求清空内存了,就猜测可能是发到其它进程去了,看到有MojoMessages相关的。

查了下:

Mojom是chromium最新的跨平台进程通信框架

关注点不在这,没细看。


最后发现,这个进程只是处理网络层的,具体的私信逻辑在另一个进程:




后面就是顺着调用跟踪加密流程了,弄清楚后,可以直接上frida hook PC数据(注入dll也行):

最后核对数据,确定了是有个ID来标记共享密钥:


完善这个后,再测试发送,对方就能看到内容了:


模板信息也是可以的:


顺便提一下,第一次拿码登录流程是走的http模式,数据加密也会用到密钥对的生成。


学习总结:

  1. 学习了端对端通信实现,对这种加密模式有了一定了解。

  2. 熟悉了Curve25519应用。



[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

收藏
点赞6
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/09/01 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (16)
雪    币: 41
活跃值: 活跃值 (81)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
Crimilals 活跃值 2022-8-24 17:20
2
0
pc端electron写的,可以自己整个二次开发环境调试主进程和渲染进程
雪    币: 2364
活跃值: 活跃值 (1032)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_rjdrqvpa 活跃值 2022-8-24 20:41
3
0
感谢楼主分享
WhatsApp具体版本号可以说下嘛?v2.22是大版本号
此外,图片有点模糊
雪    币: 2886
活跃值: 活跃值 (3196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
爱我佳鑫 活跃值 2022-8-25 06:03
4
0
只要能弄好这方面的需求很多, 尤其是海外电商...
雪    币: 728
活跃值: 活跃值 (599)
能力值: ( LV5,RANK:68 )
在线值:
发帖
回帖
粉丝
ArmVMP 活跃值 2022-8-25 08:55
5
0
感谢分享,重点来了如何突破发送任意条数讯息,搞定就GG了
雪    币: 3440
活跃值: 活跃值 (3269)
能力值: ( LV13,RANK:409 )
在线值:
发帖
回帖
粉丝
xwtwho 活跃值 1 2022-8-25 08:55
6
0
mb_rjdrqvpa 感谢楼主分享 WhatsApp具体版本号可以说下嘛?v2.22是大版本号 此外,图片有点模糊
v2.22.15.71
雪    币: 3440
活跃值: 活跃值 (3269)
能力值: ( LV13,RANK:409 )
在线值:
发帖
回帖
粉丝
xwtwho 活跃值 1 2022-8-25 09:01
7
0
ArmVMP 感谢分享,重点来了如何突破发送任意条数讯息,搞定就GG了
一看大佬发的,就是深入参与了业务的,介绍下经验啊
雪    币: 291
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
hack2012 活跃值 2022-8-25 10:47
8
0
不错呀兄弟
雪    币: 277
活跃值: 活跃值 (456)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
笑对VS人生 活跃值 2022-8-25 12:25
9
0
我还以为wechat呢,在国内环境官方不能查看明文是不可能的,分分钟下达整改通知书
雪    币: 2886
活跃值: 活跃值 (3196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
爱我佳鑫 活跃值 2022-8-25 12:34
10
0
mb_dtimafsn 兄弟们怎么才能私聊
点击用户名然后在右上角有私聊按钮
雪    币: 2649
活跃值: 活跃值 (1287)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Vn小帆 活跃值 2022-9-5 17:55
11
0
海外的  很多用Curve25519 
雪    币: 139
活跃值: 活跃值 (147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lvcoffee 活跃值 2022-9-5 20:52
12
0
大佬有空能分析下拉群和发消息吗?
雪    币: 12
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xunilm 活跃值 2022-9-5 23:50
13
0
出全套协yi
雪    币: 58
活跃值: 活跃值 (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Jnj3369 活跃值 2022-9-13 19:18
14
0
谢谢分享
很有趣的内容 
雪    币: 3440
活跃值: 活跃值 (3269)
能力值: ( LV13,RANK:409 )
在线值:
发帖
回帖
粉丝
xwtwho 活跃值 1 2022-9-17 11:17
15
0
lvcoffee 大佬有空能分析下拉群和发消息吗?
拉群和发群信息其实套路类似的,初始的密钥设置有点不同,群这个是发送者对其它成员发送senderkey相关信息,不同人用的加密key都不同,后续的具体信息直接就可以用senderkey扩展出的key加密发送了,第一条信息可以跟上面key交换信息一起发出去。
其它操作的套路都差不多,顺着数据流来就可以搞清楚。
雪    币: 222
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
憨豆爆发 活跃值 2022-9-17 16:01
16
0
风控封号才是最蛋疼的
雪    币: 0
活跃值: 活跃值 (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
breakM 活跃值 2022-9-21 15:21
17
0
学习 学习
游客
登录 | 注册 方可回帖
返回