人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!

前言

人均瑞数系列,瑞数 4 代 JS 逆向分析

瑞数动态安全 Botgate(机器人防火墙)以”动态安全”技术为核心,通过动态封装、动态验证、动态混淆、动态令牌等技术对服务器网页底层代码持续动态变换,增加服务器行为的”不可预测性”,实现了从用户端到服务器端的全方位”主动防护”,为各类 Web、HTML5 提供强大的安全保护。

瑞数 Botgate 多用于政企、金融、运营商行业,曾一度被视为反爬天花板,随着近年来逆向大佬越来越多,相关的逆向文章也层出不穷,真正到了人均瑞数的时代了,这里也感谢诸如 Nanda、懒神等逆向大佬,揭开了瑞数神秘的面纱,总结的经验让后来人少走了不少弯路。

过瑞数的方法基本上有以下几种:自动化工具(要隐藏特征值)、RPC 远程调用、JS 逆向(硬扣代码和补环境),本文介绍的是 JS 逆向硬扣代码,尽可能多的介绍各种细节。

瑞数特征以及不同版本的区别

对于绝大多数使用睿数的网站,有以下几个特点(可能有不同的特殊版本,先看看主流版本):

[En]

For the vast majority of sites that use Ruisu, there are the following features (there may be special versions that are different, first look at the mainstream ones):

1、打开开发者工具(F12)会依次出现两个典型的无限 debugger:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

2、瑞数的 JS 混淆代码中,变量、方法名大多类似于 _$xx,有众多的 if-else 控制流,新版瑞数还可能会有 jsvmp 以及众多三目表达式的情况:

人均瑞数系列,瑞数 4 代 JS 逆向分析

3、看请求,会有典型的三次请求,首次请求响应码是 202(瑞数3、4代)或者 412(瑞数5代),接着单独请求一个 JS 文件,然后再重新请求页面,后续的其他 XHR 请求中,都带有一个后缀,这个后缀的值是由 JS 生成的,每次都会变化,后缀的值第一个数字为瑞数的版本,比如 MmEwMD=4xxxxx 就是4代瑞数, bX3Xf9nD=5xxxxx 就是5代瑞数:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

4、看 Cookie,瑞数 3、4 代有以 T 和 S 结尾的两个 Cookie,其中以 S 开头的 Cookie 是第一次的 201 那个请求返回的,以 T 开头的 Cookie 是由 JS 生成的,动态变化的,T 和 S 前面一般会跟 80 或 443 的数字,Cookie 值第一个数字为瑞数的版本(为什么可以通过第一个数字来判断版本?难道相同版本第一个数字不会变吗?这些问题我们在分析 JS 的时候可以找到答案),比如:

  • FSSBBIl1UgzbN7N80T=37Na97B.nWX3....:数字 80 是 http 协议的默认端口号,对应 http 请求,其值第一位为 3,表示 3 代瑞数;
  • FSSBBIl1UgzbN7N443T=4a.tr1kEXk.....:数字 443 是 https 协议的默认端口号,对应 https 请求,其值第一位为 4,表示 4 代瑞数。

人均瑞数系列,瑞数 4 代 JS 逆向分析

瑞数 5 代也有以 T 和 S 结尾的两个 Cookie,但有些特殊的 5 代瑞数也有以 O 和 P 结尾的,同样的,以 O 开头的是第一次的 412 那个请求返回的,以 P 开头的是由 JS 生成的,Cookie 值第一个数字同样为瑞数的版本,和 3、4 代不同的是,5 代没有加端口号了,比如:

  • vsKWUwn3HsfIO=57C6DwDUXS.....:以 O 结尾,其值第一位为 5,表示 5 代瑞数;
  • WvY7XhIMu0fGT=53.9fybty......:以 T 结尾,其值第一位为 5,表示 5 代瑞数。

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

5、看入口,瑞数有个流程是在虚拟机 VM 中加载 1w+ 行的代码,加载此代码的入口,不同版本也不一样(这个入口具体在哪里?怎么定位?在后续逆向分析中再详细介绍),示例如下:

  • 3 代: _$aW = _$c6[_$l6()](_$wc, _$mo);_$c6 实际上是 eval_$l6() 实际上是 call

