JS逆向 - (国外)SHEIN站 - 请求头(armorToken、Anti-in)
文章目录
-
- 概要
- 整体架构流程
- 技术名词解释
- 小结
概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系
逆向:JS逆向 - (国外)SHEIN站 - 请求头(armorToken、Anti-in)
URL:aHR0cHM6Ly9pZC5zaGVpbi5jb20vUmVjb21tZW5kU2VsZWN0aW9uL0hvbWUtS2l0Y2hlbi1zYy0wMTcxODU1NDYuaHRtbD9pY2k9aWRlbl90YWIwNW5hdmJhcjA1JnNyY19tb2R1bGU9dG9wY2F0JnNyY19pZGVudGlmaWVyPWZjJTNESG9tZSUyMCUyNiUyMEtpdGNoZW4lNjBzYyUzREhvbWUlMjAlMjYlMjBLaXRjaGVuJTYwdGMlM0QwJTYwb2MlM0QwJTYwcHMlM0R0YWIwNW5hdmJhcjA1JTYwamMlM0RpdGVtUGlja2luZ18wMTcxODU1NDYmc3JjX3RhYl9wYWdlX2lkPXBhZ2VfaG9tZTE3NTAzMTk2NDQ2NzQmY2F0ZWdvcnlKdW1wPTY2MTE3MV8hXzAmcGFnZT0y
提示:需要翻墙
整体架构流程
提示:分析参数生成
1、参数位置和验证接口:
响应内容:会返回一个token
2、堆栈分析位置或者搜索关键字:armorToken,这里就不带着一起跟了,直接搜索
提示:需要将浏览器加载的缓存全部清理
3、下断,直接刷新网页,NcWc(“0x3c”)跳进去吗,发现是从zc函数进行加密的
注意:手动去执行它加密的时候,浏览器会将生成好的值存储到localStorage/sessionStorage
4、进入到zc函数,我们可以看到,如果$c这个对象里面的value有值的话,我们可以给它赋值字符串,重新生成一个
w(this, Rc, $c, [[\"S\", at[t(\"0x11\")]()][t(\"0x51\")](\"\"), pt(), te[t(\"0x22\")](mc[t(\"0x4e\")](Dn[t(\"0x4f\")](b(this, Rc, Kc)[t(\"0xf\")](this)), Dn[t(\"0x4f\")](At()), { iv: J[t(\"0x4f\")](\"\"), mode: L[t(\"0x5c\")][t(\"0x5d\")], padding: Pc })[t(\"0x50\")]), (new Date)[t(\"0x5e\")]()][t(\"0x51\")](\"_\"))
分析这块代码
-
att(“0x11”):固定、pt():版本号
-
b(this, Rc, Kc)t(“0xf”):这里观察是下面的Kc函数获取,Qr就是一个标准的MD5加密
const CryptoJs = require(\'crypto-js\');var getReportUrl_metricCount = 0 var version = \"3.7.0\" var armorUuid = \'浏览器返回\' var userAgent = \"换成自己的\" var now_time = new Date().getTime() get8LRandomStr = function () { return \'xxxxxxxx\'[\'replace\'](/[xy]/g, (function (t) { var n = 16 * Math[\"random\"]() | 0; return (\"x\" == t ? n : 3 & n | 8)[\'toString\'](16) } )) }(); armorToken_list = [getReportUrl_metricCount, version, armorUuid, userAgent, now_time, get8LRandomStr, \'-\'].join(\"^@^\") armorToken_list_data = [armorToken_list, CryptoJs.MD5(armorToken_list).toString()[\"slice\"](-6)].join(\"^@^\")
-
继续看一下key是什么:发现是固定的\"Yp22&mqMv#3t28Zh\"
-
继续观察它是一个AES加密,并且是标准的,但是转字符串的函数是魔改的,你会看到AES加密其实取的是ciphertext
CryptoJs.enc.toString_ = function toString(t) { var r = !0; var e = t[\"words\"] , x = t[\"sigBytes\"] , a = r ? \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\" : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"; t[\"clamp\"](); for (var i = [], o = 0; o < x; o += 3) for (var c = (e[o >>> 2] >>> 24 - o % 4 * 8 & 255) << 16 | (e[o + 1 >>> 2] >>> 24 - (o + 1) % 4 * 8 & 255) << 8 | e[o + 2 >>> 2] >>> 24 - (o + 2) % 4 * 8 & 255, u = 0; u < 4 && o + .75 * u < x; u++) i[\"push\"](a[\'charAt\'](c >>> 6 * (3 - u) & 63)); var s = a[\'charAt\'](64); if (s) for (; i[\'length\'] % 4; ) i[\"push\"](s); return i[\'join\'](\"\")}aes_encrypt = function (data, key, iv) { key = CryptoJs.enc.Utf8.parse(key); iv = CryptoJs.enc.Utf8.parse(iv); var encrypted = CryptoJs.AES.encrypt(data, key, { iv: iv, mode: CryptoJs.mode.CBC, padding: CryptoJs.pad.Pkcs7 }); return CryptoJs.enc.toString_(encrypted.ciphertext);}
最后将上面的值进行拼接就得到了armorToken
7、继续分析我们的第二个参数Anti-in,这里划一下水,自己跟一下栈,比较容易跟
你会发现它是通过浏览器指纹进行加密最好得到一大串字符串的,这里Zc就是加密函数
var x = { data: b(e, r, Zc)[n(\"0xf\")](e, t), appName: at[n(\"0x19\")]() };
8、进入到加密函数,我们观察可以看到,mc也是一个AES,key的值是:“Q5eV2XXICMBi0CBL”,但是它是ECB模式的,需要注意一下,肯定也是对toString进行了魔改的
aes_encrypt_Ecb = function (data, key) { key = CryptoJs.enc.Utf8.parse(key); var encrypted = CryptoJs.AES.encrypt(data, key, { mode: CryptoJs.mode.ECB, padding: CryptoJs.pad.Pkcs7 }); return encrypted.ciphertext;}
- 这里我们会发现i的值就是对指纹数组进行转字符串,然后先经过oc处理这个字符串得到一个Uint8Array数组,这里其实就是一个字符串压缩算法
const pako = require(\'pako\');const encoder = new TextEncoder();const utf8Bytes = encoder.encode(指纹字符串);const compressedBytes = pako.deflate(utf8Bytes); // 默认生成 zlib 头 const zhiw_stringify_uint8Array = new Uint8Array(compressedBytes);
-
继续我们看到,对这个压缩后的数组进行转WrodArry,其实这个J[r(“0x49”)]函数就是标准的CryptoJs.enc.Hex.parse
-
Qr(i)n(“0xc”)n(“0x4d”):说一下这里其实也是对指纹进行MD5然后取后面6位
-
最后再说一下这个Mc(u, Tc):它也是一个魔改的stringify
function Tc(t, r) { return 64 === t ? 64 : 63 === t ? r : t >= r ? t + 1 : t }function Mc(t, n) { var e = t[\"words\"] , x = t[\"sigBytes\"] , i = \"xYACKb9gwIn12kHtuiG7RVSJjTU-Z8cq_NOvmXzeaFoyWQpDh3LB4rs0EM6fd5lP=\"; t[\"clamp\"](); for (var a = [], o = Math[\"floor\"](64 * Math[\"random\"]()), u = 0; u < x; u += 3) for (var c = (e[u >>> 2] >>> 24 - u % 4 * 8 & 255) << 16 | (e[u + 1 >>> 2] >>> 24 - (u + 1) % 4 * 8 & 255) << 8 | e[u + 2 >>> 2] >>> 24 - (u + 2) % 4 * 8 & 255, s = 0; s < 4 && u + .75 * s < x; s++) { var f = c >>> 6 * (3 - s) & 63; a[\'push\'](i[\'charAt\'](n(f, o))) } var v = i[\'charAt\'](64); if (v) for (; a[\'length\'] % 4; ) a[\'push\'](v); return a[\'join\'](\"\")[\'replace\'](/=/g, \"\") + i[o]}
技术名词解释
提示:py调用
小结
提示:学习交流主页,星球持续更新中:链接https://t.zsxq.com/AJTw2(+星球主页+v)