如何调用逆向出来的JS代码_逆向调用call
文章标签:
javascript下载安装教程
JavaScript 为什么需要调用JavaScript代码
在 JavaScript 逆向中,我们往往是将浏览器的 JavaScript 代码在本地还原,执行后获取逆向结果。然尔 JavaScript 逆向基本都是为 Python 爬虫服务的,所以我们经常需要在 Python 代码中调用 JavaScript 代码。本文详细介绍了几种常用的方法。
JavaScript 调用JavaScript代码的方法
JavaScript 使用PyExecJS调用JavaScript函数
前提条件
- 安装 PyExecJS 库
pip install PyExecJS
#技术分享
- 安装一个 JavaScript 运行时 PyExecJS 只是一个“调度员”,它需要一个真正的“工人”(JS 运行时)来执行代码。强烈推荐安装 Node.js,因为它最稳定且兼容性最好。
- 访问 Node.js 官网 下载并安装。
- 安装完成后,在你的终端(命令行)输入 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 的文件中。这个文件包含了:
- 核心的 JS 业务逻辑 ( getSign 函数)。
- 使用 Express 创建的 HTTP 服务器。
- 处理 /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 脚本需要被设计成一个命令行工具,它必须:
- 从标准输入(stdin)读取数据。
- 执行核心逻辑(可以是异步的)。
- 将最终结果打印到 标准输出(stdout) 。
- 如果出错,将错误信息打印到 标准错误(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 等格式进行转换。
- 进程开销:每次调用都会启动新进程,不适合超高频次的场景。