首页/新闻资讯/正文详情

某广告推广平台 API 签名算法逆向分析还原

发布时间:2026/9/26 4:08:51 来源:云帆数科 栏目:资讯中心
某广告推广平台 API 签名算法逆向分析还原
阅读须知本文章中所有内容仅供学习交流使用不用于其他任何目的不提供完整代码抓包内容、敏感网址、数据接口等均已做脱敏处理严禁用于商业用途和非法用途否则由此产生的一切后果均与作者无关擅自使用本文讲解的技术而导致的任何意外作者均不负责若有侵权请在公众号联系作者立即删除分析概览|参数|所在位置|算法|密钥/参数来源|| — | — | — | — ||‎username|登录请求 Body|AES-256-CBC|Key/IV 硬编码在 JS bundle||‎password|登录请求 Body|RSA-1024 PKCS[#1](javascript: v1.5|公钥硬编码在 JS bundle||‎iamData|每个请求 Header|RSA-1024 PKCS[#1](javascript: v1.5|明文 ‎dspAccountId,dspRoleId来自登录响应||‎Extra-Data|每个请求 Header|RSA-1024 PKCS[#1](javascript: v1.5|明文 ‎{}或 ‎{providerId, adAccountId}|JS 源码溯源分析从抓包入手核心代码全部位于 Vite 打包产物https://xxx.com/assets/index-Cnrq_27l.js ← 主 bundle670 KB https://xxx.com/assets/index-Dzn80_QX.js ← 登录页组件10 KB模块别名追踪链Vite tree-shaking 后函数名被混淆|原始函数|主 bundle 导出别名|登录组件导入别名|作用|| — | — | — | — ||‎MH|‎ai|‎we|username AES 加密||‎tv|‎ah|‎he|RSA 加密password / header||‎bH|‎aj|‎ye|登录 API 调用|登录组件核心调用index-Dzn80_QX.jsconst h{username: we(String(n.username).trim().toLowerCase()), // MH()password: he(n.password)// tv()};const tawait ye(h);// POST /account/login请求拦截器index-Cnrq_27l.js每次请求自动注入gt.interceptors.request.use(async e{const tda();// Pinia store const{accessToken: n, dspAccountId: r, dspRoleId: o}t.userInfo||{};if(ro)e.headers.iamDatatv(${r},${o});e.headers[UBiX-Auth]Bearer n;const{adAccountId: s, providerId: a}t.operatedAccountInfo||{};leti{};if(sa)i{providerId: a, adAccountId: s};e.headers[Extra-Data]tv(JSON.stringify(i));returne;});加密算法还原1. username — AES-256-CBCJS 源码函数名MH使用 CryptoJSfunctionMH(e){const tmn.enc.Utf8.parse(9h1ho2lhu0gr67fpe56fi09n9ned6g6h);// key(32bytes)const nmn.enc.Utf8.parse(com.ubix.platfor);// iv(16bytes)const rmn.enc.Utf8.parse(e);const omn.AES.encrypt(r, t,{iv: n, mode: mn.mode.CBC, padding: mn.pad.Pkcs7});returnmn.enc.Base64.stringify(o.ciphertext);}算法参数|项|值|| — | — ||算法|AES-256-CBC||Key|‎9h1ho2lhu0gr67fpe56fi09n9ned6g6h32 字节 UTF-8 字符串||IV|‎com.ubix.platfor16 字节 UTF-8 字符串||Padding|PKCS7||输入预处理|‎trim().toLowerCase()||输出格式|标准 Base64|验证输入ddddddddqq.comPHP 输出: Po67jmVvqLVmekwpghfGDpm/HXTLl6KBQ9e8UfnSiQA抓包实际: Po67jmVvqLVmekwpghfGDpm/HXTLl6KBQ9e8UfnSiQA匹配: ✅ 完全一致PHP 实现define(UBIX_AES_KEY,9h1ho2lhu0gr67fpe56fi09n9ned6g6h);define(UBIX_AES_IV,com.ubix.platfor);functionubix_encrypt_username(string$username): string{$usernamestrtolower(trim($username));$encryptedopenssl_encrypt($username,aes-256-cbc, UBIX_AES_KEY, OPENSSL_RAW_DATA, UBIX_AES_IV);returnbase64_encode($encrypted);}2. password / Extra-Data / iamData — RSA-1024 PKCS[#1](javascript: v1.5三者共用同一个加密函数tv()区别仅在于明文内容。JS 源码tv→fNfunctiontv(e){returnfN(e,MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV-h87Pz_xcHOG...);}functionfN(e, t){const nnew JSEncrypt();// JSEncrypt 库PKCS#1 v1.5n.setPublicKey(t);// 公钥为 URL-safe Base64 编码的 SPKI const rn.getKey();// 超过117UTF-8 字节时分段加密 // 每段 ≤117字节分别 RSA 加密hex 拼接后统一编码 const lr.encrypt(e);// 返回 hex 字符串returnQ2(l);// 自定义 hex → base64见下节}RSA 公钥JS 中为 URL-safe Base64PHP 中需转换为标准 PEMJS bundle 原始值URL-safe Base64- 代替 _ 代替 /: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV-h87Pz_xcHOGIlu6bizg... **算法参数**|项|值||----|-----||算法|RSA-1024PKCS#1 v1.5 填充 ||公钥格式|SPKISubjectPublicKeyInfoDER 编码Base64 包装||最大单次明文|117字节128 字节模数 −11字节 padding overhead||超长分段策略|每段 ≤117UTF-8 字节各段独立 RSA 加密原始字节拼接后统一 Base64||输出格式|标准 Base64128 字节密文 →172字符1 个填充|**PHP 实现** phpfunctionubix_rsa_encrypt(string$plaintext): string{$pubKeyopenssl_pkey_get_public(UBIX_RSA_PUBLIC_KEY);if(strlen($plaintext)117){openssl_public_encrypt($plaintext,$result,$pubKey, OPENSSL_PKCS1_PADDING);returnbase64_encode($result);}// 超长分段$chunks[];$current;$currentBytes0;foreach(preg_split(//u,$plaintext, -1, PREG_SPLIT_NO_EMPTY)as$char){$cbstrlen($char);if($currentBytes$cb117$current!){$chunks[]$current;$current;$currentBytes0;}$current.$char;$currentBytes$cb;}if($current!)$chunks[]$current;$bin;foreach($chunksas$chunk){openssl_public_encrypt($chunk,$out,$pubKey, OPENSSL_PKCS1_PADDING);$bin.$out;}returnbase64_encode($bin);}关键发现Q2 函数等价于标准 Base64JS bundle 中对 RSA 密文未使用btoa()而是自定义Q2()函数进行编码const vsABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/;functionQ2(hexStr){lett0, n, r;for(;t 3hexStr.length;t3){nparseInt(hexStr.substring(t, t 3),16);// 取3个 hex 字符12bits rvs.charAt(n6) vs.charAt(n63);// 输出2个 Base64 字符}// 处理剩余1或2个 hex 字符并补填充...}初看像自定义编码实际上是标准 Base64 的等价实现。数学证明对于任意 3 字节[B1, B2, B3]其十六进制串为 6 个字符Q2 第一组h1h2h3B1 的两个 nibble B2 高 nibble: nB1*16 (B24)→ n6B12Base64 标准第1字符 n63B1[1:0]4|B2[7:4]Base64 标准第2字符 Q2 第二组h4h5h6B2 低 nibble B3 的两个 nibble: nB2[3:0]*256 B3 → n6B2[3:0]2|B36Base64 标准第3字符 n63B3[5:0]Base64 标准第4字符结论Q2(hex(bytes))≡base64(bytes)PHP 直接base64_encode()即可无需实现 Q2。请求头生成逻辑iamData明文${dspAccountId},${dspRoleId}来源登录响应data字段直接提供{dspAccountId:qq123456789,dspRoleId:9}示例明文qq123456789,9生成ubix_rsa_encrypt(qq123456789,9)→ 172 字符 Base64免责声明本报告仅供安全研究和学习目的请勿用于非法用途。本文章中所有内容仅供学习交流使用不用于其他任何目的不提供完整代码抓包内容、敏感网址、数据接口等均已做脱敏处理严禁用于商业用途和非法用途否则由此产生的一切后果均与作者无关擅自使用本文讲解的技术而导致的任何意外作者均不负责若有侵权请在公众号联系作者立即删除

相关推荐

React 列表与表单
React 列表与表单

React 列表与表单 前置&#xff1a;React State 与事件 目标&#xff1a;map key 渲染列表&#xff1b;表单提交增加待办。 动手 完整代码&#xff1a;react2/04-lists-forms/demo cd react2/04-lists-forms/demo npm install npm run dev要点 {todos.map((todo) > (<… · 2026/9/26 4:08:51

【大数据毕设精品】基于大数据的智能制造资源效率数据分析与可视化,附源码_数据可视化_数据分析_数据挖掘_Hadoop_spark_文档指导_毕设指导
【大数据毕设精品】基于大数据的智能制造资源效率数据分析与可视化,附源码_数据可视化_数据分析_数据挖掘_Hadoop_spark_文档指导_毕设指导

&#x1f496;&#x1f496;作者&#xff1a;计算机毕业设计杰瑞 &#x1f499;&#x1f499;个人简介&#xff1a;曾长期从事计算机专业培训教学&#xff0c;本人也热爱上课教学&#xff0c;语言擅长Java、微信小程序、Python、Golang、安卓Android等&#xff0c;开发项目包括… · 2026/9/26 4:08:51

Linux 端口被占用怎么办?复现一次 8000 端口冲突
Linux 端口被占用怎么办?复现一次 8000 端口冲突

启动一个服务时&#xff0c;终端突然出现 Address already in use&#xff0c;很容易下意识去搜索“如何杀掉端口”。但端口不是进程&#xff0c;真正需要查清的是&#xff1a;哪个地址上的哪个协议端口&#xff0c;正被哪个进程使用&#xff1f;它是不是自己刚启动的测试服务&… · 2026/9/26 4:08:51

开源贡献入门指南:从零开始提 Pull Request 的完整实操路线
开源贡献入门指南:从零开始提 Pull Request 的完整实操路线

刚接触开源社区的朋友&#xff0c;十有八九都问过我同一个问题&#xff1a;"我也想给开源项目做贡献&#xff0c;但到底该从哪下手&#xff1f;" 每次收到这种消息&#xff0c;我都特别理解那种感觉——看着 GitHub 上成片的仓库&#xff0c;星星多、贡献者众&#x… · 2026/9/26 4:44:56

从零部署OpenClaw:接入本地模型与飞书渠道的完整实践
从零部署OpenClaw:接入本地模型与飞书渠道的完整实践

上个月我用了两个周末&#xff0c;把OpenClaw从零到一完整部署起来&#xff0c;接上了本地模型&#xff0c;跑通了飞书和终端两个渠道&#xff0c;还顺手解决了几个能把人逼疯的报错。这篇东西就是那段时间的完整记录&#xff0c;包括部署思路、能直接照着敲的命令、参数怎么定… · 2026/9/26 4:44:56

停产控制板重产实战:从PCB反向工程到小批量工艺验证
停产控制板重产实战:从PCB反向工程到小批量工艺验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 4:44:56

MATLAB/Simulink 2机5节点电力系统暂态稳定仿真建模实践
MATLAB/Simulink 2机5节点电力系统暂态稳定仿真建模实践

做电力系统暂态稳定仿真&#xff0c;2机5节点是绕不开的经典算例。别看这个网络只有两台发电机、五条母线&#xff0c;单机无穷大系统里看不到的“相对功角摇摆”“故障切除后的振荡”“临界切除时间搜索”&#xff0c;它都能完整复现。这篇文章我完整梳理了一个基于MATLAB/Sim… · 2026/9/26 4:44:50

Linux 设备驱动中的 GPIO 子系统:基于描述符(gpiod)新标准接口实战
Linux 设备驱动中的 GPIO 子系统:基于描述符(gpiod)新标准接口实战

Linux 设备驱动中的 GPIO 子系统&#xff1a;基于描述符&#xff08;gpiod&#xff09;新标准接口实战在 Linux 嵌入式设备驱动开发中&#xff0c;通用输入输出引脚&#xff08;GPIO, General Purpose Input/Output&#xff09;是控制外设芯片复位&#xff08;Reset&#xff09… · 2026/9/26 4:44:50

前端项目实战复盘:从技术选型到上线避坑的完整指南
前端项目实战复盘:从技术选型到上线避坑的完整指南

写这个系列写到第七篇&#xff0c;我最大的感受是&#xff1a;纯靠收藏前端面试题和背知识点&#xff0c;已经撑不起一个像样的项目了。最近我把手头几个真实上线的 web 前端项目翻出来重新梳理了一遍&#xff0c;发现真正消耗时间的地方&#xff0c;全在那些题海和文档里几乎不… · 2026/9/26 4:44:50

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介&#xff1a;万常选版《数据库原理与设计》课后习题答案资源&#xff0c;覆盖第2至6章及第9章&#xff0c;适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件&#xff0c;含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故&#xff0c;是很多团队绕不过去的坎。线上环境里&#xff0c;服务端明明已经上线了新版接口&#xff0c;老的移动端还在照着旧文档传参数。请求一到网关&#xff0c;校验直接拒绝&#xff0c;用户操作失败&#xff0c;客服群炸了锅&#xff0c;开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码