最近看了下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扩展得到中间数据和密钥,包括用来加密下面的数据,
第一个发送包中包含有手机环境信息:
这个数据校验通过后,就是连接正常建立了,后面就可以发送私信了。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)