爬過網易雲評論的都知道,網易雲的歌曲都是通過 <iframe> 便簽進行層層迭代,而且數據都是異步加載的,就算是使用Selenium也要進行框架的轉換,非常麻煩,且效率低下。
通過Chrome抓包得到評論的URL
可以看到評論的URL使用POST傳進了兩個參數,這一看就是加密過的,直接訪問肯定是進不去的,猜測應該是JS加密,要破解只能去查看JS源碼了。
在Initiator中可以看到 JS 目錄的位置,在
格式化后放到本地,查找參數關鍵字以找到相關的JS代碼,比如查找 “encSecKey”
運氣不錯一下就找到了,可以看到參數的值分別是bYc1x.encText,bYc1x.encSecKey,而bYc1x是由asrsea()方法傳進4個參數構建的,再查找asrsea,
得到一長串混淆的JS代碼,根本沒法解析變量的意思,但是似乎找到了加密的方式 CryptoJS.mode.CBC。
要是想完全解密經過多層混淆的代碼估計JS功底得非常深厚,所以這里取巧直接在本地輸出參數看下參數的值,然后進行反加密。
這里我使用的是 Fiddler 去替換原來的JS代碼,在控制台輸出參數的值。因為服務器的資源是先放到瀏覽器上,瀏覽器再展示給我們,所以可以替換掉服務器的代碼,輸出參數的值。
打開 Fiddler,點擊AutoResponser, 把Enable rules , Unmatched requests passthrough和 Enable Latency全部勾上。
然后刷新頁面,在下方輸入 Select Script
找到我們需要更改的JS源碼,拖到右側AutoResponser界面。
其中左邊是你需要替換掉的JS文件,右邊是你想要應用的文件路徑。
我們想要輸出未經加密的參數,所以在源碼中添加

console.log(i3x);console.log(bkY2x(["流淚", "強"]));console.log(bkY2x(VM8E.md));console.log(bkY2x(["愛心", "女孩", "驚恐", "大笑"]));
PS:我是在沒有格式化JS代碼的時候就要添加了,格式化后會報錯變量未定義什么的,所以是直接在源碼適當的地方直接插入。報錯的可以試着換個位置插入。
然后在AutoResponse中點擊 save ,刷新網易雲的頁面,點擊控制台,會看到:
多次輸出檢驗可以后3個參數是定值,而第一個參數就包含了歌曲信息:
rid:就是歌曲的 id信息。
offset:用作評論的分頁,比如offset=100,就是從第101條評論開始。
limit:限制的評論數,上限為100,超過會變成20,限制輸出的評論數。
其他參數暫時還沒有發現其用處。
部分源碼分析:提取的源碼如下:

function a(a) { var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = ""; for (d = 0; a > d; d += 1) e = Math.random() * b.length, e = Math.floor(e), c += b.charAt(e); return c } function b(a, b) { var c = CryptoJS.enc.Utf8.parse(b), d = CryptoJS.enc.Utf8.parse("0102030405060708"), e = CryptoJS.enc.Utf8.parse(a), f = CryptoJS.AES.encrypt(e, c, { iv: d, mode: CryptoJS.mode.CBC }); return f.toString() } function c(a, b, c) { var d, e; return setMaxDigits(131), d = new RSAKeyPair(b, "", c), e = encryptedString(d, a) } function d(d, e, f, g) { var h = {}, i = a(16); return h.encText = b(d, g), h.encText = b(h.encText, i), h.encSecKey = c(i, e, f), h } function e(a, b, d, e) { var f = {}; return f.encText = c(a + e, b, d), f } window.asrsea = d,
函數 asrsea() 傳進了4個參數,然后asrsea 調用了 函數 a() ,閱讀a()的代碼,可以知道返回的是一個長度為 16 的隨機字符串。那么我們可以給它一個定值。
再看對象 h,易知 h.encSecKey = c(i, e, f)是一個定值,最后就是帶有歌曲參數的屬性 h.encText,這個屬性是通過兩次加密后得到的。
研究加密算法后,知道 “0102030405060708” 是 vi偏移量,加密模式是 CryptoJS.mode.CBC。
然后回到反加密的過程,這里使用python編寫解密過程。參考了網上的教程和該加密算法的加解密過程,代碼如下:
PS:需要 Crypto 包

from Crypto.Cipher import AES import base64 import json # limit里面可以得到更多的評論,rid后加歌曲id # 下面參數通過控制台可以得到大部分,都是定值 # offset可以 first_param = '{rid: "R_SO_4_167844", offset: "120", total: "false", limit: "100", csrf_token: ""}' second_param = '010001' third_param = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7' fourth_param = '0CoJUm6Qyw8W8jud' def get_params(): #根據該加密算法做出解密 iv = '0102030405060708' first_key = fourth_param second_key = 16 * 'F' h_encText = AES_encrypt(first_param, first_key, iv) h_encText = AES_encrypt(h_encText, second_key, iv) return h_encText def get_encSeckey(): #這個也是定值 encSecKey = "257348aecb5e556c066de214e531faadd1c55d814f9be95fd06d6bff9f4c7a41f831f6394d5a3fd2e3881736d94a02ca919d952872e7d0a50ebfa1769a7a62d512f5f1ca21aec60bc3819a9c3ffca5eca9a0dba6d6f7249b06f5965ecfff3695b54e1c28f3f624750ed39e7de08fc8493242e26dbc4484a01c76f739e135637c" return encSecKey def AES_encrypt(text, key, iv): if type(text) == type(b'123'): #這是判斷當前變量的類型是bytes還是字符串,因為pycryptodome要 #求參數要是字節類型 text = text.decode('utf-8') pad = 16 - len(text) % 16 text = text + pad*chr(pad) iv = iv.encode('utf-8') key = key.encode('utf-8') encryptor = AES.new(key, AES.MODE_CBC, iv) text = text.encode('utf-8') encrypt_text = encryptor.encrypt(text) encrypt_text = base64.b64encode(encrypt_text) return encrypt_text if __name__ == '__main__': params = get_params() encSecKey = get_encSeckey() print(params.decode('utf-8')) print(encSecKey)
參考文章:
知乎:https://www.zhihu.com/question/36081767/answer/386606315
csdn:https://blog.csdn.net/weixin_40444270/article/details/81260638