有道翻译API逆向
此次逆向涉及到MD5加密
初步准备
首先随意输入文字,请求翻译的结果:
得到接口:
https://fanyi.youdao.com/translate_o
观察传递的表单及参数
再输入任意文字,对比表单和参数
可以观察到需要关注的表单项目为:
- salt
- lts
- sign
- bv
这里初步估计salt
和lts
均为时间戳相关,而sign
和bv
都是32位,初步估计为MD5加密
通过MD5寻找加密处
猜测加密方式为MD5加密,我们可尝试直接搜索md5
关键字,有一处匹配,但未能发现和接口相关的代码。
尝试在该js文件内继续搜索关键字,仅发现一个可能相关处:
可以在此处代码下断点对比观察,如果恰好相关则省时省力
通过搜寻参数
同上,不再赘述
通过XHR断点
如果都不能很好确定,使用XHR断点最为直接。
这里下translate_o
的XHR断点,观察堆栈
可以看到下图是传送请求起始,表单来源为e
根据下一堆栈对其函数调用,发现e
即为下列对象:
到目前为止,可以考虑开始“扣代码”
扣代码
关心的四个参数代码:
salt: r.salt,
sign: r.sign,
lts: r.ts,
bv: r.bv,
都与r
相关,而其声明恰好在函数内:
将相关代码“扣”下来:
let n = w.val()
, r = v.generateSaltSign(n)
, i = n.length;
let salt = r.salt,
sign = r.sign,
lts = r.ts,
bv = r.bv
这里可以直接发现n
即我们输入的文字,因此免去“扣”w.val()
,将其先设置为任意文字
将涉及到的其它函数源码“扣”下来,例如 v.generateSaltSign(n)
,其对应代码如下:
var r = function(e) {
var t = n.md5(navigator.appVersion)
, r = "" + (new Date).getTime()
, i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5")
}
};
将其稍微修改加入本地代码:
let generateSaltSign = function(e) {
var t = n.md5(navigator.appVersion)
, r = "" + (new Date).getTime()
, i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5")
}
};
这里navigator.appVersion
可直接进行替换,而n.md5()
可以尝试使用CryptoJS MD5替代,观察对比:
值一致
其实这里的目的是查看网站加密的是否为标准的MD5加密算法,如果是,则可以使用现成的MD5加密库生成,因此可以使用现成的在线工具加密然后对比即可,推荐:the-x 常规MD5 / 文件MD5 在线哈希工具
进行补全后:
const cryptojs = require('crypto-js')
let generateSaltSign = function(e) {
const navigator = {
appVersion:'5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.56'
}
let t = cryptojs.MD5(navigator.appVersion).toString()
, r = "" + (new Date).getTime()
, i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: cryptojs.MD5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5").toString()
}
};
let n = '测试'
, r =generateSaltSign(n)
, i = n.length;
let need = {
salt : r.salt,
sign : r.sign,
lts :r.ts,
bv :r.bv
}
console.log(need)
将其封装一下,最终代码:
const cryptojs = require('crypto-js')
let generateSaltSign = function(e) {
const navigator = {
appVersion:'5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.56'
}
let t = cryptojs.MD5(navigator.appVersion).toString()
, r = "" + (new Date).getTime()
, i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: cryptojs.MD5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5").toString()
}
};
function getIt(text){
let n = text
, r =generateSaltSign(n)
, i = n.length;
let need = {
salt : r.salt,
sign : r.sign,
lts :r.ts,
bv :r.bv
}
return need
}
module.exports = {get:getIt}
补充
实际测试中发现,此API还需要Cookie,通过参数搜索,定位到以下代码:
可以暂时将除___rl__test__cookies
作为定值使用,而___rl__test__cookies
则为时间戳