聲明
本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用涯保,不用于其他任何目的诉濒,不提供完整代碼,抓包內(nèi)容夕春、敏感網(wǎng)址未荒、數(shù)據(jù)接口等均已做脫敏處理,嚴禁用于商業(yè)用途和非法用途及志,否則由此產(chǎn)生的一切后果均與作者無關(guān)片排!
本文章未經(jīng)許可禁止轉(zhuǎn)載寨腔,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外率寡,作者均不負責(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 提供強大的安全保護醋奠。
瑞數(shù) Botgate 多用于政企榛臼、金融、運營商行業(yè)窜司,曾一度被視為反爬天花板沛善,隨著近年來逆向大佬越來越多,相關(guān)的逆向文章也層出不窮塞祈,真正到了人均瑞數(shù)的時代了金刁,這里也感謝諸如 Nanda、懶神等逆向大佬议薪,揭開了瑞數(shù)神秘的面紗尤蛮,總結(jié)的經(jīng)驗讓后來人少走了不少彎路。
過瑞數(shù)的方法基本上有以下幾種:自動化工具(要隱藏特征值)斯议、RPC 遠程調(diào)用产捞、JS 逆向(硬扣代碼和補環(huán)境),本文介紹的是 JS 逆向硬扣代碼哼御,盡可能多的介紹各種細節(jié)坯临。
瑞數(shù)特征以及不同版本的區(qū)別
對于絕大多數(shù)使用了瑞數(shù)的網(wǎng)站來說,有以下幾點特征(可能有特殊版本不一樣恋昼,先僅看主流的):
1看靠、打開開發(fā)者工具(F12)會依次出現(xiàn)兩個典型的無限 debugger:
2、瑞數(shù)的 JS 混淆代碼中液肌,變量挟炬、方法名大多類似于 _$xx
,有眾多的 if-else
控制流,新版瑞數(shù)還可能會有 jsvmp 以及眾多三目表達式的情況:
3谤祖、看請求婿滓,會有典型的三次請求,首次請求響應(yīng)碼是 202(瑞數(shù)3泊脐、4代)或者 412(瑞數(shù)5代)空幻,接著單獨請求一個 JS 文件,然后再重新請求頁面容客,后續(xù)的其他 XHR 請求中,都帶有一個后綴约郁,這個后綴的值是由 JS 生成的缩挑,每次都會變化,后綴的值第一個數(shù)字為瑞數(shù)的版本鬓梅,比如 MmEwMD=4xxxxx
就是4代瑞數(shù)供置,bX3Xf9nD=5xxxxx
就是5代瑞數(shù):
4、看 Cookie绽快,瑞數(shù) 3芥丧、4 代有以 T 和 S 結(jié)尾的兩個 Cookie,其中以 S 開頭的 Cookie 是第一次的 201 那個請求返回的坊罢,以 T 開頭的 Cookie 是由 JS 生成的续担,動態(tài)變化的,T 和 S 前面一般會跟 80 或 443 的數(shù)字活孩,Cookie 值第一個數(shù)字為瑞數(shù)的版本(為什么可以通過第一個數(shù)字來判斷版本物遇?難道相同版本第一個數(shù)字不會變嗎?這些問題我們在分析 JS 的時候可以找到答案)憾儒,比如:
-
FSSBBIl1UgzbN7N80T=37Na97B.nWX3....
:數(shù)字 80 是 http 協(xié)議的默認端口號询兴,對應(yīng) http 請求,其值第一位為 3起趾,表示 3 代瑞數(shù)诗舰; -
FSSBBIl1UgzbN7N443T=4a.tr1kEXk.....
:數(shù)字 443 是 https 協(xié)議的默認端口號,對應(yīng) https 請求训裆,其值第一位為 4眶根,表示 4 代瑞數(shù)。
瑞數(shù) 5 代也有以 T 和 S 結(jié)尾的兩個 Cookie缭保,但有些特殊的 5 代瑞數(shù)也有以 O 和 P 結(jié)尾的汛闸,同樣的,以 O 開頭的是第一次的 412 那個請求返回的艺骂,以 P 開頭的是由 JS 生成的诸老,Cookie 值第一個數(shù)字同樣為瑞數(shù)的版本,和 3、4 代不同的是别伏,5 代沒有加端口號了蹄衷,比如:
-
vsKWUwn3HsfIO=57C6DwDUXS.....
:以 O 結(jié)尾,其值第一位為 5厘肮,表示 5 代瑞數(shù)愧口; -
WvY7XhIMu0fGT=53.9fybty......
:以 T 結(jié)尾,其值第一位為 5类茂,表示 5 代瑞數(shù)耍属。
5、看入口巩检,瑞數(shù)有個流程是在虛擬機 VM 中加載 1w+ 行的代碼厚骗,加載此代碼的入口,不同版本也不一樣(這個入口具體在哪里兢哭?怎么定位领舰?在后續(xù)逆向分析中再詳細介紹),示例如下:
- 3 代:
_$aW = _$c6[_$l6()](_$wc, _$mo);
迟螺,_$c6
實際上是eval
冲秽,_$l6()
實際上是call
;
- 4 代:
ret = _$DG.call(_$6a, _$YK);
矩父,_$DG
實際上是eval
锉桑,有關(guān)鍵字ret
,call
是明文浙垫;
- 5 代:5 代種類比較多了刨仑,最初和 4 代的類似,比如
ret = _$Yg.call(_$kc, _$mH);
夹姥,有關(guān)鍵字 ret杉武,call 是明文,也有沒有 ret 關(guān)鍵字的版本辙售,比如_$ap = _$j5.call(_$_T, _$gp);
轻抱,也有像 3 代那樣全部混淆了的,比如:_$x8 = _$mP[_$nU[15]](_$z3, _$Ec);
旦部,_$mP
實際上是eval
祈搜,_$nU[15]
實際上是call
,混淆的call
與 3 代的區(qū)別就是 5 代是在一個數(shù)組里取值得到的士八;
當(dāng)然要想精準區(qū)分不同版本容燕,得各個條件結(jié)合起來看,最主要的還是得看看內(nèi)部的實現(xiàn)邏輯婚度,以及頁面的代碼結(jié)構(gòu)蘸秘,比如 4 代有一個生成假 Cookie 的步驟,而 5 代沒有,有的特殊版本雖然看起來是 5 代醋虏,但是加了 jsvmp 和三目表達式寻咒,和傳統(tǒng)的 5 代又有區(qū)別,偶爾愚人節(jié)啥的突然來個新版本颈嚼,也會不一樣毛秘,各版本在分析一遍之后,就很容易區(qū)分了阻课。
Cookie 入口定位
本文案例中瑞數(shù) 4 代網(wǎng)站為:aHR0cDovL3d3dy5mYW5nZGkuY29tLmNuL25ld19ob3VzZS9uZXdfaG91c2VfZGV0YWlsLmh0bWw=
首先過掉無限 debugger(過不過其實無所謂叫挟,后面的分析其實這個基本上沒影響),直接右鍵 Never pause here
永不在此處斷下即可:
定位 Cookie限煞,首選 Hook 來的最快霞揉,通過 Fiddler 等抓包工具、油猴腳本晰骑、瀏覽器插件等方式注入以下 Hook 代碼:
(function() {
// 嚴謹模式 檢查所有錯誤
'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;
}
});
})();
Hook 發(fā)現(xiàn)會有生成兩次 Cookie 的情況,斷下之后往上跟棧绊序,可以看到組裝 Cookie 的代碼硕舆,類似如下結(jié)構(gòu):
仔細觀察這兩次 Cookie 生成的地方,分別往上跟棧骤公,你就會發(fā)現(xiàn)兩個 Cookie 分別是經(jīng)過了兩個不同方法得到的抚官,如下圖所示:
這里的代碼存在于 VM 虛擬機中,且是 IIFE 自執(zhí)行代碼阶捆,我們還得往前跟椓杞冢看看這些 VM 代碼是從哪里加載出來的,跟棧來到首頁(202頁面)帶有 call 的位置:
我們在文章開頭介紹的這個位置就是這么分析得來的洒试,這個位置通常在分析瑞數(shù)的時候作為入口倍奢,圖中 _$te
實際上是 eval 方法,傳入的第一個參數(shù) _$fY
是 Window 對象垒棋,第二個對象 _$F8
是我們前面看到的 VM 虛擬機中的 IIFE 自執(zhí)行代碼卒煞。
在知道了瑞數(shù)大致的入口之后,我們也可以使用事件監(jiān)聽中的 Script 斷點叼架,一直下一個斷點(F8)就可以走到 202 頁面畔裕,然后搜索 call 關(guān)鍵字就能快速定位到入口,Script 斷點中的兩個選項乖订,第一個表示運行 JS 腳本的第一條語句時斷下扮饶,第二個表示 JS 因為內(nèi)容安全政策而被屏蔽時斷下,一般選擇第一個就可以了乍构,如下圖所示:
文件結(jié)構(gòu)與邏輯
想要后續(xù)分析 Cookie 的生成甜无,我們不得不要觀察一下 202 頁面的代碼,meta 標簽有個 content 內(nèi)容,引用了一個類似于 c.FxJzG50F.dfe1675.js
的 JS 文件毫蚓,接著跟一個自執(zhí)行的 JS占键,如下圖所示:
第1部分 meta 標簽的 content 內(nèi)容,每次都是變化的元潘,第2部分引用的這個外部 JS 在不同頁面也有所差別畔乙,但是同一個網(wǎng)站同一個頁面 JS 里的內(nèi)容一般是固定不會變的,第3部分自執(zhí)行代碼每次變化的只是變量名翩概,整體邏輯不變牲距,后續(xù)我們在扣代碼的時候,也會用到這里的部分方法钥庇。自執(zhí)行代碼里同樣也是有很多 if-else
控制流牍鞠,開頭的那個數(shù)組,比如上圖中的 _$Dk
就是用來控制后續(xù)的控制流的评姨。
引用的 c.FxJzG50F.dfe1675.js
直接打開看是亂碼的难述,而自執(zhí)行 JS 的主要作用是將這 JS 亂碼還原成 VM 里的 1w+ 行的正常代碼,并且定義了一個全局變量 window.$_ts
并賦了許多值吐句,這個變量在后續(xù) VM 中作用非常大胁后,meta 標簽的 content 內(nèi)容同樣也會在 VM 里用到。
由于很多值嗦枢、變量都是動態(tài)變化的攀芯,肯定不利于我們的分析,所以我們需要固定一套代碼到本地文虏,打斷點侣诺、跟棧都會更加方便,隨便保存一份 202 頁面的代碼氧秘,以及該頁面對應(yīng)的外鏈 JS 文件年鸳,如 c.FxJzG50F.dfe1675.js
到本地,使用瀏覽器自帶的 overrides 重寫功能敏储、或者瀏覽器插件 ReRes阻星、或者抓包工具的響應(yīng)替換功能(如 Fiddler 的 AutoResponder)進行替換。
VM 里面的代碼是生成 Cookie 的主要代碼已添,包含眾多的 if-else
控制流妥箕,無疑增加了我們分析代碼的成本,這里就可以使用 AST 技術(shù)做一下反混淆更舞,比如 Nanda 就將 if-else
控制流轉(zhuǎn)換成了 switch-case
的畦幢,同一個控制流下的代碼放在了同一個 case
下,然后在 call
入口那個地方缆蝉,將 VM 代碼做一下本地替換宇葱,具體可以參考 Nanda 的文章:《某數(shù)4代邏輯分析》瘦真,感興趣的可以試試,不了解 AST 的可以看看以前的文章《逆向進階黍瞧,利用 AST 技術(shù)還原 JavaScript 混淆代碼》诸尽,后續(xù)有時間 K 哥再寫寫 AST 還原瑞數(shù)代碼的實戰(zhàn),本文咱們選擇硬剛印颤!
VM 代碼以及 $_ts 變量獲取
前面我們了解了 VM 代碼和 $_ts
的重要性您机,所以我們第一步是要想辦法拿到他們,至于在什么時候有用到年局,文章后續(xù)再說际看,復(fù)制外鏈 JS,即 c.FxJzG50F.dfe1675.js
的代碼和 202 頁面的自執(zhí)行代碼到文件矢否,本地直接運行即可仲闽,需要輕度補一下環(huán)境,缺啥補啥僵朗,大致補一下 window赖欣、location、document 就行了验庙,補的具體內(nèi)容可以直接在瀏覽器控制臺使用 copy()
命令復(fù)制過來畏鼓,然后 VM 代碼我們就可以直接 Hook eval 的方式得到,大致的補環(huán)境代碼如下:
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"]
}
觀察 $_ts
的 key 和 value壶谒,和瀏覽器中得到的是一樣的:
注意事項:c.FxJzG50F.dfe1675.js
外鏈 JS 如果你直接下載下來用編輯器打開可能會被自動編碼,和原始數(shù)據(jù)有出入膳沽,導(dǎo)致運行報錯汗菜,這里建議直接在瀏覽器在線訪問這個文件,手動復(fù)制過來挑社,或者在抓包軟件里將響應(yīng)內(nèi)容復(fù)制過來陨界,觀察以下兩種情況,第一種情況就可能會導(dǎo)致運行出錯痛阻,第二種是正常的:
扣代碼
前面說了這么多菌瘪,現(xiàn)在終于可以進入主題了,那就是扣代碼阱当,找個好椅子俏扩,準備把屁股坐穿,此時你的鍵盤只有 F11 有用弊添,不斷單步調(diào)試录淡,只需要億點點細節(jié),就完事兒了油坝!
扣代碼步驟太多嫉戚,不可能每一步都截圖寫出來刨裆,只寫一下比較重要的,如有遺漏的地方彬檀,那也沒辦法帆啃,首先先在我們替換的 202 頁面里,自執(zhí)行代碼開始的地方手動加個 debugger窍帝,一進入頁面就斷下努潘,方便后續(xù)的分析:
通過前面我們的分析,已經(jīng)知道了入口在 call 的地方盯桦,快速搜索并下斷點:
通過前面我們的分析慈俯,我們也知道了有兩次生成 Cookie 的地方,快速搜索 (5)
拥峦,搜索結(jié)果第二個即為入口:
假 Cookie 生成邏輯
首先單步跟假 Cookie贴膘,雖然是假的,但是后續(xù)生成真 Cookie 中會用到略号,在跟的時候你會走到這個邏輯里面:
有一步會調(diào)用 _$8e()
方法刑峡,而 _$8e = _$Q9
,_$Q9
又嵌套在 _$d0
里的玄柠,搜索一下哪里調(diào)用了 _$d0
突梦,發(fā)現(xiàn)是代碼開頭:
那么傳入的參數(shù) _$Wn
是啥呢?單步跟入羽利,是一個方法宫患,作用就是取 202 頁面的 content 內(nèi)容,那么我們在本地就直接刪掉這個 _$Wn
方法这弧,直接傳入 content 的值即可娃闲,如下圖所示:
另外,我們發(fā)現(xiàn)匾浪,代碼有非常多的在數(shù)組里面按索引取值的情況皇帮,比如上圖中的 _$PV[68]
的值,實際上就是字符串 content蛋辈,很顯然我們要把這個數(shù)組的來源找到属拾,直接搜索 _$PV =
,可以找到疑似定義和賦值的地方:
所以我們得看看這個 _$iL
方法冷溶,傳入了一個非常長的字符串渐白,打斷點進去看看,果然生成了 _$PV
逞频,是一個 725 位的數(shù)組:
接下來在扣代碼的過程中礼预,你會經(jīng)常遇到一個變量,在本文中是 _$sX
:
有沒有很熟悉虏劲?這個值就是我們前面拿到的 $_ts
變量托酸,在開頭就可以看到是將 window.$_ts
賦值給了 _$sX
:
繼續(xù)走褒颈,會走到以下邏輯中:
這里會遇到六個數(shù)組,他們都已經(jīng)有值了励堡,所以我們得找到他們是咋來的谷丸,任意搜索其中一個數(shù)組名稱,會找到定義和賦值的地方:
賦值明顯是調(diào)用了 _$rv
方法应结,再搜 _$rv
方法刨疼,發(fā)現(xiàn)是開頭就調(diào)用了:
后續(xù)沒有什么特別的,一直單步,最后有個 join('')
操作,就生成了假 Cookie:
接下來是生成 Cookie 的名字 FSSBBIl1UgzbN7N80T
宾巍,然后將 Cookie 賦值給 document.cookie
钱豁,然后又向 localStorage
里面的 $_ck
賦了個值雳旅,localStorage
的內(nèi)容可以直接復(fù)制下來,沒有太大影響。
真 Cookie 生成邏輯
單步跟真 Cookie,在本文中也就是 _$ZN(768, 1);
蜗搔,可以看到開始進入了無窮無盡的 if-else
控制流:
這里本地應(yīng)該怎樣處理呢?我的做法是以 _$Hn
和其值命名函數(shù)八堡,function _$Hn768(){}
就表示所有走 768 號控制流的方法樟凄,繼續(xù)跟,生成真 Cookie 的方法基本上在 747 號控制流兄渺,后續(xù)我們主要以 747 號控制流的各個步驟來看缝龄,747 號控制流扣出來的代碼大致如下:
取假 Cookie
單步跟 747 號控制流,會有個進入第 709 號控制流的步驟挂谍,會取先前生成的假 Cookie二拐,經(jīng)過一系列操作之后返回一個數(shù)組:
至此我們在本地同步扣的代碼,如果正常的話凳兵,返回的數(shù)組也應(yīng)該是一樣的(后續(xù)的數(shù)據(jù)就不一樣了,有一些時間戳之類的參數(shù)參與運算):
自動化工具檢測
繼續(xù)跟 747 號控制流企软,會進入 268 號控制流庐扫,接著進入 154 號控制流,這里面會針對自動化工具做一些檢測仗哨,如下圖所示:
這里定義了一個變量 _$iL
形庭,檢測不通過就是1,后續(xù)又把這個變量賦值給了 _$aW
厌漂,所以我們本地保持一致萨醒,也為 false 即可(其實我們不用自動化工具的話,這一段檢測就不用管直接返回 false 就行):
20 位核心數(shù)組
繼續(xù)跟 268 號控制流苇倡,會進入 668 號控制流富纸,668 號控制流就兩個操作囤踩,一是生成一個 16 位數(shù)組,二是取 $_ts
里面的 4 個變量晓褪,加到前面的 16 位后面堵漱,組成一個 20 位數(shù)組,這 20 位數(shù)組的最后 4 位是瑞數(shù)核心涣仿,其中的映射關(guān)系搞錯了請求是通不過的勤庐,在五代中這部分的處理邏輯會更加復(fù)雜。
這里不是單純的取 $_ts
里的鍵值對好港,你在扣代碼的時候愉镰,你也許會發(fā)現(xiàn)怎么本地到這里取值的時候,取出來的不是數(shù)字钧汹,而是字符串呢丈探?就像下面這種情況:
實際上我們最開始得到的 $_ts
值,是經(jīng)過了二次處理的崭孤,我們以第一個 _$sX._$Xb
為例类嗤,直接搜索 _$sX._$Xb
,可以發(fā)現(xiàn)這么一個地方:
很明顯這里給 _$sX._$Xb
重新賦值了一遍辨宠,我們可以看到等號右邊遗锣,先取了一次 _$sX._$Xb
,其值為 _$Rm
嗤形,這和我們初始 $_ts
里面對應(yīng)的值是一樣的精偿,然后我們就得再看看 _$sX["_$Rm"]
又是何方神圣,直接搜索發(fā)現(xiàn)是開頭賦值了一個方法赋兵,通過調(diào)用這個方法來生成新的值:
另外其他三個值也是同樣的套路笔咽,賦值的代碼分別為:
_$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);
實際上應(yīng)該是:
_$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);
靜態(tài)分析沒問題霹期,我們可以先固定下來叶组,但是實際應(yīng)用當(dāng)中這些值都是動態(tài)的,那我們應(yīng)該怎么處理呢历造?先來多看幾個對比一下找找規(guī)律:
可以發(fā)現(xiàn)每次對應(yīng)的位次都不一樣甩十,但是實際上相同位置的方法點進去都是一樣的,也就是說吭产,變的只有方法名和變量名侣监,實現(xiàn)的邏輯是不變的,所以我們只要知道了這四個值分別對應(yīng)的位置臣淤,就能夠拿到正確的值橄霉,在本地,我們就可以這樣做:
1邑蒋、先利用正則匹配出這四個值姓蜂,如:[_$sX._$Xb, _$sX._$oI, _$sX._$EN, _$sX._$D9]
按厘;
2、再匹配出 VM 代碼開頭的 20 個賦值的語句覆糟,如:_$sX._$RH = _$wI; _$sX._$i5 = _$n5;
等刻剥;
3、然后通過 $_ts
取這四個值對應(yīng)的值滩字,相當(dāng)于:_$sX._$Xb = _$ts._$Xb = _$Rm
造虏;然后再找這四個值所定義的方法在 20 個賦值語句中的位置,相當(dāng)于:查找 _$sX._$Rm = _$1k;
在 20 個賦值語句中的位置為 7(索引從 0 開始)
4麦箍、我們知道了這四個方法在 20 個賦值語句中的位置漓藕,那么我們直接匹配本地對應(yīng)位置的名稱,進行動態(tài)替換即可挟裂,當(dāng)然前提是咱們本地已經(jīng)扣了一套代碼出來了:
經(jīng)過這樣處理后享钞,就能夠保證這四個值的準確性了。
其他用到 $_ts 值的地方
除了上面說的 20 位數(shù)組里用到了 4 個 $_ts
的值以外诀蓉,還有其他地方有 7 個值也用到了栗竖,直接搜索就能定位,這 7 個值相對較簡單渠啤,每次都是固定取 $_ts
里面的第 2狐肢、3、4沥曹、15份名、16、17妓美、19 位的值僵腺,同樣的,找到對應(yīng)位置壶栋,進行動態(tài)替換即可:
注意事項
特別注意 VM 代碼開頭辰如,會直接調(diào)用執(zhí)行一些方法,某些變量的值就是通過這些方法生成的贵试,當(dāng)你一步一步跟的時候發(fā)現(xiàn)某些參數(shù)不對琉兜,或者沒有,那么就得注意開頭這些方法了锡移,可能一開始就已經(jīng)生成了。
后綴 MmEwMD 生成邏輯
后續(xù)的其他 XHR 請求中漆际,都帶有一個后綴淆珊,這個后綴的值同樣是由 JS 生成的,每次都會變化奸汇,當(dāng)然不同網(wǎng)站施符,后綴名不一定都是一樣的往声,本例中是 MmEwMD
,先下一個 XHR 斷點戳吝,當(dāng) XHR 請求中包含了 MmEwMD=
時就斷下浩销,然后刷新網(wǎng)頁:
可以看到后傳入 l.open()
的 URL 還是正常的,斷下后到 l.send()
就帶有后綴了听哭,再看 l.open()
其實就是 xhr.open()
慢洋,明顯和正常的有區(qū)別,同樣這個方法也在 VM 代碼里陆盘,應(yīng)該是重寫了方法普筹,可以和正常的做對比:
跟到 VM 代碼里去看看,經(jīng)過了 _$sd(arguments[1])
方法就變成了帶有后綴的完整鏈接了:
跟進 _$sd
方法隘马,前面都是對 url 做一些處理太防,后面有個進入第 779 號控制流的流程,實際上就是原來我們生成 Cookie 的步驟酸员,跟一下就行了蜒车。
善用 Watch 跟蹤功能
開發(fā)者工具的 Watch 功能能夠持續(xù)跟蹤某個變量的值,對于這種控制流很多的情況幔嗦,設(shè)置相應(yīng)的變量跟蹤酿愧,能夠讓你知道你現(xiàn)在處于哪個控制流中,以及生成的數(shù)組的變化崭添,不至于跟著跟著不知道到哪一步了寓娩。
結(jié)果驗證
如果整個流程沒問題,代碼也扣得正確呼渣,攜帶正確的 Cookie 和正確的后綴棘伴,就能成功訪問: