14.js加密和js混淆
知識點
1.js加密
對於提交表單的數據進行加密
2.js混淆
JS混淆:對js函數的實現代碼進行加密
3.js逆向
//手動逆向
字節解密出來js代碼進行代碼執行
//模塊逆向
使用模塊PyExecJS
使用js執行我們的代碼
3.案列分析流程
3.1.某ip的爬取
1.判斷一個網站有沒有動態加載數據
查看response的數據是不是可以局部搜索到搜索到就部署動態加載數據 反之則是
1.2.捕獲動態加載數據
基於抓包工具進行全局搜索,最終可以定位到動態加載數據對應的數據包。
沒有搜索到對應的結果 就意味着 爬取的數據從服務端請求
2.判斷頁面每10s刷新一次,刷新數據沒有變說明是ajax請求的
3.2詳細流程
- 爬取的數據是動態加載
- 並且我們進行了抓包工具的全局搜索,沒有查找到結果
- 意味着:爬取的數據從服務端請求到的是加密的密文數據
- 頁面每10s刷新一次,刷新后發現數據更新,但是瀏覽器地址欄的url沒有變,說明加載出的數據是由ajax請求到的。
- 動態加載出來的數據是由ajax請求到的,並且請求到的數據為加密數據
- 定位到ajax數據包,從中可以看到url和動態變化的請求參數和加密的相應數據
- 將ajax請求到的密文數據捕獲
- 動態的獲取動態變化的請求參數
- 基於抓包工具進行了動態變化請求參數token的全局搜索,定位到了token產生的源頭,就是如下js代碼:
- var token = md5(String(page) + String(num) + String(timestamp));
- 對密文數據進行解密
- 通過分析找到了解密的js函數:decode_str(encode_str),encode_str就是密文數據
- 查找encode_str的實現:
- js逆向:將js代碼轉換成python代碼。開發環境只能執行python代碼
3.3具體解題思路
1.
查詢到是動態加載並且傳入的token是密文的,所以優先查看token
token是一串加密的數據優先查詢 因為是動態數據需要進行全局搜索
token: 6eaacd1a30be918477d14fa3c47b6810
var token = md5(String(page) + String(num) + String(timestamp));
#獲取token值
2.自己手寫一個md5加密 然后做出token值 等待發送 發送完之后 得到密文數據
proxy?page=' + page + '&num=' + num + '&token=' + token + '&t=' + timestamp對應的動態變換的值
#result 是返回的值
#result.list 就是返回的密文
#返回的值
{list: "OUofBg89Mwc2BS4HKzY7DCIVDRA/BDAUI","status":true}
var encode_str = result.list;
var items = str_to_json(decode_str(encode_str));#對密文進行解密
#對應decode的代碼
function decode_str(scHZjLUh1) {
#Base64.decode(scHZjLUh1)
scHZjLUh1 = Base64["\x64\x65\x63\x6f\x64\x65"](scHZjLUh1);
key = '\x6e\x79\x6c\x6f\x6e\x65\x72';#key = 'b'nyloner'
len = key["\x6c\x65\x6e\x67\x74\x68"];
code = '';
for (i = 0; i < scHZjLUh1["\x6c\x65\x6e\x67\x74\x68"]; i++) {
var coeFYlqUm2 = i % len;
code += window["\x53\x74\x72\x69\x6e\x67"]["\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65"](scHZjLUh1["\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74"](i) ^ key["\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74"](coeFYlqUm2))
}
return Base64["\x64\x65\x63\x6f\x64\x65"](code)
}
3.發現是編碼過的數據
使用utf-8對16進制字節進行轉換編碼格式
#"\x64\x65\x63\x6f\x64\x65".encode('utf-8')#重新編碼 這是16進制加密
4.#js逆向之后的結果
def decode_str(scHZjLUh1):
#解密成字符串
scHZjLUh1 = base64.decodestring(scHZjLUh1.encode())
key = 'nyloner'
lenth = len(key)
code = ''
sch_lenth = len(scHZjLUh1)
for i in range(sch_lenth):
coeFYlqUm2 = i % lenth
#chr(0-255)返回對應編碼的字符
#ord(a-z)返回編碼數值
code += chr(scHZjLUh1[i] ^ ord(key[coeFYlqUm2]))
code = base64.decodestring(code.encode())
code = code.decode('utf-8')
return code
5.然后就獲取了對應值進行相同格式的加密
var token = md5(String(page) + String(num) + String(timestamp));
token = getToken()
url = 'https://nyloner.cn/proxy'
param = {
'num':'15',
'page':'1',
't':str(int(time.time())),
'token':token
}
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
'Cookie':'sessionid=20ryihg87smnkko2kx6634jbcf4umhfp'
}
code = requests.get(url,headers=headers,params=param).json().get('list')
str_code = decode_str(code)#對獲取的數據進行解碼
str_code#打印獲取的數據
圖解
1.查找token值
全局搜索