人均瑞数系列,瑞数 4 代 JS 逆向分析
  • 4 代: ret = _$DG.call(_$6a, _$YK);_$DG 实际上是 eval,有关键字 retcall 是明文;

人均瑞数系列,瑞数 4 代 JS 逆向分析
  • 5 代:5 代种类比较多了,最初和 4 代的类似,比如 ret = _$Yg.call(_$kc, _$mH);,有关键字 ret,call 是明文,也有没有 ret 关键字的版本,比如 _$ap = _$j5.call(_$_T, _$gp);,也有像 3 代那样全部混淆了的,比如: _$x8 = _$mP[_$nU[15]](_$z3, _$Ec);_$mP 实际上是 eval_$nU[15] 实际上是 call,混淆的 call 与 3 代的区别就是 5 代是在一个数组里取值得到的;

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

当然要想精准区分不同版本,得各个条件结合起来看,最主要的还是得看看内部的实现逻辑,以及页面的代码结构,比如 4 代有一个生成假 Cookie 的步骤,而 5 代没有,有的特殊版本虽然看起来是 5 代,但是加了 jsvmp 和三目表达式,和传统的 5 代又有区别,偶尔愚人节啥的突然来个新版本,也会不一样,各版本在分析一遍之后,就很容易区分了。

Cookie 入口定位

本文案例中瑞数 4 代网站为: aHR0cDovL3d3dy5mYW5nZGkuY29tLmNuL25ld19ob3VzZS9uZXdfaG91c2VfZGV0YWlsLmh0bWw=

首先过掉无限 debugger(过不过其实无所谓,后面的分析其实这个基本上没影响),直接右键 Never pause here 永不在此处断下即可:

人均瑞数系列,瑞数 4 代 JS 逆向分析

定位 Cookie,首选 Hook 来的最快,通过 Fiddler 等抓包工具、油猴脚本、浏览器插件等方式注入以下 Hook 代码:

(function() {
    // 严谨模式 检查所有错误
    'use strict';
    // document 为要hook的对象 这里是hook的cookie
    var cookieTemp = "";
    Object.defineProperty(document, 'cookie', {
        // hook set方法也就是赋值的方法
        set: function(val) {
                // 这样就可以快速给下面这个代码行下断点
                // 从而快速定位设置cookie的代码
                console.log('Hook捕获到cookie设置->', val);
                debugger;
                cookieTemp = val;
                return val;
        },
        // hook get 方法也就是取值的方法
        get: function()
        {
            return cookieTemp;
        }
    });
})();

Hook 发现会有生成两次 Cookie 的情况,断下之后往上跟栈,可以看到组装 Cookie 的代码,类似如下结构:

人均瑞数系列,瑞数 4 代 JS 逆向分析

仔细观察这两次 Cookie 生成的地方,分别往上跟栈,你就会发现两个 Cookie 分别是经过了两个不同方法得到的,如下图所示:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

这里的代码存在于 VM 虚拟机中,且是 IIFE 自执行代码,我们还得往前跟栈看看这些 VM 代码是从哪里加载出来的,跟栈来到首页(202页面)带有 call 的位置:

人均瑞数系列,瑞数 4 代 JS 逆向分析

我们在文章开头介绍的这个位置就是这么分析得来的,这个位置通常在分析瑞数的时候作为入口,图中 _$te 实际上是 eval 方法,传入的第一个参数 _$fY 是 Window 对象,第二个对象 _$F8 是我们前面看到的 VM 虚拟机中的 IIFE 自执行代码。

在知道了瑞数大致的入口之后,我们也可以使用事件监听中的 Script 断点,一直下一个断点(F8)就可以走到 202 页面,然后搜索 call 关键字就能快速定位到入口,Script 断点中的两个选项,第一个表示运行 JS 脚本的第一条语句时断下,第二个表示 JS 因为内容安全政策而被屏蔽时断下,一般选择第一个就可以了,如下图所示:

人均瑞数系列,瑞数 4 代 JS 逆向分析

文件结构与逻辑

想要后续分析 Cookie 的生成,我们不得不要观察一下 202 页面的代码,meta 标签有个 content 内容,引用了一个类似于 c.FxJzG50F.dfe1675.js 的 JS 文件,接着跟一个自执行的 JS,如下图所示:

