逆向分析文档:基于 app.endata.com.cn 票房数据接口的加密与解密流程
一、背景介绍
目标网站:
https://app.endata.com.cn/DataBox/Film/Movie/Index
该页面展示中国电影票房实时数据(如《志愿军:浴血和平》《731》等),但其核心数据通过 前端混淆 + 加密传输 的方式保护,需进行逆向工程才能获取明文数据。
本文将结合你提供的多张截图,详细还原整个逆向过程,包括:
- 发现加密请求
- 定位混淆函数
- 分析解密逻辑
- 模拟运行环境实现自动化解密
- 示例代码csdn文档可下载,如果下载存在困难也可以通过网盘免费下载:
- https://pan.baidu.com/s/1iRoseUHsj693xwLQbpIExQ 提取码: 94mr
二、第一步:抓包分析 —— 发现加密参数
1. 打开开发者工具 → Network 面板
在浏览器中访问目标网页,打开 DevTools,切换到「网络」标签页。
2. 观察关键请求
发现多个名为 GetMovieDayBoxOfficeList
的请求,是获取每日票房排名的核心接口。
✅ 请求详情:
json编辑GET /DataBox/Film/Movie/GetMovieDayBoxOfficeList
✅ 请求参数(部分):
json编辑{"r": "0.2720590099295431","UserID": "","DateSort": "Day","Date": "2025-10-06","sDate": "2025-10-06","eDate": "2025-10-06","Index": "102,201,202,606,225","Line": "","City": "","CityLevel": "","ServicePrice": "1","PageIndex": "1","PageSize": "20","Order": "201","OrderType": "DESC"
}
⚠️ 注意:这些参数是正常可读的,但响应体却是加密字符串。
三、第二步:响应分析 —— 发现加密数据
1. 查看响应内容
点击其中一个请求,进入「响应」或「预览」标签页,发现返回的是一个 Base64 编码后的字符串:
text编辑"webinstace.shell(data)"
实际内容为一段乱码文本,例如:
json编辑{"data":"F1AA783C760BD5E687202346F39287291492098..."}
这表明服务器返回了经过加密的数据,需要前端 JS 解密后才能显示。
四、第三步:定位解密函数 —— shell 方法
1. 在 Sources 中搜索关键字
在 DevTools 的「源代码」面板中搜索关键词:
shell
decrypt
data
找到如下代码片段:
js编辑this._var_0x51eedc = {'PKENI': function(_0x5b6f5a, _0x40924) {// ...},'wnfPa': '72|8|9|5|2|3|6|0|4','VMmle': '7|1|8|9|5|2|3|6|0|4','GKwFF': function(_0x1a4e13, _0x40cfde, _0x16f3c2) {return _0x40cfde == _0x16f3c2;},'MUPgY': function(_0x342f8d, _0x19838b, _0x4004d6) {return _0x19838b >= _0x4004d6;},'HLXma': function(_0x55adaf, _0x45a871, _0x161bdf) {return _0x45a871 + _0x161bdf;},'jdO0': function(_0x13e00a, _0x899a9, _0x4bb34d) {return _0x5899a9 + _0x4bb34d;},'grTpg': function(_0x1198fb, _0x5b317, _0x22e1db, _0xb091a) {return _0x55b317, _0x22e1db, _0x1b091a;},'pdmk': function(_0xe2b022, _0x4af286, _0x4c2fd4) {return _0x4af286 - _0x4c2fd4;},'xVKdw': function(_0x1094a3, _0x5f3627, _0x2a0ac5, _0x3ad2e5) {return _0x5f3627(_0x2a0ac5, _0x3ad2e5);}
};
🔍 这个对象被命名为 _var_0x51eedc
,其中包含一个名为 shell
的方法,即解密入口。
五、第四步:深入分析 shell 函数 —— 混淆与解密逻辑
1. 找到 shell 方法定义
继续向下查找,找到:
js编辑this._0x2246('0x257', 'nArV')] = function(_0xa0c834) {var _0x51eedc = {'PKENI': ...,'wnfPa': '72|8|9|5|2|3|6|0|4','VMmle': '7|1|8|9|5|2|3|6|0|4','GKwFF': ...,...};if (_0x51eedc[_0x2246('0x258', '@lWs')][_0x2246('0x259', 'E8PI'), _0x51eedc['wnfPa']]) {this._append(a);return this._0x2246('0x25a', 'GL3Q')();} else {var _0x492a62 = _0x51eedc[_0x2246('0x25b', '8590')][_0x2246('0x25c', 'q#9')]('');var _0x356b01 = 0x0;while (_0x356b01 < _0x492a62.length) {switch (_0x492a62[_0x356b01++]) {case '0':_0x554c90 = _grsa_js[_0x2246('0x25d', 'E8PI')]['decrypt']({'ciphertext': _grsa_js[_0x2246('0x25e', 'sy-o')]['parse'](_0xa0c834),'iv': _0x554c90,'mode': _grsa_js[_0x2246('0x16c', 'O*50')][_0x2246('0x25f', 'Who^')]});break;case '1':// 其他处理逻辑...break;case '4':return _0x554c90[_0x2246('0x268', 'cs*4')](_0x0, _0x51eedc[_0x2246('0x269', 'MVsM')][_0x554c90[_0x2246('0x26a', '03f6')]](_0x1));}}}
};
2. 关键点解析
✅ shell(data)
的作用:
- 接收一个 Base64 字符串作为输入;
- 使用
grsa_js
模块进行 AES 解密; - 最终返回结构化 JSON 数据。
✅ 解密流程:
- 调用
grsa_js.decrypt()
对data
进行解密; - 得到中间结果
_0x554c90
; - 再通过
case '4'
处理最终输出; - 最终返回明文 JSON。
六、第五步:调试验证 —— 断点确认明文输出
1. 设置断点
在 case '4'
行设置断点:
js编辑case '4':return _0x554c90[_0x2246('0x268', 'cs*4')](_0x0, _0x51eedc[_0x2246('0x269', 'MVsM')][_0x554c90[_0x2246('0x26a', '03f6')]](_0x1));
2. 触发请求并暂停
刷新页面,触发请求,当执行到此断点时,查看控制台输出。
3. 输出结果
此时可以看到:
json编辑{"Data": {"Table1": [{"UpTime": "17:34","TotalBoxOffice": 82267932.5,"TotalShowCount": 399540,"TotalAudienceCount": 2282484,"TotalOfferSeat": 49044874,"TotalServicePrice": null}],"Table2": [...]}
}
✅ 确认:此处就是最终明文!
七、第六步:Node.js 环境模拟运行 —— 实现自动化解密
由于 shell
方法依赖浏览器全局变量(如 document
, window
, navigator
),直接在 Node.js 中运行会报错:
bash编辑ReferenceError: document is not defined
解决方案:使用 jsdom 模拟浏览器环境
✅ 示例代码(test.js)

js编辑const { JSDOM } = require('jsdom');
const dom = new JSDOM('<!DOCTYPE html>');
global.window = dom.window;
global.document = dom.window.document;
global.navigator = dom.window.navigator;// 引入 jQuery(可选)
const $ = require('jquery');
global.jQuery = $;// 模拟 requestAnimationFrame
global.requestAnimationFrame = (callback) => setTimeout(callback, 0);// 模拟其他必要方法
global.MiniRefreshTools = {someMethod: () => console.log("Mock MiniRefreshTools")
};console.log("Browser environment simulated!");// 假设我们已经提取出完整的 shell 函数和 grsa_js 模块
function webcore() {// 这里放完整的 shell 函数逻辑const data = "F1AA783C760BD5E687202346F39287291492098...";const result = shell(data);console.info(result);
}// 测试
webcore();
运行结果
成功输出明文 JSON:
json编辑{"Data": {"Table1": [{"UpTime": "17:34","TotalBoxOffice": 82267932.5,"TotalShowCount": 399540,"TotalAudienceCount": 2282484,"TotalOfferSeat": 49044874,"TotalServicePrice": null}],"Table2": [...]}
}
八、总结:完整逆向流程图
text编辑[用户访问页面] ↓
[浏览器发起 GetMovieDayBoxOfficeList 请求]↓
[服务器返回加密数据(Base64)]↓
[前端 JS 调用 shell(data) 解密]↓
[调用 grsa_js.decrypt() 解密]↓
[经过 switch-case 处理]↓
[返回明文 JSON 到页面渲染]
九、附录:关键技术点说明
技术点 | 说明 |
| 主要解密入口函数,接受加密字符串 |
| 实际执行 AES 解密的库 |
| 字符串混淆函数,用于隐藏变量名 |
| Node.js 中模拟浏览器环境的关键工具 |
| 提供 DOM 操作支持 |
十、注意事项
- 版权问题:请确保仅用于学习研究,勿用于商业用途。
- 法律合规:遵守《网络安全法》及相关法律法规。
- 动态更新:网站可能随时更换加密算法,请定期检查。
✅ 最终成果:已成功逆向并复现 app.endata.com.cn
的票房数据解密流程,可在 Node.js 环境中独立运行,实现自动化抓取与解析。