有道翻译-案例
网址: https://fanyi.youdao.com
抓包:

看一下需要的参数,看到下面参数中,唯一可能加密的是 sign这个参数(经验之谈:sign字眼基本都需要逆向的)。

经验之谈:猜测 mysticTime 这个时间参数和sign参数大概率有关系,因为传递的其他参数除了时间和sign以外,都是固定的。
尝试输入多次 like 这个单词然后翻译,发现sign也是变化的,所以猜测时间参数和sign参数大概率有关系。换句话说,如果多次输入like 看看翻译结果,sign并没有变化,那么就跟时间参数mysticTime无关了。
接下来尝试用fromdata的参数来搜索。这里面优先使用 sign和mysticTime 这两个变化的参数来搜索。先用sign搜索,发现结果很多。

再用mysticTime这个关键字搜索,发现只有一个JS文件,双击下面JS文件:

然后进入下面界面:

然后Ctrl+F,再次搜索:

设置断点:

结合前面fromdata的参数,看到下面的参数,因此可以断定就是加密的地方:

当然,除了搜索mysticTime关键字以外,还有其他搜索的方案,比如搜索URL中的webtranslate关键字。

然后看到URL相同的 webtranslate关键字 所在行打断点


下面是小知识点:只有打了断点,才会出现下面的四个蓝色东西,它们表示的是这一行有好几个调用的地方,也就是可以断点的地方。

而URL后面是参数,所以打断点应该要打在4 那个地方,因为要离参数近一点的地方。
默认是第一个,注意看第一个颜色深一点,其他颜色浅一点。

所以要在4 打上断点,就是点一下,打完之后,呈现下面的样子,变成了第四个颜色深一点,其他颜色浅一点。

尝试输入一个单词,发现就断点断在这里了

注意:看看这个函数,返回的结果是 后面object那一串。

看一下参数:


我们要找的sign函数在 f(t)函数里,看一下t是什么。

我们再看看f这个函数,我们可以看到t 这个就是时间戳。

我们在f这个函数设断点,然后 t 和 sign是有关系的,sing是通过 b(t,e) 函数来的

多次运行b函数,发现没有变化。

并且算123456的时候不是标准md5值(记住这个值,123456 md5加密后是 e10adc3949ba59abbe56e057f20f883e)

我们来看看这个b函数到底是啥

点进去,打个断点:

看看这一串是什么

p函数就是在算md5

看看,p函数就是标准的md5加密函数

看看这串代码的输出:
let a = {
    "from": "auto11111",
    "to_a": "",
}
let b = {
    "from": "auto2222",
    "to_b": "",
}
let c = {...a, ...b}
console.log(c);
至此,理解了前面的 ...e, ...f(t)

