有道翻译js逆向

发布时间 2023-09-07 14:27:38作者: Hp_mzx

有道翻译

数据分析

生成sign

通过抓取数据,有道翻译是请求这个接口 https://dict.youdao.com/webtranslate,请求参数如下所示:

1694047786722

通过观察参数,mysticTime为时间搓,sign为加密算法生成的数据,其他参数不变,所以只需找到sign的生成函数就可以了。

通过全局搜索,在每个出现sign位置打上断点,找到生成sign的函数

1694049701269

sign是有w函数生成,w函数接收两个值,一个是当前的时间搓,另一个经过重复获取,发现是固定值。

w函数内部通过字符串格式化后把值传给A函数,观察A函数,只是把传过来的值进行md5加密。

使用python实现生成sign

localtime = str(int(time.time() * 1000))
data = "client=fanyideskweb&mysticTime={}&product=webfanyi&key=fsdsogkndfokasodnaso".format(localtime)
sign = hashlib.md5(data.encode(encoding='utf-8')).hexdigest()

设置cookie

生成sign后,可以构造请求发送请求获取数据。

可以观察,请求需要携带cookie,通过清除游览器的cookie刷新界面,再次发送请求,发现cookie是通过请求这个接口 https://dict.youdao.com/login/acc/query/accountinfo,在请求这个接口的请求结果头部设置了cookie

1694050707438

使用python实现设置cookie。

url = "https://dict.youdao.com/login/acc/query/accountinfo"
self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
    "Referer": "https://fanyi.youdao.com/index.html"
}
response = requests.get(url=url, headers=headers)
headers["Cookie"] = response.headers["Set-Cookie"]

解密请求结果

设置cookie,生成sign后请求数据,获取请求结果,发现请求结果是密文,需要通过解密获取具体的结果信息。通过添加断点以及堆栈信息,一步步查找。

1694051545902

可以观察到,密文o传入到tt["a"].decodeData函数后传回给a的是明文数据。点击tt["a"].decodeData跳转到decodeData的具体函数。

1694051868883

通过观察,on 参数为固定值,并都是作为参数传值给 j 函数,点击j函数跳转到具体位置,发现j函数是只是进行md5加密后的数据返回。然后把密文和数据传给createDecipheriv函数进行解密得到明文。

如果使用python对数据进行处理的会得到各种报错,因此使用execjs库直接把数据交个js处理。

const crypto=require('crypto')

function getDatas(t){
    const o = 'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl';
const n = 'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4';
    const a = Buffer.alloc(16, crypto.createHash('md5').update(o).digest())
    const r = Buffer.alloc(16, crypto.createHash('md5').update(n).digest())
    const i = crypto.createDecipheriv("aes-128-cbc", a, r);
    let s = i.update(t, "base64", "utf-8");
    return s += i.final("utf-8"), s
}

代码封装

根据上述,我们通过对js逆向对有道翻译进行处理得到明文数据,对上述步骤进行封装整理成类。

import time
import json
import hashlib
import requests

import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
import execjs

class YouDaoTranslate():
    def __init__(self):
        self.js_path = "有道.js"
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
            "Referer": "https://fanyi.youdao.com/index.html"
        }
        self.__set_cookie()
        self.langDict = {}
        self.__langType()

    def translate(self,query,from_="auto",to=""):
        url = "https://dict.youdao.com/webtranslate"
        localtime = str(int(time.time() * 1000))
        data = "client=fanyideskweb&mysticTime={}&product=webfanyi&key=fsdsogkndfokasodnaso".format(localtime)
        sign = hashlib.md5(data.encode(encoding='utf-8')).hexdigest()
        data = {
            "i": query,
            "from": from_,
            "to": to,
            "dictResult": "true",
            "keyid": "webfanyi",
            "sign": sign,
            "client": "fanyideskweb",
            "product": "webfanyi",
            "appVersion": "1.0.0",
            "vendor": "web",
            "pointParam": "client,mysticTime,product",
            "mysticTime": localtime,
            "keyfrom": "fanyi.web"
        }
        response = requests.post(url=url, headers=self.headers, data=data).text
        with open(self.js_path, 'r', encoding='utf-8') as po:
            signs = execjs.compile(po.read()).call('datas', response)
            text = json.loads(signs)
            try:
                return text['dictResult']['ce']['word']['trs'][0]['#text']
            except:
                return text['translateResult'][0][0]['tgt']

    def __langType(self):
        """语言类型"""
        url = "https://api-overmind.youdao.com/openapi/get/luna/dict/luna-front/prod/langType"
        response = requests.get(url=url, headers=self.headers)
        text = response.json()
        common = text["data"]["value"]["textTranslate"]["common"]
        specify = text["data"]["value"]["textTranslate"]["specify"]
        for data in common + specify:
            self.langDict[data["code"]] = data["label"]


    def __set_cookie(self):
        url = "https://dict.youdao.com/login/acc/query/accountinfo"
        response = requests.get(url=url, headers=self.headers)
        self.headers["Cookie"] = response.headers["Set-Cookie"]


if __name__ == '__main__':
    obj = YouDaoTranslate()
    res = obj.translate('你好,世界')
    print(res)


该类下还增加了获取语言类型方法,通过translate方法的from_to参数控制翻译的语言。