人均瑞数系列,瑞数 4 代 JS 逆向分析

第1部分 meta 标签的 content 内容,每次都是变化的,第2部分引用的这个外部 JS 在不同页面也有所差别,但是同一个网站同一个页面 JS 里的内容一般是固定不会变的,第3部分自执行代码每次变化的只是变量名,整体逻辑不变,后续我们在扣代码的时候,也会用到这里的部分方法。自执行代码里同样也是有很多 if-else 控制流,开头的那个数组,比如上图中的 _$Dk 就是用来控制后续的控制流的。

引用的 c.FxJzG50F.dfe1675.js 直接打开看是乱码的,而自执行 JS 的主要作用是将这 JS 乱码还原成 VM 里的 1w+ 行的正常代码,并且定义了一个全局变量 window.$_ts 并赋了许多值,这个变量在后续 VM 中作用非常大,meta 标签的 content 内容同样也会在 VM 里用到。

由于很多值、变量都是动态变化的,肯定不利于我们的分析,所以我们需要固定一套代码到本地,打断点、跟栈都会更加方便,随便保存一份 202 页面的代码,以及该页面对应的外链 JS 文件,如 c.FxJzG50F.dfe1675.js 到本地,使用浏览器自带的 overrides 重写功能、或者浏览器插件 ReRes、或者抓包工具的响应替换功能(如 Fiddler 的 AutoResponder)进行替换。

人均瑞数系列,瑞数 4 代 JS 逆向分析

VM 里面的代码是生成 Cookie 的主要代码,包含众多的 if-else 控制流,无疑增加了我们分析代码的成本,这里就可以使用 AST 技术做一下反混淆,比如 Nanda 就将 if-else 控制流转换成了 switch-case 的,同一个控制流下的代码放在了同一个 case 下,然后在 call 入口那个地方,将 VM 代码做一下本地替换,具体可以参考 Nanda 的文章:《某数4代逻辑分析》,感兴趣的可以试试,不了解 AST 的可以看看以前的文章《逆向进阶,利用 AST 技术还原 JavaScript 混淆代码》,后续有时间 K 哥再写写 AST 还原瑞数代码的实战,本文咱们选择硬刚!

人均瑞数系列,瑞数 4 代 JS 逆向分析

VM 代码以及 $_ts 变量获取

前面我们了解了 VM 代码和 $_ts 的重要性,所以我们第一步是要想办法拿到他们,至于在什么时候有用到,文章后续再说,复制外链 JS,即 c.FxJzG50F.dfe1675.js 的代码和 202 页面的自执行代码到文件,本地直接运行即可,需要轻度补一下环境,缺啥补啥,大致补一下 window、location、document 就行了,补的具体内容可以直接在浏览器控制台使用 copy() 命令复制过来,然后 VM 代码我们就可以直接 Hook eval 的方式得到,大致的补环境代码如下:

var eval_js = ""

window = {
    $_ts:{},
    eval:function (data) {
        eval_js = data
    }
}

location = {
    "ancestorOrigins": {},
    "href": "http://www.脱敏处理.com.cn/new_house/new_house_detail.html",
    "origin": "http://www.脱敏处理.com.cn",
    "protocol": "http:",
    "host": "www.脱敏处理.com.cn",
    "hostname": "www.脱敏处理.com.cn",
    "port": "",
    "pathname": "/new_house/new_house_detail.html",
    "search": "",
    "hash": ""
}

document = {
    "scripts": ["script", "script"]
}

人均瑞数系列,瑞数 4 代 JS 逆向分析

观察 $_ts 的 key 和 value,和浏览器中得到的是一样的:

人均瑞数系列,瑞数 4 代 JS 逆向分析

注意事项: c.FxJzG50F.dfe1675.js 外链 JS 如果你直接下载下来用编辑器打开可能会被自动编码,和原始数据有出入,导致运行报错,这里建议直接在浏览器在线访问这个文件,手动复制过来,或者在抓包软件里将响应内容复制过来,观察以下两种情况,第一种情况就可能会导致运行出错,第二种是正常的:

人均瑞数系列,瑞数 4 代 JS 逆向分析

