聲明
本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用店读,不用于其他任何目的嗦枢,不提供完整代碼攀芯,抓包內(nèi)容屯断、敏感網(wǎng)址、數(shù)據(jù)接口等均已做脫敏處理侣诺,嚴(yán)禁用于商業(yè)用途和非法用途殖演,否則由此產(chǎn)生的一切后果均與作者無(wú)關(guān)!
本文章未經(jīng)許可禁止轉(zhuǎn)載年鸳,禁止任何修改后二次傳播趴久,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外,作者均不負(fù)責(zé)搔确,若有侵權(quán)彼棍,請(qǐng)聯(lián)系作者立即刪除!
前言
瑞數(shù)動(dòng)態(tài)安全 Botgate(機(jī)器人防火墻)以“動(dòng)態(tài)安全”技術(shù)為核心膳算,通過(guò)動(dòng)態(tài)封裝座硕、動(dòng)態(tài)驗(yàn)證、動(dòng)態(tài)混淆涕蜂、動(dòng)態(tài)令牌等技術(shù)對(duì)服務(wù)器網(wǎng)頁(yè)底層代碼持續(xù)動(dòng)態(tài)變換华匾,增加服務(wù)器行為的“不可預(yù)測(cè)性”,實(shí)現(xiàn)了從用戶端到服務(wù)器端的全方位“主動(dòng)防護(hù)”机隙,為各類 Web蜘拉、HTML5 提供強(qiáng)大的安全保護(hù)萨西。
在 K 哥往期的文章《人均瑞數(shù)系列,瑞數(shù) 4 代 JS 逆向分析》中旭旭,詳細(xì)介紹了瑞數(shù)的特征谎脯、如何區(qū)分不同版本、瑞數(shù)的代碼結(jié)構(gòu)以及各自的作用持寄,本文就不再贅述了穿肄,不了解的同志可以先去看看之前的文章。
Cookie 入口定位
本文案例中瑞數(shù) 5 代網(wǎng)站為:aHR0cHM6Ly93d3cubm1wYS5nb3YuY24vZGF0YXNlYXJjaC9ob21lLWluZGV4Lmh0bWw=
定位 Cookie际看,首選 Hook 來(lái)的最快咸产,通過(guò) Fiddler 插件、油猴腳本仲闽、瀏覽器插件等方式注入以下 Hook 代碼:
(function() {
// 嚴(yán)謹(jǐn)模式 檢查所有錯(cuò)誤
'use strict';
// document 為要hook的對(duì)象 這里是hook的cookie
var cookieTemp = "";
Object.defineProperty(document, 'cookie', {
// hook set方法也就是賦值的方法
set: function(val) {
// 這樣就可以快速給下面這個(gè)代碼行下斷點(diǎn)
// 從而快速定位設(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 的過(guò)程顶吮,5代就沒(méi)有了社牲,如下圖所示:
再往前跟棧,來(lái)到首頁(yè)代碼悴了,這里就是我們熟悉的 call 位置了搏恤,圖中 _$ug
實(shí)際上是 eval 方法,傳入的第一個(gè)參數(shù) _$Cs
是 Window 對(duì)象湃交,第二個(gè)對(duì)象 _$Dm
是我們前面看到的 VM 虛擬機(jī)中的 IIFE 自執(zhí)行代碼熟空。
VM 代碼以及 $_ts 變量獲取
獲取 VM 代碼和 $_ts
變量是第一步,和4代類似搞莺,復(fù)制外鏈 JS(例如 fjtvkgf7LVI2.a670748.js
)的代碼和 412 頁(yè)面的自執(zhí)行代碼到文件息罗,本地直接運(yùn)行即可,需要輕度補(bǔ)一下環(huán)境才沧,缺啥補(bǔ)啥迈喉,大致補(bǔ)一下 window、location温圆、document 就行了挨摸,補(bǔ)的具體內(nèi)容可以直接在瀏覽器控制臺(tái)使用 copy()
命令復(fù)制過(guò)來(lái),然后 VM 代碼我們就可以直接 Hook eval 的方式得到捌木,這里 $_ts
變量的獲取和4代有點(diǎn)兒區(qū)別油坝,4代我們的做法是運(yùn)行完代碼后直接取 window.$_ts
就行了,5代運(yùn)行完代碼后會(huì)有一個(gè)清空 $_ts
的操作,可以自己跟棾喝Γ看一下邏輯彬檀,要么把清空的邏輯刪了,要么定義一個(gè)全局變量瞬女,然后直接在 call 的地方將 $_ts
的值導(dǎo)出來(lái):
大致的補(bǔ)環(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 跟蹤功能
在跟棧分析之前窍帝,有必要了解一下瀏覽器開(kāi)發(fā)者工具的 Watch 功能,它能夠持續(xù)跟蹤某個(gè)變量的值诽偷,對(duì)于瑞數(shù)這種控制流很多的情況坤学,設(shè)置相應(yīng)的變量跟蹤,能夠讓你知道你現(xiàn)在處于哪個(gè)控制流中报慕,以及生成的數(shù)組的變化深浮,不至于跟著跟著不知道到哪一步了。如下圖所示眠冈,_$S8
表示目前正處于第 279 號(hào)大控制流飞苇,_$5x
表示大控制流下的哪個(gè)分支,_$mz
表示 128 位大數(shù)組蜗顽。
跟棧分析
老樣子布卡,本地替換一套 412 頁(yè)面的代碼,固定下來(lái)雇盖,然后開(kāi)始跟棧分析忿等。直接從 (772, 1)
開(kāi)始跟(文中說(shuō)的第多少號(hào)控制流、第幾步均為作者自己的叫法崔挖,第多少步并不代表實(shí)際上的步驟贸街,僅表示關(guān)鍵步驟):
單步進(jìn)來(lái),_$qh
是傳進(jìn)來(lái)的參數(shù) 1虚汛,即將進(jìn)入 742 號(hào)控制流:
進(jìn)入 742 號(hào)控制流匾浪,第 1 步通過(guò)一個(gè)方法獲取了一個(gè)時(shí)間戳皇帮,進(jìn)入這個(gè)方法內(nèi)部卷哩,對(duì)時(shí)間戳進(jìn)行了差值計(jì)算,會(huì)發(fā)現(xiàn)有兩個(gè)變量 _$tb
和 _$t1
已經(jīng)生成了值:
這兩個(gè)值也是時(shí)間戳属拾,怎么來(lái)的将谊?直接搜索這兩個(gè)變量,搜索結(jié)果有幾個(gè)全部打上斷點(diǎn)渐白,刷新斷下后往前跟棧尊浓,會(huì)發(fā)現(xiàn)是最開(kāi)始走了一遍 703 號(hào)控制流:
先單步跟一遍 703 號(hào)控制流,703 號(hào)控制流第 1 步是進(jìn)入 699 號(hào)控制流纯衍,返回一個(gè)數(shù)組栋齿,沒(méi)有特別的,直接扣代碼即可:
703 號(hào)控制流第 2、3 步分別取數(shù)組的值:
703 號(hào)控制流第 4瓦堵、5基协、6 步生成兩個(gè)時(shí)間戳并賦值給前面提到的 _$tb
、_$t1
變量菇用,涉及到的方法也沒(méi)有什么特別的澜驮,缺啥搜啥補(bǔ)啥即可:
703 號(hào)控制流第 7 步,這里修改了 $_ts
的某個(gè)值(VM 代碼中惋鸥,$_ts
被賦值給了另一個(gè)變量杂穷,下圖中是 _$iw
),_$iw._$uq
原本的值是 _$ou
卦绣,修改后的值是 181耐量,這個(gè)值也是后面關(guān)鍵 4 位數(shù)組中的其中一個(gè),具體邏輯后面再講滤港。
703 號(hào)控制流結(jié)束拴鸵,我們繼續(xù)前面的 742 號(hào)控制流,742 號(hào)控制流第 2 步蜗搔,將前面生成的時(shí)間戳賦值給另一個(gè)變量劲藐。
742 號(hào)控制流第 3 步,進(jìn)入 279 號(hào)控制流樟凄,279 號(hào)控制流是生成 128 位數(shù)組的關(guān)鍵聘芜。
進(jìn)入 279 號(hào)控制流,第 1 步定義了一個(gè)變量:
279 號(hào)控制流缝龄,第 2 步汰现,進(jìn)入 157 號(hào)控制流,157 號(hào)控制流主要是做自動(dòng)化檢測(cè)
279 號(hào)控制流叔壤,第 3瞎饲、4、5 步炼绘,做了一些運(yùn)算嗅战,一些全局變量的值會(huì)改變,后續(xù)的數(shù)組里會(huì)用到俺亮。
279 號(hào)控制流驮捍,第 6 步,初始化了一個(gè) 128 位的空數(shù)組脚曾,后續(xù)的操作都是為了往這個(gè)數(shù)組里面填充值东且。
279 號(hào)控制流,第 7 步本讥,進(jìn)入 695 號(hào)控制流珊泳,生成一個(gè) 20 位的數(shù)組鲁冯。
進(jìn)入 695 號(hào)控制流看一下,第 1 步色查,取 $_ts
的一個(gè)值晓褪,生成 16 位數(shù)組。
695 號(hào)控制流综慎,第 2 步涣仿,取 $_ts
里的四個(gè)值,與前面的 16 位數(shù)組一起組成 20 位數(shù)組示惊。
這里注意這四個(gè)值怎么來(lái)的好港,以第二個(gè)值 _$iw._$KI
為例,搜索發(fā)現(xiàn)有一條語(yǔ)句 _$iw._$KI = _$iw[_$iw._$KI](_$bl, _$n2);
米罚,首先等號(hào)右邊取 _$iw._$KI
的值為 _$Mo
钧汹,然后 _$iw["_$Mo"]
實(shí)際上就是 _$iw._$Mo
,前面的定義 _$iw._$Mo = _$1D
录择,_$1D
是個(gè)方法拔莱,所以原語(yǔ)句相當(dāng)于 _$iw._$KI = _$1D(_$bl, _$n2)
,其他三個(gè)值的來(lái)源也是類似的隘竭。
695 號(hào)控制流結(jié)束塘秦,回到 279 號(hào)控制流,第 8 步动看,將前面的時(shí)間戳轉(zhuǎn)換成了一個(gè) 8 位數(shù)組尊剔。
279 號(hào)控制流,第 9 步菱皆,往 128 位數(shù)組里面添加了一個(gè)值须误。
_$ae
這個(gè)值怎么來(lái)的?搜索下斷點(diǎn)并跟棧仇轻,發(fā)現(xiàn)是開(kāi)頭走了第 178 號(hào)控制流得來(lái)的京痢,跟著走一遍即可。
279 號(hào)控制流篷店,第 10 步祭椰,又往 128 位數(shù)組里面添加了一個(gè)值,這個(gè)值是開(kāi)始 279 號(hào)控制流傳過(guò)來(lái)的船庇。
279 號(hào)控制流吭产,第 11、12鸭轮、13、14 步橄霉,時(shí)間戳相關(guān)計(jì)算窃爷,然后生成兩個(gè) 2 位數(shù)組邑蒋。注意這里面的兩個(gè)變量,_$ll
和 _$ed
按厘,在刷新 cookie医吊、生成后綴的時(shí)候可能是有值的,僅訪問(wèn)主頁(yè)沒(méi)有值不影響逮京。
279 號(hào)控制流卿堂,第 15 步,往 128 位數(shù)組里面添加了一個(gè) 4 位數(shù)組 _$bl
懒棉,搜索也可以找到是通過(guò) 723 號(hào)控制流得來(lái)的草描。
這里的 723 號(hào)控制流,實(shí)際上是取了 $_ts
某個(gè)值進(jìn)行運(yùn)算策严,生成 16 位數(shù)組穗慕,然后截取前 4 位數(shù)組返回的。
279 號(hào)控制流妻导,第 16 步逛绵,往 128 位數(shù)組里面添加了一個(gè) 8 位數(shù)組 _$Yb
。
8 位數(shù)組 _$Yb
同樣搜索打斷點(diǎn)倔韭,可以在一個(gè)賦值語(yǔ)句斷下:
可以看到 _$EJ
的值就是 _$Yb
术浪,往前跟棧,會(huì)發(fā)現(xiàn)先后經(jīng)過(guò)了 657 號(hào)寿酌、10 號(hào)添吗、777 號(hào)控制流,其中 777 號(hào)控制流是入口:
如果單步跟 777 號(hào)控制流份名,你會(huì)發(fā)現(xiàn)步驟較多碟联,中間有些語(yǔ)句不好處理,且容易跟丟僵腺,所以我們這里就直接關(guān)注 657 號(hào)控制流就行了鲤孵,777 號(hào)控制流直接到 10 號(hào)控制流,再到 657 號(hào)控制流辰如,中間的一些過(guò)程暫時(shí)不管普监,跟到缺什么的時(shí)候再說(shuō)(后續(xù)有很多取值賦值等操作都是在 777 號(hào)控制流里實(shí)現(xiàn)的,可以注意一下)琉兜,這段邏輯在本地表現(xiàn)的代碼如下圖所示:
這里直接單步跟一下 657 號(hào)控制流凯正,第 1、2 步 new 了一個(gè)方法豌蟋。
這里就要注意了铆帽,容易跟丟胎撇,先進(jìn)入 _$bH
方法打上斷點(diǎn),然后下一個(gè)斷點(diǎn)就走到里面了即寒,接著在單步調(diào)試,會(huì)進(jìn)到另一個(gè)小的控制流里面,如下圖所示:
開(kāi)始單步跟第 96 號(hào)小控制流,第 1 步定義了一個(gè)變量。
96 號(hào)小控制流胁澳,第 2 步將 _$PI
的值賦值給了 _$fT
,而 _$PI
的值其實(shí)是 window.localStorage.$_YWTU
米者,window.localStorage
里面有很多值韭畸,這個(gè)東西我們文章最后再講,其中一些值與瀏覽器指紋相關(guān)蔓搞,這里先知道他是取值就行了胰丁。
96 號(hào)小控制流,第 3 步败明,進(jìn)入第 94 號(hào)小控制流隘马,最終生成的是一個(gè) 8 位數(shù)組,這個(gè)其實(shí)就是前面我們想要的 _$Yb
的值了妻顶。
后面沒(méi)有什么特別的酸员,中間幾步我就省略了,照著扣代碼就行了讳嘱,然后 96 號(hào)小控制流幔嗦,第 4 步,就將 _$EJ
的值賦值給 _$Yb
了沥潭。
到這里先別急著結(jié)束邀泉,后面還有關(guān)鍵的幾步,96 號(hào)小控制流钝鸽,第 5 步汇恤,又遇到了和前面類似的寫法。
同樣的拔恰,先進(jìn) _$pu
打斷點(diǎn)因谎,再單步跟。
來(lái)到另一個(gè)小控制流颜懊,如下圖所示:
10 號(hào)小控制流第 1 步财岔,取 window.localStorage.$_cDro
的值,轉(zhuǎn)為 int 類型河爹,賦值給 _$5s
匠璧,這個(gè) _$5s
后續(xù)也會(huì)加到 128 位大數(shù)組里面。
10 號(hào)小控制流后續(xù)還有幾步咸这,沒(méi)啥用可以省略夷恍,最后一步返回 96 號(hào)小控制流。
然后 96 號(hào)小控制流后續(xù)也沒(méi)啥了炊苫,返回 657 號(hào)控制流裁厅。
此時(shí)我們已經(jīng)拿到 _$Yb
了冰沙,777 號(hào)控制流就先不管了侨艾,后續(xù)還有些代碼先不管不用扣执虹,等用到的時(shí)候再說(shuō),返回 279 號(hào)控制流唠梨,接著前面的步驟袋励,來(lái)到第 17 步,變量 _$5s
經(jīng)過(guò) 264 號(hào)控制流后当叭,生成了一個(gè)值并添加到 128 位大數(shù)組里面茬故,而 _$5s
的值正是前面我們跟 _$Yb
時(shí),通過(guò) 777 號(hào)控制流拿到的蚁鳖,實(shí)際上也就是取 window.localStorage.$_cDro
的值磺芭,轉(zhuǎn)為了 int 類型。
279 號(hào)控制流醉箕,第 18钾腺、19、20 步讥裤,往 128 位數(shù)組里面添加了兩個(gè)定值放棒、一個(gè) 8 位數(shù)組。
279 號(hào)控制流己英,第 21 步间螟,往 128 位數(shù)組里面添加了一個(gè) undefined
占位,后續(xù)會(huì)有操作將其填充值损肛。
279 號(hào)控制流厢破,第 22 步,進(jìn)入 58 號(hào)控制流治拿,58 號(hào)控制流與 window.localStorage.$_fb
的值有關(guān)摩泪,如果有這個(gè)值,就會(huì)生成 20 位數(shù)組忍啤,如果沒(méi)有就是 undefined加勤。58 號(hào)控制流就只有一步,返回一個(gè)變量同波,本文中是 _$0g
鳄梅。
這個(gè) _$0g
是咋來(lái)的呢?同樣的直接搜索未檩,下斷點(diǎn)戴尸,發(fā)現(xiàn)是通過(guò) 112 號(hào)控制流得來(lái)的,往前跟棧冤狡,同樣是先經(jīng)過(guò)了 777 號(hào)控制流孙蒙,和之前的情況類似项棠,中間的過(guò)程就不看了,直接看這個(gè) 112 號(hào)控制流挎峦。
本文中香追,112 號(hào)控制流傳的參是 _$bd[279]
即 $_fb
,112 號(hào)控制流第 1 步坦胶,進(jìn)入 247 號(hào)控制流透典。
247 號(hào)控制流就 3 步,先將 window.localStorage
賦值給一個(gè)變量顿苇,然后取其中 $_fb
的值再返回峭咒。
112 號(hào)控制流第 2、3 步纪岁,一個(gè) try-catch
語(yǔ)句凑队,取 window.localStorage.$_fb
計(jì)算得到 25 位數(shù)組,然后取前 20 位并返回幔翰,這就是前面我們需要的 _$0g
的值了漩氨。
279 號(hào)控制流,第 23 步导匣,將前面 window.localStorage.$_fb
計(jì)算得到的 20 位數(shù)組添加到 128 位大數(shù)組里面才菠,注意這一步如果沒(méi)有 window.localStorage.$_fb
值的話,是不會(huì)添加的贡定。
279 號(hào)控制流赋访,第 24 步,對(duì)一個(gè)變量進(jìn)行位運(yùn)算缓待,然后取 window.localStorage.$_f0
進(jìn)行運(yùn)算蚓耽,如果 $_f0
為空的話是不會(huì)往 128 位大數(shù)組里添加值的。
279 號(hào)控制流旋炒,第 25 步步悠,對(duì)一個(gè)變量進(jìn)行位運(yùn)算,然后取 window.localStorage.$_fh0
進(jìn)行運(yùn)算瘫镇,如果 $_fh0
為空的話是不會(huì)往 128 位大數(shù)組里添加值的鼎兽。
279 號(hào)控制流,第 26 步铣除,對(duì)一個(gè)變量進(jìn)行位運(yùn)算谚咬,然后取 window.localStorage.$_f1
進(jìn)行運(yùn)算,如果 $_f1
為空的話是不會(huì)往 128 位大數(shù)組里添加值的尚粘。
279 號(hào)控制流择卦,第 27 步,進(jìn)入 611 號(hào)控制流,611 號(hào)控制流主要是檢測(cè) window.navigator.connection.type
秉继,即 NetworkInformation
網(wǎng)絡(luò)相關(guān)信息祈噪,里面判斷了 type
是不是 bluetooth
、cellular
尚辑、ethernet
辑鲤、wifi
、wimax
腌巾,正常的話應(yīng)該返回 0遂填。
279 號(hào)控制流铲觉,接下來(lái)幾步都是類似的澈蝙,這里就直接統(tǒng)稱第 28 步了,首先對(duì)一個(gè)變量進(jìn)行位運(yùn)算撵幽,然后分別取 window.localStorage.$_fr
灯荧、 window.localStorage.$_fpn1
、 window.localStorage.$_vvCI
盐杂、 window.localStorage.$_JQnh
進(jìn)行運(yùn)算逗载,同樣如果這些變量為空的話,也是不會(huì)往 128 位大數(shù)組里添加值的链烈。
279 號(hào)控制流厉斟,第 29 步,往 128 位大數(shù)組里添加了一個(gè)定值 4强衡,本文中該變量名是 _$kW
擦秽。
_$kW
這個(gè)變量是咋來(lái)的,和前面的套路類似漩勤,直接搜索下斷感挥,同樣是經(jīng)過(guò)開(kāi)頭的 777 號(hào)控制流得來(lái)的,如下圖所示:
繼續(xù) 279 號(hào)控制流越败,中間有一些變量位運(yùn)算之類的就省略了触幼,第 30、31 步究飞,取了一個(gè) https:443
的長(zhǎng)度進(jìn)行計(jì)算置谦,先后往 128 位大數(shù)組里添加了一個(gè)定值和一個(gè) 9 位數(shù)組。
279 號(hào)控制流亿傅,接下來(lái)幾步都是在取值媒峡,都差不多,就統(tǒng)稱為第 32 步了袱蜡。
279 號(hào)控制流丝蹭,第 33 步,之前 128 位大數(shù)組第 12 位是個(gè) undefined
,這里就將第 12 位填充上了一個(gè) 4 位數(shù)組奔穿,其中有個(gè)變量 _$8L
镜沽,前面我們跟步驟的時(shí)候就有一個(gè)變量一直在做位運(yùn)算,此處的 _$8L
就是這么來(lái)的贱田。
279 號(hào)控制流缅茉,最后兩步,原來(lái)的 128 位大數(shù)組男摧,只取有值的前 21 位蔬墩,一共有多少位與 window.localStorage
的某些值有關(guān),有值的話就長(zhǎng)一些耗拓,沒(méi)有就短一些拇颅,然后再將數(shù)組的每個(gè)元素合并成最終的一個(gè)大數(shù)組并返回,279 號(hào)控制流就結(jié)束了乔询。
返回到文章開(kāi)頭的邏輯樟插,279 號(hào)控制流結(jié)束,返回到 742 號(hào)控制流竿刁,第 2 步黄锤,定義了一個(gè)變量并生成了一個(gè) 32 位數(shù)組。
742 號(hào)控制流食拜,第 3 步鸵熟,取 $_ts
里面的某個(gè)值并賦值給一個(gè)變量。
742 號(hào)控制流负甸,第 4 步流强,將前面 279 號(hào)控制流得到的大數(shù)組與上一步 $_ts
里面的某個(gè)值進(jìn)行合并,合并后計(jì)算得到一個(gè)值惑惶。
742 號(hào)控制流煮盼,第 4 步,將上一步得到的值進(jìn)一步計(jì)算得到一個(gè) 4 位數(shù)組带污,再將其和大數(shù)組合并僵控。
742 號(hào)控制流,接下來(lái)幾步是對(duì)時(shí)間戳進(jìn)行各種操作鱼冀,這里統(tǒng)稱為第 5 步报破。
742 號(hào)控制流,第 6 步千绪,將上一步得到的 4 個(gè)時(shí)間戳進(jìn)行計(jì)算充易,得到一個(gè) 16 位數(shù)組。
742 號(hào)控制流荸型,第 7 步盹靴,將上一步得到的 16 位數(shù)組進(jìn)行異或運(yùn)算。
742 號(hào)控制流,第 8 步稿静,將上一步的 16 位數(shù)組進(jìn)行計(jì)算梭冠,得到一個(gè)字符串。
742 號(hào)控制流改备,第 9 步控漠,正式生成 cookie 值,其中 _$bd[274]
定值悬钳,一般視為版本號(hào)盐捷,將上一步得到的字符串、之前得到的大數(shù)組和一個(gè) 32 位數(shù)組進(jìn)行計(jì)算默勾、組合碉渡,得到最終結(jié)果。
742 號(hào)控制流結(jié)束灾测,返回 772 號(hào)控制流爆价,利用了一個(gè)方法,組裝 cookie媳搪,然后賦值給 document.cookie
,整個(gè)流程就結(jié)束了骤宣。
代碼中用到的 $_ts
的值需要我們自己去匹配出來(lái)秦爆,動(dòng)態(tài)替換,這些步驟和 4 代是類似的憔披,本文就不再重復(fù)敘述等限,可以參考 K 哥 4 代的那篇文章進(jìn)行處理即可。
后綴生成
本例中芬膝,請(qǐng)求頭中有個(gè) sign 參數(shù)望门,Query String Parameters 有兩個(gè)后綴參數(shù),這兩個(gè)后綴和 4 代類似锰霜,都是瑞數(shù)生成的筹误。
和 4 代的處理方法一樣,我們下一個(gè) XHR 斷點(diǎn)癣缅,先讓網(wǎng)頁(yè)加載完畢厨剪,然后打開(kāi)開(kāi)發(fā)者工具,過(guò)掉無(wú)限 debugger 后友存,點(diǎn)擊搜索就會(huì)斷下祷膳,如下圖所示:
往上跟棧到 hasTokenGet
,是一個(gè) sojson 旗下的 jsjiami v6 混淆屡立,不值一提直晨,重點(diǎn)是 jsonMD5ToStr
方法,先對(duì)傳進(jìn)去的參數(shù)做了一些編碼處理,最后返回的是 hex_md5
勇皇,和在線 MD5 加密的結(jié)果是一樣的奕巍,說(shuō)明是標(biāo)準(zhǔn)的 MD5。
重點(diǎn)來(lái)看瑞數(shù)的兩個(gè)后綴生成方式儒士,和 4 代一樣的止,XMLHttpRequest.send
和 XMLHttpRequest.open
被重寫了,如下圖所示着撩,在 XMLHttpRequest.open
下個(gè)斷點(diǎn)诅福,也就是圖中的 _$RQ
方法,arguments[1]
就是原始 URL拖叙,經(jīng)過(guò)圖中的 _$tB
方法處理后就能拿到后綴氓润。
跟進(jìn)圖中的 _$tB
方法,_$tB
方法里嵌套了一些其他方法薯鳍,走一遍邏輯咖气,到圖中的 _$5j
方法里,前面的一部分都是在對(duì)傳入的 URL 做處理挖滤。
接下來(lái)是生成了一個(gè) 16 位數(shù)組:
然后這個(gè) 16 位數(shù)組經(jīng)過(guò)一個(gè)方法后就生成了第一個(gè)后綴崩溪,如下圖所示,本文中這個(gè)方法是 _$ZO
斩松。
跟進(jìn) _$ZO
方法伶唯,主要有以下 5 步:
第 1 步:生成了一個(gè) 32 位數(shù)組;
第 2 步:將之前的 16 位數(shù)組以及兩個(gè)變量拼接生成一個(gè) 50 位的數(shù)組惧盹;
第 3 步:進(jìn)入 744 控制流乳幸,這里你會(huì)發(fā)現(xiàn)和之前我們跟 cookie 時(shí)的 742 號(hào)控制流是一樣的,重復(fù)走了一遍钧椰,所以這里就不再跟了粹断;
第 4 步:將生成的第一個(gè)后綴值進(jìn)行處理,得到一個(gè)兩位的字符串嫡霞,這個(gè)字符串在獲取第二個(gè)后綴的時(shí)候會(huì)用到瓶埋;
第 5 步:將第一個(gè)后綴名稱和值進(jìn)行拼接并返回,此時(shí)秒际,第一個(gè)后綴 hKHnQfLv
就生成了悬赏。
接著前面的 _$5j
方法,圖中的 _$5j
這一步娄徊,就是獲取第二個(gè)后綴 8X7Yi61c
的值:
主要是看一下圖中的 _$UM
方法闽颇,先將前面生成的兩位的字符串與 URL 參數(shù)進(jìn)行拼接,然后會(huì)經(jīng)過(guò)一個(gè) _$Nr
方法就能得到第二個(gè)后綴的值了寄锐。
再來(lái)看一下 _$Nr
方法兵多,先生成一個(gè)類似 53924 的值尖啡,然后一個(gè) try 語(yǔ)句,注意這里有個(gè)方法剩膘,圖中的 _$Js
方法衅斩,里面用到了 $_ts
里面的某個(gè)值,后面又生成了一個(gè)由數(shù)字組成的字符串怠褐,再次經(jīng)過(guò)組合畏梆、計(jì)算后得到最終的值。
回到前面的 _$UM
方法奈懒,前綴 8X7Yi61c
與值組合奠涌,自此,兩個(gè)后綴都拿到了:
指紋生成
我們前面已經(jīng)分析了磷杏,在往 128 位數(shù)組里添加值的時(shí)候溜畅,會(huì)有取 window.localStorage
里面的某些值進(jìn)行計(jì)算的步驟,這些值就是取瀏覽器 canvas 等指紋生成的极祸,指紋隨機(jī)就能并發(fā)慈格,通常訪問(wèn)單獨(dú)的一個(gè) html 頁(yè)面是不校驗(yàn)指紋的,生成的短 cookie 就能通過(guò)遥金,但是一些查詢數(shù)據(jù)接口會(huì)校驗(yàn)指紋浴捆,通過(guò)觸發(fā) load 事件來(lái)向 cookie 里添加指紋,使得 cookie 長(zhǎng)度變長(zhǎng)汰规,怎么查找指紋在哪里生成的汤功,這里推薦直接看視頻資料,已經(jīng)講得很清楚了溜哮,篇幅太長(zhǎng),本文就不再贅述了色解,資料鏈接:https://mp.weixin.qq.com/s/DEUc1K8WaO_Cq1a2r0Ge5g