真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

人均瑞數(shù)系列,瑞數(shù) 5 代 JS 逆向分析

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計、網(wǎng)站制作、匯川網(wǎng)絡(luò)推廣、微信小程序開發(fā)、匯川網(wǎng)絡(luò)營銷、匯川企業(yè)策劃、匯川品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供匯川建站搭建服務(wù),24小時服務(wù)熱線:18982081108,官方網(wǎng)址:www.cdcxhl.com

聲明

本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用,不用于其他任何目的,不提供完整代碼,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口等均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無關(guān)!

本文章未經(jīng)許可禁止轉(zhuǎn)載,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外,作者均不負(fù)責(zé),若有侵權(quán),請在公眾號【K哥爬蟲】聯(lián)系作者立即刪除!

前言

瑞數(shù)動態(tài)安全 Botgate(機器人防火墻)以“動態(tài)安全”技術(shù)為核心,通過動態(tài)封裝、動態(tài)驗證、動態(tài)混淆、動態(tài)令牌等技術(shù)對服務(wù)器網(wǎng)頁底層代碼持續(xù)動態(tài)變換,增加服務(wù)器行為的“不可預(yù)測性”,實現(xiàn)了從用戶端到服務(wù)器端的全方位“主動防護”,為各類 Web、HTML5 提供強大的安全保護。

在 K 哥往期的文章《人均瑞數(shù)系列,瑞數(shù) 4 代 JS 逆向分析》中,詳細(xì)介紹了瑞數(shù)的特征、如何區(qū)分不同版本、瑞數(shù)的代碼結(jié)構(gòu)以及各自的作用,本文就不再贅述了,不了解的同志可以先去看看之前的文章。

Cookie 入口定位

本文案例中瑞數(shù) 5 代網(wǎng)站為:aHR0cHM6Ly93d3cubm1wYS5nb3YuY24vZGF0YXNlYXJjaC9ob21lLWluZGV4Lmh0bWw=

定位 Cookie,首選 Hook 來的最快,通過 Fiddler 插件、油猴腳本、瀏覽器插件等方式注入以下 Hook 代碼:

(function() {
    // 嚴(yán)謹(jǐn)模式 檢查所有錯誤
    'use strict';
    // document 為要hook的對象 這里是hook的cookie
	var cookieTemp = "";
    Object.defineProperty(document, 'cookie', {
		// hook set方法也就是賦值的方法 
		set: function(val) {
				// 這樣就可以快速給下面這個代碼行下斷點
				// 從而快速定位設(shè)置cookie的代碼
				console.log('Hook捕獲到cookie設(shè)置->', val);
                debugger;
				cookieTemp = val;
				return val;
		},
		// hook get 方法也就是取值的方法 
		get: function()
		{
			return cookieTemp;
		}
    });
})();

斷下之后往上跟棧,可以看到組裝 Cookie 后賦值給 document.cookie 的代碼,類似如下結(jié)構(gòu):

繼續(xù)往上跟棧,和4代瑞數(shù)類似,(772, 1) 的位置是入口,4代有一次生成假 cookie 的過程,5代就沒有了,如下圖所示:

再往前跟棧,來到首頁代碼,這里就是我們熟悉的 call 位置了,圖中 _$ug 實際上是 eval 方法,傳入的第一個參數(shù) _$Cs 是 Window 對象,第二個對象 _$Dm 是我們前面看到的 VM 虛擬機中的 IIFE 自執(zhí)行代碼。

VM 代碼以及 $_ts 變量獲取

