刚开始了解了下WhatsApp,说是消息端对端加密的,信息只能双方解密,服务器都不知道的,初始看了一脸懵。
不过看网上资料其实有点尴尬,刚开始不知道的时候看也看不懂,各种密钥概念,加密过程直接绕晕了,等开始分析app,能看懂的时候,发现也搞完了,回过头来看,确实上面写的(特别是白皮书)都是对的,只是初始不了解的时候理解不了,毕竟上面文章不是实操流程。
首先看下数据流,确定下网络传输方式,结合Wireshark,通过hook及下断点等方式确定了是TCP。
查了下IP:157.240.199.61香港 Facebook
知道发送点后,再结合JNI函数(根据名称就可以确定重要的模块libwhatsapp.so,libcurve25519.so),逐步确定调用线。
在密码学中,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),这个时候要初始化一对密钥,公钥会在连接建立后的第一个发送包中包含,发给服务器。