此分享只用於學習用途,不作商業用途,若有冒犯,請聯絡處理
反爬前置資訊
站點:aHR0cDovLzEyMC4yMTEuMTExLjIwNjo4MDkwL3hqendkdC94anp3ZHQvcGFnZXMvaW5mby9wb2xpY3k=
介面:/xjzwdt/rest/xmzInfoDeliveryRest/getInfoDeliveryList
破解結果預覽
何謂補環境
補環境其實是補瀏覽器有而Node沒有的環境,即補BOM和DOM的物件
,一切環境補的結果都是向瀏覽器實際結果靠齊,入門補環境只需要記住缺啥補啥這個技巧,當執行提示缺少某個環境,則直接在瀏覽器執行該環境是啥結果然後補上該結果。
反爬機制
站點有兩個反爬項,請求體加密
和響應結果解密
逆向研究
補環境處理的是關鍵程式碼,所以我們還是要定位到關鍵程式碼位置拿到關鍵程式碼
找到介面的呼叫堆疊,點選下面圖片標識的堆疊進入程式碼
在1
處打上斷點重新發起請求,在2
處可以看到這裡已經實現請求體加密
了,那我們得往前走,也就是點選3
處標識堆疊
然後在1
處打上斷點重新發起請求,點選2
處進入函式引用程式碼位置
這裡就能看到關鍵程式碼了,它重新封裝了ajax,請求體加密
和響應結果解密
都是在這裡進行的
但是我們要補的不是這個位置,因為我們又不是直接構建請求的,我們要破解的只是加解密,所以要補的是window.sm2Util.encrypt
和window.sm2Util.aesDecrypt
,而它們都在sm2Util.js
檔案中,接下來我們直接補sm2Util.js
程式碼就行。
注意直接拿全部程式碼,不要格式化
補環境
先直接執行程式碼,發現報下面所示錯誤,這是因為window
不是Node
的環境,這裡一般是使用global
替代
補好window
環境後再次執行報下面所示錯誤,繼續補navigator
補好navigator
環境後再次執行報下面所示錯誤,這是因為在瀏覽器環境下exports
是undefined
,但是在Node環境下exports
是Object
物件,所以這裡我們要處理
補好exports
後就不會報錯了
列印看看發現能拿到想要的方法了,這裡就初步補好環境了,要確定是否真正補全了還得執行一下程式碼,我們就拿除錯時拿到的請求體加密原文進行除錯
ok,這裡測試的請求體加密
成功了,說明encrypt
補好了,接下來測試下響應文字解密
,直接拿介面返回的響應文字測試即可
ok,這裡測試的響應文字解密
也成功了,也就說明咱們補好了。
補環境補充-掛代理
上面講解遇到缺失的環境都是物件本身,所以我們能直接知道缺了啥,然後對此做出處理。
但是如果缺失的是物件某個引數呢,比如下圖所示我們是沒法知道是哪個物件哪個引數出的問題的。大家可能會說不是有程式碼位置提示嗎,但是這是在明文程式碼下能清楚提示,遇到混淆程式碼就不行了,所以我們需要掛代理
所謂掛代理
其實就是使用Proxy
物件,它是一種物件代理機制,可以在物件和函式之間新增一箇中間層,從而實現對物件和函式的攔截和控制。
使用下面這段程式碼,新增想要監控的物件
function getEnv(proxy_array) {
for (var i = 0; i < proxy_array.length; i++) {
handler = `{\n
get: function(target, property, receiver) {\n
console.log('方法:get',' 物件:${proxy_array[i]}',' 屬性:',property,' 屬性型別:',typeof property,' 屬性值型別:',typeof target[property]);
return target[property];
},
set: function(target, property, value, receiver){\n
console.log('方法:set',' 物件:${proxy_array[i]}',' 屬性:',property,' 屬性型別:',typeof property,' 屬性值型別:',typeof target[property]);
return Reflect.set(...arguments);
}
}`;
eval(`
try {
${proxy_array[i]};
${proxy_array[i]} = new Proxy(${proxy_array[i]}, ${handler});
} catch (e) {
${proxy_array[i]} = {};
${proxy_array[i]} = new Proxy(${proxy_array[i]}, ${handler});
}
`)
}
}
這樣它會列印出呼叫的物件、屬性等資訊,這不就清晰多了。
我們在本案例測試,可以看到程式碼使用的全部環境了,然後看到哪些環境或者屬性是undefined
就把它補好。
程式碼展示
import json
import subprocess
from functools import partial
import requests
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8") # 修改全域性編碼
import execjs # 必須在修改編碼後引入
with open('sm2Utils.js', 'r', encoding='utf8') as fr:
str_data = fr.read()
js_code = execjs.compile(str_data)
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Language": "zh-CN,zh;q=0.9",
"Content-Type": "application/json;charset=UTF-8",
"Origin": "Origin",
"Referer": "Referer",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"encrypt": "1"
}
url = "url "
params = {
"foreSessionClusterIntercept": "true"
}
post_data = {"token": "Epoint_WebSerivce_**##0601",
"params": {"categuids": "4bcbbec7-2428-403a-8eed-b0db5c0e01a5", "titlename": "", "currpage": 0,
"pagesize": 10}}
print('encrypt data: ', json.dumps(post_data, separators=(',', ':')))
data = js_code.call('encrypt', json.dumps(post_data, separators=(',', ':')))
print('encrypt result: ', data)
response = requests.post(url, headers=headers, params=params, data=data, verify=False)
print('request result: ', response.text)
decrypt_result = js_code.call('decrypt', response.text)
print('decrypt result: ', decrypt_result)