獲取 VM 代碼和 $_ts 變量是第一步,和4代類似,復(fù)制外鏈 JS(例如 fjtvkgf7LVI2.a.js)的代碼和 412 頁面的自執(zhí)行代碼到文件,本地直接運行即可,需要輕度補一下環(huán)境,缺啥補啥,大致補一下 window、location、document 就行了,補的具體內(nèi)容可以直接在瀏覽器控制臺使用 copy() 命令復(fù)制過來,然后 VM 代碼我們就可以直接 Hook eval 的方式得到,這里 $_ts 變量的獲取和4代有點兒區(qū)別,4代我們的做法是運行完代碼后直接取 window.$_ts 就行了,5代運行完代碼后會有一個清空 $_ts 的操作,可以自己跟??匆幌逻壿?,要么把清空的邏輯刪了,要么定義一個全局變量,然后直接在 call 的地方將 $_ts 的值導(dǎo)出來:

大致的補環(huán)境代碼如下:

var eval_js = ""
var rs_ts = ""

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

location = {
    "ancestorOrigins": {},
    "href": "https://脫敏處理/datasearch/home-index.html",
    "origin": "https://脫敏處理",
    "protocol": "https:",
    "host": "www.脫敏處理.cn",
    "hostname": "www.脫敏處理.cn",
    "port": "",
    "pathname": "/datasearch/home-index.html",
    "search": "",
    "hash": ""
}

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

獲取 VM 代碼以及 $_ts 變量:

善用 Watch 跟蹤功能

在跟棧分析之前,有必要了解一下瀏覽器開發(fā)者工具的 Watch 功能,它能夠持續(xù)跟蹤某個變量的值,對于瑞數(shù)這種控制流很多的情況,設(shè)置相應(yīng)的變量跟蹤,能夠讓你知道你現(xiàn)在處于哪個控制流中,以及生成的數(shù)組的變化,不至于跟著跟著不知道到哪一步了。如下圖所示,_$S8 表示目前正處于第 279 號大控制流,_$5x 表示大控制流下的哪個分支,_$mz 表示 128 位大數(shù)組。

跟棧分析

老樣子,本地替換一套 412 頁面的代碼,固定下來,然后開始跟棧分析。直接從 (772, 1) 開始跟(文中說的第多少號控制流、第幾步均為作者自己的叫法,第多少步并不代表實際上的步驟,僅表示關(guān)鍵步驟):

單步進來,_$qh 是傳進來的參數(shù) 1,即將進入 742 號控制流:

進入 742 號控制流,第 1 步通過一個方法獲取了一個時間戳,進入這個方法內(nèi)部,對時間戳進行了差值計算,會發(fā)現(xiàn)有兩個變量 _$tb_$t1 已經(jīng)生成了值:

這兩個值也是時間戳,怎么來的?直接搜索這兩個變量,搜索結(jié)果有幾個全部打上斷點,刷新斷下后往前跟棧,會發(fā)現(xiàn)是最開始走了一遍 703 號控制流:

先單步跟一遍 703 號控制流,703 號控制流第 1 步是進入 699 號控制流,返回一個數(shù)組,沒有特別的,直接扣代碼即可:

703 號控制流第 2、3 步分別取數(shù)組的值:

703 號控制流第 4、5、6 步生成兩個時間戳并賦值給前面提到的 _$tb、_$t1 變量,涉及到的方法也沒有什么特別的,缺啥搜啥補啥即可:

703 號控制流第 7 步,這里修改了 $_ts 的某個值(VM 代碼中,$_ts 被賦值給了另一個變量,下圖中是 _$iw),_$iw._$uq 原本的值是 _$ou,修改后的值是 181,這個值也是后面關(guān)鍵 4 位數(shù)組中的其中一個,具體邏輯后面再講。

703 號控制流結(jié)束,我們繼續(xù)前面的 742 號控制流,742 號控制流第 2 步,將前面生成的時間戳賦值給另一個變量。

742 號控制流第 3 步,進入 279 號控制流,279 號控制流是生成 128 位數(shù)組的關(guān)鍵。

進入 279 號控制流,第 1 步定義了一個變量:

279 號控制流,第 2 步,進入 157 號控制流,157 號控制流主要是做自動化檢測

