如何调用逆向出来的JS代码_逆向调用call

JavaScript 为什么需要调用JavaScript代码

在 JavaScript 逆向中,我们往往是将浏览器的 JavaScript 代码在本地还原,执行后获取逆向结果。然尔 JavaScript 逆向基本都是为 Python 爬虫服务的,所以我们经常需要在 Python 代码中调用 JavaScript 代码。本文详细介绍了几种常用的方法。

JavaScript 调用JavaScript代码的方法

JavaScript 使用PyExecJS调用JavaScript函数

前提条件

  1. 安装 PyExecJS 库
pip install PyExecJS
 #技术分享
  1. 安装一个 JavaScript 运行时 PyExecJS 只是一个“调度员”,它需要一个真正的“工人”(JS 运行时)来执行代码。强烈推荐安装 Node.js,因为它最稳定且兼容性最好。
  2. 访问 Node.js 官网 下载并安装。
  3. 安装完成后,在你的终端(命令行)输入 node -v,如果能看到版本号,就说明安装成功了。

执行简单的 JavaScript 表达式

这是最基础的用法,可以直接执行一行 JS 代码并获取返回值。我们使用 execjs.eval() 函数。

import execjs

# 使用 .eval() 执行一个简单的JS字符串操作

js_expression = "'Hello PyExecJS'.split('').reverse().join('')" result = execjs.eval(js_expression)

print(f"JS 表达式的结果: {result}")

# 输出: JS 表达式的结果: SJcexEyp olleH

调用一个定义好的 JavaScript 函数

当你有一段包含多个函数定义的 JS 代码时,你需要先“编译”这段代码,然后再通过函数名来调用指定的函数。这需要用到 execjs.compile() 和 .call() 假设你有一个 math.js 文件,里面有一个 add 函数。

function add(x, y) {
    return x +

}

function subtract(x, y) { return x -

}

则可以在 Python 脚本中这样调用:

import execjs

with open('math.js', 'r', encoding='utf-8') as f: js_code = f.read()

ctx = execjs.compile(js_code)

result = ctx.call("add", 10, 5)

print(f"调用 JS add(10, 5) 函数的结果是: {result}")

优缺点

优点 (Pros)

  • 非常简单:上手快,调用 JS 函数就一两行代码。
  • 安装方便: pip install PyExecJS 就行,库本身很小。
  • 比较灵活:能自动寻找你电脑上安装的 JavaScript 环境(比如 Node.js)。

缺点 (Cons)

  • 必须依赖外部程序:你的电脑上必须安装 Node.js 才能运行,否则会报错,增加了部署的麻烦。
  • 性能很差:每次调用 JS 都像重新打开一个程序,速度慢,不适合频繁调用。
  • 不支持现代 JS:无法运行 Promise 或 async/await 等异步代码,很多新网站的 JS 都跑不了。
  • 已经“过时”了:这个项目自 2018 年以来就没更新过,对于新项目来说,使用它存在风险。

JavaScript JavaScript 逻辑封装成 Node.js 微服务

安装 Express

npm install express

实现Node.js 服务

将以下所有代码保存在一个名为 server.js 的文件中。这个文件包含了:

  1. 核心的 JS 业务逻辑 ( getSign 函数)。
  2. 使用 Express 创建的 HTTP 服务器。
  3. 处理 /get-signature 路由的逻辑。
const express = require('express');

async function getSign(params) { console.log(`[JS Logic] 接收到参数:`, params); await new Promise(resolve => setTimeout(resolve, 50)); const sortedValues = Object.values(params).sort(); const baseString = sortedValues.join('-'); const signature = `express_signed_${baseString}_${Date.now()}`; console.log(`[JS Logic] 生成签名为: ${signature}`); return signature; }

const app = express(); const PORT = 3000;

app.use(express.json());

app.post('/get-signature', async (req, res) => { console.log('[Server] /get-signature 路由被调用'); try { const params = req.body;

if (!params || Object.keys(params).length === 0) { return res.status(400).json({ success: false, error: '请求体不能为空' }); }

const signature = await getSign(params);

res.json({ success: true, signature: signature });

} catch (error) { console.error('[Server] 处理请求时发生错误:', error); res.status(500).json({ success: false, error: '服务器内部错误' }); } });

app.listen(PORT, () => { console.log(`Express 服务已启动,正在监听 http://127.0.0.1:${PORT}`); });