扣代码

前面说了这么多,现在终于可以进入主题了,那就是扣代码,找个好椅子,准备把屁股坐穿,此时你的键盘只有 F11 有用,不断单步调试,只需要亿点点细节,就完事儿了!

扣代码步骤太多,不可能每一步都截图写出来,只写一下比较重要的,如有遗漏的地方,那也没办法,首先先在我们替换的 202 页面里,自执行代码开始的地方手动加个 debugger,一进入页面就断下,方便后续的分析:

人均瑞数系列,瑞数 4 代 JS 逆向分析

通过前面我们的分析,已经知道了入口在 call 的地方,快速搜索并下断点:

人均瑞数系列,瑞数 4 代 JS 逆向分析

通过前面我们的分析,我们也知道了有两次生成 Cookie 的地方,快速搜索 (5),搜索结果第二个即为入口:

人均瑞数系列,瑞数 4 代 JS 逆向分析

假 Cookie 生成逻辑

首先单步跟假 Cookie,虽然是假的,但是后续生成真 Cookie 中会用到,在跟的时候你会走到这个逻辑里面:

人均瑞数系列,瑞数 4 代 JS 逆向分析

有一步会调用 _$8e() 方法,而 _$8e = _$Q9_$Q9 又嵌套在 _$d0 里的,搜索一下哪里调用了 _$d0,发现是代码开头:

人均瑞数系列,瑞数 4 代 JS 逆向分析

那么传入的参数 _$Wn 是啥呢?单步跟入,是一个方法,作用就是取 202 页面的 content 内容,那么我们在本地就直接删掉这个 _$Wn 方法,直接传入 content 的值即可,如下图所示:

人均瑞数系列,瑞数 4 代 JS 逆向分析

另外,我们发现,代码有非常多的在数组里面按索引取值的情况,比如上图中的 _$PV[68] 的值,实际上就是字符串 content,很显然我们要把这个数组的来源找到,直接搜索 _$PV =,可以找到疑似定义和赋值的地方:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

所以我们得看看这个 _$iL 方法,传入了一个非常长的字符串,打断点进去看看,果然生成了 _$PV,是一个 725 位的数组:

人均瑞数系列,瑞数 4 代 JS 逆向分析

接下来在扣代码的过程中,你会经常遇到一个变量,在本文中是 _$sX

人均瑞数系列,瑞数 4 代 JS 逆向分析

有没有很熟悉?这个值就是我们前面拿到的 $_ts 变量,在开头就可以看到是将 window.$_ts 赋值给了 _$sX

人均瑞数系列,瑞数 4 代 JS 逆向分析

如果你坚持下去,你会得出以下逻辑:

[En]

If you keep going, you will come to the following logic:

人均瑞数系列,瑞数 4 代 JS 逆向分析

在这里,我们将遇到六个数组,它们都已经有了值,所以我们必须找出它们来自哪里。搜索任意数组名称,并找到定义和分配它们的位置:

[En]

Here we will encounter six arrays, all of which already have values, so we have to find out where they came from. Search any of the array names and find the places where they are defined and assigned:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

赋值明显是调用了 _$rv 方法,再搜 _$rv 方法,发现是开头就调用了:

人均瑞数系列,瑞数 4 代 JS 逆向分析

后续没有什么特别的,一直单步,最后有个 join('') 操作,就生成了假 Cookie:

人均瑞数系列,瑞数 4 代 JS 逆向分析

接下来是生成 Cookie 的名字 FSSBBIl1UgzbN7N80T,然后将 Cookie 赋值给 document.cookie,然后又向 localStorage 里面的 $_ck 赋了个值, localStorage 的内容可以直接复制下来,没有太大影响。

人均瑞数系列,瑞数 4 代 JS 逆向分析

真 Cookie 生成逻辑

单步跟真 Cookie,在本文中也就是 _$ZN(768, 1);,可以看到开始进入了无穷无尽的 if-else 控制流:

人均瑞数系列,瑞数 4 代 JS 逆向分析

这里本地应该怎样处理呢?我的做法是以 _$Hn 和其值命名函数, function _$Hn768(){} 就表示所有走 768 号控制流的方法,继续跟,生成真 Cookie 的方法基本上在 747 号控制流,后续我们主要以 747 号控制流的各个步骤来看,747 号控制流扣出来的代码大致如下:

人均瑞数系列,瑞数 4 代 JS 逆向分析

取假 Cookie

单步跟 747 号控制流,会有个进入第 709 号控制流的步骤,会取先前生成的假 Cookie,经过一系列操作之后返回一个数组:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

到目前为止,我们在本地同步代码。如果正常,则返回的数组也应该相同(后续数据不同,时间戳等参数参与操作):

[En]

So far, we synchronize the code locally. If it is normal, the returned array should also be the same (the subsequent data is different, and some parameters such as timestamps participate in the operation):

人均瑞数系列,瑞数 4 代 JS 逆向分析

自动化工具检测

继续跟 747 号控制流,会进入 268 号控制流,接着进入 154 号控制流,这里面会针对自动化工具做一些检测,如下图所示:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

这里定义了一个变量 _$iL,检测不通过就是1,后续又把这个变量赋值给了 _$aW,所以我们本地保持一致,也为 false 即可(其实我们不用自动化工具的话,这一段检测就不用管直接返回 false 就行):

人均瑞数系列,瑞数 4 代 JS 逆向分析

20 位核心数组

继续跟 268 号控制流,会进入 668 号控制流,668 号控制流就两个操作,一是生成一个 16 位数组,二是取 $_ts 里面的 4 个变量,加到前面的 16 位后面,组成一个 20 位数组,这 20 位数组的最后 4 位是瑞数核心,其中的映射关系搞错了请求是通不过的,在五代中这部分的处理逻辑会更加复杂。

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

这里不是单纯的取 $_ts 里的键值对,你在扣代码的时候,你也许会发现怎么本地到这里取值的时候,取出来的不是数字,而是字符串呢?就像下面这种情况:

人均瑞数系列,瑞数 4 代 JS 逆向分析

实际上我们最开始得到的 $_ts 值,是经过了二次处理的,我们以第一个 _$sX._$Xb 为例,直接搜索 _$sX._$Xb,可以发现这么一个地方:

人均瑞数系列,瑞数 4 代 JS 逆向分析

很明显这里给 _$sX._$Xb 重新赋值了一遍,我们可以看到等号右边,先取了一次 _$sX._$Xb,其值为 _$Rm,这和我们初始 $_ts 里面对应的值是一样的,然后我们就得再看看 _$sX["_$Rm"] 又是何方神圣,直接搜索发现是开头赋值了一个方法,通过调用这个方法来生成新的值:

人均瑞数系列,瑞数 4 代 JS 逆向分析

其他三个值遵循相同的模式,赋值代码为:

[En]

The other three values follow the same pattern, and the codes for assignment are:

_$sX._$Xb = _$sX[_$sX._$Xb](_$BH, _$DP);
_$sX._$oI = _$sX[_$sX._$oI](_$ZJ, _$DS)
_$sX._$EN = _$sX[_$sX._$EN]();
_$sX._$D9 = _$sX[_$sX._$D9](_$iL);

实际上应该是:

_$sX._$Xb = _$sX["_$Rm"](_$BH, _$DP);
_$sX._$oI = _$sX["_$Nw"](_$ZJ, _$DS)
_$sX._$EN = _$sX["_$Uh"]();
_$sX._$D9 = _$sX["_$ci"](_$iL);

进一步来说,实际上是:

_$sX._$Xb = _$1k(_$BH, _$DP);
_$sX._$oI = _$jH(_$ZJ, _$DS)
_$sX._$EN = _$9M();
_$sX._$D9 = _$oL(_$iL);

静态分析是可以的,我们可以先修复它,但在实际应用中,这些值是动态的,那么我们应该如何处理它们?首先,让我们再来看看几个比较,以找出规则:

[En]

Static analysis is fine, we can fix it first, but in practical application, these values are dynamic, so how should we deal with them? First, let’s take a look at a few more comparisons to find the rules:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

可以发现,每次对应的顺序不同,但实际上相同位置的方法都是相同的,也就是说,只有方法名和变量名改变了,实现的逻辑没有变化。所以只要我们知道这四个值的对应位置,我们就可以得到正确的值。在本地,我们可以做到这一点:

[En]

It can be found that the corresponding order is different each time, but in fact, the method in the same position is all the same, that is to say, only the method name and variable name are changed, and the implemented logic is unchanged. So as long as we know the corresponding position of these four values, we can get the correct value. Locally, we can do this:

1、先利用正则匹配出这四个值,如: [_$sX._$Xb, _$sX._$oI, _$sX._$EN, _$sX._$D9]

人均瑞数系列,瑞数 4 代 JS 逆向分析

2、再匹配出 VM 代码开头的 20 个赋值的语句,如: _$sX._$RH = _$wI; _$sX._$i5 = _$n5; 等;

人均瑞数系列,瑞数 4 代 JS 逆向分析

3、然后通过 $_ts 取这四个值对应的值,相当于: _$sX._$Xb = _$ts._$Xb = _$Rm;然后再找这四个值所定义的方法在 20 个赋值语句中的位置,相当于:查找 _$sX._$Rm = _$1k; 在 20 个赋值语句中的位置为 7(索引从 0 开始)

人均瑞数系列,瑞数 4 代 JS 逆向分析

4、我们知道了这四个方法在 20 个赋值语句中的位置,那么我们直接匹配本地对应位置的名称,进行动态替换即可,当然前提是咱们本地已经扣了一套代码出来了:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

经过这种处理后,这四个值的准确性是可以保证的。

[En]

After this treatment, the accuracy of these four values can be guaranteed.

其他用到 $_ts 值的地方

除了上面说的 20 位数组里用到了 4 个 $_ts 的值以外,还有其他地方有 7 个值也用到了,直接搜索就能定位,这 7 个值相对较简单,每次都是固定取 $_ts 里面的第 2、3、4、15、16、17、19 位的值,同样的,找到对应位置,进行动态替换即可:

人均瑞数系列,瑞数 4 代 JS 逆向分析

注意事项

特别注意 VM 代码开头,会直接调用执行一些方法,某些变量的值就是通过这些方法生成的,当你一步一步跟的时候发现某些参数不对,或者没有,那么就得注意开头这些方法了,可能一开始就已经生成了。

人均瑞数系列,瑞数 4 代 JS 逆向分析

后缀 MmEwMD 生成逻辑

后续的其他 XHR 请求中,都带有一个后缀,这个后缀的值同样是由 JS 生成的,每次都会变化,当然不同网站,后缀名不一定都是一样的,本例中是 MmEwMD,先下一个 XHR 断点,当 XHR 请求中包含了 MmEwMD= 时就断下,然后刷新网页:

人均瑞数系列,瑞数 4 代 JS 逆向分析

可以看到后传入 l.open() 的 URL 还是正常的,断下后到 l.send() 就带有后缀了,再看 l.open() 其实就是 xhr.open(),明显和正常的有区别,同样这个方法也在 VM 代码里,应该是重写了方法,可以和正常的做对比:

人均瑞数系列,瑞数 4 代 JS 逆向分析

跟到 VM 代码里去看看,经过了 _$sd(arguments[1]) 方法就变成了带有后缀的完整链接了:

人均瑞数系列,瑞数 4 代 JS 逆向分析

跟进 _$sd 方法,前面都是对 url 做一些处理,后面有个进入第 779 号控制流的流程,实际上就是原来我们生成 Cookie 的步骤,跟一下就行了。

人均瑞数系列,瑞数 4 代 JS 逆向分析

善用 Watch 跟踪功能

人均瑞数系列,瑞数 4 代 JS 逆向分析

开发者工具的 Watch 功能能够持续跟踪某个变量的值,对于这种控制流很多的情况,设置相应的变量跟踪,能够让你知道你现在处于哪个控制流中,以及生成的数组的变化,不至于跟着跟着不知道到哪一步了。

结果验证

如果整个流程没问题,代码也扣得正确,携带正确的 Cookie 和正确的后缀,就能成功访问:

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

人均瑞数系列,瑞数 4 代 JS 逆向分析

Original: https://www.cnblogs.com/ikdl/p/16453681.html
Author: K哥爬虫
Title: 人均瑞数系列,瑞数 4 代 JS 逆向分析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/499127/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球