【爬虫JS逆向实战】某排排网数据解密逆向

0 阅读5分钟

声明:本文仅提供逆向思路方法,不提供完整代码,所有一切仅供学习交流使用,切勿使用爬虫脚本对网站进行高频率高并发数据爬取行为,如对网站造成损失的,后果自负!!!


💻网址

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)

解密需要的加密库实现了,接下来就是参数观察,未知的参数有:keydatas

  • 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公众号“小恰学逆向”,我们一起讨论学习。