成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供灞橋企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、HTML5、小程序制作等業(yè)務(wù)。10年已為灞橋眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計(jì)公司優(yōu)惠進(jìn)行中。
關(guān)注微信公眾號(hào):K哥爬蟲,持續(xù)分享爬蟲進(jìn)階、JS/安卓逆向等技術(shù)干貨!
本文章中所有內(nèi)容僅供學(xué)習(xí)交流,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無(wú)關(guān),若有侵權(quán),請(qǐng)聯(lián)系我立即刪除!
acw_sc__v2
加密分析aHR0cHM6Ly94dWVxaXUuY29tL3RvZGF5
acw_tc=...
我們的爬蟲目標(biāo)是:精華 —> 今日話題 —> X球熱帖,熱帖是 Ajax 加載的,很容易找到數(shù)據(jù)接口,接口沒(méi)有其他的加密參數(shù),主要是 cookie 里有一些值,沒(méi)有 cookie 是無(wú)法訪問(wèn)的,其中,cookie 里又有一個(gè) acw_sc__v2
的值,是通過(guò) JS 生成的,其他值都是首次訪問(wèn)首頁(yè)得到的,抓包如下:
我們清除一下 cookie,打開(kāi) F12 開(kāi)發(fā)者工具,刷新頁(yè)面,發(fā)現(xiàn)會(huì)進(jìn)入反調(diào)試,出現(xiàn)了無(wú)限 debugger,往上跟調(diào)用棧,可以看到這個(gè)方法里有一大串混淆后的代碼,拼接起來(lái)其實(shí)就是 debugger,如下圖所示:
過(guò)掉 debugger 也很簡(jiǎn)單,需要注意的是這個(gè)站比較刁鉆,第一次訪問(wèn)首頁(yè)直接是混淆的 JS 代碼,后面才會(huì)跳轉(zhuǎn)到正常的 HTML 頁(yè)面,如果你想本地替換 JS 的話,debugger 倒是過(guò)掉了,不過(guò)后續(xù)就有可能無(wú)法調(diào)試了,感興趣的朋友可以自己試試,這里K哥就直接右鍵 Never pause here 永不在此處斷下了:
我們觀察這個(gè)混淆代碼,直接搜索 acw_sc__v2
,可以看到最后面有設(shè)置 cookie 的操作,其中 x 就是 acw_sc__v2
的值:
我們往上跟調(diào)用棧,看看 x 是怎么得來(lái)的,這里 setTimeout 時(shí)間一到就會(huì)執(zhí)行 '\x72\x65\x6c\x6f\x61\x64\x28\x61\x72\x67\x32\x29'
,控制臺(tái)輸出一下會(huì)發(fā)現(xiàn)就是 reload 方法,傳入的參數(shù)是 arg2,arg2 的值就是 acw_sc__v2
的值,如下圖所示:
arg1 在頭部定義了,需要注意的是,每次刷新,這個(gè) arg1 會(huì)變,所以我們?cè)诤竺嫒≈禃r(shí)要?jiǎng)討B(tài)獲取,我們把關(guān)鍵代碼單獨(dú)拿出來(lái)分析一下:
var arg1 = '6A6BE0CAF2DC9A2ADBC2E8D21D48FD';
var _0x5e8b26 = _0x55f3('0x3', '\x6a\x53\x31\x59');
var _0x23a392 = arg1[_0x55f3('0x19', '\x50\x67\x35\x34')]();
arg2 = _0x23a392[_0x55f3('0x1b', '\x7a\x35\x4f\x26')](_0x5e8b26);
可以看到主要就是這個(gè) _0x55f3()
方法,如果你直接把這個(gè)方法扣下來(lái)的話,本地運(yùn)行會(huì)直接進(jìn)入死循環(huán),多調(diào)試幾遍就會(huì)發(fā)現(xiàn) _0x5e8b26
調(diào)用函數(shù)傳參每次都是一樣的,每次的結(jié)果也是一樣的,所以可以直接寫成定值,arg2 的 _0x23a392[_0x55f3('0x1b', '\x7a\x35\x4f\x26')]
其實(shí)就是用了一個(gè)匿名函數(shù),如下圖所示:
我們直接跟進(jìn)這個(gè)匿名函數(shù),可以看到里面同樣調(diào)用了很多 _0x55f3()
方法,我們直接在控制臺(tái)輸出一下,然后把結(jié)果直接拿到本地即可:
所有結(jié)果替換掉后,會(huì)發(fā)現(xiàn)還會(huì)依賴另一個(gè)匿名函數(shù),最后將這兩個(gè)匿名函數(shù)全部扣下來(lái)即可:
當(dāng)然如果遇到調(diào)用非常多 _0x55f3()
方法的情況,那就不可能挨個(gè)替換了,就需要進(jìn)一步分析該函數(shù)里面的邏輯,在本地單步調(diào)試,看是由于什么原因進(jìn)入了死循環(huán),里面非常多的 if-else 語(yǔ)句,肯定是缺少某個(gè)環(huán)境導(dǎo)致進(jìn)入 else 語(yǔ)句,從而導(dǎo)致死循環(huán)了,直接刪除 else 語(yǔ)句、補(bǔ)環(huán)境走 if 語(yǔ)句等做法都是可以的。
GitHub 關(guān)注 K 哥爬蟲,持續(xù)分享爬蟲相關(guān)代碼!歡迎 star !https://github.com/kgepachong/
以下只演示部分關(guān)鍵代碼,不能直接運(yùn)行! 完整代碼倉(cāng)庫(kù)地址:https://github.com/kgepachong/crawler/
/* ==================================
# @Time : 2021-12-29
# @Author : 微信公眾號(hào):K哥爬蟲
# @FileName: get_acw_sc_v2.js
# @Software: PyCharm
# ================================== */
var _0x5e8b26 = ''
var getAcwScV2 = function (arg1) {
String['prototype']['hexXor'] = function (_0x4e08d8) {
var _0x5a5d3b = '';
for (var _0xe = 0x0; _0xe < this['length'] && _0xe < _0x4e08d8['length']; _0xe += 0x2) {
var _0x401af1 = parseInt(this['slice'](_0xe, _0xe + 0x2), 0x10);
var _0x105f59 = parseInt(_0x4e08d8['slice'](_0xe, _0xe + 0x2), 0x10);
var _0x189e2c = (_0x401af1 ^ _0x105f59)['toString'](0x10);
if (_0x189e2c['length'] == 0x1) {
_0x189e2c = '0' + _0x189e2c;
}
_0x5a5d3b += _0x189e2c;
}
return _0x5a5d3b;
};
String['prototype']['unsbox'] = function () {
var _0x4b082b = [0xf, 0x23, 0x1d, 0x18, 0x21, 0x10, 0x1, 0x26, 0xa, 0x9, 0x13, 0x1f, 0x28, 0x1b, 0x16, 0x17, 0x19, 0xd, 0x6, 0xb, 0x27, 0x12, 0x14, 0x8, 0xe, 0x15, 0x20, 0x1a, 0x2, 0x1e, 0x7, 0x4, 0x11, 0x5, 0x3, 0x1c, 0x22, 0x25, 0xc, 0x24];
var _0x4da0dc = [];
var _0xe = '';
for (var _0x20a7bf = 0x0; _0x20a7bf < this['length']; _0x20a7bf++) {
var _0x385ee3 = this[_0x20a7bf];
for (var _0x = 0x0; _0x < _0x4b082b['length']; _0x++) {
if (_0x4b082b[_0x] == _0x20a7bf + 0x1) {
_0x4da0dc[_0x] = _0x385ee3;
}
}
}
_0xe = _0x4da0dc['join']('');
return _0xe;
};
var _0x23a392 = arg1['unsbox']();
arg2 = _0x23a392['hexXor'](_0x5e8b26);
return arg2
};
// 測(cè)試輸出
// var arg1 = 'D86A52A5BB43A13A80BAE6C4122A73';
// console.log(getAcwScV2(arg1))
# ==================================
# --*-- coding: utf-8 --*--
# @Time : 2021-12-29
# @Author : 微信公眾號(hào):K哥爬蟲
# @FileName: main.py
# @Software: PyCharm
# ==================================
import re
import execjs
import requests
index_url = "脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler"
news_test_url = "脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler"
headers = {
"Host": "脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler",
"Referer": "脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
}
def get_complete_cookie():
complete_cookie = {}
# 第一次不帶參數(shù)訪問(wèn)首頁(yè),獲取 acw_tc 和 acw_sc__v2
response = requests.get(url=index_url, headers=headers)
complete_cookie.update(response.cookies.get_dict())
arg1 = re.findall("arg1='(.*?)'", response.text)[0]
with open('get_acw_sc_v2.js', 'r', encoding='utf-8') as f:
acw_sc_v2_js = f.read()
acw_sc__v2 = execjs.compile(acw_sc_v2_js).call('getAcwScV2', arg1)
complete_cookie.update({"acw_sc__v2": acw_sc__v2})
# 第二次訪問(wèn)首頁(yè),獲取其他 cookies
response2 = requests.get(url=index_url, headers=headers, cookies=complete_cookie)
complete_cookie.update(response2.cookies.get_dict())
return complete_cookie
def news_test(cookies):
response = requests.get(url=news_test_url, headers=headers, cookies=cookies)
print(response.json())
if __name__ == '__main__':
complete_cookie = get_complete_cookie()
news_test(complete_cookie)