某网站瑞数5代环境检测JS逆向分析

news/2024/11/22 5:26:39/

1. 写在前面

  逆向技术确实很有挑战,经常有看到各种爬虫与逆向群里面五花八门的奇技Y巧。爬虫领域里面就需要更多的分享,才能够成就更好的自己。本期要说的这个网站用到的加密技术相对比较难!我在找案例的时候同时也在学习其他大佬的思路与技巧,学习逆向没有捷径,只能靠我们自己一点点的去分析与累积

目标站点

aHR0cHM6Ly9xaWthbi5jcXZpcC5jb20vUWlrYW4vSm91cm5hbC9TdW1tYXJ5P2tpbmQ9MSZnY2g9OTUyNDNYJmZyb209UWlrYW5fSm91cm5hbF9TdW1tYXJ5

2. 目标分析

首先,打开这个案例网站,点击翻页。本次主要针对的就是获取更多加载里面内容的加密分析,这个网站里面搜索也是加密区
在这里插入图片描述
本次分析的目标就是问号后面的这串密文,只要把这串加密的密文逆向还原出来,就可以通过此url获取到更多数据内容

这个网站检索区那块网上已经有较多的人对此进行了分析,有硬刚加密瑞数的,也有RPC技术的

这个url到其它浏览器上面打开看看,发现没有收到任何数据,这是因为维普期刊网站除了对这个参数做了加密外,还做了特殊处理让我们无法直接从url获取数据,必须从维普期刊网站打开url才能获取数据,这样在一定程度上就保护了维普期刊上面的数据,从而实现反爬的目的

前一部分:

https://*.com/Journal/RightArticle?

加密部分:

X2sCXRB4=0IsPQ0alqEtID3EakumIk.NZiLQ9yQeCdROMNRaLtSO0U74P8MpIcElFncx8UMr8l36GA6zSqfi_DEzmmnT2wbnwsgTuYbvql

经过多次翻页加载发现前一部分是固定的,而加密部分则是不断变化的,并且字符串X2sCXRB4也是固定的

很明显整个URL通过加密后生成一段密文与前一部分进行拼接而成

翻页动作网站使用了ajax技术来实现,不管如何封装发送ajax请求,底层一定是用的XMLHttpRequest技术实现,否则无法无刷新发送请求给服务器,然后网页无刷新返回数据

触发翻页返回数据的流程大至如下:

点击翻页->经过某些初始化->进行加密并拼接完整URL->发送给服务器->服务器接受请求->呈现到网页

接下来要做的就是把加密拼接URL这个环节的代码抠出来进行调用,拼接完整的翻页URL,才能不断获取到更多的数据

加密代码一般很多网站会有混淆,就跟有价值的的网錾数据都会要求账号登录一样(后续会针对模拟登陆的多种方案做一个详细的讲解),直接搜索一般搜索不到的

而这个网站无法直接定位到加密处代码,也没有能够搜索的关键词,所有我们只能从接口开始定位

通过XHR断点:
在这里插入图片描述

因为每次一的翻页都是经过Journal/RightArticle,所以我们直接断它,然后点击其他翻页就会在Ajax请求处给断住

在这里插入图片描述

当然,也可以通过Initiator
在这里插入图片描述

在XMLHttpRequest技术中,定位到栈内的发送函数send是实现与服务器通信的最后一步。通过该函数,将请求的URL发送给服务器。栈内的最后一个函数是加密函数,然而,鉴于加密函数通常经过混淆处理,所以不建议优先研究该函数。相反,建议先分析send函数的逻辑

通过这个请求服务器流程可以看出,加密一定是在send发送前实现的

XMLHttpRequest实现流程:

xhr = XMLHttpRequest()
xhr.open('get', 'http://*.com...', false)
xhr.send(data)

定位send函数:
在这里插入图片描述

因为jquery.js文件是第三方js框架,这个框架里面一般是不会写加密函数的,根据前面的分析,网站都是会改写open函数

分析open函数,给open函数所在的行打上断点,并重新点击翻页:
在这里插入图片描述

把鼠标放在open函数上面,可以发现这个open函数被重写了,我们点链接进入到被重写的函数里面:

在这里插入图片描述

向下跟执行代码跟进,进入到n.apply(this, arguments)
在这里插入图片描述

这个函数很可能是一个加密函数入口,我们继续往下走并在控制台看看

在这里插入图片描述

上面猜测这个函数就是一个加密函数入口

_$8f(arguments[1])

对加密的这个url重写发送请求,得到的结果跟现在是一样的,可以确定这个加密的url就是我们要逆向的url

明明是一个明文字符串,经过函数_KaTeX parse error: Expected group after '_' at position 20: …以后就变成了一个对象,对象里面_̲bt值就是加密的url

return _$6y[_$V8[36]](this, arguments)

