此次逆向涉及到MD5加密

初步准备

首先随意输入文字,请求翻译的结果:
翻译1

得到接口:
https://fanyi.youdao.com/translate_o

观察传递的表单及参数
表单

再输入任意文字,对比表单和参数
表单2

可以观察到需要关注的表单项目为:

  • salt
  • lts
  • sign
  • bv

这里初步估计saltlts均为时间戳相关,而signbv都是32位,初步估计为MD5加密

通过MD5寻找加密处

猜测加密方式为MD5加密,我们可尝试直接搜索md5关键字,有一处匹配,但未能发现和接口相关的代码。
搜索MD5关键字

尝试在该js文件内继续搜索关键字,仅发现一个可能相关处:
可能相关

可以在此处代码下断点对比观察,如果恰好相关则省时省力

通过搜寻参数

同上,不再赘述

通过XHR断点

如果都不能很好确定,使用XHR断点最为直接。

这里下translate_o的XHR断点,观察堆栈
堆栈

可以看到下图是传送请求起始,表单来源为e
起始

根据下一堆栈对其函数调用,发现e即为下列对象:
e

到目前为止,可以考虑开始“扣代码”

扣代码

关心的四个参数代码:

salt: r.salt,
sign: r.sign,
lts: r.ts,
bv: r.bv,

都与r相关,而其声明恰好在函数内:
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加密算法,如果是,则可以使用现成的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,通过参数搜索,定位到以下代码:
COOKIE

可以暂时将除___rl__test__cookies作为定值使用,而___rl__test__cookies则为时间戳

验证

使用PyExecJS为Python爬虫提供加密参数