爬虫逆向之瑞数五案例:某某医学院(补环境,联调)
声明:本文仅作学习交流,请遵守法律法规
只讲联调和补环境。
因为是本人第一次讲瑞数,所以会讲详细一点
案例:aHR0cHM6Ly93d3cueG1tYy5lZHUuY24vaW5kZXgvemJjZy5odG0=
请用base64解码
此案例其实没有效验cookies,但拿来练手刚刚好
简单简述一下瑞数的特征
两个cookies键最后一个字母不同
两个cookies值,一个从接口返回,一个从js返回。
其中一个cookie值或两个开头字符是5的话则是瑞数5,是6则是瑞数6
瑞数第一步:
过debugger,有些有瑞数网站有debugger,有些没有
第二步清除cookies并打开脚本重新刷新
第一段生成js文件
第二段生成js,cookie在这段代码里生成,这是第一段请求,状态码412,返回第一个cookie和生成第二个cookie的js代码
搜索.call
没有搜到代表call被混淆了,这时用hook cookie方式
断住cookies生成的位置
蓝色框代表由一开始生成的js文件加上第二段js文件生成虚拟vm文件
红色框代表生成vm文件的入门,只需要定位到那即可。
对这个文件进行替换内容处理,瑞数页面是会变化的,不替换内容基本调试不了。
这里是第一段js文件传参入口 ,JSVMP
第一段JS文件相当于乱码,第二段JS相当于解释器。对这段乱码进行解析,生成cookies
对 这段文件进行解析
红色框JS链接是生成第一段js代码的地址,有些瑞数位置会相反过来
绿色框可能会作为传值到补环境里面去,但并不是绝对。
接下来只需要这两段JS文件,进行补环境即可
用吐环境脚本
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)
window是必补的
缺top
top是window本身。这个值基本也很常见,不管三七二十一补上
window = global
window.top = global
接下来就是缺什么补什么
document缺一个createElement,这是个方法,js知识浅的话,可以自行百度一下
document.createElement = function (args){console.log('document->createElement->',args)}
这样子补,因为方法可能会返回参数
返回div标签
html标签是对象,要判断,直接这样补即可,因为可能会返回不同值,所以要判断
document.createElement = function (args){console.log('document->createElement->',args)if (args == 'div'){return {}}}
补完后还是报错
直接联调,对比网页 ,node自带的联调工具,注意路径不要搞错。。。命令行如下:
node --inspect-brk xxx.js
点击页面这个绿色点点
进入联调页面 ,两个断点打勾
一个是报错的异常,一个捕获异常
去原网页对比
发现是div里的getElementsByTagName方法
document.createElement = function (args) {console.log('document->createElement->', args)if (args == 'div') {return {getElementsByTagName: function (args) {console.log('div->getElementsByTagName->', args)}}}}
返回一个i
控制台输出是一个数组
document.createElement = function (args) {console.log('document->createElement->', args)if (args == 'div') {return {getElementsByTagName: function (args) {console.log('div->getElementsByTagName->', args)if (args == 'i'){return []}}}}}
接下来基本都是这样,简单的我忽略,有undefined补环境,没undefined联调看看哪里出错了,补环境补着补着到返回一个meta
联调对比网页
输出有三个meta,meta标签也是对象,有些瑞数其实是两个meta,具体多少看网页
其实就是这三个
补三个对象
document.getElementsByTagName = function (args) {console.log('document->getElementsByTagName->', args)if (args == 'meta'){return [{},{},{}]}
}
接下来
其实就是这个,动态的,每次请求不一样
先写死,把环境全都补出来 。再写活,是第三个meta,其实在第一次请求页面也能看得出
接下来又遇到这个错误
parentNode是个对象,注意
这样补
return [{parentNode:{removeChild:function (args) {console.log('parentNode->removeChild->', args)}},]
接下来基本都是这样,有方法undefined补方法,看不出联调看看哪里出错了,
又有一个错误,联调进入else
但网页没有进入else
经联调会经过很多次这个 ,window,document,html都有这个属性,这是这个网站最大的难点,我觉得
跟栈找html
html是document里的documentElement里的html ,html也是对象,页面标签统一写{},
非标签的对象写对象名:{}
documentElement是对象
document.documentElement ={addEventListener:function (args){console.log('documentElement->addEventListener->',args)}}
接下来补script标签,为两个,包括属性。
遇到死循环清空定时器
window.setTimeout = function () {
}
window.setInterval = function () {
}
最后出结果了
当然这个结果不知道对不对,网页也没有效验cookie。
这是所有的环境
window = global
window.top = global
window.setTimeout = function () {
}
window.setInterval = function () {
}
window.addEventListener = function (args) {console.log('window->addEventListener->', args)}
location = {"ancestorOrigins": {},"href": "https://www.xmmc.edu.cn/index/zbcg.htm","origin": "https://www.xmmc.edu.cn","protocol": "https:","host": "www.xmmc.edu.cn","hostname": "www.xmmc.edu.cn","port": "","pathname": "/index/zbcg.htm","search": "","hash": ""
}
document = {}
document.createElement = function (args) {console.log('document->createElement->', args)if (args == 'div') {return {getElementsByTagName: function (args) {console.log('div->getElementsByTagName->', args)if (args == 'i'){return []}}}}}
document.getElementsByTagName = function (args) {console.log('document->getElementsByTagName->', args)if (args == 'meta'){return [{parentNode:{removeChild:function (args) {console.log('parentNode->removeChild->', args)}},}, {parentNode:{removeChild:function (args) {console.log('parentNode->removeChild->', args)}},},{parentNode:{removeChild:function (args) {console.log('parentNode->removeChild->', args)}},content :"{qqhK2kB.IG6Ig.qkq1aqqqq.ygsD62xql6zI07MWlzHpibynmbqU1SzSFJip5TSRsq9l4098~Rsb3jJcq8DfljUvVcEmy6UoN3qTVMJAEVDfWoA6VdkSEkAGG1xVa9DOZCtPaCm6YWDc7NtcNWm4z_TSd_xIVlyvUSqIEb7oMSr4EbySP4iQ7zzoU7IMGKCkuOmj2Zy1hgDwz6e6UkIHZMT1kEmdVP6aF2EF78Nqd6wzAwTvMc8igZvonYJX2T5Oujm7394uuZt8mZ2s6ciHTeefvSrZAryvKrIH0t0oB5meYZOuCqH57mOaBIcLQxjq1K3H3jZvvCIdTG.k6ZhIG5Bv8JItZ2vO8N3HLjdvvPI52GXk6L8NLQzrBOh8AqBr5zwMZVjPtlE5gGPAth8w7kz1cAtJ7yOujqxFAqqqqqVIdfiu0.t1WTxn9uWsQYHt1083703328?giYyPxpzzUaVEETRpYPwLEmlqAAxVrmLp3r251qWaYS2YqpVqsqJYUmQlYpgYoVa3YY2UqTVMmpRWmYVvmY9txbJisSSKsD6oIX3tCTo7MwROaoUrD4TPy9u2YFRUd2UGm8JWg2KOY5YYdpUZsHeYXmIGYIN9XSXzUWrYjDBU1H2YuC6IIwSzuoFYFNrgGAHdYerYnfUxsWpYfYIIYQQYa9urY3xUC2UQmweW62UXmR3WSo53VLrNOUMa3wyWZoO.kLSJn0H5DdNP.0nXY8eU7YKNmFfWjTU9Y4SYNfK2strYgY84YFJ9drBbFtVEgbd_YEYABCccFLfUz28hF5egdGiDY_zY7SKisETYu28KY3GYP0ntYQzUvYKmm3pWfTKSmQedNb.3sFxZS9CM8jJLBT5p1yJ67vDxDZJP2lnUYwrUPmK1mRmHMm3zYowKMSRjsC2Kt2pnYbpvxpfJY9S0iDqZs22ssKSeUDpZKfp0cvTMJarJYDxKwrR6s6RKJTpNYvlKQleuYGSVYmRim9TH1mRgmGpSoafe8AwVUGNWk9fnIVxospQxqTpaDqffUVe3Yf2VATRMm2RHYY3KYlyKVrRssTxKlTATYPTvMfGiQfRtrbE0Mvwat0WRsrzUIq0QqnN4MqqVYcYKHp3ZsueK8mAGYOLKiVZ0YvYVhT36mOxHWY3kmvT6H0abwG2WHoazcqJslbW98sf7i2Z.Dmmfq9ZrY9xVD23QmfeHo2RIYqmKDp33sSzKYmAWYfRvYSGzcpxQ1qZ7AZ3x4mOGQ7r6T2so1WJeNAksYHSKyfM2s5rKLYs4YXWKd9deY.yVy2MgmBzH52Mtm.NB09.6IdRL4VHnY5RUy9OUsXLHdYU9Dxyfn0dtYLzV6YMmm7pHSTFqYJfKafMrseSKvYsoYzevbrOBkIfaTDHAKwJjCmMYAif.PDuXYIShgGcFYhwK.SFjs_2K_21nYjAKN05bYXwVXYFfmjrHLTFJmBJMXVjpYhrU2bcbmtw82U5jQtr3bKCMDiwf7l5uY7SV2mFimLTHPmMxYxJKPSFDsgYKS218YLrvapPxVjTqGKCxF.T4LDizQFYEvqODU3rMCacfYEyK9rFssyxK0TYTYC0UMlyBYnfYQmwjmC2iRmwVmnf1VKa0FspeUmJPQ1pWpaJG8vfKElS1D1SG8Vy0YuYYMTw6m6xiQYQnYKNUsrwHs9yUkTYpY02bcf2hmUSVMVmwMozUwD2VKvpf8vNUsTSFlqmL3DZRFSpNYTRcY0yJ1rY_s9eVU2JHYTf8snVYElGnAClUWl9aUfzbFTVeYnVUxlgvYCrYimQPmnmiHmweY1wUHCRgD1psxTrXFsVkMoqEFnm7t9g5VORADlNcqsNYmTQHmaNicYwtYpxUrrQosGRUpTVRYalUqlgkYn0UV0ZsYSAxW2qaVpeZmUgScqNpl2q.8f0RpCqAsfJU.mU0Y5gU4V4LY_2YZTI.m5RiyY8bYIyUgDFfDIGiXK.jq7zndvteI_QcLvvRVXT1gYj4qQmY42IamdJiZ28uYwYUupIWs7eUPmUAYZLUnV4lYdpDf2U8YZrbNaUhxQkd9hZ18lkgl4g14xl_Vlqqqqr1k674QENEYNfXPD_qANf1Bl_WMjScLlt7YiHH7huqvirQAmnGqqq!J7z,aac,amr,asm,avi,bak,bat,bmp,bin,c,cab,css,csv,com,cpp,dat,dll,doc,dot,docx,exe,eot,fla,flc,fon,fot,font,gdb,gif,gz,gho,hlp,hpp,htc,ico,ini,inf,ins,iso,js,jar,jpg,jpeg,json,java,lib,log,map,mid,mp4,mpa,m4a,mp3,mpg,mkv,mod,mov,mim,mpp,msi,mpeg,obj,ocx,ogg,olb,ole,otf,py,pyc,pas,pgm,ppm,pps,ppt,pdf,pptx,png,pic,pli,psd,qif,qtx,ra,rm,ram,rmvb,reg,res,rtf,rar,so,sbl,sfx,swa,swf,svg,sys,tar,taz,tif,tiff,torrent,txt,ttf,vsd,vss,vsw,vxd,woff,woff2,wmv,wma,wav,wps,xbm,xpm,xls,xlsx,xsl,xml,z,zip,apk,plist,ipar7r0D4d1721l8cfUqqqqr0hQD05l4YSr90XD0puWDZTFoSCx97ZEnlNcV9DKATOicgyUUwV3PEaEK3B3qc64qqqqr0YmJiNHAwh0BlhSrs1u7K5.r1c64qqqqqhLINKJ7j.AfVr0qqqqq"},]}if (args == 'base'){return []}if (args == 'script'){return [{getAttribute:function (args) {console.log('script->getAttribute->', args)}},{getAttribute :function (args) {console.log('script->getAttribute->', args)}}]}
}
document.getElementById = function (args){console.log(args)
}
document.addEventListener = function (args){console.log('document->addEventListener->',args)
}
document.documentElement ={addEventListener:function (args){console.log('documentElement->addEventListener->',args)}}navigator = {}navigator.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36'
基本瑞数大同小异,不考虑风控下,联调加补环境。不过有些瑞数很恶心,出假值cookie结果,那就要找undefined,一个一个找,一个一个补,最后才出结果。
这网站最难的地方,联调进入else语句,网页是进入if语句。就是一个if语句执行很多次,每次判断是不同对象里不同属性,还要跟栈找。然后都补完就没什么难度了。