某氣象站的爬取
流程
白話分析
1.首先判斷頁面是否是動態加載的
發現局部搜索不到說明是動態加載的數據
2. 使用全局搜索也搜索不到說明進行了加密
1.通過點擊a標簽的事件(推薦使用火狐)
2. 尋找到點擊事件 執行對應的getdata函數
'''
$("#btnSearch").click(function(){
getData();
});
'''
3.執行getData DATA內部有一個按小時的封裝
type為hour
1.內部封裝了兩個函數
getAQIData();
getWeatherData();
2.
function getAQIData()
{
var method = 'GETDETAIL';
var param = {};
字典內封裝了city,type,startTime,endTime
param.city = city;
param.type = type;
param.startTime = startTime;
param.endTime = endTime;
getServerData(method, param, function(obj)
function getWeatherData()
{
var method = 'GETCITYWEATHER';
var param = {};
param.city = city;
param.type = type;
param.startTime = startTime;
param.endTime = endTime;
getServerData(method, param, function(obj)
4.兩個函數的共同點內部都維護一個相同的字典
1.局部查詢Serverdata查詢不到
2.全局查詢Serverdata 查詢到了一加密js代碼
5.暴力破解js代碼
分析getServerData函數的實現:
終於找到了ajax請求對應的代碼
參數d的構成:getParam(method, object)返回
method:method
object:param字典,四個鍵值分別是城市名稱。type,起始時間,結束時間
請求到的密文數據的解密方式:
decodeData(data):data參數就是響應的密文數據,返回值就是解密后的原文 數據
6. JS逆向:
使用 PyExecJS 庫來實現模擬JavaScript代碼執行。
環境的安裝:
pip install PyExecJS
必須還要安裝nodeJs的開發環境
安裝nodejs
具體代碼實現
import execjs
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
node = execjs.get()
file = 'test.js'
ctx = node.compile(open(file,encoding='utf-8').read())
#如何五個變量會作為getPostParamCode的參數
method = 'GETDETAIL'#GETCITYWEATHER
city = '北京'
type = 'HOUR'
start_time = '2018-01-25 00:00:00'
end_time = '2018-01-25 23:00:00'
#模擬執行getPostParamCode函數
js = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)
params = ctx.eval(js)
# print(params)#請求參數
url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
data = {
'd':params
}
#獲取了加密的響應數據
response_code = requests.post(url=url,headers=headers,data=data).text
# response_code
#模擬執行decodeData函數對密文數據進行解密
js = 'decodeData("{0}")'.format(response_code)
page_text = ctx.eval(js)
print(page_text)
為什么火狐比谷歌更容易查看點擊事件
上圖
谷歌!

火狐

如果所示
1.火狐可以更加清晰的看出點擊事件的觸發 谷歌只能查看對應的返回值
2.谷歌的代碼沒有js代碼自動換行 火狐內部做了處理可以查看函數的整體架構
但是火狐的一些搜索有點冗余
