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

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

💻网址

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

全部评论

相关推荐

工作职责 1、根据需求完成数据平台相关系统的前端开发与迭代,覆盖 Web 场景,移动端以响应式适配为主;2、在现有技术栈与规范下实现页面与交互,复用组件库与设计系统,保证交付质量与一致性;3、配合后端完成接口联调与问题排查,按期交付需求、修复缺陷并进行回归验证;4、基于常用图表库实现数据可视化,完成报表、看板和简单的交互分析;在指导下进行基础性能优化;5、遵循工程规范(代码风格、Git 流程、提交规范),参与代码评审与文档补充。任职要求1、2027届及之后毕业的在校生,本科及以上学历,计算机相关专业;2、熟练掌握 JavaScript/TypeScript 与 HTML/CSS,至少熟悉 Vue 或 React 其中一种,能独立完成中后台页面开发;3、熟悉常见前端工程化工具与包管理(Vite/Webpack、NPM/Yarn/Pnpm),会使用常见脚手架;4、能阅读 PRD/原型并快速还原设计,注重交互一致性与可用性;5、具备数据可视化开发经验,能使用 ECharts/AntV/G2Plot 等实现常见图表与图表联动;6、良好的沟通协作与时间管理能力,能按里程碑交付、响应问题并持续优化。面向对象2027届及之后毕业的在校生投递链接https://jobs.mihoyo.com/?sharePageId=121176&recommendationCode=052BT&isRecommendation=true#/campus/position/8148
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务