【2023最新教程】超详细!!!有道翻译js逆向

前言

有道翻译两个加密

第一个是表单的sign 用MD5加密

可以点击目录的 加密字段实现 直接跳转

第二个是返回值AES加密,而且AES的密匙他还用md5加密了一下

可以点击目录的 函数实现解密返回值 直接跳转

一 表单sign字段加密

确定加密字段

image-20231022140708377

表单根据多次请求发现 sign这个字段不断变化,所以是加密了

mysticTime一看就是时间戳,不管他

破解加密字段

在右上角点击搜索

输入sign:

要加英文的冒号,这样结果更精准

image-20231022140846338

可以看到有4个文件含有sign

接着我们打开 发起程序

image-20231022141114551

可以看到app这个文件也是程序发起之一,而且都是排在前面 ,很可疑 ,直接从他开始一个一个查找

image-20231022141319396

可以看到,这段代码可疑,很多字段表单中都有,打个断点测试一下

记得打两个断点,开始一个断点,结束一个断点

因为这样可以直接运行到这段代码的结束位置,这样就可以查看中间的值,不至于直接跳出断点

image-20231022144110559

image-20231022141455294

很明显,K(o,e)返回的值就是 sign,这里直接运行退出去看下是不是

image-20231022141604261

很明显,就是他 ,一模一样,所以我们直接找到 k函数就行

image-20231022141650355

点击跳转

image-20231022141905746

看着这里,已经非常明显了,

k(o,e) 函数解读

o 是时间戳

e是一个固定的字符串

image-20231022142140823

k函数的作用 就是组成一个 除了时间戳 不一样,其他都一样的字符串

然后交给 j函数 进行MD5加密

digest(‘hex’)的意思就是返回16进制的值

image-20231022142501829

最后返回的结果,就是 sign的值

加密字段实现

我们直接上实战

image-20231022143136065

先把md5加密写出函数

我们先使用之前的时间戳,看看和表单上的是否一样

看的出来,我们sign值就破解成功了

直接写成函数装进请求头中

image-20231022143533806

这五个请求头都是要的

import time
import requests
import hashlib  # 导入hash库函数
# 时间戳
ti = str(int(time.time() * 1000))

def sign():
    str_md5 = f'client=fanyideskweb&mysticTime={str(ti)}&product=webfanyi&key=fsdsogkndfokasodnaso'
    sign = hashlib.md5(str_md5.encode("utf-8")).hexdigest()
    return sign

headers = {
    "Origin": "https://fanyi.youdao.com",
    "Referer": "https://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61",
    'Host':'dict.youdao.com',
    'cookie':'OUTFOX_SEARCH_USER_ID=-2034389685@10.110.96.157; OUTFOX_SEARCH_USER_ID_NCOO=1994625046.2245197',
}
url = "https://dict.youdao.com/webtranslate"
data = {
    "i": '狗' ,
    "from": "auto",
    "to": "",
    "domain": "0",
    "dictResult": "true",
    "keyid": "webfanyi",
    "sign":sign(),
    "client": "fanyideskweb",
    "product": "webfanyi",
    "appVersion": "1.0.0",
    "vendor": "web",
    "pointParam": "client,mysticTime,product",
    "mysticTime": str(ti),
    "keyfrom": "fanyi.web",
    "mid": "1",
    "screen": "1",
    "model": "1",
    "network": "wifi",
    "abtest": "0",
    "yduuid": "abcdefg"
}

response = requests.post(url, headers=headers,data=data )
print(response)
print(response.text)

image-20231022144351983

看的出来,我们确实请求成功,并且返回了值,但是,这个值加密了

二 返回值AES解密

跟踪堆栈

首先呢,还是先打上断点,在sign那里

image-20231022164541134

运行到最后一步就可以开始跟踪了,我们点击调用堆栈,现在是E, 我们往下点 ,点击 I

image-20231022164900686

看的出来,调用sign值的时候先调用的这里,所以调用完sign后会往下执行, 所以 我们接着往下打断点

在return的地方打断点,因为都是返回值

image-20231022165714925

打完断点后继续往后运行

image-20231022165817454

可以看到t的值,这不就是加密后的返回值吗

我们直接从头开始打断点,精准点

image-20231022151108534

断点之后继续查看

image-20231022151433478

可以确定t是加密后的值

s就是解密后的值

image-20231022151548615

找到解密后的返回值

我们在回过头好好看看这段代码

image-20231022152249807

我们仔细看过之后也是很明显了,这是一个AES加密 CBC模式

先把密匙和偏移量进行md5加密 digest()是返回二进制的值

然后在进行解密就行,而且我看密匙 和 偏移量都是固定的值

image-20231022152745572

image-20231022152736846

使用全局搜索 ,可以看到就是固定的值,所以这段也不用扣js代码

image-20231022153021005

函数实现解密返回值

def result(text_AES):
    #   偏移量
    decodeiv = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"
    # 秘钥
    decodekey = "ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"
    # 先把密匙和偏移量进行md5加密 digest()是返回二进制的值
    key = hashlib.md5(decodekey.encode(encoding='utf-8')).digest()
    iv = hashlib.md5(decodeiv.encode(encoding='utf-8')).digest()
    # AES解密 CBC模式解密
    aes_en = AES.new(key, AES.MODE_CBC, iv)
    # 将已经加密的数据放进该方法
    data_new = base64.urlsafe_b64decode(text_AES)
    # 参数准备完毕后,进行解密
    result = aes_en.decrypt(data_new).decode('utf-8')
    return result

