JS逆向——某道翻译

文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,如有侵权,请联系作者立即删除!

  • 目标网站:aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tL2luZGV4Lmh0bWwjLw==

一、定位接口

  • 使用Chrome浏览器,打开Network进行抓包
  • 输入要翻译的字符串:Hello World !

页面没有重新加载,初步判断是Ajax请求,我们看 Fetch/XHR请求,有两个请求

  

  • 分析接口 

   经过查看分析,key的请求返回内容中不是我们需要的信息,只剩下webtranslate返回的内容,但是返回的内容是一长串字符串,我们先看一下请求参数,然后再换个要翻译的内容,看看参数有哪些变化。

  • 参数对比

  两次请求参数对比,发现,只有i、sign、mysticTime三个参数发生了变化

  

  i:要翻译的字符串

  sign:加密字符串

  mysticTime:1701264377572,13位数字字符串,去掉后三位放入时间戳转换工具,发现就是时间戳

  • 寻找sign加密位置

  全局搜索sign:(小技巧),搜索的位置打上断点,逐个排除

  

  再次请求,返现断点这个位置暂停,发现mysticTime就是时间戳

  

  进入k(o, e)函数,看一下函数构造

  执行会发现,k(o, e)函数右进入了j(e)函数,进行了一些列跟MD5有关的操作,先把这些函数抠出来

  在看k(o, e)函数的传参,o是时间戳,e呢?

  通过堆栈不难发现t就是e,那这个值怎么生成的(我这里查看了很久都没找到),但是发现不管翻译的内容如何,这t的值是固定,我们可以写死。

  

所以抠出的JS代码如下图,我们调用输出一下:

var t='fsdsogkndfokasodnaso';
var e=new Date().getTime()

function j(e) {
   return c.a.createHash("md5").update(e.toString()).digest("hex")
}
function k(e, t) {
   return j(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`)
}
console.log(k(e,t))

  

  ReferenceError: u is not defined u未定义

  在继续打上断点看一下

  

  在JavaScript中``反引号为模板字符串,反引号包括的字符串中出现${}占位符的意思,相当于Python的f'{}'

  

  观察u的值,通过测试发现u的值和d的值也是固定,我们也可以写死

  

  再次运行代码,提示ReferenceError: c is not definedc未定义,我们看一下内容,明显是MD5加密,使用Python MD5或者Node.js的都行,这里我用Node.js的的,crypto代替c.a

  

var crypto = require('crypto');
var t='fsdsogkndfokasodnaso';
var u="fanyideskweb"
var d="webfanyi"
var e=new Date().getTime()

function j(e) {
   return crypto.createHash("md5").update(e.toString()).digest("hex")
}
function k(e, t) {
   return j(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`)
}
console.log(k(e,t))

  再次运行,发现运行成功

  

  对比页面上的加密字符串(防止魔改MD5),发现跟页面上的加密字符串不一致

  

  在进行分析,组成加密字符串的时间戳一直再变动,所以生成的加密字符串不一致,那我们传入跟页面上一样的字符串在本地JS代码中测试一下

  

  

  

  这次生成的加密字符串一致了

  开始编写程序,请求接口看看返回的内容

  JS代码:

var crypto = require('crypto');
var u="fanyideskweb"
var d="webfanyi"

