JavaScript逆向教程之破解某麥引數加密的思路
原 文:http://www.threetails.xyz/2019/05/19/初探js逆向(二)
· 正 · 文 · 來 · 啦 ·
前言
如果你是沒有任何 js 逆向經驗的爬蟲萌新,且沒看過上篇的《JavaScript逆向教程,不來了解一下麼?》,建議先移步去看,因為本篇所使用的案例相對上篇,難度會更大一些。
在上一篇中,我們學習了一個入門案例的逆向流程。然而,加密的方式有很多,不可能以一概全。在進入本篇正題前,我們先回憶一下上篇的逆向思路:
…
不妨思考一下,引數雖做了加密,但網頁畢竟要正常顯示內容,所以在網頁渲染的過程中,一定有個地方對這個引數做了解密,然後將資料寫入html。
也就是說,我們需要在網頁渲染的過程裡,一步步觀察,看看到底是哪個位置對這個引數做了解密。
…
其實,這個思路有個前提:加密引數必須是請求返回的結果引數。如果網站在請求發起時就對請求引數做了加密,這個思路就不管用了。
另外,在上篇中,因為案例比較簡單,在找到解密函式之後工作就完成了 90%,所以摳程式碼的部分我們一筆帶過。而本篇的案例,即便找到了加密位置,可能也只完成了一半工作。
所以本篇將以七麥資料這個網站為例,介紹‘當請求引數被加密時的逆向思路’以及‘摳程式碼’的正確姿勢。
網站分析
訪問 https://www.qimai.cn/rank/marketRank/market/3/category/-2/date/2019-05-18 這個地址,可以看到:
紅框中的App榜單列表即為我們的目標資料。來看看它發起了哪些請求:
在 marketRank
這個請求的響應內容裡能夠找到我們的目標資料,而且是清晰的 json 結構。但不要高興得太早,我們再看一下它的請求引數:
market(3)
、category(-2)
、date
分別表示應用商店(應用寶)、類別(全部遊戲)和日期,想構造它們都很簡單,為了後文描述方便,我們暫且稱之為‘簡單三參’。
需要重點關注的是這個 analysis
,它是一個被加密的必選引數,請求時必須攜帶,否則無法正常返回資料。這時候你可能會想:“那我直接把它拷貝下來,模擬請求時再帶上不就行了?”,然而,只要你稍微分析下就會發現,這個引數並不是固定的,它會隨著簡單三參的變化而改變。且這類榜單資料通常具有時效性,如果你想進行批量
說了這麼多,好像有些偏離主題了,我們的目的不是爬取網站,而是學習 js 逆向。
下面進入正題。
逆向思路
我們先用上篇中提到的方式,在xhr請求裡打上斷點,重新整理一下網頁。
程式碼執行到了 h.send(f)
,等等,好像哪裡不對。send 不就是把請求傳送出去嗎?那是不是意味著請求引數在這步之前就已經生成完畢?觀察一下上面幾行程式碼,果然如此:
1558181366544
在 t
物件的 url 屬性中可以看到,analysis 已經生成好了。那麼我們再往下執行也沒意義了,因為這個請求已經被髮送到了服務端,客戶端沒必要再對它的引數進行解密。況且我們的目的是研究如何生成 analysis,而不是如何解密。
那怎樣才能找到生成 analysis 的位置呢?我們可以先把它的值記錄下來,
fGR5SX10dQ0oY3lVeGIkBH1HDQ1wExcWVlYPG1sAQltVRGJRXlMkFAxXBANUAQUHBQQFcBtV
然後把斷點打在一個比較早的地方(analysis 生成之前),一步步往下執行,這個值首次出現的位置,就是它生成的位置。
想把斷點打在 analysis 生成之前,可以在 Network 選項卡下,該請求的 Initiator 列裡看到它的呼叫棧,呼叫順序由上而下:
1558182881027
在前幾條裡隨便選一個,點進去打上斷點,這裡我看get
比較順眼,就選了這條,並在預設位置打上斷點。打上斷點後別急著重新整理網頁,這裡有個坑需要先避一下。因為除了marketRank
之外,marketList
這個請求也有一個 analysis 引數,它請求的是應用商店列表(百度、應用寶、360…)。為了避免干擾,我們不要重新整理網頁,而是切換類別:
通過這種方式來觸發除錯介面,就不會再去請求應用商店列表了。切換類別後即可觸發彈出除錯介面:
1558183179819
可以發現,簡單三參都已經出現了,但還沒發現 analysis,它應該還沒生成,讓我們繼續往下執行。注意,執行過程中時刻關注是否出現類似(切換了類別,analysis肯定會變化,所以是類似)我們之前記錄下來的那個值。
此處省略一萬步除錯……,只要你耐心足夠,就能找到下圖中的程式碼:
1558184945255
可以看到,r
的值與我們之前記錄的值很類似,為了進一步確定,可以在除錯執行完成後看下請求中的 analysis 值是否與這個 r
的值一致。
答案是一致的。也就是說,接下來只要把 r
的生成程式碼全部摳下來,我們就能生成 analysis 了。感覺也沒那麼難對吧?其實這個網站,摳程式碼才是重頭戲。
摳程式碼
開頭中提到,本案例即便找到了加密位置,也只完成了一半工作。因為加密函式中做了大量的程式碼混淆和迷惑眼球的函式呼叫,想把它完整摳下來也不是件容易的事。如果你沒有強大的心臟和足夠的耐心,請止步於此;但如果你就喜歡折騰,請接著往下看。
鑑於本文的目的主要在於介紹‘請求引數被加密時的逆向思路’,所以不會對‘摳程式碼’的部分做詳細講解,也不會提供完整程式碼,但會稍微做一些提示,希望能對你有所幫助。以下提示內容只有真正去嘗試摳程式碼的人才能看懂了。
-
b
寫死。 -
摳出
e
的生成函式,生成e
。
-
時間戳與寫死的-44
-
摳出
m
的生成函式,通過簡單三參+URL 字尾+e
生成m
。
-
簡單三參 sort 與 join
-
忽略迷惑程式碼
ano[Ao]…
-
進入 e 內部打斷點
-
只關注被呼叫並執行的程式碼
-
new一個Unit8Array
-
找到寫入Unit8Array的程式碼
-
轉base64
-
封裝
f[La]
,便於步驟4呼叫
-
摳出
r
的生成函式,通過m
和b
生成r
。
-
搞定步驟3之後心態千萬不要崩,因為勝利就在眼前
-
幾個寫死的變數
-
String["fromCharCode"]
貼張逆向成功的截圖:
總結
當請求的引數被加密時,將斷點打在加密引數生成之前,在它的值首次出現的位置找到它的加密函式。
摳程式碼時,如果程式碼做了大量混淆。需要辨別哪些程式碼是迷惑你的,哪些程式碼是真正起作用的,哪些程式碼是不需要摳的,哪些程式碼是可以自己用其他方式替代的。
大週末的在家研究js破解,辛苦作者了。