先使用网页上返回的数据进行测试

image-20231022153626036

可以看到,没有问题

语言转换

我们搜索 zh-CHS,可以看到我们想要转换的语言 代码 code可以转换

image-20231022154939643

我们提取出来就行

image-20231022155701038

太多语言了,我这里就简单选几个,并且写出函数

image-20231022163104467

接下来合并代码

三 完整代码

import base64
import time
from Crypto.Cipher import AES
import requests
import hashlib

ti = str(int(time.time() * 1000))

# sign值加密
def sign():
    str_md5 = f'client=fanyideskweb&mysticTime={str(ti)}&product=webfanyi&key=fsdsogkndfokasodnaso'
    sign = hashlib.md5(str_md5.encode("utf-8")).hexdigest()
    return sign

# 返回值解密
def result(text_AES):
    #   偏移量
    decodeiv = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"
    # 秘钥
    decodekey = "ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"
    # 先把密匙和偏移量进行md5加密 digest()是返回二进制的值
    key = hashlib.md5(decodekey.encode(encoding='utf-8')).digest()
    iv = hashlib.md5(decodeiv.encode(encoding='utf-8')).digest()
    # AES解密 CBC模式解密
    aes_en = AES.new(key, AES.MODE_CBC, iv)
    # 将已经加密的数据放进该方法
    data_new = base64.urlsafe_b64decode(text_AES)
    # 参数准备完毕后,进行解密
    result = aes_en.decrypt(data_new).decode('utf-8')
    return result


headers = {
    "Origin": "https://fanyi.youdao.com",
    "Referer": "https://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61",
    'Host':'dict.youdao.com',
    'cookie':'OUTFOX_SEARCH_USER_ID=-2034389685@10.110.96.157; OUTFOX_SEARCH_USER_ID_NCOO=1994625046.2245197',
}

# 语言字典
dic_code = {0: '自动识别', 'code0': 'auto', 1: '阿拉伯文', 'code1': 'ar', 2: '冰岛文', 'code2': 'is', 3: '波兰文', 'code3': 'pl', 4: '德文', 'code4': 'de', 5: '俄文', 'code5': 'ru', 6: '法文', 'code6': 'fr', 7: '芬兰文', 'code7': 'fi', 8: '弗里西文', 'code8': 'fy', 9: '菲律宾文', 'code9': 'tl', 10: '韩文', 'code10': 'ko', 11: '荷兰文', 'code11': 'nl', 12: '蒙古文', 'code12': 'mn', 13: '缅甸文', 'code13': 'my', 14: '尼泊尔文', 'code14': 'ne', 15: '挪威文', 'code15': 'no', 16: '葡萄牙文', 'code16': 'pt', 17: '日文', 'code17': 'ja', 18: '瑞典文', 'code18': 'sv', 19: '世界文', 'code19': 'eo', 20: '土耳其文', 'code20': 'tr', 21: '乌克兰文', 'code21': 'uk', 22: '西班牙文', 'code22': 'es', 23: '希腊文', 'code23': 'el', 24: '夏威夷文', 'code24': 'haw', 25: '英文', 'code25': 'en', 26: '意大利文', 'code26': 'it', 27: '中文', 'code27': 'zh-CHS'}

# 获取输入语言
def get_from():
    print('选择数字,输入为什么语言:')
    # 判断是否报错
    try:
        from_data = int(input(f'{dic_code}:'))
        code_from = dic_code.get(f"code{from_data}")
        if code_from == None:
            get_from()
        print(f'输入为{dic_code.get(from_data)}')
        return code_from
    # 报错函数回调
    except:
        get_from()
# 翻译成语言
def get_to():
    print('选择数字,翻译成什么语言:')
    try:
        from_data = int(input(f'{dic_code}:'))
        code_from = dic_code.get(f"code{from_data}")
        if code_from == None:
            get_from()
        print(f'翻译为为{dic_code.get(from_data)}')
        return code_from
    except:
        get_from()

get_from1 = get_from()
# 判断是不是选择了自动选择
if get_from1 == 'auto':
    to = ''
else:
    to = get_to()

word = input('请输入语句')

data = {
    "i": word ,
    "from": str(get_from1),
    "to": str(to),
    "domain": "0",
    "dictResult": "true",
    "keyid": "webfanyi",
    "sign":sign(),
    "client": "fanyideskweb",
    "product": "webfanyi",
    "appVersion": "1.0.0",
    "vendor": "web",
    "pointParam": "client,mysticTime,product",
    "mysticTime": str(ti),
    "keyfrom": "fanyi.web",
    "mid": "1",
    "screen": "1",
    "model": "1",
    "network": "wifi",
    "abtest": "0",
    "yduuid": "abcdefg"
}
url = "https://dict.youdao.com/webtranslate"

response = requests.post(url, headers=headers,data=data )
print(response)
print(response.text)

result1 = result(response.text)
print(result1)

四 效果展示

image-20231022163409086

image-20231022163447557

教程有什么不明白的地方,欢迎评论