WhatsApp群发私信协议实现记录(一)

刚开始了解了下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),这个时候要初始化一对密钥,公钥会在连接建立后的第一个发送包中包含,发给服务器。

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的实现例子: 首先,在QT项目中创建一个插件项目。 在插件项目中的.pro文件中添加如下代码: ``` TARGET = CustomTitleBar TEMPLATE = lib CONFIG += plugin QT += widgets HEADERS += customtitlebar.h SOURCES += customtitlebar.cpp ``` 然后,在customtitlebar.h中定义我们需要的接口,包括设置标题、设置图标、设置背景颜色等等: ```c++ #ifndef CUSTOMTITLEBAR_H #define CUSTOMTITLEBAR_H #include <QWidget> class CustomTitleBar : public QWidget { Q_OBJECT public: explicit CustomTitleBar(QWidget *parent = nullptr); // 接口函数 virtual void setTitle(const QString &title) = 0; virtual void setIcon(const QIcon &icon) = 0; virtual void setBackgroundColor(const QColor &color) = 0; signals: }; #endif // CUSTOMTITLEBAR_H ``` 在customtitlebar.cpp中实现接口函数: ```c++ #include "customtitlebar.h" #include <QLabel> #include <QHBoxLayout> CustomTitleBar::CustomTitleBar(QWidget *parent) : QWidget(parent) { QLabel *titleLabel = new QLabel(this); QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(titleLabel); setLayout(layout); } ``` 这里只是一个简单的例子,我们可以根据实际需求添加更多的接口函数和实现。 最后,我们需要在插件中导出这个类: ```c++ #include "customtitlebar.h" #include <QtPlugin> QT_BEGIN_NAMESPACE class CustomTitleBarInterface : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface") Q_INTERFACES(QDesignerCustomWidgetInterface) public: CustomTitleBarInterface(QObject *parent = nullptr); QString name() const; QString group() const; QString toolTip() const; QString whatsThis() const; QString includeFile() const; QIcon icon() const; bool isContainer() const; QWidget *createWidget(QWidget *parent); bool domXml() const; private: bool initialized = false; }; QT_END_NAMESPACE CustomTitleBarInterface::CustomTitleBarInterface(QObject *parent) : QObject(parent) { } QString CustomTitleBarInterface::name() const { return QStringLiteral("CustomTitleBar"); } QString CustomTitleBarInterface::group() const { return QStringLiteral("Custom Widgets"); } QString CustomTitleBarInterface::toolTip() const { return QStringLiteral("Custom title bar widget"); } QString CustomTitleBarInterface::whatsThis() const { return toolTip(); } QString CustomTitleBarInterface::includeFile() const { return QStringLiteral("customtitlebar.h"); } QIcon CustomTitleBarInterface::icon() const { return QIcon(); } bool CustomTitleBarInterface::isContainer() const { return false; } QWidget *CustomTitleBarInterface::createWidget(QWidget *parent) { return new CustomTitleBar(parent); } bool CustomTitleBarInterface::domXml() const { return true; } Q_EXPORT_PLUGIN2(customtitlebar, CustomTitleBarInterface) ``` 这里我们使用了QT的插件机制,将我们定义的接口类CustomTitleBarInterface导出到插件中。 最后,在我们需要使用自定义标题栏的代码中,加载这个插件并设置标题栏: ```c++ QDesignerCustomWidgetCollectionInterface *pluginInterface = QDesignerCustomWidgetCollectionInterface::customWidgets(); QDesignerCustomWidgetInterface *customTitleBarPlugin = pluginInterface->customWidget("CustomTitleBar"); if (customTitleBarPlugin) { QWidget *customTitleBar = customTitleBarPlugin->createWidget(nullptr); customTitleBarPlugin->initialize(customTitleBar); customTitleBarPlugin->setIcon(QIcon(":/images/icon.png")); customTitleBarPlugin->setTitle("Custom Title Bar"); customTitleBarPlugin->setBackgroundColor(Qt::red); mainWindow->setWindowTitle("Main Window"); mainWindow->setWindowIcon(QIcon(":/images/icon.png")); mainWindow->setCentralWidget(new QTextEdit(mainWindow)); mainWindow->setMenuWidget(customTitleBar); } ``` 这样,我们就可以在主窗口中使用自定义的标题栏了。当然,这只是一个简单的例子,实际使用中可能还需要添加更多的功能和接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值