JS逆向之瑞数6案例(某某大学华南附属医院)

发布时间:2026/6/5 5:34:58

JS逆向之瑞数6案例(某某大学华南附属医院) 目录解决的问题1.cookies加密第一个技巧第二个技巧第三个技巧第四个技巧2.请求体参数分析和响应数据解密第五个技巧本文章中所有内容仅供学习交流使用不用于其他任何目的。否则由此产生的一切后果均与作者无关目标网站aHR0cHM6Ly9zY2guc3p1LmVkdS5jbi9obnl5Y21zd2ViL2Fubm91bmNlbWVudC9wcmUtcHVyY2hhc2UtcmVzZWFyY2g解决的问题请求体加密响应加密cookie加密1.cookies加密瑞数6cookie加密第一步清空cookie第二步开启脚本断点刷新加载第一个脚本是我们需要的第二个脚本也是我们需要扣的搜索.call,打上断点如果call被混淆了就hook cookie跟栈这是生成VM文件的地方如果脚本没加载首页面。。就手动进入如图所示替换文件。网页上页面先固定死。因为会动态变化方便调试。所以瑞数6就扣两个文件然后用吐环境脚本。联调补环境function get_enviroment(proxy_array) { for (var i 0; i proxy_array.length; i) { handler {\n get: function(target, property, receiver) {\n console.log(方法:, get , 对象:, proxy_array[i] , 属性:, property, 属性类型:, typeof property, // 属性值:, target[property], 属性值类型:, typeof target[property]);\n // if (typeof target[property] undefined){debugger} return target[property];\n },\n set: function(target, property, value, receiver) {\n console.log(方法:, set , 对象:, proxy_array[i] , 属性:, property, 属性类型:, typeof property, // 属性值:, target[property], 属性值类型:, typeof target[property]);\n return Reflect.set(...arguments);\n }\n } eval(try{\n proxy_array[i] ;\n proxy_array[i] new Proxy( proxy_array[i] , handler )}catch (e) {\n proxy_array[i] {};\n proxy_array[i] new Proxy( proxy_array[i] , handler )}) } } proxy_array [window, document, location, navigator, history, screen, div, script] get_enviroment(proxy_array)补到一般陷入死循环可能是定时器搞的清空定时器还是会死循环。第一个技巧往这里打上debuggernode --inspect-brk xxx.js输入命令行点击浏览器即进入联调页面最好把异常断点打上断住了往端口看去就能清晰看到环境缺失环境补上补标签则补对象标签为对象如果你不知道找不到哪里直接联调打上断点看看i返回什么联调。在同网页对比网页搜这个地方第二个技巧调试的时候会有很多个debugger要么替换文件过debugger把_$c9改为_$c9.replaceAll(debugger,)要么注入代码然后进入VM文件VM文件为虚拟生成文件只有VM文件生成时才能打断点刷新后断点全消失。i返回一个数组补上接下来优先补最后一个undefined如果补上还运行不了那就补往上一个undefined像以上这种不知道可返回可不返回直接打上debugger同原网页对比优先解决最后一个返回的补着补着卡住了一般两种情况第一种定时器第二种代码压缩检测第三个技巧清空定时器并把代码压缩压缩替换到node环境里切记别用去掉debugger的文件可能会有检测接下来缺失script其实就是这网页的两个标签可以自己调试去看看把script补完后顺利出值这个值不一定对测试一下把ts文件改一下cookie整理一下改一下可能会检测这两个在node环境最好加上这两个整理我擦我边逆向边记录博客一次成功而且环境也不算多一次成功纯属运气好以下为全部环境delete __dirname delete __filename window global window.top global window.setTimeout function () { } window.setInterval function () { } window.addEventListener function (agrs){ console.log(window-addEventListener-,agrs) } window.addEventListener function (agrs){ console.log(window-attachEvent-,agrs) } div { getElementsByTagName: function (args) { console.log(div-getElementsByTagName-, args) if (args i) return [] } } script { getAttribute:function (args) { console.log(script-getAttribute-,args) } } document {} location { ancestorOrigins: {}, href: https://sch.szu.edu.cn/hnyycmsweb/announcement/bidding-information/win-bid-publicity, origin: https://sch.szu.edu.cn, protocol: https:, host: sch.szu.edu.cn, hostname: sch.szu.edu.cn, port: , pathname: /hnyycmsweb/announcement/bidding-information/win-bid-publicity, search: , hash: } document.createElement function (args) { console.log(document-createElement-, args) if (args div) { return div } } document.appendChild function (args) { console.log(document-appendChild-, args) } document.getElementById function (args) { console.log(document-getElementById-, args) } document.removeChild function (args) { console.log(document-removeChild-, args) } document.addEventListener function (args) { console.log(document-addEventListener-, args) } document.addEventListener function (args) { console.log(document-addEventListener-, args) } document.getElementsByTagName function (args) { console.log(document-getElementsByTagName-, args) if (args base) { return [] } if (args script){ return [script,script] } } navigator {} navigator.userAgent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36第四个技巧事实上如果是假cookie则先补返回的标签如果还不行往这里打debugger联调对比原网页,不是undefined则和网页一致2.请求体参数分析和响应数据解密事实上有些人在调试代码时过debugger第五个技巧把瑞数的debugger过完或者注入代码清空debugger然后翻页想调试。就报这个错误结果翻不了页调试不了这是因为瑞数会在代码中插入时间差检测或执行流完整性校验如果你在某一行暂停太久比如你在 debugger 里一步一步走它会检测到“执行时间异常”然后触发 自毁逻辑比如故意抛出异常修改关键变量让后续解密流程失败导致页面渲染不出来。直接VM文件匿名脚本忽略掉就会出现这个东西切记用于瑞数cookie调试时不能忽略不然调试不了直接跳过VM的调试。这时候直接XHR调试异步之前直接扣代码即可加密方式很容易包括响应内容的解密。AES加解密用原生库即可var CryptoJS require(crypto-js) class aY { constructor() { var e []; this.add t, this.find i, this.remove r, this.count s, this.showAll o, this.clear a, this.sort l; function t(c, u) { e[c] u } function i(c) { return e[c] } function r(c) { if (e[c]) delete e[c]; else return Not Found } function s() { var c 0; for (var u in e) c; return c } function o() { for (var c in e) console.log(c - e[c]) } function a() { for (var c in e) delete e[c] } function l() { for (var c new Array, u Object.keys(e).sort(), d 0; d u.length; d) c.push(u[d] e[u[d]]); return c.join() } } } t { pageTag: MenuId_17, pageNum: 4, pageSize: 15, timeReversal: true } cY () { for (var n [], e 0123456789abcdef, t 0; t 36; t) n[t] e.substr(Math.floor(Math.random() * 16), 1); n[14] 4, n[19] e.substr(n[19] 3 | 8, 1), n[8] n[13] n[18] n[23] -; var i n.join(); return i } function get(n, e) { var t null; return t ! null t ! undefined ? JSON.parse(t) : e } function QK(n, e) { let t CryptoJS.enc.Utf8.parse(e) , i CryptoJS.enc.Utf8.parse(n) , s CryptoJS.AES.encrypt(i, t, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).ciphertext.toString().toUpperCase() , o CryptoJS.enc.Hex.parse(s); return CryptoJS.enc.Base64.stringify(o) } const lY (n, e, t, i, r) { var s new aY; s.add(appId, n), s.add(appKey, e), s.add(timestamp, t), s.add(once, i), s.add(data, r); var o CryptoJS.MD5(s.sort()); return o.toString().toUpperCase() } function fY(n,e) { const t new Date().getTime() , i cY() , r get(zyy_physical_secretkey, 76D96C41A4178B49) , s {}; return s.once i, s.appId 5DB62454F1FA2422DD7BA9DAD8855F6D, s.timestamp t, s.data QK(JSON.stringify(e), 76D96C41A4178B49), s.sign lY(5DB62454F1FA2422DD7BA9DAD8855F6D, 55F5DB6D7BA942DDAD882454F1FA26D2, t, i, JSON.stringify(e)), s } // 3uMu5nQrVbQnXzKAaeUV4AaHpa9FZGV5xB3M0k/K7CEogH8cuLi6jfZILChGltuueW/RVDyyCrobxtyplVwvS7EH4LXbgiggoPubqAIviw // JPNIgdKUQxmqFW50uESIsB9RerDC1hINtBVdxaymXEA function eY(n) { e 76D96C41A4178B49 let t CryptoJS.enc.Utf8.parse(e); return CryptoJS.AES.decrypt(n, t, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8).toString() }干掉瑞数后剩下的加解密就非常简单了顺利出数据作者有感其实瑞数做习惯了基本有些东西都不用调试就知道了一开始补windowtop清空定时器压缩代码一看到i就补数组一看script就补两个对象的数组。一看到base也补数组 navigator必补包括它的属性还有.....瑞数没有原型链检测相对好补跟打螺丝没什么区别。都说瑞数是爬虫逆向的一座大山等翻过瑞数这座大山后才发现瑞数只是众多山峰中的一座小峰逆向真正的挑战远不止于此。像安全产品阿里滑块极验易盾等众多验证码轨迹生成更考虑行为像不像人而不是所谓的加密。甚至有些奇奇怪怪的验证码要自己去训练。。。更有行为验不是看你“能不能跑”而是看你“跑得像不像人”。鼠标轨迹、键盘节奏、滚动速度、点击热区、停留时间……一点点偏差就触发风控。一句话道路还长。

相关新闻