279 號控制流,第 3、4、5 步,做了一些運算,一些全局變量的值會改變,后續(xù)的數(shù)組里會用到。

279 號控制流,第 6 步,初始化了一個 128 位的空數(shù)組,后續(xù)的操作都是為了往這個數(shù)組里面填充值。

279 號控制流,第 7 步,進入 695 號控制流,生成一個 20 位的數(shù)組。

進入 695 號控制流看一下,第 1 步,取 $_ts 的一個值,生成 16 位數(shù)組。

695 號控制流,第 2 步,取 $_ts 里的四個值,與前面的 16 位數(shù)組一起組成 20 位數(shù)組。

這里注意這四個值怎么來的,以第二個值 _$iw._$KI 為例,搜索發(fā)現(xiàn)有一條語句 _$iw._$KI = _$iw[_$iw._$KI](_$bl, _$n2);,首先等號右邊取 _$iw._$KI 的值為 _$Mo,然后 _$iw["_$Mo"] 實際上就是 _$iw._$Mo,前面的定義 _$iw._$Mo = _$1D,_$1D 是個方法,所以原語句相當(dāng)于 _$iw._$KI = _$1D(_$bl, _$n2),其他三個值的來源也是類似的。

695 號控制流結(jié)束,回到 279 號控制流,第 8 步,將前面的時間戳轉(zhuǎn)換成了一個 8 位數(shù)組。

279 號控制流,第 9 步,往 128 位數(shù)組里面添加了一個值。

_$ae 這個值怎么來的?搜索下斷點并跟棧,發(fā)現(xiàn)是開頭走了第 178 號控制流得來的,跟著走一遍即可。

279 號控制流,第 10 步,又往 128 位數(shù)組里面添加了一個值,這個值是開始 279 號控制流傳過來的。

279 號控制流,第 11、12、13、14 步,時間戳相關(guān)計算,然后生成兩個 2 位數(shù)組。注意這里面的兩個變量,_$ll_$ed,在刷新 cookie、生成后綴的時候可能是有值的,僅訪問主頁沒有值不影響。

279 號控制流,第 15 步,往 128 位數(shù)組里面添加了一個 4 位數(shù)組 _$bl,搜索也可以找到是通過 723 號控制流得來的。

這里的 723 號控制流,實際上是取了 $_ts 某個值進行運算,生成 16 位數(shù)組,然后截取前 4 位數(shù)組返回的。

279 號控制流,第 16 步,往 128 位數(shù)組里面添加了一個 8 位數(shù)組 _$Yb

8 位數(shù)組 _$Yb 同樣搜索打斷點,可以在一個賦值語句斷下:

可以看到 _$EJ 的值就是 _$Yb,往前跟棧,會發(fā)現(xiàn)先后經(jīng)過了 657 號、10 號、777 號控制流,其中 777 號控制流是入口:

如果單步跟 777 號控制流,你會發(fā)現(xiàn)步驟較多,中間有些語句不好處理,且容易跟丟,所以我們這里就直接關(guān)注 657 號控制流就行了,777 號控制流直接到 10 號控制流,再到 657 號控制流,中間的一些過程暫時不管,跟到缺什么的時候再說(后續(xù)有很多取值賦值等操作都是在 777 號控制流里實現(xiàn)的,可以注意一下),這段邏輯在本地表現(xiàn)的代碼如下圖所示:

這里直接單步跟一下 657 號控制流,第 1、2 步 new 了一個方法。

這里就要注意了,容易跟丟,先進入 _$bH 方法打上斷點,然后下一個斷點就走到里面了,接著在單步調(diào)試,會進到另一個小的控制流里面,如下圖所示:

開始單步跟第 96 號小控制流,第 1 步定義了一個變量。

96 號小控制流,第 2 步將 _$PI 的值賦值給了 _$fT,而 _$PI 的值其實是 window.localStorage.$_YWTU,window.localStorage 里面有很多值,這個東西我們文章最后再講,其中一些值與瀏覽器指紋相關(guān),這里先知道他是取值就行了。

