声明
本教程只用于交流学习,不可用于商业用途,不可对目标网站进行破坏性请求,请遵守相关法律法规。
目标分析
确定目标
- 获取图片下载链接
目标检索
- 并不能搜索到链接明文数据,说明数据是动态渲染的。
- 查看发包,有一个
getData
很可疑,返回加密数据
- 添加XHR断点,切换页面触发函数
- 一步步走,找到密文数据
- 继续跟,找到明文数据,说明解密函数就在其中
- 进一步分析,可以找到解密处,
json parse
之后就从密文变成了明文,可见,这就是解密函数
代码补全
- 复制加密片段,控制台打印,发现
_0x1683d3['a']['decipher']
就是_0x58b5da
函数
out_data = JSON['parse'](_0x1683d3['a']['decipher'](_0x16dafc['data']['result']))
ori_code = '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'
out_data = JSON['parse'](_0x58b5da(ori_code))
console.log(out_data)
- 下面就是缺什么补什么,直接搜索加进去就好了
有一点需要注意的是,出现 ReferenceError: window is not defined
的情况 ,这是浏览器环境缺失,只要在开头添加一个 var window = global;
- 成功拿到明文数据
完整代码
var window = global;
function _0x3ef903(_0x44e9d9) {
for (var _0x39da63, _0x53f955, _0x16f530 = '', _0x134aef = 0x0; _0x134aef < _0x44e9d9['length'];)
_0x39da63 = _0x44e9d9[_0x134aef],
_0x53f955 = 0x0,
_0x39da63 >>> 0x7 === 0x0 ? (_0x16f530 += String['fromCharCode'](_0x44e9d9[_0x134aef]),
_0x134aef += 0x1) : 0xfc === (0xfc & _0x39da63) ? (_0x53f955 = (0x3 & _0x44e9d9[_0x134aef]) << 0x1e,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x1]) << 0x18,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x2]) << 0x12,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x3]) << 0xc,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x4]) << 0x6,
_0x53f955 |= 0x3f & _0x44e9d9[_0x134aef + 0x5],
_0x16f530 += String['fromCharCode'](_0x53f955),
_0x134aef += 0x6) : 0xf8 === (0xf8 & _0x39da63) ? (_0x53f955 = (0x7 & _0x44e9d9[_0x134aef]) << 0x18,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x1]) << 0x12,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x2]) << 0xc,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x3]) << 0x6,
_0x53f955 |= 0x3f & _0x44e9d9[_0x134aef + 0x4],
_0x16f530 += String['fromCharCode'](_0x53f955),
_0x134aef += 0x5) : 0xf0 === (0xf0 & _0x39da63) ? (_0x53f955 = (0xf & _0x44e9d9[_0x134aef]) << 0x12,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x1]) << 0xc,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x2]) << 0x6,
_0x53f955 |= 0x3f & _0x44e9d9[_0x134aef + 0x3],
_0x16f530 += String['fromCharCode'](_0x53f955),
_0x134aef += 0x4) : 0xe0 === (0xe0 & _0x39da63) ? (_0x53f955 = (0x1f & _0x44e9d9[_0x134aef]) << 0xc,
_0x53f955 |= (0x3f & _0x44e9d9[_0x134aef + 0x1]) << 0x6,
_0x53f955 |= 0x3f & _0x44e9d9[_0x134aef + 0x2],
_0x16f530 += String['fromCharCode'](_0x53f955),
_0x134aef += 0x3) : 0xc0 === (0xc0 & _0x39da63) ? (_0x53f955 = (0x3f & _0x44e9d9[_0x134aef]) << 0x6,
_0x53f955 |= 0x3f & _0x44e9d9[_0x134aef + 0x1],
_0x16f530 += String['fromCharCode'](_0x53f955),
_0x134aef += 0x2) : (_0x16f530 += String['fromCharCode'](_0x44e9d9[_0x134aef]),
_0x134aef += 0x1);
return _0x16f530;
}
function _0x3ed467(_0x58f7d4) {
for (var _0x4f1bcd = [-0x6f, 0x34, 0x5b, 0x41, -0x41, 0x74, 0x77, 0x6a, -0x79, -0x52, -0x5, 0x50, 0x33, 0x61, 0x44, -0x53, -0x70, -0x33, 0x17, -0x2e, -0x22, -0x72, -0x37, -0xb, -0x7f, 0x5a, 0x21, 0x16, -0x1f, 0x32, -0x11, 0x14, -0x2c, 0xf, -0x5e, -0x7b, 0x76, -0x17, -0x3d, 0x72, 0x47, -0x68, -0x7e, -0x75, -0x51, -0x36, -0x12, -0x6e, -0x4, -0x5f, -0x5b, 0x5e, -0x50, -0xe, 0x78, 0x69, 0x55, 0x68, -0x56, -0x6c, 0x43, 0x19, 0x65, 0x6c, 0x10, -0x69, 0x6f, -0xa, 0x75, -0x49, 0x4d, 0x59, -0x1d, -0x62, -0x44, 0x70, 0x6b, -0x1, 0x56, 0x79, 0x58, -0x65, -0x7c, 0x45, -0x1e, -0x8, -0x71, -0x4a, -0x76, 0x39, -0x19, 0xc, -0x73, -0x6a, 0x5f, 0x7f, 0x54, 0x7c, -0x66, -0x1c, 0x49, 0x2b, -0x3c, 0x1c, 0x2e, 0x73, 0x1e, 0x7a, -0x4b, 0x7d, -0x43, -0x4d, 0x3, -0x7, -0x35, -0xd, 0x35, 0x4e, -0x48, 0x1, 0xb, -0x47, -0x27, -0x4f, -0x3, 0x13, 0x29, 0x7e, -0x2b, -0x7d, -0x1b, 0x22, 0x3f, 0x8, 0x48, -0x23, -0x29, -0x3f, 0x3c, -0x18, 0x66, 0x2f, -0x77, -0x67, -0x16, 0x2d, 0x3b, 0x40, -0x60, 0x31, 0x53, -0x6b, -0x78, -0x39, -0x46, 0x0, -0x26, -0x54, -0x28, 0x18, 0xe, 0x30, 0x1d, 0x2c, -0x24, -0x2f, 0x38, -0x5c, 0x26, 0x25, 0x4, -0x32, 0x67, 0xa, -0x59, 0x37, 0x71, -0x1a, 0x6e, 0x36, 0x24, -0x14, -0x4e, -0xc, -0x74, 0x46, -0x25, 0x5, -0x3e, -0x4c, -0x30, -0x40, 0x4f, 0x64, 0x28, 0x6, -0x3a, -0x5a, -0x13, -0x9, 0x27, 0x5d, -0x63, 0x15, 0x7, 0x1a, -0x2, 0x1b, -0x2d, 0x51, 0x3a, -0x7a, 0x4c, -0x42, 0x2, 0x5c, -0x2a, 0x62, -0x10, 0x9, 0x3d, 0x3e, -0xf, 0x63, -0x15, 0x1f, -0x38, 0x57, 0x11, -0x34, -0x45, -0x21, -0x3b, -0x55, 0x42, 0x4a, 0x12, -0x5d, -0x80, -0x57, -0x20, 0x2a, 0x20, -0x58, 0x6d, 0x60, 0xd, -0x6, 0x4b, -0x64, -0x31, 0x23, -0x61, 0x52, -0x6d, 0x7b], _0x39eb66 = 0x0, _0x46445e = 0x0, _0x1360a5 = 0x0, _0x596013 = new Array(), _0x411913 = 0x0; _0x411913 < _0x58f7d4['length']; _0x411913++) {
_0x39eb66 = _0x39eb66 + 0x1 & 0xff,
_0x46445e = (0xff & _0x4f1bcd[_0x39eb66]) + _0x46445e & 0xff;
var _0x5e20d4 = _0x4f1bcd[_0x39eb66];
_0x4f1bcd[_0x39eb66] = _0x4f1bcd[_0x46445e],
_0x4f1bcd[_0x46445e] = _0x5e20d4,
_0x1360a5 = (0xff & _0x4f1bcd[_0x39eb66]) + (0xff & _0x4f1bcd[_0x46445e]) & 0xff,
_0x596013['push'](_0x58f7d4[_0x411913] ^ _0x4f1bcd[_0x1360a5]);
}
return _0x596013;
}
function _0x4207c2(_0x2219f6) {
for (var _0x9c7ad4 = window['atob'](_0x2219f6), _0x2dd788 = new Int8Array(_0x9c7ad4['length']), _0x7c7af6 = 0x0; _0x7c7af6 < _0x9c7ad4['length']; _0x7c7af6++)
_0x2dd788[_0x7c7af6] = _0x9c7ad4['charCodeAt'](_0x7c7af6);
return _0x2dd788;
}
function _0x563330(_0x1e29f9) {
return _0x3ef903(_0x3ed467(_0x4207c2(_0x1e29f9)));
}
爬虫逻辑
下面就是编写爬虫的 Python
代码逻辑
- 获取加密数据
- 调用JS解密
- 根据解密数据下载壁纸
完整代码
import os
import requests
import execjs
import json
def fetch_wallpaper_data(page=2, size=24):
"""从API获取壁纸数据。"""
url = 'https://api.zzzmh.cn/bz/v3/getData'
payload = {
"size": size,
"current": page,
"sort": 0,
"category": 0,
"resolution": 0,
"color": 0,
"categoryId": 0,
"ratio": 0
}
headers = {
'Referer': 'https://bz.zzzmh.cn/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
}
response = requests.post(url=url, json=payload, headers=headers)
return response.json()['result']
def compile_js():
"""编译JavaScript代码。"""
with open('极简壁纸.js', encoding='utf-8') as file:
js_code = file.read()
return execjs.compile(js_code)
def decode_wallpaper_data(js_compiler, data):
"""使用编译的JavaScript代码解码壁纸数据。"""
return json.loads(js_compiler.call('_0x563330', data))
def download_wallpaper(image_data, headers):
"""下载并保存壁纸。"""
if not os.path.exists('img'):
os.mkdir('img')
for wallpaper in image_data['list']:
num_suffix = '11' if wallpaper['t'] == 1 else '21'
img_id = f"{wallpaper['i']}{num_suffix}"
img_url = f'https://api.zzzmh.cn/bz/v3/getUrl/{img_id}'
img_content = requests.get(url=img_url, headers=headers).content
with open(f'img/{wallpaper["i"]}.jpg', mode='wb') as file:
file.write(img_content)
img_filename = f'img/{wallpaper["i"]}.jpg'
print(f'已下载壁纸:{img_filename}')
def main():
wallpaper_data = fetch_wallpaper_data()
js_compiler = compile_js()
decoded_data = decode_wallpaper_data(js_compiler, wallpaper_data)
headers = {
'Referer': 'https://bz.zzzmh.cn/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
}
download_wallpaper(decoded_data, headers)
if __name__ == '__main__':
main()