逆向分析文档:基于 app.endata.com.cn 票房数据接口的加密与解密流程

一、背景介绍

目标网站:
https://app.endata.com.cn/DataBox/Film/Movie/Index

该页面展示中国电影票房实时数据(如《志愿军:浴血和平》《731》等),但其核心数据通过 前端混淆 + 加密传输 的方式保护,需进行逆向工程才能获取明文数据。

本文将结合你提供的多张截图,详细还原整个逆向过程,包括:


二、第一步:抓包分析 ------ 发现加密参数

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 数据。
✅ 解密流程:
  1. 调用 grsa_js.decrypt()data 进行解密;
  2. 得到中间结果 _0x554c90
  3. 再通过 case '4' 处理最终输出;
  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 到页面渲染]

九、附录:关键技术点说明

|-----------------------|-----------------------|
| 技术点 | 说明 |
| shell() | 主要解密入口函数,接受加密字符串 |
| grsa_js.decrypt() | 实际执行 AES 解密的库 |
| 0x2246() | 字符串混淆函数,用于隐藏变量名 |
| jsdom | Node.js 中模拟浏览器环境的关键工具 |
| node_modules/jquery | 提供 DOM 操作支持 |


十、注意事项

  1. 版权问题:请确保仅用于学习研究,勿用于商业用途。
  2. 法律合规:遵守《网络安全法》及相关法律法规。
  3. 动态更新:网站可能随时更换加密算法,请定期检查。

最终成果 :已成功逆向并复现 app.endata.com.cn 的票房数据解密流程,可在 Node.js 环境中独立运行,实现自动化抓取与解析。

相关推荐
Samsong9 天前
如何调用逆向出来的JS代码
javascript·逆向
GarrettGao19 天前
Frida常见用法
javascript·python·逆向
CYRUS_STUDIO20 天前
一文搞懂 Frida Stalker:对抗 OLLVM 的算法还原利器
android·逆向·llvm
CYRUS_STUDIO20 天前
Frida Stalker Trace 实战:指令级跟踪与寄存器变化监控全解析
android·逆向
CYRUS_STUDIO21 天前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向
CYRUS_STUDIO21 天前
Frida 实战:Android JNI 数组 (jobjectArray) 操作全流程解析
android·逆向
CYRUS_STUDIO22 天前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO22 天前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
Samsong23 天前
JavaScript逆向之对称加密算法
javascript·逆向