96 號小控制流,第 3 步,進入第 94 號小控制流,最終生成的是一個 8 位數(shù)組,這個其實就是前面我們想要的 _$Yb 的值了。

后面沒有什么特別的,中間幾步我就省略了,照著扣代碼就行了,然后 96 號小控制流,第 4 步,就將 _$EJ 的值賦值給 _$Yb 了。

到這里先別急著結(jié)束,后面還有關(guān)鍵的幾步,96 號小控制流,第 5 步,又遇到了和前面類似的寫法。

同樣的,先進 _$pu 打斷點,再單步跟。

來到另一個小控制流,如下圖所示:

10 號小控制流第 1 步,取 window.localStorage.$_cDro 的值,轉(zhuǎn)為 int 類型,賦值給 _$5s,這個 _$5s 后續(xù)也會加到 128 位大數(shù)組里面。

10 號小控制流后續(xù)還有幾步,沒啥用可以省略,最后一步返回 96 號小控制流。

然后 96 號小控制流后續(xù)也沒啥了,返回 657 號控制流。

此時我們已經(jīng)拿到 _$Yb 了,777 號控制流就先不管了,后續(xù)還有些代碼先不管不用扣,等用到的時候再說,返回 279 號控制流,接著前面的步驟,來到第 17 步,變量 _$5s 經(jīng)過 264 號控制流后,生成了一個值并添加到 128 位大數(shù)組里面,而 _$5s 的值正是前面我們跟 _$Yb 時,通過 777 號控制流拿到的,實際上也就是取 window.localStorage.$_cDro 的值,轉(zhuǎn)為了 int 類型。

279 號控制流,第 18、19、20 步,往 128 位數(shù)組里面添加了兩個定值、一個 8 位數(shù)組。

279 號控制流,第 21 步,往 128 位數(shù)組里面添加了一個 undefined 占位,后續(xù)會有操作將其填充值。

279 號控制流,第 22 步,進入 58 號控制流,58 號控制流與 window.localStorage.$_fb 的值有關(guān),如果有這個值,就會生成 20 位數(shù)組,如果沒有就是 undefined。58 號控制流就只有一步,返回一個變量,本文中是 _$0g。

這個 _$0g 是咋來的呢?同樣的直接搜索,下斷點,發(fā)現(xiàn)是通過 112 號控制流得來的,往前跟棧,同樣是先經(jīng)過了 777 號控制流,和之前的情況類似,中間的過程就不看了,直接看這個 112 號控制流。

本文中,112 號控制流傳的參是 _$bd[279]$_fb,112 號控制流第 1 步,進入 247 號控制流。

247 號控制流就 3 步,先將 window.localStorage 賦值給一個變量,然后取其中 $_fb 的值再返回。

112 號控制流第 2、3 步,一個 try-catch 語句,取 window.localStorage.$_fb 計算得到 25 位數(shù)組,然后取前 20 位并返回,這就是前面我們需要的 _$0g 的值了。

279 號控制流,第 23 步,將前面 window.localStorage.$_fb 計算得到的 20 位數(shù)組添加到 128 位大數(shù)組里面,注意這一步如果沒有 window.localStorage.$_fb 值的話,是不會添加的。

279 號控制流,第 24 步,對一個變量進行位運算,然后取 window.localStorage.$_f0 進行運算,如果 $_f0 為空的話是不會往 128 位大數(shù)組里添加值的。

279 號控制流,第 25 步,對一個變量進行位運算,然后取 window.localStorage.$_fh0 進行運算,如果 $_fh0 為空的話是不會往 128 位大數(shù)組里添加值的。

279 號控制流,第 26 步,對一個變量進行位運算,然后取 window.localStorage.$_f1 進行運算,如果 $_f1 為空的話是不會往 128 位大數(shù)組里添加值的。

