JS逆向之补环境过瑞数详解
JS逆向之补环境过瑞数详解
“瑞数” 是逆向路上的一座大山是许多JS逆向者绕不开的一堵围墙也是跳槽简历上的一个亮点我们必须得在下次跳槽前攻克它 好在现在网上有很多讲解瑞数相关的文章贴心的一步一步教我们去分析瑞数流程分析如何去扣瑞数逻辑企图以此教会我们 (手动狗头)。却鲜有文章详细去讲解如何通过纯补环境的方式过瑞数。今天它来了
为了让大家彻底搞定瑞数这个老大哥本文将从以下四个部分进行描述
- rs的流程逻辑
- 浅谈扣代码过rs
- 详解补环境过rs
- 扣代码与补环境对比
- 弯道超车环节
篇幅较长坐稳发车咯
注本文内容均以一个新人友好型 rs4网站 网上房地产为例
一rs的流程逻辑
我们在做逆向的时候首先得分析出哪些加密参数
是需要逆向的然后再是去逆向这些参数。当然瑞数也是一样。
所以我们第一步就是明确逆向的目标
- 现象上了rs的网站会请求两次page_url第二次请求page_url时才能得到正确的页面内容
- 分析分析其请求体发现第二次请求page_url时带上了cookie_s和cookie_t, 而cookies_s是来自第一次请求page_url时其响应头set的;
- 结论那么我们的目标就确定了 – 破解
cookie_t的生成逻辑
;
现在我们知道了需要逆向的加密参数是cookie_t那么cookie_t是从何而来呢我们先分析一下网站的请求
瑞数网站请求流程分析
第一次请求
请求page_url响应状态码202响应头中 set了 cookie_s
响应体是HTML源码从上到下可以分为四部分我先剧透一下它们的作用
- 一个meta标签其content内容很长且是
动态
的每次请求会变化会在eval执行第二层JS代码时使用到 - 一个外链js文件一般同一页面中其内容是
固定
的下面的自执行函数会解密文件内容生成eval执行时需要的JS源码也就是第二层vm代码 - 一个大自执行函数每次请求首页都会
动态
变化主要是解密外链JS内容给window添加一些属性如$_ts会在vm中使用; - 末尾的两个script标签中的函数调用会
更新cookie
使其变长。这里我们可以不用关注这个。
第二次请求
请求外链js一般内容是固定的
第三次请求
请求page_url,返回200携带cookie_s,cookie_T即可正常请求
那么当我们在浏览器中访问该网站时到底发生了什么其中有什么值得我们关注的
我们先人工模拟一下浏览器加载page_url源码
会发生什么
- 浏览器加载meta
- 浏览器请求
外链js
并执行js内容 - 执行page_url源码
自执行函数
它内部会将外链js解密
成eval需要的万行js字符串并给window.$_ts添加了很多属性然后调用eval函数进入VM
执行解密后的js生成cookieeval执行完毕继续执行自执行函数 - 执行末尾script标签中的代码这些代码会更新cookie_t可以不用管
- 执行setTimeout、eventlistener回调函数可以不用管
瑞数执行流程图解
如下
这里我们需要关注eval调用
的位置也就是VM的入口
cookie生成的位置。
注浏览器v8调用eval执行代码时会开启一个虚拟机VM+数字去执行JS代码。
我们直接hook eval
或搜索.call
就可以定位到调用eval的位置
_$Ln就是解密后
的js代码字符串进入vm是一个自执行函数其中有生成cookie
的逻辑定位cookie可以直接hook或在vm代码中搜索 (5)
hook cookie代码
// hook 指定cookie赋值
(function () {
'use strict';
Object.defineProperty(document, 'cookie', {
set: function (cookie) {
if(cookie.indexOf("FSSBBIl1UgzbN7N80T")!= -1){
debugger;
}
return cookie;
}
});
})();
好了以上就是瑞数的整体流程逻辑那么我们该如何通过扣代码
去生成cookie_t过瑞数呢
二、浅谈扣代码过瑞数
由于每次请求瑞数page_url其源码是动态
变化的VM代码
也是动态变化的所以我们要保存一份静态代码方便调试
直接如图这样固定page_url响应即可
这样请求时page_url中的 外链JS
是固定的自执行函数
是固定的VM中的代码
也是固定的那么这份固定代码每次生成的cookie_t 是不是也固定呢
答案不是因为cookie_t的生成用到了随机数和时间戳我们将这两个变量也hook固定住最终生成的cookie_t就是固定的啦。
此时我们就可以开始扣这份静态代码了扣到node生成的cookie_t
与浏览器执行静态代码生成的cookie_t
一致就说明扣成功了。
扣代码需要扣两部分page_url源码部分和VM中生成cookie_t部分。
按照我们之前的分析VM中代码会用到window.$_ts
因此我们得先保证从page_url源码中扣下来的代码执行到eval时能正常生成window.$_ts
。
我们将page_url的自执行函数
和外链JS内容
先扣下来meta content也先扣下来然后根据执行报错简单补一下环境使得扣下来代码执行到eval时其window.$_ts
和解密出的VM JS代码
与本地静态代码生成的一致。
这就说明我们page_url源码部分扣好了接下来就可以去扣VM中生成cookie_t的部分。
上面我们分析到cookie的定位
可以知道 _$bO这个函数中生成了二次cookie_t那这就是我们扣代码的起点
将该函数扣到文件末尾直接执行然后缺啥补啥遇到使用BOM、DOM api
的代码时我们可以使用等价逻辑替换
比如此处原逻辑是获取meta标签中的content内容然后再删除meta标签我们可以直接等价替换成 return meta_content。如图
如果扣到最后node生成的cookie_t与本地静态代码生成的不一致则说明我们扣的代码有些环境检测没过我们可以根据node与浏览器执行的差异去定位比如node执行到某个地方的值与浏览器执行静态代码得到的不一样说明前面逻辑有差异继续向前定位如此反复即可找出所有遗漏的环境检测完成VM部分扣取。
此时我们就完成了这份静态rs代码的扣取并取得成功但是rs网站的代码是动态
的啊每次请求时 window.$_ts
和VM js
都会变化难道我们每份都要去扣吗不其实我们现在离真正成功只差一个映射
VM的万行js代码 虽然每次都会变化但是变化的只是变量名其他的都不变。
映射就是将动态window.$_ts
中的属性名与 我们扣的VM 中JS用到的window.$_ts
中的固定属性名一一对应。
所以在扣的过程中我们需要注意VM中哪些地方使用了外部变量
即一个函数中哪个变量来自其他作用域就算外部变量我们需要关注这些外部变量是从哪来的如果是VM自执行函数中定义的那就不用管如果是来自window.$_ts
则需要记录下来这就是需要映射传入的。
这里的计算逻辑使用到了 window.$_ts._$IK
所以我们要做映射时要传入这个值window.$_ts={_$IK:对应的动态属性名}
解决完映射也就成功扣代码过rs了。
好了扣代码到此为止接下来就是我们本文的重点。
三、详解补环境过rs
不知道补环境原理的同志可以参考我上篇文章JS逆向之浏览器补环境详解
;
其实纯补环境
过瑞数原理很简单我们来观察瑞数执行流程图解基于浏览器环境执行这些动态JS可以生成可用的 cookie_t。那么只要我们补的浏览器环境足够完美使得在这些动态JS看来我们补的环境===浏览器环境
那么我们补的环境执行这些动态JS同样也能生成可用的 cookie_t然后我们再通过 document.cookie 将cookie_t 提取出来不就好了。
用伪代码表示就是
// 补的环境头
window = this;
... 省略大量环境头
// 模拟meta标签及其content
document.createElement('meta');
Meta$content = "{qYnKTJPAw84QfF5jm0I2_1IqhgTvRw8Y0yCBPxIVn6od8AeJE6CBz8ZSU6U...省略";
// 固定的外链js
$_ts=window['$_ts'];if(!$_ts)$_ts={};$_ts.scj=[];$_ts['dfe1675']='þþ+...省略';
// page_url动态自执行函数
(function(){var _$CK=0,_$WI=[[9,3,6,0,4,1; ...ret = _$su.call(_$fr, _$WR); 很长...省略}}}}}}}})();;
// 获取cookie
function get_cookie(){
return document.cookie;
}
// 获取MmEwMD参数
function get_mme(){{
XMLHttpRequest.prototype.open("GET","http://脱敏/",true);
return XMLHttpRequest.prototype.uri;
}}
这就是我们最后要补成的文件样子由于Meta$content 和page_url动态自执行函数是动态变化的因此我们每次请求page_url 都需要用正则提取出这两个字符串然后拼接到该文件中然后python pyexecjs调用get_cookie即可得到可用cookie_t;
在上面的扣代码过瑞数中也提到了由于有随机数和时间戳参与生成cookie_t 运算导致同一份静态JS代码
生成的cookie_t 是变化的我们可以通过hook
使得时间戳和随机数固定这样同一份静态JS生成的cookie_t就是固定的。
// 固定定随机数和时间戳
Date.prototype.getTime = function(){return 1672931693};
Math.random = function(){return 0.5};
我们也可以通过最终生成的cookie_t 来判断自己补的环境
是不是===浏览器环境
。
原理很简单接下来就是如何实践我们需要补出一份完美的环境头使得这份静态JS
执行得到的cookie_t与浏览器执行得到的一致。
因为补环境是一个系统性工作是有通用套路的我们可以使用上篇文章提到的补环境框架
进行系统性补环境我们要做的就是根据log输出
以及出现的问题不断完善这个框架。
如图启动框架上面是我们补的环境头下面是我们扣的代码
继续调试当我们Proxy拦截器
拦截到BOM、DOM api
的使用时就会debugger住我们可以根据 调用栈 去查看是哪行代码使用的浏览器环境然后再看到框架中模拟的结果是不是跟浏览器一致如果不一致则需要补这个环境。
如此往复的补环境直到最后可以生成cookie_t
判断是否与浏览器本地生成的一致如果不一致则使用二分法去定位看是哪个浏览器环境没补好直到 最终得到正确的cookie_t
这里贴一下最后执行效果图
这是最后打印的一部分环境检测点
这是取出最终得到的cookie_t
同理MmEwMD
参数的补环境也是一样的逻辑当环境头补到完美时在python中执行最终结果文件即可得到如下结果
四、补环境与扣代码总结
对于js逆向
来说这是两种常规且实用的手段也各有优劣势
不管使用哪种方式我们都是先从网站中将加密JS代码扣出然后再选择是继续扣代码将使用到的浏览器环境api
进行逻辑替换还是使用补环境让加密JS代码仿佛在浏览器环境中运行。
- 扣代码与补环境都依赖对JS的熟练度扣代码更侧重js语法和代码逻辑补环境更侧重原型链及BOM、DOM对象的模拟。
- 扣代码熟练度依赖逆向经验补环境几乎只依赖JS熟练度。
- 扣代码需要调试跟踪大量逻辑对于rs如果不解混淆的话屁股得坐出痔疮
- 扣代码需要替换环境检测逻辑所以也需要知道哪里使用了浏览器环境 补环境框架可以只用于监测浏览器环境的使用可以当做扣代码的一个辅助工具。
- 由于瑞数是动态的扣代码只能扣一份静态的所以需要找到vm中使用到的所有动态属性进行映射。而补环境是通用的补的越多可通杀的网站就越多。
- 扣代码比补环境执行效率高毕竟补环境的代码数比扣代码多很多可以通过剔除不需要的环境来缩小差距
- 扣代码人工耗时远高于补环境。
总而言之扣代码
侧重js语法和代码逻辑其熟练度依赖于逆向经验对不同网站要扣的不一样难以通用人工效率低但是程序执行效率高。补环境
侧重原型链及浏览器环境模拟熟练度几乎只依赖对JS的原理掌握程度对于不同网站补的越多可通杀的网站越多人工效率巨高但是程序执行效率不高。
五、弯道超车环节
过瑞数几乎是每个新手逆向者的小目标也是面试官常见的提问点。通过本篇文章我们已经了解了 瑞数的流程及破解思路
接下来我们可以尝试自己从头实现一个完善的补环境框架去纯环境黑盒过瑞数
但是这会花费很长一段时间来进行开发而且其中有很多重复性工作比较无聊复制粘贴对比等。
走快车道
本文该版本 补环境框架 是基于上篇文章框架进行系统性完善的目前可以过瑞数这种级别网站可以说是相当完善了补了相当多的环境如果你想省下大量时间、极大提高效率
、直接弯道超车
的话可以 微信联系我dengshengfeng666 付费源码借鉴
春节优惠价199节后恢复统一固定价 233付完直接发框架项目源码有最新图文readme可直接小白上手后续有疑问可以直接问我。
或者直接在CSDN私信我。
该版本与上版本改进点
- 优化Proxy13种拦截器做到了Proxy的极限并使其能递归代理支持a.b.c.d.e…级别的深度检测
- 完善最终结果文件.js的调用机制使其无需改动能直接用于V8和node调用
- 新增部分BOM、DOM对象如XMLHttpRequestXMLHttpRequestEventTarget等等
- 补全rs用到的所有浏览器环境方法使其可以黑盒过rs
- 优化调试方式可以在想断的时候断点不想断的时候跳过检测
- 增加py直接调用结果文件案例可以使用python以v8和node方式调用
- 优化readme图文介绍环境配置及使用方式。
弯道超车从我做起
该版本框架目录
共同学习,写下你的评论
评论加载中...
作者其他优质文章