这行代码里面的_$6y就是open函数,如下图所示:

在这里插入图片描述

由此可以确定了open函数就是被重写了,最后返回的还是open函数

分析加密函数_$8f

function _$8f(_$H_, _$wH) {var _$Pv, _$pq = null;var _$8_ = _$H_;function _$Rv(_$tx, _$65) {var _$xW = [];var _$DY = '';var _$dF = _$u3(_$4i());_$xW = _$xW[_$V8[9]](_$65, _$tx, _$wH || 0, _$dF);var _$eq = _$4b(923, _$2l[186], true, _$xW);var _$Q6 = _$rW + _$eq;_$pq = _$Tt(_$XH(_$Q6), _$2l[27]);return _$hT[_$V8[5]](_$DY, _$ph, _$V8[26], _$Q6);}function _$_L(_$tx) {if (_$tx._$V8) {var _$xW = _$ht(_$ht(_$tx._$wa, _$V8[38])[0], _$V8[78])[1];if (_$xW[_$V8[3]](_$Z_) >= 0 && _$xW[_$V8[3]](_$ph) >= 0) {return true;}}return false;}function _$Hc() {try {if (typeof _$H_ !== _$V8[0])_$H_ += '';_$Pv = _$wa(_$H_);if (_$_L(_$Pv)) {return;}if (_$45) {_$H_ = _$MJ(_$H_, _$Pv);}} catch (_$xW) {return;}if (_$Pv === null || _$Pv._$uF > _$2l[40]) {_$4b(953, _$2l[186]);return;}if (_$_u(_$Pv)) {_$4b(953, _$2l[186]);return;}_$H_ = _$Pv._$iB + _$Pv._$fp;var _$DY = _$s3(_$Pv);var _$dF = _$DY ? _$V8[78] + _$DY : '';var _$eq = _$3v(_$zB(_$iL(_$Pv._$nu + _$dF)));var _$Q6 = 0;if (_$Pv._$9h) {_$Q6 |= 1;}if (_$bP & _$2l[49]) {_$Q6 |= _$2l[40];}_$H_ += _$V8[78] + _$Rv(_$Q6, _$eq, _$wH);if (_$DY.length > 0) {if (_$24 && _$24 <= _$2l[149]) {_$H_ = _$e7(_$H_);}if (!(_$bP & _$2l[9])) {_$DY = _$e7(_$DY);}_$DY = _$V8[66] + _$zL(_$DY, _$pq, _$2l[40]);}_$H_ += _$DY;}function _$xa(_$tx) {_$5H(_$2l[27], _$Ka());if (_$pq === null || _$lh(_$Pv) === false) {return _$tx;}if (typeof _$tx === _$V8[0] || typeof _$tx === _$V8[447] || typeof _$tx === _$V8[347]) {_$tx = '' + _$tx;if (_$tx.length <= _$pC) {_$tx = _$zL(_$tx, _$pq, _$2l[178]);}}return _$tx;}function _$BZ() {return _$pq !== null;}function _$dF(_$tx, _$65) {if ((_$tx === 'get' || _$tx === _$V8[106]) && _$BZ() && (_$4o & 1) && (_$bP & _$2l[49]) && _$Pv && _$Pv._$uF < _$2l[178] && _$P4(_$Pv)) {if (_$Pv._$9h) {this._$Tt = true;} else {if (_$65 === _$Sc || _$65 === null || _$65 === '') {_$65 = _$V8[105];}if (_$65 === _$V8[105]) {this._$Tt = true;return _$65;}}}return '';}_$Hc();return {_$ni: _$8_,_$bt: _$H_,_$rI: _$xa,_$K$: _$dF,_$Wu: _$Qw,_$Tt: false};
}

函数里面又定义了几个函数和变量,在最后调用了Hc()函数,为什么这里要调用一下?由上面可知8f函数的结果有返回值,并且返回了加密后的url,所以这里调用函数_$Hc()很有可能是在生成加密参数

最后返回一个对象,在对象里面找一下键为bt的,确实找到了这个键对应的值就是加密的url,也就是说$H就是好个加密后的url

这个H哪里来的?在整个8f函数里面,只有_Hc()函数调用执行了,其它函数只是声明了函数并没有调用,可以猜测H这个url值肯定是在_$Hc()函数生成的,因为别的函数没有调用

分析_$Hc()函数

这个函数里面真正生成url的是下面这行代码:

_$H_ += _$V8[78] + _$Rv(_$Q6, _$eq, _$wH)

V8[78]是一个问号,而后面的_$Rv函数才是真正生成url加密参数的函数

现在进一步找到了真正生成加密参数的是函数_$Rv,而这个函数正是上面大函数_$8f里面的第一个定义的函数

分析_$Rv函数

在这个函数里面真正加密的函数,_$4b才是真正加密的函数,后面的代码是把加密好的代码通过函数concat接拼起来

return _$hT[_$V8[5]](_$DY, _$ph, _$V8[26], _$Q6)

_$ph值是:

X2sCXRB4

这个字符串不就是url问号后面跟的第一个字符串吗,从这一点也可以确定真正生成加密字符串的函数是_$4b

分析_$4b函数,进入这个函数发现有几千行代码,_$4b函数是一个控制流程平坦化结构的反爬加混淆代码

url加密参数就是在这个平坦流代码中加密生成的,简化_$4b代码如下

var _$1V, _$IF, _$f4 = _$P2, _$je = _$oY[0];
function _$4b(_$xI, _$H_, _$wH, _$_M) {function _$bc() {}function _$Lp() {}function _$gd() {}function _$q9() {}function _$xQ() {}function _$Po() {}var _$Pv, _$Xl, _$Rv, _$BZ, _$_L, _$pq, _$gy, _$xp, _$Xt, _$xW, _$8_, _$cy, _$iO, _$Xi, _$bX, _$DY, _$dF, _$Q6, _$p4, _$aB, _$9P, _$eq, _$zH, _$Hc, _$ss, _$xq, _$Hu, _$ya, _$xa, _$hI;var _$LP, _$vc, _$Rb = _$xI, _$eS = _$oY[1];while (1) {_$vc = _$eS[_$Rb++];if (_$vc < 256) {...}}
}

省略处大量if逻辑

到此已经找到具体的加密代码,后面就是如何把这些混淆的代码抠出来,平坦流结构代码是难点重点,时间有限,之后找时间补

如果走RPC的话,完全可以不用抠代码,只要找到加密函数入口直接调用就行

另外,感兴趣的朋友可以看看这个网站,文章里面的函数,以及变量名称是动态变化的,因为Chrome在虚拟主机生成的代码,只要刷新一次浏览器就会重新生成变更和函数名

  好了,到这里又到了跟大家说再见的时候了。创作不易,帮忙点个赞再走吧。你的支持是我创作的动力,希望能带给大家更多优质的文章


http://www.ppmy.cn/news/971334.html

相关文章

有奖征文丨AIGC + Cocos 社区征稿全面开启

AIGC游戏开发,已经发展到何种恐怖地步? 晓衡做了一个视频,介绍了社区大佬,也是晓衡的朋友、老师(之一)——孙二喵,最近的AIGC研究,真的是让人有种瑟瑟发抖的感觉! 视频中…

2023年上半年部分团队的总结

把各个环节连起来 从我加入 CSDN 后不久,我就开始公开地总结我们的工作,我分管的团队留下了不少的总结和思考: 这是 2022 年下半年的汇报 这是 2022 年上半年的汇报 这是 2021 年年底的汇报 经过这些思考改进迭代的团队,是不是…

GitHub Copilot Labs 体验「收手吧,外面全是 ChatGPT」

本文正在参加 ✍🏻 技术视角深入 ChatGPT 征文活动 相信大家或多或少都体验过了 ChatGPT,或者更进一步,在 IDE 中也装上了对应的插件 不过真正在 coding 中用上的频率有多高呢?可能大多数人都只是尝个鲜然后就忘了,至…

【JAVA】云HIS系统功能菜单知识(二)

随着医疗信息化和互联网技术的不断发展,云HIS在大数据管理和应用的优势日益凸显。对于医疗机构而言,云HIS平台可以帮助其实现更高效的医疗服务管理,并提高医疗服务的整体水平和效率。 一、系统管理 1.医院信息 基本信息、法人代表、主要负责…

Unity小游戏——无线滚动的背景的改良

在上文介绍的算法中,背景只在每次调用Update()时移动一次。这样一来,如果武士移动的距离很长,即速度很快,就可能出现背景和角色移动不协调的情况.虽然我们这个游戏中不会打到那样快的移动速度,但…

Leetcode 3. 无重复字符的最长子串

题目描述 题目链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/ 思路 首先想到了双指针控制窗口,无重复的字符又想到Map存储。 遍历一遍字符串初始start指向0,end指向当前遍历字符的下标Map存储每个字…

(笔记)插入排序

插入排序 插入排序是一种简单且常见的排序算法,它通过重复将一个元素插入到已经排好序的一组元素中,来达到排序的目的。在插入排序算法中,将待排序序列分为已排序和未排序两个部分。初始时,已排序部分只包含一个记录,…

@PostConstruct和@PreDestroy与servlet生命周期的关系

执行顺序结果 /*** 服务器加载Servlet* ---> 创建servlet实例,实现servlet构造函数* ---> 执行注解PostConstruct* ---> servlet.Init()* ---> servlet/service() 方法* ---> 执行注解PreDestroy* ---> servlet.destroy()* ---> 服务器卸载Se…