网站地址为:aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tLyMv
如有问题请联系作者,将及时进行相应处理
一、分析过程
1.1 还原抓包过程
在使用该款翻译软件时,就想着自己能不能用代码的形式来实现翻译功能,说干就干。
在左边的框中输入需要翻译的英语单词”like”,在右边的框中就会出现翻译后的结果。
在进行翻译时,按键盘快捷键”F12″,可以打开Google 浏览器的DevTools工具(开发者工具),然后查看翻译时发起的网络请求,
依次选择”Network(网络)” –> “Fetch/XHR” –> 然后选择 “webtranslate”开头的网络请求
1.2 解释表单字段意义
通过仔细观察就可以知道。每个表单数据的意义如下所示:
表单字段 | 意义 |
---|---|
i | 即输入的词汇 |
from、to | 即输入的语言和输出的语言(通俗点就是什么语言翻译成什么)en–>zh-CHS |
useTerm | 使用条款,默认为false |
domain | 默认为0 |
dictResult | 字典结果,默认为true |
keyid | webfanyi (固定字符串) |
sign | 不固定。需要逆向分析 |
client | fanyideskweb |
product | webfanyi |
appVersion | 1.0.0 |
vendor /pointParam | web 、 client,mysticTime,product |
mysticTime | 请求的时间戳 |
keyfrom | fanyi.web |
mid、screen、model、network、yduuid | 这些都是固定值,无需解释。 |
以上字段值,就只有i、sign、mysticTime这三个字段的值是变化的,由于i是输入的词汇,mysticTime是时间戳(毫秒级),所以,需要逆向分析的字段就只有sign字段。
1.3 js逆向分析sign字段值
分析时可以选择其中一个方法进行分析
1.3.1 直接搜索字符串
点击请求的链接处,然后点右上角三个”…“的地方,点击Search。
在下方的弹出的输入框中输入“sign”关键字
可以发现搜索出来的结果有点多,不太适合分析……那换下一种方式吧。
1.3.2 断点跟踪
选择翻译的请求,点击”initiator”,然后点击请求调用堆栈中的第一个。
点击进入后就是这样子的,然后点击左侧边框,即可下断点。
然后重新发起一个新的请求,即可将断点断下来
注意可以发现左上角多了一个类似暂停的符号,就是成功断下来了。
需要值得注意的是,该请求是否为自己所分析的请求。因为一般网络发送接口(send函数等)都是通用的,不会只用来发送一条翻译的请求!
技巧就是:断下来后,按一下快键键F8即可,端下来后就像这样,这便是我们需要找的
通过观察f参数,发现请求为”https://**/webtranslate/key” ,正是我们所需要的请求,接着往下分析。
为了更方便、更直观的知道处理的位置,会采用更直接的方法告知流程
断点断下来之后,点击十三次这个按钮
搜索”sign: S(“这个字符串,找到加密的处理sign字段值的位置:
可以很清楚的看见处理流程,sign –> S函数处理(拼接字符串)—>_函数(进行md5哈希算法)
其中,拼接字符串中的d、e、u、t参数分别是:
d:”fanyideskweb”
e:1722780312911 (当前时间戳)
u:”webfanyi”
t:”asdjnjfenknafdfsdfsd”
经过分析后发现,除了e为时间戳之外,其余参数都不会变,具体实现的Python代码如下:
def sign():
# 该方法实现有道词典请求中sign字段的构成
# 获取当前时间戳,以毫秒为单位
timestamp_milliseconds = time.time() * 1000
# 要拼接的字符串列表
mysticTime=f"{'mysticTime=1722781084310'}" # 实际使用中需要替换这个地方为f"{'mysticTime='}{str(int(timestamp_milliseconds))}"
print("当前时间戳:",str(int(timestamp_milliseconds)))
string_list = ["client=fanyideskweb&", mysticTime, "&product=webfanyi","&key=asdjnjfenknafdfsdfsd"]
# 使用join方法将字符串列表拼接成一个字符串
combined_string = ''.join(string_list)
# 创建一个MD5哈希对象
md5_hash = hashlib.md5()
# 更新哈希对象的内容为拼接后的字符串
md5_hash.update(combined_string.encode('utf-8'))
# 获取MD5哈希值的十六进制表示
md5_hex = md5_hash.hexdigest()
return md5_hex
输出结果为:a7b495722dcb9840a806eec6ef683b75
和网页中的结果进行对比:
可以发现是一致的,到此,sign字段值的生成便找到了.
由于mysticTime的值并不是固定的,所以再使用以上代码时,需要进行一点点更改,参考#后的提示
分析完sign字段的值后,接着向下分析,
请求后,可以发现返回包中的数据是不可见的,具体如下所示:
接下来就要分析返回包中的数据了,
1.4 返回包解密
老规矩,还是断点调试更直接,断下来后,需要注意的是,因为之前说过,你要明白现在调试的请求,就是你需要分析的请求,所以需要先跳过一次请求
点击红色框中的“继续运行”按钮一次
为啥要跳过一次呢?等下后面再说
然后还是点击13次跳过当前函数按钮
来到了这个位置,可以发现e= {data:’一串加密’}
点击两次“继续执行”按钮,进入a(e.data)函数中
进入a函数后,可以发现已经到了解密的地方了,其中参数o就是我们需要解密的返回值字符串
xa.A.state.text.decodeKey:解密所需的key
xa.A.state.text.decodeIv:解密所需的iv
那么接下来就要进入到_a.A.decodeData函数中查看具体的算法和处理,
进入之后可以清楚的看见算法为aes,并且为128位,模式为cbc
其中a和n就是解密所需的key和iv,继续单步调试
可以发现T函数就是做了一次md5,而参数e则是一串字符串,
e= “ydsecret://query/key/BRGygVywfNBwpmBaZgWT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl”
一直调试完参数a的赋值函数后,会发现出现了一个类似“绷带”的图标
点击一下,出现了一串16字节的十六进制数值。这串值就是最后解密所需的key,就是md5(e)
进行验证一下
确实一致,那么就可以确定key = 08149da73c59ce62555b01e92f34e838,根据以上的操作,继续执行
可以知道iv = md5(“ydsecret://query/key/BRGygVywfNBwpmBaZgWT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl”)
即iv=43e84bfa8149ef67ac7453dc18218a2f
那么到这儿就已经很清楚了,解密返回包的值,就是base64 + aes_128_cbc
之前还留有一个问题,为什么要跳过一次请求???因为在进行翻译时,会向服务器申请解密所需的key和iv
如上图第一个请求,key?keyid=webfanyi
返回包中就是我们解密所需要的key和iv
好啦,到这儿,YD翻译的全部过程就已经分析完了,
二、总结
请遵守相关法律法规,不要做损害别人利益的事儿,