聲明:本文内容僅供學習交流,嚴禁用于商業用途,否則由此産生的一切後果均與作者無關,請于24小時内删除。
1,前提:
1.1 本期内容分為文章和視訊兩部分,視訊是對文章内容的重制及擴充(打字也太多了,還是讓我在視訊裡多說點吧),視訊今天或明天會釋出到公衆号裡,是以歡迎大家關注一波我的公衆号哦。
1.2 本文及視訊,都會基于反混淆的代碼,這樣有助于大家對整體流程認識的更直覺,一張截圖就能截取很多邏輯,如果用原js檔案,一張截圖隻能截取if else混淆中的一個語句,太不友好。
1.3 如何使用我分享到github上的反混淆檔案輔助調試下文及視訊也會講的,當然你用原js檔案調試也是可以的,變量名不一樣,但js語句的執行順序都是一樣的。
2,分析某數4代請求
2.1 先響應狀态碼202傳回一個頁面,隻有js邏輯,并有***S的set-cookie
2.2 上一步傳回的頁面生成cookie ***T
2.3 攜帶***S和***T的兩個cookie可通路到響應狀态碼200的真正頁面
2.4 我們主要關注cookie ***T怎麼生成的
3,首頁js邏輯 -- 詳講
3.1 首頁控制流程由下圖中_$iV的數組控制(每次通路變量名稱都會變化,但整體邏輯不變,本文中我提到的變量名都隻限我的截圖中,下文不再提這一點)
3.2 方法定義略過,到了第一部分,定義了一些變量,然後主流程進入下一層混淆,如圖
3.3 第二層混淆中的邏輯就是往一個對象裡綁定了些參數,這個對象的參數會在eval中用到。具體怎麼用的下文或視訊裡講。主要邏輯如下面三圖:
3.3.1 第二層混淆主流程:
3.3.2 每兩個字母為一組,切分為數組儲存到對象的_$ds上,
3.3.3 定義一些屬性
3.4 主流程進入第三層混淆,
這一塊的主要邏輯就是用c.FxJzG50F.dfe1675.js 這個檔案裡的那一長串字元生成出eval用到的字元串,下圖中還可以看到其中有點時間校驗以及var _$nc = _$ML(71); 檢驗eval有沒有被hook,就這些東西。
3.5 接下來主流程進入第四層混淆
就是直接拿着3.4中生成的字元串用eval運作,中間他還對ie引擎做了下适配,execScript那個。
3.6 至此,首頁邏輯完成。我們這次講到eval裡生成完第二次cookie,是以先不需要關注後面的邏輯。
4,如何使用我分享到github上的反混淆檔案輔助調試
4.1 github位址:
https://github.com/chencchen/webcrawler
4.2 借助于fiddler的AutoResponder功能,攔截到指定請求後直接傳回本地檔案
AutoResponder使用介紹:https://blog.csdn.net/yu1014745867/article/details/72843259
4.3 call的地方,随便發一個請求,用AutoResponder将eval解混淆的代碼擷取到,再eval執行擷取到的反混淆代碼,使用的代碼及修改示例圖如下:
var result = null;var xhr = new XMLHttpRequest();xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { result = xhr.responseText; }}xhr.open('GET', 'http://www.fangdi.com.cn/eval_decrypt', false);xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send();result = result.replace('debugger;', '/*debugger;*/');
5,第一次生成cookie的邏輯 -- 詳講
5.1 這次我們就不一步一步走了哈,因為生成cookie前的步驟有些多 [捂臉],我們直接定位到生成cookie的地方就好了,然後再往回扣代碼,缺啥補啥。
5.2 定位cookie生成的地方,方法很多,我這裡提出沒有反混淆檔案情況下的兩個方案
5.2.1 二分法打斷點,然後document.cookie檢視目标參數有沒有生成,這樣很快就能鎖定位置
5.2.2 hook cookie的指派,也可以直接斷到cookie指派的地方。我用的第一種,是以第二種我也沒有,就不上demo了,也歡迎有的老哥給我發一份,十分感謝,哈哈。
5.3 然後我們就定位到了如圖位置,搜"(5);"可以快速定位,var _$lK = _$ZL(5);生成第一次cookie(無效),_$J_(768, 1);生成第二次cookie(我們本文的目标)
5.4 第一次生成cookie細節
5.4.1 進入_$ZL方法,可以看到繼續向下調用
5.4.2:進入_$d6方法,本處需要前面代碼去找,參數_$1T實際就是首頁中meta,然後被圖中邏輯分割為字元串數組, 外部就可以通過_$d6方法擷取這個數組的元素了。中間用到了兩個外部定義的變量:_$x0._$q3和_$XP(_$lK);中的_$x0._$65,在3.3.3處定義的。這兩個變量名稱是變化的,但是在外部的出現索引是不變的。看3.3.3的圖,一個在第一個,一個在第三個,是以取這兩個值可以在這個規律上取。
5.4.3 接下來我們回到上一層,再進入_$dW方法看看,這個方法中_$fG(2, _$d$(9))暫時沒用,後文有用但可以寫死,是以直接忽略。
5.4.4 然後我們看_$p3(_$1T)方法,
_$p3裡我們要關注一下_$HH這個方法,裡面有6個數組是eval開始時定義的,就是_$jQ,_$1w那幾個,我們需要提前生成一下。
_$p3裡其他的js語句就是就是一系列的數組運算,不涉及外部變量,直接copy出來就好。
5.4.5 然後回上一層,再看最後一個函數_$1j以及該函數最後面的_$MS,還是不涉及外部變量的一系列數組運算,繼續直接複制出來。
5.4.6 至此,第一次生成cookie的邏輯就完成了
6,第二次生成cookie的邏輯 -- 分享一下各個方法都幹了啥
6.1 總生成邏輯
6.2 各步注釋
function _Rshu_5_747(_Rshu_2614, _Rshu_2615, _Rshu_2616, _Rshu_2617) { var _Rshu_2650 = _Rshu_557(_Rshu_561()); // 讀取ts對象中的值某些值 var _Rshu_2651 = _Rshu_5_709(709, _Rshu_2650); // 假cookie轉數組 有時會傳回空(可能時間過長) // 到此處_Rshu_2651應與浏覽器生成一緻,下面的會有時間戳或random,能變化 var _Rshu_2652 = _Rshu_2651[1]; _Rshu_2663 = _Rshu_2652 === ''; if (!_Rshu_2663) { } else { return; } var _Rshu_2653 = _Rshu_217(); // 時間戳與背景傳來的時間計算 _Rshu_2663 = _Rshu_2653 <= _Rshu_508; if (!_Rshu_2663) { } else { _Rshu_2653 = _Rshu_508 + 1; } _Rshu_508 = _Rshu_2653; var _Rshu_2654 = _Rshu_559([_Rshu_2653 / 0x100000000 & 0xffffffff, _Rshu_2653 & 0xffffffff, Math.floor(_$f1 / 1000), Math.floor(_$Nu / 1000)]); // 數組運算 var _Rshu_2655 = _Rshu_5_268(268, _Rshu_2615); //檢測參數及浏覽器特征 _Rshu_2651 = _Rshu_2654.concat(_Rshu_510, _Rshu_2655); // 拼接 var _Rshu_2656 = _Rshu_540(_Rshu_2652.concat(_Rshu_2651)); // 數組運算 for (_Rshu_2660 = 0; _Rshu_2660 < _Rshu_506 + 1; _Rshu_2660++) { _Rshu_2652[_Rshu_2660] ^= _Rshu_2656; } var _Rshu_2644 = _Rshu_5_685(685, _Rshu_2650); // 數組運算 var _Rshu_2647 = _Rshu_618(_Rshu_2651, _Rshu_2644); // 數組運算 return _Rshu_509 + _Rshu_474(_Rshu_2652.concat(_Rshu_2656, _Rshu_2647)); // 生成cookie}
6.3 第二次cookie生成比第一次複雜了些,靠文章來講述工作量有點大,是以文章先寫到這,我在視訊裡再通過調試和大家說說吧。
7,xhr後面的參數是如何被添加的及生成邏輯介紹,下篇文章再寫。
如果本文對你有幫助,歡迎請作者喝杯咖啡哦。