到此,可以写Python代码了:
import requests
from hashlib import md5
import time
t = int(time.time() * 1000)
obj = md5()
obj.update(f"client=fanyideskweb&mysticTime={t}&product=webfanyi&key=fsdsogkndfokasodnaso".encode("utf-8"))
sign = obj.hexdigest()  # 获取md5值
data = {
    "i": "like",
    "from": "auto",
    "to": "",
    "dictResult": "true",
    "keyid": "webfanyi",
    "sign": sign,
    "client": "fanyideskweb",
    "product": "webfanyi",
    "appVersion": "1.0.0",
    "vendor": "web",
    "pointParam": "client,mysticTime,product",
    "mysticTime": t,
    "keyfrom": "fanyi.web",
}
headers = {
    "Cookie": "OUTFOX_SEARCH_USER_ID=-922898077@10.110.96.160; _ga=GA1.2.50793062.1656497331; OUTFOX_SEARCH_USER_ID_NCOO=1490949463.084894; search-popup-show=11-8; _gid=GA1.2.342404349.1677055676",
    "Referer": "https://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
resp = requests.post("https://dict.youdao.com/webtranslate", data=data, headers=headers)
print(resp.text)看preview中的数据,和我们打印的数据是一致的。

Python代码:
import requests
from hashlib import md5
import time
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
url = "https://dict.youdao.com/webtranslate"
tm = str(int(time.time() * 1000))
str_temp = f'client=fanyideskweb&mysticTime={tm}&product=webfanyi&key=fsdsogkndfokasodnaso'
obj = md5()
obj.update(str_temp.encode("utf-8"))
sign = obj.hexdigest()
word = input("请输入一个单词:")
data = {
    "i": word,
    "from": "auto",
    "to":"",
    "dictResult": "true",
    "keyid": "webfanyi",
    "sign": sign,
    "client": "fanyideskweb",
    "product": "webfanyi",
    "appVersion": "1.0.0",
    "vendor": "web",
    "pointParam": "client,mysticTime,product",
    "mysticTime": tm,
    "keyfrom": "fanyi.web"
}
headers = {
    "Referer": "https://fanyi.youdao.com/",
    "Cookie": "OUTFOX_SEARCH_USER_ID_NCOO=119698985.05373167; OUTFOX_SEARCH_USER_ID=-317747724@2408:8207:7892:c51:5a1d:c86e:753e:2525",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
session = requests.session()
resp = session.post(url, data=data, headers=headers)
print(resp.text)
def my_md5(data):
    obj2 = md5()
    obj2.update(data.encode())
    ret = obj2.digest()  # 返回字节
    return ret
t = resp.text
# t = 'Z21kD9ZK1ke6ugku2ccWuwRmpItPkRr5XcmzOgAKD0GcaHTZL9kyNKkN2aYY6yiOQXFI3D7RP4_e7hP07ZgORviZXWZKf4FffFcQFOosBBe8jQd4mwR9kTXelgpJc4ZSi4slgGNvt3ZRTXugWrfToCTG8_aV-Nuc2JSAQrOVV7Gi_HBoLlfcx1lS9kIKR17-JkhbGt10PnUD8FoXEH0_jg=='
o = 'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
n = 'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
key = my_md5(o)
iv = my_md5(n)
t = t.replace("_", "/").replace("-", "+")
aes = AES.new(key=key, iv=iv, mode=AES.MODE_CBC)
ming_bs = aes.decrypt(base64.b64decode(t))
ming_bs = unpad(ming_bs, 16)
print(ming_bs.decode("utf-8"))
js版本
var crypto = require("crypto");
function g(e) {
    return crypto.createHash("md5").update(e).digest();
}
var decrypt = (t,o,n)=>{
    if (!t)
        return null;
    const a = Buffer.alloc(16, g(o))
      , c = Buffer.alloc(16, g(n))
      , i = crypto.createDecipheriv("aes-128-cbc", a, c);
    let s = i.update(t, "base64", "utf-8");
    return s += i.final("utf-8"),
    s
}
decodeKey = "ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"
decodeIv = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"
o = 'Z21kD9ZK1ke6ugku2ccWu-MeDWh3z252xRTQv-wZ6jddVo3tJLe7gIXz4PyxGl73nSfLAADyElSjjvrYdCvEP4pfohVVEX1DxoI0yhm36ytQNvu-WLU94qULZQ72aml6zO1yoK0DK2VcGfF9AO8MQzIhlk5-YVeZJ0SoCsfoaZipfpB8leC7Qy4Rvv-j3XfmTUT98JN-VRT9SOviXKvHtUO5gQeRhl8QnIH4714L1gabIYTbvusAnhYKKbbfL2mJVmXBqGmQDh5X8gAgX-smvYT7yDzyZ_hXwkFeAVfd1XdHk0pgVZVd9vnqlcJbf45o0lKKwEwnCKdHJIzLIKVihqckMgpp67oQb4G6CfQpubwHOrUFUCtWNfOfHgWWvFZcYEz2wZOKJny6GqXW_zd1nal0UkpFsoefOjYH49myvu5S017AoOCwtiM8Mr6NM06OIvcd4k1Q8nfDEUElkB-k1UG63gN80P4XPmRnR3abJgUHjQX5d-sv6_4T_lKtj7sRZWdXuaJOKKnKBkArs6o0EXX2czkgfD_PDn_EYDzkhXaAvgYAVLnRfbcEs-82sqjlUBJG9d7G7I8m2fP26TUoTw=='
r = decrypt(o, decodeKey, decodeIv)
console.log(r);
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号