百度翻译#js逆向#2024:从sign参数破解到完整Python调用实战
1. 百度翻译JS逆向的核心挑战
百度翻译作为国内领先的机器翻译服务,其前端采用了多重防护机制来保护核心接口。2024年的最新版本中,sign参数的生成逻辑变得更加复杂,这对逆向工程提出了新的挑战。我最近在调试时发现,新版百度翻译的加密逻辑至少包含三层嵌套函数调用,而且加入了环境检测机制。
最让人头疼的是那个动态变化的token参数。记得有一次调试时,我花了整整三个小时才定位到token的生成位置——它居然藏在某个被压缩到单行的eval函数里。不过别担心,接下来我会带你一步步破解这些难题。
2. 准备工作与环境搭建
2.1 必备工具清单
工欲善其事,必先利其器。在开始逆向之前,你需要准备好以下工具:
- Chrome浏览器:最新版,开发者工具是我们的主战场
- Fiddler/Charles:用于抓包分析网络请求
- VS Code:编辑JS和Python代码
- Node.js环境:本地执行JS代码测试
- Python 3.8+:最终实现调用的语言环境
我建议先创建一个干净的Python虚拟环境:
python -m venv baidu_fanyi source baidu_fanyi/bin/activate # Linux/Mac baidu_fanyi\Scripts\activate # Windows2.2 关键Python库安装
这些库会在后续步骤中用到:
pip install requests execjs pyexecjs json5特别提醒:如果你在Windows上遇到execjs报错,可能需要安装Node.js并确保它在系统PATH中。我在Windows 11上实测时,就因为这个坑浪费了半小时。
3. 动态调试与参数定位
3.1 抓包分析关键请求
打开Chrome开发者工具(F12),切换到Network面板,勾选"Preserve log"。在百度翻译页面输入要翻译的内容后,你会看到一堆网络请求。重点关注名字包含"v2transapi"的POST请求。
这是我最近抓到的典型请求参数:
from: en to: zh query: hello transtype: translang simple_means_flag: 3 sign: 891234.562341 token: 8a7b6c5d4e3f2g1h domain: common3.2 定位sign生成函数
在开发者工具的Sources面板,按Ctrl+Shift+F全局搜索"sign:"。你会看到类似这样的代码片段:
sign: y(n),点击进入这个y函数,你会发现它可能被重命名了(比如变成_0x1a2b3c这样的名字)。这就是我们需要破解的核心加密函数。
我最近一次分析时发现,2024版的sign生成函数开头多了这样的环境检测代码:
if(typeof window._$jsaprt !== 'undefined'){ throw new Error("Debugger detected"); }4. 逆向破解sign参数
4.1 关键加密逻辑分析
经过多次调试,我发现sign参数的生成主要依赖以下要素:
- 待翻译文本(query)
- 一个固定值"320305.131321201"(2024年仍然有效)
- 复杂的位运算和字符串操作
核心加密函数通常包含这样的结构:
function e(r) { var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g); if (null === o) { var t = r.length; t > 30 && (r = r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10)) } // ...更多加密逻辑 }4.2 补全缺失的JS环境
在本地执行这些JS代码时,经常会遇到"xxx is not defined"的错误。这是因为浏览器环境中有些内置变量在Node.js中不存在。我们需要补全这些环境:
// 在JS文件开头添加这些补丁 var window = { gtk: '320305.131321201' }; var navigator = { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' };5. Python完整调用实现
5.1 封装JS执行环境
首先把完整的加密JS保存为baidu_fanyi.js,然后通过Python调用:
import execjs import json5 import requests def get_sign(word): with open('baidu_fanyi.js', 'r', encoding='utf-8') as f: js_code = f.read() ctx = execjs.compile(js_code) return ctx.call('e', word) # e是加密函数名5.2 获取动态token
token可以通过正则表达式从页面HTML中提取:
def get_token(): url = 'https://fanyi.baidu.com' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } resp = requests.get(url, headers=headers) token = re.search(r"token: '([0-9a-z]+)'", resp.text).group(1) return token5.3 完整调用示例
def translate(word, from_lang='en', to_lang='zh'): url = 'https://fanyi.baidu.com/v2transapi' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Cookie': '你的百度Cookie', # 可选 'Referer': 'https://fanyi.baidu.com/' } data = { 'from': from_lang, 'to': to_lang, 'query': word, 'transtype': 'translang', 'simple_means_flag': 3, 'sign': get_sign(word), 'token': get_token(), 'domain': 'common' } resp = requests.post(url, headers=headers, data=data) result = json5.loads(resp.text) return result['trans_result']['data'][0]['dst']6. 常见问题与解决方案
6.1 请求返回403错误
这通常是因为缺少必要的请求头。除了User-Agent,2024年新版还需要带上:
- Referer
- X-Requested-With: XMLHttpRequest
- Origin: https://fanyi.baidu.com
6.2 sign验证失败
可能的原因包括:
- JS代码中环境变量未补全
- 待翻译文本处理逻辑有差异
- 百度更新了加密算法
解决方案是重新调试JS,确认每个步骤的输出是否与浏览器中一致。我建议在关键位置添加console.log输出,方便比对。
6.3 执行速度优化
当需要批量翻译时,原始方案性能可能不够理想。可以考虑:
- 预编译JS代码
- 复用execjs上下文
- 使用多线程/协程
优化后的代码示例:
# 预编译JS ctx = execjs.compile(open('baidu_fanyi.js').read()) def fast_translate(word): sign = ctx.call('e', word) # ...其余代码不变7. 进阶技巧与最新变化
2024年第二季度,百度翻译又进行了一次安全升级,新增了以下防护措施:
- 动态加载核心加密函数
- 增加了鼠标移动轨迹检测
- 对高频请求实施了更严格的限流
应对策略包括:
- 使用Puppeteer等无头浏览器模拟真实用户行为
- 在请求间添加随机延迟
- 轮换IP地址和User-Agent
这里分享一个我最近发现的技巧:百度翻译现在会检测execjs的执行环境,可以通过修改JS代码开头来绕过检测:
// 在JS文件最前面添加 Object.defineProperty(navigator, 'webdriver', {get: () => false});8. 完整项目结构建议
对于长期维护的项目,我推荐这样的目录结构:
baidu_fanyi/ ├── core/ │ ├── __init__.py │ ├── decrypt.py # 加密解密逻辑 │ └── api.py # 接口调用 ├── js/ │ └── baidu_v2.js # 加密JS代码 ├── tests/ # 测试用例 ├── utils/ # 工具函数 └── main.py # 入口文件这种结构方便后续维护和扩展,比如添加其他翻译平台的逆向实现。
在实际使用中,我发现百度翻译的接口稳定性很大程度上取决于请求头的完整性和Cookie的有效性。如果遇到突然失效的情况,首先检查这些基础配置,往往能节省大量调试时间。