对 js加密数据进行爬取和解密
- 分析:
- 爬取的数据是动态加载
- 并且我们进行了抓包工具的全局搜索,没有查找到结果
- 意味着:爬取的数据从服务端请求到的是加密的密文数据
- 页面每10s刷新一次,刷新后发现数据更新,但是浏览器地址栏的url没有变,说明加载出的数据是由ajax请求到的。
- 动态加载出来的数据是由ajax请求到的,并且请求到的数据为加密数据
- 定位到ajax数据包,从中可以看到url和动态变化的请求参数和加密的相应数据
- 将ajax请求到的密文数据捕获
- 动态的获取动态变化的请求参数
- 基于抓包工具进行了动态变化请求参数taken的全局搜索,定位到了taken产生的源头,就是如下js代码:
- var token = md5(String(page) + String(num) + String(timestamp));
- 对密文数据进行解密
- 通过分析找到了解密的js函数:decode_str(encode_str),encode_str就是密文数据
- 查找encode_str的实现:
- js逆向:将js代码转换成python代码。开发环境只能执行python代码
- 首先将js代码中的ASCII码进行转换:
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) }
'\x64\x65\x63\x6f\x64\x65'.encode('utf-8') b'decode'
function decode_str(scHZjLUh1) { #Base64.decode(scHZjLUh1) scHZjLUh1 = Base64.decode(scHZjLUh1); key = 'nyloner'; len = key.length; code = ''; for (i = 0; i < scHZjLUh1.length; i++) { var coeFYlqUm2 = i % len; code += window.String.fromCharCode(scHZjLUh1.charCodeAt(i) ^ key.charCodeAt(coeFYlqUm2)) } return Base64.decode(code) }
- 代码实现:
import time import hashlib import requests import base64
将js代码装换成python代码:
#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
def getToken(): page = str(1) num = str(15) t = str(int(time.time())) md5 = hashlib.md5() md5.update((page+num+t).encode('utf-8')) token = md5.hexdigest() return token
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' } # 获取的是一个json串 code = requests.get(url,headers=headers,params=param).json().get('list') str_code = decode_str(code) str_code
下面是js代码中的获取数据和调用解密函数的部分代码:
function get_proxy_ip(page, num, click_btn) { var timestamp = Date.parse(new Date()); timestamp = timestamp / 1000; var token = md5(String(page) + String(num) + String(timestamp)); $.get('../proxy?page=' + page + '&num=' + num + '&token=' + token + '&t=' + timestamp, function (result) { if (result.status === 'true') { var setHtml = ""; $("#ip-list").html(setHtml); var encode_str = result.list; var items = str_to_json(decode_str(encode_str)); for (var index = 0; index < items.length; ++index) { item = items[index]; setHtml += "<tr>\n<td>" + (index + 1) + "</td>\n"; setHtml += "<td>" + item.ip.toString() + "</td>\n"; setHtml += "<td>" + item.port.toString() + "</td>\n"; setHtml += "<td>" + item.time.toString() + "</td>\n</tr>\n"; } $("#ip-list").html(setHtml); if (click_btn === 'next') { document.getElementById("last-page").disabled = false; if (items.length < 15) { document.getElementById("next-page").disabled = true; } } else { document.getElementById("next-page").disabled = false; if (page === 1) { document.getElementById("last-page").disabled = true; } } } }); }