279 號控制流,第 27 步,進入 611 號控制流,611 號控制流主要是檢測 window.navigator.connection.type,即 NetworkInformation 網(wǎng)絡(luò)相關(guān)信息,里面判斷了 type 是不是 bluetooth、cellular、ethernetwifi、wimax,正常的話應(yīng)該返回 0。

279 號控制流,接下來幾步都是類似的,這里就直接統(tǒng)稱第 28 步了,首先對一個變量進行位運算,然后分別取 window.localStorage.$_fr、 window.localStorage.$_fpn1window.localStorage.$_vvCI、 window.localStorage.$_JQnh 進行運算,同樣如果這些變量為空的話,也是不會往 128 位大數(shù)組里添加值的。

279 號控制流,第 29 步,往 128 位大數(shù)組里添加了一個定值 4,本文中該變量名是 _$kW。

_$kW 這個變量是咋來的,和前面的套路類似,直接搜索下斷,同樣是經(jīng)過開頭的 777 號控制流得來的,如下圖所示:

繼續(xù) 279 號控制流,中間有一些變量位運算之類的就省略了,第 30、31 步,取了一個 https:443 的長度進行計算,先后往 128 位大數(shù)組里添加了一個定值和一個 9 位數(shù)組。

279 號控制流,接下來幾步都是在取值,都差不多,就統(tǒng)稱為第 32 步了。

279 號控制流,第 33 步,之前 128 位大數(shù)組第 12 位是個 undefined,這里就將第 12 位填充上了一個 4 位數(shù)組,其中有個變量 _$8L,前面我們跟步驟的時候就有一個變量一直在做位運算,此處的 _$8L 就是這么來的。

279 號控制流,最后兩步,原來的 128 位大數(shù)組,只取有值的前 21 位,一共有多少位與 window.localStorage 的某些值有關(guān),有值的話就長一些,沒有就短一些,然后再將數(shù)組的每個元素合并成最終的一個大數(shù)組并返回,279 號控制流就結(jié)束了。

返回到文章開頭的邏輯,279 號控制流結(jié)束,返回到 742 號控制流,第 2 步,定義了一個變量并生成了一個 32 位數(shù)組。

742 號控制流,第 3 步,取 $_ts 里面的某個值并賦值給一個變量。

742 號控制流,第 4 步,將前面 279 號控制流得到的大數(shù)組與上一步 $_ts 里面的某個值進行合并,合并后計算得到一個值。

742 號控制流,第 4 步,將上一步得到的值進一步計算得到一個 4 位數(shù)組,再將其和大數(shù)組合并。

742 號控制流,接下來幾步是對時間戳進行各種操作,這里統(tǒng)稱為第 5 步。

742 號控制流,第 6 步,將上一步得到的 4 個時間戳進行計算,得到一個 16 位數(shù)組。

742 號控制流,第 7 步,將上一步得到的 16 位數(shù)組進行異或運算。

742 號控制流,第 8 步,將上一步的 16 位數(shù)組進行計算,得到一個字符串。

742 號控制流,第 9 步,正式生成 cookie 值,其中 _$bd[274] 定值,一般視為版本號,將上一步得到的字符串、之前得到的大數(shù)組和一個 32 位數(shù)組進行計算、組合,得到最終結(jié)果。

742 號控制流結(jié)束,返回 772 號控制流,利用了一個方法,組裝 cookie,然后賦值給 document.cookie,整個流程就結(jié)束了。

代碼中用到的 $_ts 的值需要我們自己去匹配出來,動態(tài)替換,這些步驟和 4 代是類似的,本文就不再重復(fù)敘述,可以參考 K 哥 4 代的那篇文章進行處理即可。

后綴生成

本例中,請求頭中有個 sign 參數(shù),Query String Parameters 有兩個后綴參數(shù),這兩個后綴和 4 代類似,都是瑞數(shù)生成的。

