逆向主题:有道翻译sign参数及解密返回结果。
(注:文章所涉及内容只做学习参考交流,不做除此之外的任何其它用途!!!)
逆向sign参数
首先,打开浏览器抓包工具,进行页面刷新,全局搜索sign,在资源面板中打开js文件。步骤如下:
然后,Ctrl+F,搜索sign,发现只有一处(很nice),找到并打上断点。
开始在页面进行请求,断点 调试数据。
已经拦截到了, 然后就是一步步调式了。
1、进入v(t, e)函数,
2、进入g(e)函数,就进行加密了。
到此,sign参数加密就完成了。如果不知道c.a.createHash(“md5”).update(e.toString()).digest(“hex”)这个算法是怎么实现的,直接复制去百度搜索,不要跟进去一步一步扣代码!!!因为,有现成的js库,直接调用即可。
js实现
import execjs
def get_sign(timestamp):
js_code = '''
const crypto = require('crypto');
const l = 'fanyideskweb',
d = 'webfanyi';
function g(e) {
return crypto.createHash("md5").update(e.toString()).digest("hex")
}
function v(e, t) {
return g(`client=${l}&mysticTime=${e}&product=${d}&key=${t}`)
}
'''
e = 'fsdsogkndfokasodnaso'
return execjs.compile(js_code).call('v', timestamp, e)
if __name__ == '__main__':
print(get_sign(1678674935386))
py实现
import hashlib
def get_sign(timestamp):
msg = f'client=fanyideskweb&mysticTime={timestamp}&product=webfanyi&key=fsdsogkndfokasodnaso'
return hashlib.md5(msg.encode('utf-8')).hexdigest()
if __name__ == '__main__':
print(get_sign(1678674935386))
解密返回结果
找到刚刚请求抓到的这个包,然后进去(当然,我这里挨着找的,所以在③处直接就进去了)。
打上断点,发送请求,e.data就是返回加密结果。
单步调试跟进去,如下图:
nn[“a”].decodeData(o, an[“a”].state.text.decodeKey, an[“a”].state.text.decodeIv)
参数o:加密数据
参数an[“a”].state.text.decodeKey和an[“a”].state.text.decodeIv:代码中写死
继续跟进去,这部分代码执行完就得到了最终结果,完成!!!
注意:里面的方法也都是可以由js的crypto解密库所实现,所以也不用自己跟进每个方法里面去扣代码逻辑!如果不知道怎么写js代码,就如同上面所说,直接复制每行代码去问度娘就好!!!
js实现
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import execjs
# 需要node环境!!!
# 如果执行if分支,则需注意导入包的顺序,这样才能进行定义编码,可能不会报错
# 如果执行else分支,则只需要导入import subprocess即可
def decrypt_data(msg, select=True):
if select:
js_code = '''
const crypto = require('crypto');
var o = 'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
var n = 'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
function decrypt_data(t) {
const a = crypto.createHash('md5').update(o).digest()
, r = crypto.createHash('md5').update(n).digest()
, i = crypto.createDecipheriv("aes-128-cbc", a, r);
let s = i.update(t, "base64", "utf-8");
return s += i.final("utf-8"),
s
}
'''
return execjs.compile(js_code).call('decrypt_data', msg)
else:
return subprocess.Popen(['node', './js实现.js', msg], stdout=subprocess.PIPE).stdout.read()
msg = 'Z21kD9ZK1ke6ugku2ccWuwRmpItPkRr5XcmzOgAKD0GcaHTZL9kyNKkN2aYY6yiOmuh9nNfHAP8nmQ1U8cWs8AsPk-qsI0Oi3S_EIBseAYim7wIT81haR5hYOoRK649xgJV2OCWi8mdYBjL3nNw_m22LYYPt_dDmdoFiMiMwddUtdr42g1o9A-MqBEvxSK-H'
print(decrypt_data(msg))
py未实现
用py写法没有实现,如果有大佬实现了,欢迎在评论区中贴出,先感谢一波!!!
实战
import requests, hashlib, time, random
from js实现 import decrypt_data
class YouDaoFanYi:
def __init__(self):
self.session = requests.Session()
self.headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://fanyi.youdao.com",
"Pragma": "no-cache",
"Referer": "https://fanyi.youdao.com/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
"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",
"sec-ch-ua": "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\""
}
self.get_cookies()
def get_cookies(self):
try:
_ = 2147483647 * random.random()
cookies = {
"OUTFOX_SEARCH_USER_ID_NCOO": str(_),
}
response = requests.get(f"https://rlogs.youdao.com/rlog.php?_npid=fanyiweb&_ncat=event"
f"&_ncoo={_}&_ntms={str(int(time.time()*1000))}"
f"&show=text_translation_result", headers=self.headers, cookies=cookies)
self.cookies = {
"search-popup-show": "9-7",
"OUTFOX_SEARCH_USER_ID_NCOO": str(_),
"OUTFOX_SEARCH_USER_ID": response.cookies.values()[0]
}
except Exception as e:
raise Exception("cookies获取失败!!!程序退出>>>异常信息:", e)
def get_sign(self):
msg = f'client=fanyideskweb&mysticTime={self.timestamp}&product=webfanyi&key=fsdsogkndfokasodnaso'
return hashlib.md5(msg.encode('utf-8')).hexdigest()
def get_data(self):
self.timestamp = str(int(time.time()*1000))
data = {
"i": self.txt,
"from": "auto",
"to": "",
"domain": "0",
"dictResult": "true",
"keyid": "webfanyi",
"sign": self.get_sign(),
"client": "fanyideskweb",
"product": "webfanyi",
"appVersion": "1.0.0",
"vendor": "web",
"pointParam": "client,mysticTime,product",
"mysticTime": self.timestamp,
"keyfrom": "fanyi.web"
}
text = self.session.post("https://dict.youdao.com/webtranslate", headers=self.headers,
cookies=self.cookies, data=data).text
self.res_data = decrypt_data(text)
def parse_data(self):
print("结果>>>",self.res_data)
print()
def main(self):
while True:
self.txt = input("输入要翻译的文本(0退出):").strip()
if self.txt == '0': break
self.get_data()
self.parse_data()
self.session.close()
if __name__ == '__main__':
YouDaoFanYi().main()