WebPack站点实战(一)

news/2025/1/8 0:43:10/文章来源:https://www.cnblogs.com/o-O-oO/p/18658758

以下文章来源于一位不愿透露姓名的热心网友 ,作者不愿透露姓名的热心网友

文章配套B站视频,很多话语简略了,建议配着视频看。

地址:https://www.bilibili.com/video/BV13F411P7XB/

开始之前了,简单过一下下面几个方法加深印象,便于更好理解加载器。也可以直接从webpack标题开始看起。

Function/函数/方法

常规的js函数命名方法:

//1. 常规function
var test = function(){console.log(123);
}function test(){console.log(2);
}

今天的主角,自执行函数。

//2. 自执行function
!function(){console.log(1);
}()
// => function a(){} a() //2.1
!function(e){console.log(e)var n={t:"txt",exports:{},n:function(){console.log("function n ")}
}
}("echo this")//2.2
!function(e){console.log(e)var n={t:"txt",exports:{},n:function(){console.log("function n ")}}
}({"test":function(){console.log("test")}}    
)
//(["test":function(){console.log])

call/apply Function

[Fcuntion prototype call and applay ](Function.prototype.call() - JavaScript | MDN (mozilla.org))

允许为不同的对象分配和调用属于另一个对象的函数/方法。

call和apply的使用效果基本一致,可以让A对象调用B对象的方法:

Vx对象调用_x对象的say()方法

var Vx={name:"一位不愿透露姓名的热心网友",age:"18cm"
};
var _x={name:"热心网友",age:"18mm",say:function(){console.log("name:"+this.name+" age:"+this.age)}
}
_x.say.call(Vx)
//name:一位不愿透露姓名的热心网友 age:18cm

Webpack

webpack 一个静态模块打包器,有入口、出口、loader 和插件,通过loader加载器对js、css、图片文件等资源进行加载渲染。

实战站点:https://spa2.scrape.center/

WebPack 站点长什么样

方法1: 右键查看源码发现只会有js链接文件,没有其他多余的前端信息,f12看元素就会有很多数据。

方法2: 看Js文件,一般会有一个app.xxxx.js或长得像MD5的文件名,然后js内容有很多a、b、c、d、n...的变量来回调用,反正就是看着乱。

loader加载器

Webpack站点与普通站点的JS代码扣取是不一样的,因为Webpack站点的资源加载是围绕着加载器进行的,然后把静态资源当作模块传入调用传入的模块就是参数,需要加载什么就运行什么模块。

先简单看一下加载器长相。

!function(e){var t={}function d(n){if (t[n])return t[n].exports;console.log(n)var r = t[n] = {i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,d),r.l = !0;r.exports}d(1)}([function(){console.log("function1");console.log(this.r.i)},function(){console.log("function2")}]
);

加载器分析

将加载器拆分为两部分:

1、函数方法部分:

!function(e){var t={}function d(n){if (t[n])return t[n].exports;var r = t[n] = {i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,d),r.l = !0;r.exports}d(1)
2、参数部分:

(
[
function(){console.log("function1");console.log(this.r.i)}
,
function(){console.log("function2")}
]
)
/* 这里的参数可以是传入数组,也可以是对象,都是经常看见的。
*/
(
{
"1":function(){console.log("function1");console.log(this.r.i)}
,
"2":function(){console.log("function2")}
}
)

这里的加载器是将参数作为一个数组`[` `]`传入的,格式为:`!function(e){}(数组) ` 参数e就是传入的数组, 接着看:

var t={}
function d(n){
if (t[n])
return t[n].exports;
var r = t[n] = {
i:n,
l:!1,
exports:{}
};
return e[n].call(r.exports,r,r.exports,d),
r.l = !0;
r.exports
}
d(1)

上述代码声明了一个d方法并执行,传入1作为参数,d方法中的if (t[n])并没有实际意义,因为t本来就没有声明的,可以缩减为:

function d(n){
var r = t[n] = {
i:n,
l:!1,
exports:{}
};
return e[n].call(r.exports,r,r.exports,d),
r.l = !0;
r.exports
}
d(1)

那么r=t[n]={ xxxx} 可以变成 var r = { xxx},现在就剩下一句:```
return e[n].call(r.exports,r,r.exports,d)
```前面说过了,e是传入的参数,也就是数组;n是d(1)传入的值,为1。r.exports 就是r对象里的exports属性为空对象{}。转化代码:

return 数组[1].call({},r对象,{},d函数自己)

--> 继续转换:

function(){
console.log("function2")
}.call({},r对象,{},d函数)

由于call()方法是用于调用方法的,所以其他参数可以忽略,缩减为:```
function(){
console.log("function2")
}.call(d函数)
```加载器并没有太多实际的意义,就是自己调用自己,只是用来混淆的;经过分析后代码可以直接缩减为(当然,只是针对现在这个例子):

!function(e){
var t={}
console.log("自执行传入的参数是:"+e)
function d(n){

    return e[n].call(d)
}d(1)

}(
[
function(){console.log("function1");console.log()},
function(){console.log("function2")}
]
);

![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108002810170-900043846.png)###分离加载在模块较多的情况下,webpack会将模块打包成一整个JS模块文件;并使用Window对象的webpackJsonp属性存储起来。然后通过push()方法传入模块。如下:
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108002854461-2031823606.png)格式为:
```(window["webpackJsonp"] =window["webpackJsonp"] || [] ).push([["xx"], {"module":function(){}} ]);
```运行结果:可以理解为appen追加内容,向webpackJsonp属性追加了[xx],和mod数组
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108002923123-71220055.png)###总结通过两个加载器的两个例子可以看出,加载器的重要性;webpack站点能否成功解析,是围绕着loader加载器和模块资源进行的,加载器好比是一口锅,而模块好似食材;将不一样的食材放入锅中,烹饪的结果都是不一样的。#WebPack实战
###分析加密Webpack站点分析的思路主要以下两点:1、首先找到食材,也就是定位到加密模块2、其次找到锅,loader加载器3、使用加载器去加载模块在这里的的难点就是定位加密模块,因为调用加密的地方肯定是只有固定的一两个点,如:登录提交。而加载器则什么地方都在调用(网站图片、css、js等资源  都是通过加载器加载出来的)在上一文[《JS逆向|40分钟视频通杀大厂登陆加密》](https://mp.weixin.qq.com/s?__biz=MzkzODEzNjA3MQ==&mid=2247485456&idx=1&sn=839bffe306d8fa8563bce289cf352791&scene=21#wechat_redirect)视频中已经讲解了常规加密的快速定位办法,在webpack站点中使用这种定位办法也有概率可能会有效,其实加密点也是有规律的,如:
```//1. 
xxxxx{a:e.name,data:e.data,b:e.url,c:n
}
```这种键值对格式的跟`ajax`请求长得很相似,有可能是请求赋值的地方,也不绝对,只是大家注意就好。访问站点右键源码就能发现这是一个webpack网站,数据并不存在于源码之中,是通过XHR获取的JSON数据。![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003036468-919025925.png)发现是这么一个URL请求的:
```
https://spa2.scrape.center/api/movie/?limit=10&offset=0&token=ODkxMjNjZGJhYjExNjRkYTJiMmQzMWY3NGY2NTE5YjZlNGIyN2M5YiwxNjU5MzM4MDg4
```翻页观察发现,limit固定不变,offset每次增加10。两个参数分别是展示的数量与展示的开始位置,token是什么信息暂时未知,但是是必须要解开是。通过XHR网络断点对所有XHR请求URL进行匹配,只要URL内包含api/movie关键词就进行下断。
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003121212-415795609.png)成功断下会展示具体在哪个uRL断的
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003141584-1140395260.png)观察堆栈挨个找
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003155508-1462533571.png)具体找法视频内会详细讲,文字太麻烦了 :sleepy:,一系列操作之后,定位到了加密位置onFetchData:```
Object(i["a"])(this.$store.state.url.index, a)
```![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003221729-677985404.png)this.$store.state.url.index和e分别是 /api/movie,0(url中的offset翻页值)
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003236212-409388644.png)加密算法也就是:Object(i["a"]) 方法
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003318164-1687830768.png)现在把`i()`的内容扣下来就搞定了,但是i方法里有 n的调用```
var o = n.SHA1(r.join(",")).toString(n.enc.Hex),
c = n.enc.Base64.stringify(n.enc.Utf8.parse([o, t].join(",")));
```主要就是这两句,n也是我们需要的,查找一下n得值来源,把n也扣取下来```
var n = r("3452");
````r`又是啥?下个断点重新运行看看。![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003352199-1594513103.png)r如果跟过去发现是一个加载器方法:```function c(t) {if (r[t])return r[t].exports;var n = r[t] = {i: t,l: !1,exports: {}};return e[t].call(n.exports, n, n.exports, c),n.l = !0,n.exports}
```而r("3452") 跟过去,发现很多调用的r(xxx)的
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003441095-1439066909.png)这种情况下很多依赖类调用,如果扣不全很可能缺少某个类从而导致报错无法运行;==在依赖少的情况下可以选择缺啥补啥的原则,缺少什么方法就去找什么方法。====依赖多的情况下也可以选择把js代码全都摘下来,这样不管有没有用到的方法我代码里都有。==但是十几万行代码运行肯定会影响性能,具体优化办法后续会说明的。
###扣取代码由于案例站点依赖比较多,所以只能演示全扣的办法,首先我们把手上的信息整理一下:

加密方法为 :e = Object(i["a"])(this.$store.state.url.index, a);
//
而 Object(i["a"]) 在“7d29”模块里,为:
function i() {
for (var t = Math.round((new Date).getTime() / 1e3).toString(), e = arguments.length, r = new Array(e), i = 0; i < e; i++)
r[i] = arguments[i];
r.push(t);
var o = n.SHA1(r.join(",")).toString(n.enc.Hex)
, c = n.enc.Base64.stringify(n.enc.Utf8.parse([o, t].join(",")));
return c
}
//
里面又又n的依赖调用, 为:r("3452");
//
r 为:加载器
function c(t) {
if (r[t])
return r[t].exports;
var n = r[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(n.exports, n, n.exports, c),
n.l = !0,
n.exports
}
//
“3452"为模块方法:
3452: function(t, e, r) {
(function(e, n, i) {
t.exports = n(r("21bf"), r("3252"), r("17e1"), r("a8ce"), r("1132"), r("72fe"), r("df2f"), r("94f8"), r("191b"), r("d6e6"), r("b86b"), r("e61b"), r("10b7"), r("5980"), r("7bbc"), r("2b79"), r("38ba"), r("00bb"), r("f4ea"), r("aaef"), r("4ba9"), r("81bf"), r("a817"), r("a11b"), r("8cef"), r("2a66"), r("b86c"), r("6d08"), r("c198"), r("a40e"), r("c3b6"), r("1382"), r("3d5a"))
}
)(0, (function(t) {
return t
}
))
}

3452模块调用的其他依赖模块太多,直接选择把chunk-4136500c.f3e9bb54.js文件的所有的模块拷贝下来命名为:demo-model1.js, window对象并不存在编译器中,记得var window=global声明一下![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003524384-859771296.png)把加载器扣出来,然后使用require()导入模块文件,然后设置一个全局变量_c ,将加载器c赋值_c导出运行可以发现报错:第二个报错提示:at Object.3846 (d:\文稿\Js逆向\demo-model1.js:727:9) 模块文件的727行报错![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003544056-1877151241.png)跟过来727行发现又有其他模块调用,应该是缺少了 r("9e1e") 或者r("86cc")导致的报错,
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003604911-864331173.png)果然搜索也只有一个调用,没有声明的地方。那么又得取扣其他页面代码了。
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003625100-1383899400.png)全局搜索网页发现,86cc模块的在chunk-vendors.77daf991.js 文件中被声明了,我们也选择将这文件的所有模块拷贝下来并命名为:demo-module2.js。这两个扣完在编译器中基本也不差模块了,两个js文件全都扣下来了。
###自吐算法上面完整分析了模块与加载器,可谓是你中有我我中有你;由于所有模块都需要经过加载器后调用,所以根据这点特征;可以在调用某个加载模块时,设置一个全局变量,hook所有接下来要调用的模块存储到变量后导出;hook有一定的局限性,只能到加密方法调用附近进行hook。

window._load = c;
window._model = t.toString()+":"+(e[t]+"")+ ",";
c = function(t){
window._load = window._load + t.toString()+":"+(e[t]+"")+ ",";
return window._load(t);
}

###自动化 | Playwright[Playwright official doc ](Fast and reliable end-to-end testing for modern web apps | Playwright)站点源码: [Burpy|一款流量解密插件](https://mp.weixin.qq.com/s?__biz=MzkzODEzNjA3MQ==&mid=2247485048&idx=1&sn=53d09b5cf6625e2bdd961afcdc5350c5&scene=21#wechat_redirect) ,在不扣去加密算法时直接就进行爆破:简单修改一下,将账户和密码都为123的密文放在后台固定写死,如果前端账户和密码都为123就返回密文,不然返回error
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003717755-2043583717.png)安装好Playwright后cmd输入 python -m playwright codegen ,会弹出一个浏览器,访问要爆破的URL。走一遍登录流程后,Playwright会自动生成流程代码。
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003734067-1238483325.png)

from playwright.sync_api import Playwright, sync_playwright, expect

def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()

# Open new page
page = context.new_page()# Click body
page.locator("body").click()# Go to http://localhost:9988/
page.goto("http://localhost:9988/")# Click input[name="userName"]
page.locator("input[name=\"userName\"]").click()# Fill input[name="userName"]
page.locator("input[name=\"userName\"]").fill("123")# Click input[name="passWord"]
page.locator("input[name=\"passWord\"]").click()# Fill input[name="passWord"]
page.locator("input[name=\"passWord\"]").fill("345")# Click input[type="submit"]
page.locator("input[type=\"submit\"]").click()# ---------------------
context.close()
browser.close()

with sync_playwright() as playwright:
run(playwright)