和 4 代的處理方法一樣,我們下一個 XHR 斷點,先讓網(wǎng)頁加載完畢,然后打開開發(fā)者工具,過掉無限 debugger 后,點擊搜索就會斷下,如下圖所示:

往上跟棧到 hasTokenGet,是一個 sojson 旗下的 jsjiami v6 混淆,不值一提,重點是 jsonMD5ToStr 方法,先對傳進去的參數(shù)做了一些編碼處理,最后返回的是 hex_md5,和在線 MD5 加密的結(jié)果是一樣的,說明是標(biāo)準(zhǔn)的 MD5。

重點來看瑞數(shù)的兩個后綴生成方式,和 4 代一樣,XMLHttpRequest.sendXMLHttpRequest.open 被重寫了,如下圖所示,在 XMLHttpRequest.open 下個斷點,也就是圖中的 _$RQ 方法,arguments[1] 就是原始 URL,經(jīng)過圖中的 _$tB 方法處理后就能拿到后綴。

跟進圖中的 _$tB 方法,_$tB 方法里嵌套了一些其他方法,走一遍邏輯,到圖中的 _$5j 方法里,前面的一部分都是在對傳入的 URL 做處理。

接下來是生成了一個 16 位數(shù)組:

然后這個 16 位數(shù)組經(jīng)過一個方法后就生成了第一個后綴,如下圖所示,本文中這個方法是 _$ZO。

跟進 _$ZO 方法,主要有以下 5 步:

第 1 步:生成了一個 32 位數(shù)組;

第 2 步:將之前的 16 位數(shù)組以及兩個變量拼接生成一個 50 位的數(shù)組;

第 3 步:進入 744 控制流,這里你會發(fā)現(xiàn)和之前我們跟 cookie 時的 742 號控制流是一樣的,重復(fù)走了一遍,所以這里就不再跟了;

第 4 步:將生成的第一個后綴值進行處理,得到一個兩位的字符串,這個字符串在獲取第二個后綴的時候會用到;

第 5 步:將第一個后綴名稱和值進行拼接并返回,此時,第一個后綴 hKHnQfLv 就生成了。

接著前面的 _$5j 方法,圖中的 _$5j 這一步,就是獲取第二個后綴 8X7Yi61c 的值:

主要是看一下圖中的 _$UM 方法,先將前面生成的兩位的字符串與 URL 參數(shù)進行拼接,然后會經(jīng)過一個 _$Nr 方法就能得到第二個后綴的值了。

再來看一下 _$Nr 方法,先生成一個類似 的值,然后一個 try 語句,注意這里有個方法,圖中的 _$Js 方法,里面用到了 $_ts 里面的某個值,后面又生成了一個由數(shù)字組成的字符串,再次經(jīng)過組合、計算后得到最終的值。

回到前面的 _$UM 方法,前綴 8X7Yi61c 與值組合,自此,兩個后綴都拿到了:

指紋生成

我們前面已經(jīng)分析了,在往 128 位數(shù)組里添加值的時候,會有取 window.localStorage 里面的某些值進行計算的步驟,這些值就是取瀏覽器 canvas 等指紋生成的,指紋隨機就能并發(fā),通常訪問單獨的一個 html 頁面是不校驗指紋的,生成的短 cookie 就能通過,但是一些查詢數(shù)據(jù)接口會校驗指紋,通過觸發(fā) load 事件來向 cookie 里添加指紋,使得 cookie 長度變長,怎么查找指紋在哪里生成的,這里推薦直接看視頻資料,已經(jīng)講得很清楚了,篇幅太長,本文就不再贅述了,資料鏈接:https://mp.weixin.qq.com/s/DEUc1K8WaO_Cq1a2r0Ge5g


分享名稱:人均瑞數(shù)系列,瑞數(shù) 5 代 JS 逆向分析
當(dāng)前網(wǎng)址:http://weahome.cn/article/dsogege.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部