当前位置: 首页 > backend >正文

爬虫逆向--Day20Day21--JS逆向案例之Webpack逆向

一、JS逆向案例之Webpack逆向

1.1、Webpack逆向概念介绍

Webpack是一个现代的静态模块打包工具,它主要用于前端开发中的模块化打包和构建。通过Webpack,开发者可以将多个模块(包括JavaScript、CSS、图片等)进行打包,生成优化后的静态资源文件,以供在浏览器中加载和运行。

Webpack的主要功能和特点包括:

  1. 模块化支持:Webpack将应用程序拆分为多个模块,通过模块化的方式管理和加载依赖关系。它支持CommonJS、ES module、AMD等多种模块化规范,并且能够将这些模块打包成最终的静态资源文件。

  2. 打包和压缩:Webpack可以将多个模块打包成一个或多个最终的静态资源文件。它支持对JavaScript、CSS、图片等资源进行压缩、合并和优化,以减小文件大小,提升加载速度和性能。

  3. 资源加载管理:Webpack可以处理各种类型的资源文件,例如JavaScript、CSS、图片、字体等。通过加载器(Loader)的配置,Webpack可以对这些资源文件进行转换和处理,使其能够被应用程序正确地引用和加载。

/*
// 数组格式
!function(形参){加载器}([模块1,模块2,...])// 字典格式   
!function(形参){加载器}({"k1":"模块1","k2":"模块2"}) 整体看上去就是一个自执行函数
*/

// 数组格式
window = global;
!function (e) {var t = {};function n(r) {if (t[r])return t[r].exports;var o = t[r] = {i: r,l: !1,exports: {}};e[r].call(o.exports, o, o.exports, n);return o.exports.exports; }window.loader = n;// n("1002");
}([ function () {console.log("foo");this.exports = 100; },function () {console.log("bar");this.exports = 200;}]
);console.log(window.loader(0));
console.log(window.loader(1));