上面代码实现很简单,主要的数据部分就是fill()方法,简单修改一下代码将账户密码变量传入过去,然后做个循环即可。至于判断回显使用page.on()对response进行监听,根据响应长度,密码错误回显为error五个字符长度,大于5则认为成功
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003750323-942885752.webp)运行结果:账户密码为123,123,加密密文为:PomtfmGnIAN54uvLYlgbH+CN/3mhNQdaAR/7+vFOAuU=
![](https://img2024.cnblogs.com/blog/3330979/202501/3330979-20250108003814798-1545773647.png)关于接入验证码就不演示了,第三方像超级鹰这类的平台都已经将识别模块打包好,导入简单修改就能用了,网上文章也相当多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/865637.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CUDA概念

1.1.0f加个f,成单精度计算,不加会默认成double 2.快速指令:__add()加两个下划线 3.CUDA计算能力1.3以上才支持双精度,4.0往后支持双精度浮点计算 单精度浮点型(float )专指占用32位存储空间的单精度(single-precision )值。单精度在一些处理器上比双精度更快而且只占用…

12.09百度机器翻译SDK实验

一、实验要求百度机器翻译SDK实验(2024.11.15日完成) 任务一:下载配置百度翻译Java相关库及环境(占10%)。 任务二:了解百度翻译相关功能并进行总结,包括文本翻译-通用版和文本翻译-词典版(占20%)。 任务三:完成百度翻译相关功能代码并测试调用,要求可以实现…

弹性波动力学笔记(十)罗格里德斯公式推导

在应力计算中大量需要轴旋转公式计算,因此本笔记给出了罗格里德斯轴旋转公式Note: Derivation of the Rodriguez Formula In this Note, we will derive a formula for \(\mathbf{R}(\widehat{\mathbf{n}},\theta)\) . Consider the three dimensional rotation of a vecto…

【Java编程】JDK 源码好用的类方法

Java JDK 提供了丰富的工具类和方法,涵盖了字符串处理、集合操作、日期时间处理、文件操作等多个方面。熟练掌握这些工具类和方法,可以显著提高开发效率和代码质量。如果你有特定的需求或问题,欢迎随时提问

C++中调用C语言代码(extern “C”)

extern "C" 可以使我们在C++程序中调用C语言代码.extern "C"向程序编译器表明这段代码需要用C语言的方式编译。extern "C" { #include <stdio.h> void sayHello() { printf("Hello C\n"); }}int main() { sa…

Tita项目管理软件:管过程,管合同,两手抓

在这个日新月异的商业世界里,项目经理们时常面临重重挑战,而高效的协同作业、严谨的项目合同管理以及精准的回款把控,无疑是决定项目成败的关键要素。正是洞察到了这些需求,Tita项目管理软件应运而生,它以一站式的解决方案,助力项目经理们轻松驾驭项目的每一个环节。 一、…

快消零售的智胜之道:智能AI加速构建员工培训SOP策略

引言 在快节奏的快消零售行业中,员工的高效培训与标准化操作是提升服务质量、增强顾客满意度的关键。然而,传统培训方式往往耗时费力,效果难以保证。随着人工智能技术的不断发展,利用智能AI快速建立员工培训SOP(标准操作程序)已成为众多零售企业的新选择。本文将分享如何…

教育机构的智能跃迁:知识中台如何驱动转型与升级

引言 在数字化转型的浪潮中,教育机构正面临着前所未有的挑战与机遇。传统的教育模式已难以满足当前多元化、个性化的学习需求,而知识中台作为连接数据与业务的关键桥梁,正逐步成为教育机构实现智能转型的重要抓手。本文将探讨教育机构如何借助知识中台,通过智能化手段优化教…

关于RAG你不得不了解的17个技巧

最近在写文章,想补上去年RAG(Retrieval-Augmented Generation)遗留的一些坑,希望能分享一些RAG的技巧帮到大家。还是那句老话:构建一个大模型的原型很容易,但把它变成一个能真正投入生产的产品却很难。这篇文章适合那些在过去一个月里刚刚构建了第一个LLM(大语言模型)应…

10.28软件设计——抽象工厂模式之人与肤色 c++

1、类图 2、源代码test4.cpp#include<iostream> #include<string> using namespace std;//抽象产品类 男人 class Man { public:virtual void makeM() = 0; }; //具体产品类 白色男人 class WhiteMan : public Man { public:void makeM(){cout << "我是…

htb Sauna

扫描端口 nmap -sC -sV -p- -Pn -v -T4 10.10.10.175 Host is up (0.41s latency). Not shown: 65515 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 53/tcp open domain Simple DNS Plus 80/tcp open http Microsoft IIS …

工作组权限

工作组权限 前言 在学习内网之前,觉得还是有必要搞清楚一下权限的问题,同样也是是为后面提权做准备。 本地用户组介绍 电脑的身份分为两种,一种为本地工作,一种为域,当然,电脑的默认都是工作组的形式。 本地工作组的电脑,所有的账号密码,群组等都存放在本地的电脑文件中…