欢迎光临
我们一直在努力

逆向拼多多长连接:Frida+Python协议还原实战

1. 为什么PDD的长连接让传统抓包工具集体失效

你有没有试过用Charles、Fiddler甚至Wireshark去抓拼多多App的网络请求,结果发现——首页加载正常,但点击“领现金”“砍一刀”“拼单详情”这些关键动作时,抓包窗口里一片空白?或者只看到几个 /api/… 的HTTP接口,但返回体全是乱码、加密字段,连 data 字段都解不开?这不是你的代理配置错了,也不是证书没装好,而是拼多多从2021年Q3开始,就系统性地把核心业务流量从HTTP/HTTPS切到了自研长连接通道。我第一次遇到这问题是在帮一个电商数据团队做竞品价格监控时,他们原本用Mitmproxy稳定跑了两年的PDD比价脚本,某天凌晨突然全量失效,所有 /api/goods/detail 返回403,日志里只有一行 {\”code\”:10001,\”msg\”:\”invalid sign\”} 。后来翻了三个月的APK,才确认:这不是签名校验的问题,是整个通信链路已经不在TLS层了。

PDD的长连接不是简单的WebSocket或Socket.IO封装。它跑在TCP之上,但协议栈被深度定制:握手阶段用RSA+AES混合加密协商密钥,心跳包带动态时间戳和设备指纹哈希,每条业务消息都经过三层处理——先用AES-CBC加密原始JSON,再Base64编码,最后用自定义的“混淆字节流”插入随机噪声字节(比如在第7、15、23位插入0x9A、0x3F等固定值)。更麻烦的是,密钥本身不静态存储,而是在App启动时通过JNI调用so库,结合Android ID、IMEI(若已授权)、当前毫秒级时间戳、以及一个硬编码在dex里的16字节种子,用SM4算法动态生成。这意味着,哪怕你dump出内存里的密钥,10秒后它就失效了。传统抓包工具之所以失效,根本原因在于它们工作在OSI模型的 应用层与传输层之间 (如HTTPS在TLS层解密),而PDD的长连接直接绕过了TLS,把加密逻辑下沉到了 应用层内部 ——就像你试图在快递分拣中心查包裹内容,结果发现所有包裹都在出厂前就被焊死了箱子,还贴了防拆封条。

这个项目标题里的“逆向PDD长连接”,核心不是破解加密算法本身(SM4是国密标准,暴力穷举不可行),而是 在加密发生前、解密完成后这两个时间窗口,把原始明文数据稳稳截住 。Python负责构建可复用的分析框架和协议解析器,Frida则像一把手术刀,精准切入App运行时内存,在JNI函数调用前后下钩子,把 encrypt() 输入的明文、 decrypt() 输出的明文实时捞出来。这不是黑产式的暴力破解,而是正向工程思维下的协议还原——我们不攻击系统,只是让隐藏的通信过程变得可见。适合三类人:做电商数据采集的工程师(需合规获取公开商品信息)、移动安全研究员(研究加固方案有效性)、以及逆向学习者(理解真实商业App的防护逻辑)。接下来的内容,全部基于我实测通过的v12.86.0(2024年Q2最新版)APK,所有步骤、代码、Hook点均经真机验证,拒绝纸上谈兵。

2. Frida Hook点选择:为什么必须盯死JNI层的三个函数

很多人一上来就想Hook OkHttp或Retrofit的 call.execute() ,结果发现PDD的请求根本没走这些框架。我试过用 Java.use(\”okhttp3.OkHttpClient\”).newCall.overload(\”okhttp3.Request\”).implementation ,Hook了三天,只捕获到登录页的几个基础HTTP请求,真正的“砍价助力”“红包雨”“限时秒杀”请求一个都没出现。后来用JADX反编译APK,全局搜索 \”socket\” 、 \”connect\” 、 \”write\” ,终于在 com.xunmeng.pinduoduo.network 包下找到核心类 PddSocketClient 。它的 send() 方法接收一个 PddPacket 对象,而 PddPacket 的构造函数里,关键逻辑是调用 com.xunmeng.pinduoduo.jni.JniBridge.encrypt(byte[]) 。这才是真正的加密入口。

Frida Hook点的选择,本质是找 数据形态转换的临界点 。对PDD长连接而言,有且仅有三个函数具备这种临界性:

2.1 JniBridge.encrypt(byte[]) :明文转密文的唯一出口

这是最优先Hook的函数。它的签名是 public static native byte[] encrypt(byte[] input) ,输入是原始JSON字符串UTF-8编码后的字节数组,输出是加密后的密文字节数组。Hook它,你能拿到所有待发送业务请求的原始明文。注意:不要Hook重载版本(如 encrypt(String) ),PDD只调用字节数组版。实测发现,该函数在每次发送前都会被调用,且输入字节数组长度稳定在200~800字节(对应典型业务请求JSON),而输出长度恒为 input.length + 16 (AES-CBC的padding补位)。我在Hook中加了日志过滤: if (input.length > 150 && input.length < 750) console.log(\”[ENCRYPT] Raw: \” + JSON.stringify(JSON.parse(new TextDec

赞(0)
未经允许不得转载:171主机测评 » 逆向拼多多长连接:Frida+Python协议还原实战
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址