声明:本文仅提供逆向思路和方法,不提供完整代码,所有一切仅供学习交流使用,切勿使用爬虫脚本对网站进行高频率或高并发数据爬取行为,如对网站造成损失的,后果自负!!!
💻网址
68747470733a2f2f64632e73696d7577616e672e636f6d2f
🚩目标
下图页面中的数据就是我们需要爬取的内容
🔍观察
响应:data疑似为加密内容,key未知,看起来像一串JS代码
利用hook的方式,找寻解密的位置
// hook脚本
(function () {
var _parse = JSON.parse;
JSON.parse = function (value) {
debugger;
return _parse(value);
}
})()
解密位置
主要JS代码
let e = MD5(key)
, t = UTF8[__Ox11208b[5]](e)
, r = UTF8[__Ox11208b[5]](e[__Ox11208b[6]](16, 32))
, n = AES[__Ox11208b[7]](window[__Ox11208b[4]](datas), t, {
iv: r,
padding: pkcs7
}).toString(UTF8);
data = JSON[__Ox11208b[5]](n)
代码中存在混淆,可以根据浏览器中的提示更改代码,增强可读性
还原的JS代码
let e = MD5(key)
, t = UTF8["parse"](e)
, r = UTF8["parse"](e["slice"](16, 32))
, n = AES["decrypt"](window["atob"](datas), t, {
iv: r,
padding: pkcs7
}).toString(UTF8);
data = JSON["parse"](n)
代码中疑似使用了AES解密,可以将源代码改写为使用node环境中的crypto-js加密库来测试一下该段JS解密代码是否被魔改
const CryptoJS = require("crypto-js"); // 下载:npm install crypto-js
let e = MD5(key)
, t = CryptoJS.enc.Utf8.parse(e)
, r = CryptoJS.enc.Utf8.parse(e["slice"](16, 32))
, n = CryptoJS.AES.decrypt(window["atob"](datas), t, {
iv: r,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
data = JSON["parse"](n)
其中代码中还有个MD5加密,经测试未被魔改,所以直接用本地库md5实现
window = global;
const CryptoJS = require("crypto-js"); // 下载:npm install crypto-js
const MD5 = require('md5'); // 下载:npm install md5
let e = MD5(key)
, t = CryptoJS.enc.Utf8.parse(e)
, r = CryptoJS.enc.Utf8.parse(e["slice"](16, 32))
, n = CryptoJS.AES.decrypt(window["atob"](datas), t, {
iv: r,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
data = JSON["parse"](n)
解密需要的加密库实现了,接下来就是参数观察,未知的参数有:key,datas
- key值:不是固定值,可以先固定作测试用
- datas值:加密值,可以先固定
测试代码
输出结果
这样看来,我们需要逆向的只有key值,datas值是请求接口传过来的值,先实现解密函数,后续通过python脚本请求加密过的数据,然后通过解密函数进行解密即可得到我们需要的数据
🔀key值逆向
在我们找到的解密函数的位置往上翻,可以找到一段疑似生成key值的位置
let key = ( () => {
let code = data[__Ox11208b[0]]
, key = eval(__Ox11208b[14] + data[__Ox11208b[15]]);
return code === 3 ? key = key[__Ox11208b[19]](__Ox11208b[16])[__Ox11208b[18]]()[__Ox11208b[17]](__Ox11208b[16]) : code === 4 ? key = key[__Ox11208b[6]](2) : code === 5 ? key = key[__Ox11208b[6]](0, key[__Ox11208b[20]] - 2) : code === 6 ? key = key[__Ox11208b[6]](1, key[__Ox11208b[20]] - 1) : code === 7 ? key = key[__Ox11208b[6]](2, key[__Ox11208b[20]] - 1) : code === 8 ? key = key[__Ox11208b[6]](1, key[__Ox11208b[20]] - 2) : code === 9 ? key = key[0] + key[__Ox11208b[6]](2, key[__Ox11208b[20]]) : code === 10 && (key = key[__Ox11208b[6]](0, key[__Ox11208b[20]] - 2) + key[key[__Ox11208b[20]] - 1]),
key
}
)()
同样的,下面是反混淆后的代码
let key = ( () => {
let code = data["encode"]
, key = eval("window." + data["id"]);
return code === 3 ? key = key["split"]("")["reverse"]()["join"]("") : code === 4 ? key = key["slice"](2) : code === 5 ? key = key["slice"](0, key["length"] - 2) : code === 6 ? key = key['slice'](1, key['length'] - 1) : code === 7 ? key = key['slice'](2, key['length'] - 1) : code === 8 ? key = key['slice'](1, key['length'] - 2) : code === 9 ? key = key[0] + key['slice'](2, key['length']) : code === 10 && (key = key['slice'](0, key['length'] - 2) + key[key['length'] - 1]),
key
}
)()
在代码中有一个未知量:data
有点眼熟,看一下数据接口接收到的数据
在这里需要注意的是,在代码中有一个eval函数执行了一个方法
经测试,这个方法就是接口接收到的key值中的代码,所以我们在写解密函数时需要注意一下,如果不更改这个位置的话,代码会报错,因为在node环境中并没有window.p177156830218083714116这个方法,这个方法是在浏览器中实时挂载的,为了不去进行多余的操作,只需要将eval函数中参数改为我们得到的JS代码即可。
📑解密函数
window = global;
const CryptoJS = require("crypto-js"); // 下载:npm install crypto-js
const MD5 = require('md5'); // 下载:npm install md5
function get_decrypt_data(data) {
let key = ( () => {
let code = data["encode"]
, key = eval(data["key"]);
return code === 3 ? key = key["split"]("")["reverse"]()["join"]("") : code === 4 ? key = key["slice"](2) : code === 5 ? key = key["slice"](0, key["length"] - 2) : code === 6 ? key = key['slice'](1, key['length'] - 1) : code === 7 ? key = key['slice'](2, key['length'] - 1) : code === 8 ? key = key['slice'](1, key['length'] - 2) : code === 9 ? key = key[0] + key['slice'](2, key['length']) : code === 10 && (key = key['slice'](0, key['length'] - 2) + key[key['length'] - 1]),
key
}
)();
var datas = data['data']
let e = MD5(key)
, t = CryptoJS.enc.Utf8.parse(e)
, r = CryptoJS.enc.Utf8.parse(e["slice"](16, 32))
, n = CryptoJS.AES.decrypt(window["atob"](datas), t, {
iv: r,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
_data = JSON["parse"](n)
return _data;
}
// 测试数据
var data = {}; // 自己自行填写
console.log(get_decrypt_data(data));
解密如下
如有爬虫相关问题,可关注wx公众号“小恰学逆向”,我们一起讨论学习。