function j(e) {
   return crypto.createHash("md5").update(e.toString()).digest("hex")
}
function return_sign(e, t) {
   return j(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`)
}

  Python代码

import time
import execjs
import requests

def get_sign(t):
   with open("1.js", "r", encoding='utf-8') as f:
       read_js = f.read()
   e = 'fsdsogkndfokasodnaso'
   sign = execjs.compile(read_js).call('return_sign', t,e)
   return sign

def get_web(str1, t):
   url = 'https://dict.youdao.com/webtranslate'
   header = {
       "Content-Type": "application/x-www-form-urlencoded",
       "Referer": "https://fanyi.youdao.com/index.html",
       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
   }
   cookie={
       "OUTFOX_SEARCH_USER_ID_NCOO":"1880472979.5706484",
       "OUTFOX_SEARCH_USER_ID":"-320001268@240e:3b8:2e6b:8db0:7dde:588a:9908:d4bb"
   }
   sign = get_sign(t)
   data = {
       "i": str1,
       "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",
       "mid": "1",
       "screen": "1",
       "model": "1",
       "network": "wifi",
       "abtest": "0",
       "yduuid": "abcdefg"
   }

   resp = requests.post(url, headers=header,cookies=cookie, data=data)
   print(resp.status_code)
   print(resp.text)

if __name__ == '__main__':
   str1 = 'Hello Wodeld !'
   t = time.time()
   get_web(str1, t)

  

  运行之后发现返回的加密的字符串

  

  在Ajax请求位置返回内容,也就是得到sign值之后,继续跟踪,寻找解密函数,会发执行完这里右侧a中就会出现翻译内容,确定解密函数位置

   

  进入解密函数,看一下执行逻辑,抠出代码

  

  对e.alloc跟踪,你会发现,这里出现Uint8Arry函数,还有一个图标

  

  点击这个图标,然后会弹出以下内容

  

  怎么看着像是内存呀,我们查查Uint8Arry的用法

   Uint8Arry数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素

  我们用Node.jsBuffer.alloc代替

  进入y(o)函数,发现就是MD5函数,我们引入crypto包,代替c.a

  

  运行代码,

  运行后报错: 'gbk' codec can't decode byte 0xb7 in position 68: illegal multibyte sequenc

  execjs包编码问题在引入前修改一下编码:

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

  

  再次运行,得到正确结果

  

  完整1.js代码

var crypto = require('crypto');
var u="fanyideskweb"
var d="webfanyi"

function j(e) {
   return crypto.createHash("md5").update(e.toString()).digest("hex")
}
function return_sign(e, t) {
   return j(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`)
}

  

  完整2.js代码

var crypto = require('crypto');

function return_text(t, o, n) {
   if (!t)
       return null;
   const a = Buffer.alloc(16, crypto.createHash("md5").update(o).digest())
       ,
       i = Buffer.alloc(16, crypto.createHash("md5").update(n).digest())
       , r = crypto.createDecipheriv("aes-128-cbc", a, i);
   let s = r.update(t, "base64", "utf-8");
   return s += r.final("utf-8"), s
}

  

  完整Python代码

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

import time
import execjs
import requests

def get_sign(t):
   with open("1.js", "r", encoding='utf-8') as f:
       read_js = f.read()
   e = 'fsdsogkndfokasodnaso'
   sign = execjs.compile(read_js).call('return_sign', t, e)
   return sign


def get_text(str1):
   with open("2.js", "r", encoding='utf-8') as f:
       read_js = f.read()
   o="ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"
   n="ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"
   str2 = execjs.compile(read_js).call('return_text', str1,o,n)
   return str2


def get_web(str1, t):
   url = 'https://dict.youdao.com/webtranslate'
   header = {
       "Content-Type": "application/x-www-form-urlencoded",
       "Referer": "https://fanyi.youdao.com/index.html",
       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
   }
   cookie = {
       "OUTFOX_SEARCH_USER_ID_NCOO": "1880472979.5706484",
       "OUTFOX_SEARCH_USER_ID": "-320001268@240e:3b8:2e6b:8db0:7dde:588a:9908:d4bb"
   }
   sign = get_sign(t)
   data = {
       "i": str1,
       "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",
       "mid": "1",
       "screen": "1",
       "model": "1",
       "network": "wifi",
       "abtest": "0",
       "yduuid": "abcdefg"
   }
   resp = requests.post(url, headers=header, cookies=cookie, data=data)
   if resp.status_code == 200:
       str3 = get_text(resp.text)
       print(str3)

if __name__ == '__main__':
   str1 = 'Hello World !'
   t = time.time()
   get_web(str1, t)

 End !!!

posted @ 2023-12-01 14:16  小二哥呀  阅读(87)  评论(0编辑  收藏  举报