在终端中运行:node server.js 就可以启动服务。

优缺点

优点 (Pros)

  • 专业级性能与稳定性:Node.js 服务是一个常驻进程,利用 V8 引擎以最高效率执行 JS。它避免了其他方法“每次调用都新建进程”的巨大开销,因此响应极快、吞吐量高,完全能胜任高并发的生产环境。
  • 彻底解决环境与依赖问题:你拥有一个完整的、真实的 Node.js 环境。可以随意使用 npm 安装任何第三方 JS 库(如 crypto-js)。
  • 强大的扩展性:这是一个真正的微服务。未来你可以轻松地增加更多 API 接口(路由),并且可以独立地对这个 JS 服务进行扩容(例如部署到多个服务器或容器),而无需改动 Python 主应用。

缺点 (Cons)

  • 增加了架构复杂度:的项目从一个“单体脚本”变成了“微服务架构”。你需要管理两个独立的服务(Python 应用和 Node.js 服务),并确保它们之间的网络通信是可靠的。

使用Python 内置的 subprocess 模块来运行 JavaScript

这是一种非常强大和灵活的“中量级”方案,它比 PyExecJS 更可靠,又比搭建完整的微服务更简单。Python 程序像一个“指挥官”,通过 subprocess 在操作系统中开启一个独立的 node 进程(“士兵”),然后通过标准输入/输出( stdin/stdout )给它下达指令并接收报告。

创建 JavaScript 脚本 (worker.js)

这个 JS 脚本需要被设计成一个命令行工具,它必须:

  1. 标准输入(stdin)读取数据。
  2. 执行核心逻辑(可以是异步的)。
  3. 将最终结果打印到 标准输出(stdout)
  4. 如果出错,将错误信息打印到 标准错误(stderr)
async function getSign(params) {

    await new Promise(resolve => setTimeout(resolve, 50));


    const baseString = Object.values(params).sort().join('_');
    const signature = `processed_${baseString}`;
    return signature;
}

function readStdin() { return new Promise((resolve, reject) => { let data = ''; process.stdin.on('data', chunk => data += chunk); process.stdin.on('end', () => resolve(data)); process.stdin.on('error', err => reject(err)); }); }

async function main() { try { const inputStr = await readStdin(); const params = JSON.parse(inputStr);

const result = await getSign(params);

console.log(JSON.stringify({ success: true, data: result }));

} catch (error) { console.error(JSON.stringify({ success: false, error: error.message })); process.exit(1); } }

main();

创建 Python脚本 (main.py)

import subprocess
import json

def run_js_with_subprocess(params: dict) -> str | None: """ 通过 subprocess 调用 worker.js 并传递参数。""" command = ['node', 'worker.js'] input_data = json.dumps(params) print(f"[Python] 准备运行命令: {' '.join(command)}") print(f"[Python] 将通过 stdin 发送数据: {input_data}")

try: result = subprocess.run( command, input=input_data, capture_output=True, text=True, check=True )

output_data = json.loads(result.stdout) if output_data.get('success'): return output_data.get('data') else: print(f"[Python] JS 脚本报告了一个逻辑错误: {output_data.get('error')}") return None

except FileNotFoundError: print("[Python] 错误: 'node' 命令未找到。请确保 Node.js 已经安装并加入到系统 PATH。") return None except subprocess.CalledProcessError as e: print("[Python] 错误: JS 脚本执行失败!") print(f" - 返回码: {e.returncode}") print(f" - 错误输出 (stderr): {e.stderr.strip()}") return None

if __name__ == "__main__": order_data = { "orderId": "TYO-20250919-001", "amount": 15000, "currency": "JPY" } signature = run_js_with_subprocess(order_data) if signature: print(f"\n[Python] 成功从 JS 获取结果: {signature}")

优缺点

优点 (Pros)

  • 无Python第三方依赖: subprocess 是内置库。
  • 完整的Node.js环境:可以随意使用 npm 包和所有 Node.js 功能,包括 async/await 。
  • 模式通用:这种通过 stdin/stdout 通信的模式可以用于调用任何命令行程序。

缺点 (Cons)

  • 需要手动序列化数据:所有数据交换都需要通过 JSON 等格式进行转换。
  • 进程开销:每次调用都会启动新进程,不适合超高频次的场景。