淺逆某里227滑塊
Target:aHR0cHM6Ly9qb2JzLjUxam9iLmNvbS9zdXpob3UtZ3l5cS8xNTMzMDczMjEuaHRtbA== ( 多刷新幾次就會觸發滑塊 )
在調試前可先用fiddler
等工具固定滑塊頁面,這樣會方便很多
跟n值生成位置
第一種方法
在滑動滑塊前先下個script
斷點,然後會斷在這裡
這時去看網路面板,可以發現滑塊的驗證是通過nocaptcha/analyze.jsonp
這個接口,其中最關鍵的參數就是n
簡單跟下棧就能找到n
的生成位置,o.__fy_options
固定就可以
第二種方法
這種方法是在別的大佬的文章看到的,一開始我是用第一種方法找到的,但第二種方法感覺也挺好的,特此記錄一下
下個全局的的mousedown
斷點
斷下後走幾步會到這裡,看到它添加了一個mousemove
事件,跟入s
看看
經過一些運算後,判斷是否進入i
,繼續深入i
看看
前面先移除了各種事件,最後進入了m
函數
然後m
函數就是n
值生成的位置
本地&瀏覽器調試
通常我找到密文生成位置後,會先嘗試導出相關函數,然後在本地運行,直到能利用出值為止( 雖然這個值大概率還不能使用 )
本地出值
由於我比較懶,我是直接將幾個可能用到的js文件放到本地的環境,然後通過導出相關函數來生成n
值。
如下所示,按awsc.js
、et_f.js
、fireyejs.js
、nc.js
的順序
在導出加密函數o.__fy.getFYToken
時發現要先初始化一些環境,跟棧找到m.init
,這裡直接導出m
本地調用如下:
然後就可以導出o.__fy.getFYToken
的o
對象 ( 代碼最好不要格式化,防止有檢測 )
本地調用如下:
在awsc.js
、et_f.js
、fireyejs.js
、nc.js
這幾個環境初始化時,或者是在getFYToken
加密的過程中,需要手動補瀏覽器的環境,以下是部份我遇到要補的環境:
- 調用
getComputedStyle
取了body所有的屬性,然後放到pe中
具體效果如這兩句代碼一致
1 | t = getComputedStyle(document.body); |
-
Performance.prototype.getEntriesByType
-
font
指紋
1 | // 1 |
補著補著就能出值了,這是個好的開始
AST解混淆
- 在進行瀏覽器跟值這一步前,強烈建議先解一解
fireyejs.js
的混淆( 主要邏輯在這個js文件裡 ),具體做法可以參考大佬的這篇文章。
( 一開始我唔信邪硬剛左一個星期,跟值跟到自閉,無奈只能放棄哩個on9做法… ) - 由於我ast比較菜,所以只解到了
多層switch
→單switch
那裡,但由於變量作用域等問題,多層switch
→單switch
的代碼無法替換瀏覽器裡原本的代碼( 簡單來說就是用不了 )。
雖然不能直接替換使用,但在分析時( 向上跟值、跟調用順序 )卻大有用處,眾所周知控制流平坦化是無法直接通過跟棧來找到上一步的,只能通過控制流的狀態變量一步一步往上跟,而只有一層的switch控制流比起多層嵌套的switch控制流就容易跟值多了。 舉例來說,以下是只有一層的switch控制流,假如狀態變量是li
,我想跟case 5157
的上一步是哪,直接搜li = 5157
,若有多個結果就全部下斷,看它走哪裡1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24case 5157:
S = b = [U + 64 * ye];
li = 19041;
break;
case 5184:
R = k = f;
if (bo = (P = (fe = fe < 15) * fe) > (Y = (A = 215 | (bo = !hi)) << 25)) {
li = 1349;
} else {
li = 14688;
}
break;
case 5185:
to = Ke = to;
lo = ao;
go = ze;
qo = ho;
To = (Xo = ne)[ei];
Lo = To[Wo](zo);
Eo = i[Je](Lo, 36, to, 0, lo, 1);
No = Xo[_o](Eo, eo);
eo = i[Je](Lo, 36, to, No, go);
li = 13380;
break; - 瀏覽器替換用的是多層switch嵌套的版本,主要處理了三目運算符、逗號表達式等阻礙調試的東西,看大佬的那篇文章有移除自執行函數這步,但在227移除自執行函數會有變量作用域問題,因此我就保留了( 這也導致ast要多判斷一些條件 ) ( 可以看到多層嵌套switch控制流,若要向上跟,要考慮多個狀態變量,十分麻煩!!!! )
瀏覽器跟值
主要目標是找到軌跡相關的邏輯
跟進o.__fy.getFYToken
,會走到i(40, e)
這裡
單步走幾步,發現s
數組,看它的內容很像是一個環境的特徵數組,s[90]
還特別像是與軌跡有關,經測試後發現確實如此( 所謂測試就是鼠標多滑幾下或少滑幾下,看看這個s[90]
的長度是否符合預期 ),接下來看看這個s
數組的某幾項:
s[5]
:鼠標點擊前的軌跡數組長度 - 1
( 計mousedown那一下的軌跡 )s[46]
:與s[5]
類似,但不計mousedown那一下的軌跡,因此比s[5]
小1,由i(25)
觸發s[26]
:前兩項是WebGLRenderingContext
的東西,第3項的"undefined"
是觸發DeviceOrientationEvent
事件而來,第4、5項是觸發MouseEvent
而來,鼠標在頁面不同位置時,對應的target
( html頁面中的某個元素 )也不一樣,取的是target["id"]
s[23]
:由ScriptProcessorNode
的onaudioprocess
事件生成,而onaudioprocess
事件是通過觸發全局的mousedown
而來,具體值的來源是AnalyserNode.prototype.getFloatFrequencyData
s[48]
:與timestamp有關的數組s[91]
:promise的回調( 看堆棧就知道 )s[52]
:同樣是某個promise的回調觸發的s[3]
:由FocusEvent
觸發s[90]
:最重要的軌跡數組,有以下幾個要點:- 由
mousedown
、mousemove
觸發( 全局正常會有2個mousemove
、mousedown
事件,要用第2個 ),每次會生成一個軌跡 - 軌跡主要取
MouseEvent.clientX
、MouseEvent.clientY
、timestamp
、MouseEvent.pageY
、MouseEvent.pageX
等,並進行了異或等運算,因此直接看s[90]
會與軌跡值對不上 - 這個軌跡數組並非鼠標點擊後才開始push,而是只要在頁面上動就會一直在push,因此軌跡數組可能要分成點擊前和點擊後
- 有兩種軌跡,分別是length為
17
和length為18
的,嘗試過找為什麼有兩種不同的軌跡,但放棄了,最後我在本地手動構建軌跡時發現我的s[90]
同樣有這兩種,就沒有深究了 - 快速獲取軌跡的方法:在
i
函數一開始下條件斷點1
o instanceof MouseEvent && ( window.slideArr ? window.slideArr.push({"pageX":o.pageX, "pageY":o.pageY, "clientX":o.clientX, "clientY":o.clientY}) : window.slideArr = [], false)
- 由
s[36]
:由滑塊的鼠標點擊事件觸發
本地調用結果
參考
感謝大佬們的分享