逆向目标
- 目标:有道翻译接口加密参数
- 接口:https://dict.youdao.com/webtranslate
- 加密参数:
- sign: e3d8fa747713d6957db7cd2eedaa0d95
- Cookie: OUTFOX_SEARCH_USER_ID=696102715@114.222.69.137; OUTFOX_SEARCH_USER_ID_NCOO=304412380.2597743
逆向过程
网络接口分析
在翻译页面输入文本,不用刷新就会翻译,因此推断是AJAX请求,F12打开开发者工具,选择XHR过滤AJAX请求,可以看到如下的POST请求:
加密参数如下:
当我们输入China后返回的翻译结果如下,数据是加密的:
Z21kD9ZK1ke6ugku2ccWu-MeDWh3z252xRTQv-wZ6jddVo3tJLe7gIXz4PyxGl73nSfLAADyElSjjvrYdCvEP4pfohVVEX1DxoI0yhm36ytQNvu-WLU94qULZQ72aml6kZ73SLZAuFYSDoo5DxD1CAD_gJoN2WmgoLKCbLnIEYzGOAyer1Jab7-s3V894sJs5T0PMYtKsruRiynDqxTpq17L4Jc3v4FYfzJpjS6tSLw343AhMilrI6zbTJTJ_L7429bntYH77EIX7ynVH3VeLEkEa_FpwAndfjS_1uXbq9vqWsfr0LlOxGegdmMZnPYhblwGSZxYvl9Od6f8bGucSAUDYVPoE3Iuj5zpiCSLmUlyxS3_WgM1MFvNV2D7oo5CZULO1inANGHfiYi61qHB5MI4BomG7ucNucRE277kAozj3I1nHTFtj9yrJvQ0PE07c9BeVncFwv2GfVZ-aKiccjPhtdWvaJmrhU1qLBpEDY28FSf52Hqcw5ThzcTmc1284dmZ8uaGCdWmjJcaHw4dZdce9mKQLMRPHanu_ro72WR3AMy3NKL4EVJmACWLsRmp2WOLAF8Zf5tY4x897gmMztmEJlaSI6cOFIverbBEbzK0H1Jq0AS5U4Zk_IF32aWrseq_uFMA5c2lJg3LD0bQoA==
加密参数分析
分析接口的启动器,可以看到一个xhr请求,我们直接点进去打上断点
进去之后跟栈分析,就可以看到关键的加密代码:
function y(e) {return c.a.createHash("md5").update(e).digest()
}
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}`)
}
function E(e, t) {const o = (new Date).getTime();return {sign: k(o, e),client: u,product: d,appVersion: p,vendor: g,pointParam: m,mysticTime: o,keyfrom: b,mid: A,screen: h,model: f,network: v,abtest: O,yduuid: t || "abcdefg"}
}
分析这段加密代码:
- d:固定字符串【fanyideskweb】
- u:固定字符串【webfanyi】
- e:固定字符串【fsdsogkndfokasodnaso】
- t:13位时间戳【(new Date).getTime()】
直接使用 nodejs 里面的加密模块 CryptoJS 来进行 MD5 加密,改写 JS 如下:
const CryptoJS = require('crypto-js');function sign(t) {let d = 'fanyideskweb', u = 'webfanyi', e = 'fsdsogkndfokasodnaso',signStr = `client=${d}&mysticTime=${t}&product=${u}&key=${e}`,sig = CryptoJS.MD5(signStr).toString();return sig;
}
返回的参数看起来像是一个base64的加密数据,推断他的解密逻辑应该先解密,然后使用JSON.parse进行格式化,可以直接控制台hook这个方法:
(function(){var parse_ = JSON.parse;JSON.parse = function(param){debugger;return parse_(param);}
})();
可以看到已经hook到了解密之后的结果,然后跟栈分析,发现解密方法
const a = Po["a"].decodeData(o, Wo["a"].state.text.decodeKey, Wo["a"].state.text.decodeIv), n = a ? JSON.parse(a) : {};0 === n.code ? e.success && t(e.success)(n) : e.fail && t(e.fail)(n)
继续跟栈进去decodeData,可以看到加密逻辑已经很清晰了,基本可以确定是AES加密了
(t,o,n)=>{if (!t)return null;const a = e.alloc(16, y(o)), i = e.alloc(16, y(n)), r = c.a.createDecipheriv("aes-128-cbc", a, i);let s = r.update(t, "base64", "utf-8");return s += r.final("utf-8"),s
}
直接使用 nodejs 里面的加密模块 crypto 来进行 AES 解密,改写 JS 如下:
const crypto = require('crypto');
function decrypt(decrypt_str) {const key = "ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl";const iv = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4";const key_md5 = crypto.createHash('md5').update(key, 'utf-8').digest();const iv_md5 = crypto.createHash('md5').update(iv, 'utf-8').digest();console.log('key_md5 = ', key_md5)console.log('iv_md5 = ', iv_md5)const decipher = crypto.createDecipheriv('aes-128-cbc', key_md5, iv_md5);let decrypted = decipher.update(decrypt_str, 'base64', 'utf8');decrypted += decipher.final('utf8');return JSON.parse(decrypted);
}
需要源码的同学们关注后私信我
原创声明:未经许可,不得转载。
如有侵权,请联系作者删除删除。