// 字典对象格式
window = global;
!function (e) {var t = {};function n(r) {if (t[r])return t[r].exports;var o = t[r] = {i: r,l: !1,exports: {}};e[r].call(o.exports, o, o.exports, n);return o.exports.exports; // 返回 o.exports.exports,而不是整个 o.exports 对象}window.loader = n;// n("1002");
}({"1001": function () {console.log("foo");this.exports = 100; // 直接修改 exports 变量},"1002": function () {console.log("bar");this.exports = 200;}
});console.log(window.loader("1001"));

1.2、Webpack理解

image

image

image

 备注:

var t = {};    // t就是一个缓冲池 把每次调用过的都放到缓存池

function n(r) {}    // 这个n函数就是【加载器函数】调用模块的一种方式,是固定格式的

【这个方法一定要认识,可能有些变量不一样,但结构一定是这样的】

if (t[r])           // 先判断缓冲池中是否有,有的话,从缓冲池中执行return t[r].exports;

image

image

1.3、Webpack关键点

1. 流程
(1) 全局变量配置:在整个项目都可以调用这个加载器函数
(2) 记录调用模块的日志
2. 初始化调用模块的注释问题

1.3.1、全局变量配置

加载器函数n只能在该作用域使用,如果想在整个项目都可以调用这个加载器函数n,就需要配一个全局变量

image

// 字典对象格式
window = {}   // 或 window = global  声明一个全局作用域
!function (e) {var t = {};function n(r) {if (t[r])return t[r].exports;var o = t[r] = {i: r,l: !1,exports: {}};e[r].call(o.exports, o, o.exports, n);return o.exports.exports; // 返回 o.exports.exports,而不是整个 o.exports 对象}// n("1002");   // barconsole.log(n("1002"))   // bar  200// 在加载器下面加一个属性,属性名可以任意,这里我们叫loader// 把加载器函数写入到了loader中,方便在外面直接调用window.loader = n}({"1001": function () {console.log("foo");this.exports = 100;},"1002": function () {console.log("bar");this.exports = 200;}
});// 在外部的任何地方都可以使用该方式进行调用,只要能拿到window就可以
window.loader("1002")

1.3.2、记录调用模块日志

补充:单文件webpack和多文件的webpack

image

 所以说明当函数在调用"1002"的时候,因为找不到报错误了,然后我们就需要想办法去源代码中去搜索"1002"这个function,然后把这个代码加进来就好了

1.3.3、初始化调用模块的注释问题

image

 1.3.4、最终代码

// 字典对象格式
window = {}   // 或 window = global  声明一个全局作用域
document = {}
navigator = {}
!function (e) {var t = {};function n(r) {if (t[r]) return t[r].exports;var o = t[r] = {i: r, l: !1, exports: {}};console.log("调用模块名:::",r)e[r].call(o.exports, o, o.exports, n);// 返回 o.exports.exports,而不是整个 o.exports 对象return o.exports.exports;}window.loader = n// 在实际的开发中,往往n会加很多的属性,有很多属性赋值的,前面的这个对象n,对应的函数就是加载器函数// n.o = function (){}// n.a = function (){}// n.b = function (){}// 初始化// console.log("1001")}({"1001": function () {console.log("test1001");window.loader("1002")console.log(document.cookie)console.log(navigator.userAgent)this.exports = 100;},"1002": function () {console.log("test1002");window.loader("1003")this.exports = 200;},"1003": function () {console.log("test1003");this.exports = 300;},
});// 在外部的任何地方都可以使用该方式进行调用
window.loader("1002")

 1.4、案例【33搜帧】

案例地址链接:https://fse.agilestudio.cn/search?keyword=%E7%81%AB%E8%BD%A6%E5%91%BC%E5%95%B8%E8%80%8C%E8%BF%87

案例爬取链接:https://fse-api.agilestudio.cn/api/search?keyword=%E7%81%AB%E8%BD%A6%E5%91%BC%E5%95%B8%E8%80%8C%E8%BF%87&page=1&limit=12&_platform=web&_versioin=0.2.5&_ts=1756434489229

1.4.1、入口定位

我们拿到网站首先还是先看那些是需要我们进行破解的对象

先看响应数据--响应数据是明文的,无需关注

再看载荷数据--是查询字符串参数,params,就一个时间戳_ts有点可疑

其次再看请求头--有一个x-signature: 是加密数据,需要特别关注

image

 我们找到我们需要爬取目标地址链接,复制URL,用【https://curlconverter.com/ 】生成基础爬虫代码

image

 我们通过key关键字【X-Signature】进行搜索确定入口,就搜索到了一个匹配项,点击进入就是我们的入口,在搜索的地方打上断点,卡在该处,并且通过url和参数确定该处就是我们要找的入口位置

image

1.4.2、代码分析

确定入口以后,点击进入函数的原始位置

image

1.4.3、扣JS

image

1.4.4、补充【】

image

image

 正常操作,就是报什么找什么,我们就是搜索什么然后打断点定在该处,看找不到的是function还是对象还是列表,不管是什么直接把对应的代码拷走,但是这次你会发现c是一个对象是什么不重要,重要的是往上看c的格式有点特殊,当看到这样的格式时,咱们要找的某个变量比如c来自于n(数字/key)比如:c=n("b85c") 这样的格式时就是典型的webpack,n是加载器,加载了某个key模块,c是模块对象,从这个模块对象中取出这个a,这个a可能是一个函数或者一个值

遇到这样的情况,我们就需要先找到这个n加载器函数,所以我们首先在报找不到的地方比如报c找不到,那就在c这里打上断点,一般这样的事件都是需要刷新页面触发,所以我们刷新页面让断点卡在该处,点击进入找到n加载器函数

image

 点击进入加载器函数

image

很多网站都是把这个自执行函数放在js文件中,该案例是放在了html中,我们只需要扣走这个自执行函数即可
扣出来以后,单独建一个文件loader.js文件存放扣出来的全部代码 ,然后就开始思考这是一个单文件还是一个多文件
一定是多文件的
如果我们调用的模块都在下面的列表中,我们只需要拿走对应的列表或者模块就行
但是我们要用到的模块可以说是没有,或者不够,这就说明还有一些模块在别的位置,这就涉及到多文件查询,一般多文件查询多一点

image

1. 流程(1) 全局变量配置:在整个项目都可以调用这个加载器函数   加上分隔符 !(2) 记录调用模块的日志
运行该文件,不报任何错误,证明扣的该自执行函数没问题

image

 在第一次创建的js文件,测试中,引入扣出来的自执行函数,由于是多文件webpack所以就会报找不到的模块

我们在根据缺失的模块进行全局搜索

require("./loader")   // 引入加载器函数所在的文件
console.log(window.loader("b85c"))

image

 把模块所在的文件,全部拷贝走 Ctrl+A   Ctrl+C,因为可能会有多个模块文件,所以可以创建文件名为mod01.js

同样在第一次创建的js文件,测试中,引入扣的模块文件   

require("./mod01") // 引入拷贝的模块文件

image

 这个时候所有的依赖全部补充完成,我们就可以替换了

image

image

image

image

1.4.5、代码文件

1.4.5.1、Python文件:33搜帧.py
import requests
import execjsheaders = {'Accept': 'application/json, text/plain, */*','Accept-Language': 'zh-CN,zh;q=0.9','Connection': 'keep-alive','Origin': 'https://fse.agilestudio.cn','Referer': 'https://fse.agilestudio.cn/','Sec-Fetch-Dest': 'empty','Sec-Fetch-Mode': 'cors','Sec-Fetch-Site': 'same-site','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',# 'X-Signature': 'ec61eb8eefc752b6d0d5eee0657958e0',   # 可以直接删除了'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"','sec-ch-ua-mobile': '?0','sec-ch-ua-platform': '"Windows"',
}
params = {'keyword': '火车呼啸而过','page': '2','limit': '12','_platform': 'web','_versioin': '0.2.5',# '_ts': '1756434489229',
}obj = execjs.compile(open("33搜帧.js", encoding="utf-8").read()).call("get_sign", params)headers["X-Signature"] = obj["Signature"]
params["_ts"] = obj["ts"]url = 'https://fse-api.agilestudio.cn/api/search'
response = requests.get(url=url, params=params, headers=headers)
print(response.text)
1.4.5.2、JS文件:33搜帧.js
require("./loader")   // 引入加载器函数所在的文件
require("./mod01")   // 引入拷贝的模块文件
// console.log(window.loader("b85c"))n = window.loader
c = n("b85c")u = n("6821")
l = n.n(u)d = function (e) {e._ts = (new Date).getTime() - 9999;var t, n = Object.keys(e), i = "", o = Object(c["a"])(n.sort());try {for (o.s(); !(t = o.n()).done;) {var a = t.value;void 0 !== e[a] && null !== e[a] && (i += "".concat(a, "=").concat(e[a], ","))}} catch (r) {o.e(r)} finally {o.f()}return {Signature: l()(i),ts: e._ts}}// 测试
function get_sign(data) {return d(data)
}// let data = {
//     "keyword": "火车呼啸而过",
//     "page": 1,
//     "limit": 12,
//     "_platform": "web",
//     "_versioin": "0.2.5"
// }
// console.log(get_sign(data))
1.4.5.3、存放自执行函数的文件:loader.js   

image

1.4.5.4、存放模块的文件:mod01.js

image

http://www.xdnf.cn/news/19576.html

相关文章:

  • GPT-5在医疗领域应用的研究效能初探(下)
  • iOS混淆工具实战 视频流媒体类 App 的版权与播放安全保护
  • 【Python语法基础学习笔记】竞赛常用标准库
  • 在 macOS 下升级 Python 几种常见的方法
  • 矩阵scaling预处理介绍
  • 自动化运维-ansible中的循环应用
  • Maven + JUnit:Java单元测试的坚实组合
  • MYSQL 认识事务
  • 大数据生态系统全景图:Hadoop、Spark、Flink、Hive、Kafka 的关系
  • three.js手机端的4种旋转方式
  • 优秀开源内容转自公众号后端开发成长指南
  • Java-114 深入浅出 MySQL 开源分布式中间件 ShardingSphere 深度解读
  • Linux 文本处理实战手册
  • 销售事业十年规划,并附上一套能帮助销售成长的「软件工具组合」
  • 爬虫实战练习
  • C 基础(1) - 初识C语言
  • 2025年数字化转型关键证书分析与选择指南
  • compile_commands.json 文件详解
  • Linux基础2
  • (3dnr)多帧视频图像去噪 (一)
  • GDAL 简介
  • C++ multiset数据结构的使用情况说明
  • 基于单片机智能饮水机/智能热水壶
  • 正式发布!2025AI SEO公司哪家专业?
  • 【数据分享】多份土地利用矢量shp数据分享-澳门
  • C# FlaUI win 自动化框架,介绍
  • 员工自愿放弃社保,企业给补贴合法吗?
  • Vue3 中 Proxy 在组件封装中的妙用
  • Windows 使用 Compass 访问MongoDb
  • 【HarmonyOS】一步解决弹框集成-快速弹框QuickDialog使用详解