- 发表于
前端逆向工程:从 Webpack/Vite 打包到滑块验证码与公私钥加密的全面解析
- 作者
- 姓名
- MASON Joey
- https://x.com/JoeyJoeMA
前端逆向工程:从 Webpack/Vite 打包到滑块验证码与公私钥加密的全面解析
Webpack 和 Vite 的详细对比
Webpack 和 Vite 是现代前端开发中两种主流的构建工具,它们在打包原理、架构设计、性能表现以及适用场景上有着显著差异。以下将从底层打包原理、架构、技术差异、Vite 在开发和生产环境的不同处理方式,以及两者的历史发展背景进行详细分析。
一、Webpack 和 Vite 的底层打包原理与架构
1. Webpack 的打包原理与架构
打包原理: Webpack 是一个静态模块打包工具,其核心理念是将项目中的各种资源(如 JavaScript、CSS、图片等)视为模块,通过分析模块之间的依赖关系,将它们打包成一个或多个静态资源文件(通常是 bundle.js)。Webpack 的打包过程可以概括为以下步骤:
- 识别入口文件:从配置的 entry 文件开始,Webpack 分析项目的入口点。
- 构建依赖图:通过解析代码中的 import、require 等语句,递归识别所有模块的依赖关系,形成一个依赖图(Dependency Graph)。
- 模块处理:利用 Loader 将非 JavaScript 文件(如 CSS、图片、TypeScript 等)转换为 JavaScript 模块,并通过 Plugin 扩展功能(如代码压缩、提取 CSS 等)。
- 代码转换与编译:对模块进行转换(例如使用 Babel 转换 ES6+ 代码)、优化(如 Tree Shaking、代码分割)等操作。
- 输出 bundle:将处理后的模块合并为一个或多个 bundle 文件,输出到指定的目录。
架构特点:
- 全量打包:Webpack 在开发和生产环境中都会对整个项目进行打包,生成完整的 bundle 文件。开发环境中通过 Webpack Dev Server 提供热更新(HMR),但仍需重新编译受影响的模块链。
- 模块化支持:支持 CommonJS、AMD、ES Modules 等多种模块化规范,兼容性强。
- Loader 和 Plugin:Webpack 的核心优势在于其强大的生态系统。Loader 用于处理非 JavaScript 文件,Plugin 用于扩展打包过程中的功能(如代码优化、文件注入等)。
- Node.js 驱动:Webpack 基于 Node.js 运行,使用 JavaScript 实现,性能受限于 JavaScript 的执行效率。
技术栈:
- 核心:Node.js(JavaScript 运行时)
- 模块解析:通过 enhanced-resolve 解析模块依赖。
- 代码转换:依赖 Loader(如 babel-loader、css-loader)和 Plugin(如 terser-webpack-plugin)。
- 开发服务器:Webpack Dev Server 提供热更新和静态文件服务。
缺点:
- 启动速度慢:大型项目需要分析整个依赖图并打包,启动开发服务器耗时较长。
- 热更新延迟:修改代码后,Webpack 需要重新编译受影响的模块链,大型项目中 HMR 速度较慢。
- 配置复杂:需要编写详细的 webpack.config.js 文件,学习曲线陡峭。
2. Vite 的打包原理与架构
打包原理: Vite 是一个现代化的前端构建工具,由 Vue.js 作者尤雨溪开发,旨在提供更快的开发体验和更简单的配置。Vite 的核心设计理念是利用浏览器原生的 ES Modules(ESM)支持,将模块分为 依赖 和 源码 两类,优化开发和生产环境的构建流程。
开发环境:
- 无打包启动:Vite 不像 Webpack 那样在启动时对整个项目进行打包,而是直接启动一个开发服务器,利用浏览器的原生 ESM 按需加载模块。
- 按需编译:当浏览器请求某个模块时,Vite 才会实时编译该模块及其依赖(例如将 Vue 单文件组件或 TypeScript 转换为 JavaScript)。这极大减少了启动时间。
- 依赖预构建:Vite 使用 esbuild(基于 Go 语言的超快构建工具)对第三方依赖(如 node_modules 中的库)进行预构建,将其转换为 ESM 格式,缓存到 node_modules/.vite 中,减少浏览器请求的模块数量。
- 热模块替换(HMR):Vite 的 HMR 基于 ESM,只更新修改的模块及其直接依赖,更新速度极快。
生产环境:
- Rollup 打包:Vite 在生产环境中使用 Rollup 进行打包。Rollup 专注于 ESM,擅长 Tree Shaking 和代码优化,生成更小的 bundle 文件。
- 按需加载:Vite 利用 ESM 的动态导入(import())和代码分割,优化生产环境的加载性能。
架构特点:
- 双引擎设计:
- 开发环境:基于 esbuild 和浏览器原生 ESM,提供快速冷启动和 HMR。
- 生产环境:基于 Rollup,提供高效的 Tree Shaking 和代码压缩。
- 原生 ESM:Vite 充分利用现代浏览器的 ESM 支持,将模块加载交给浏览器,减少构建工具的工作量。
- 简单配置:Vite 的配置文件 vite.config.js 简单直观,默认提供现代化开发环境配置,开箱即用。
- 插件系统:Vite 兼容 Rollup 的插件 API,同时支持专为 Vite 设计的插件,但生态系统较 Webpack 小。
技术栈:
- 核心:esbuild(Go 语言,预构建依赖)、Rollup(生产环境打包)。
- 模块解析:利用浏览器原生 ESM,结合 esbuild 的高效解析。
- 开发服务器:基于 Koa(Node.js 框架),提供快速的静态文件服务和 HMR。
- 文件转换:支持 Vue、React、Svelte 等框架的单文件组件,内置 CSS 和 TypeScript 处理。
缺点:
- 生态不成熟:相比 Webpack,Vite 的插件和 Loader 生态较小,某些复杂场景可能需要手动配置。
- 浏览器兼容性:依赖 ESM,要求目标浏览器支持原生 ES Modules(如 Chrome 61+、Firefox 60+),对旧浏览器支持需额外配置(如 @vitejs/plugin-legacy)。
- CommonJS 限制:Vite 不直接支持 CommonJS 模块,需通过 esbuild 转换为 ESM。
二、Webpack 和 Vite 的技术与设计差异
以下从多个维度对比 Webpack 和 Vite 的区别:
维度 | Webpack | Vite |
---|---|---|
开发模式 | 全量打包,启动开发服务器前需分析依赖图并生成 bundle | 无打包,利用浏览器 ESM,按需编译模块,启动几乎瞬时 |
打包速度 | 较慢,需处理整个项目依赖图,Node.js 驱动 | 开发环境极快(esbuild 预构建),生产环境用 Rollup 优化 |
热更新(HMR) | 全量更新,需重新编译受影响的模块链,速度随项目规模变慢 | 增量更新,仅更新修改模块,速度快且稳定 |
插件生态 | 成熟丰富,Loader 和 Plugin 支持几乎所有场景 | 基于 Rollup 插件,生态较小,但快速增长 |
配置复杂度 | 配置复杂,需详细设置 webpack.config.js | 配置简单,vite.config.js 开箱即用,适合快速开发 |
模块化支持 | 支持 CommonJS、AMD、ESM 等多种格式,兼容性强 | 专注于 ESM,需转换 CommonJS,适合现代浏览器 |
生产环境 | 全程使用 Webpack 打包,生成 bundle,支持复杂优化 | 使用 Rollup 打包,注重 Tree Shaking 和代码分割,生成更小 bundle |
适用场景 | 大型、复杂项目,需要高度定制化 | 中小型项目、快速原型开发,注重开发体验 |
技术差异:
- 底层语言:
- Webpack 使用 JavaScript(Node.js)实现,性能受限于 JavaScript 的执行效率。
- Vite 的依赖预构建使用 esbuild(Go 语言,速度比 JavaScript 快 10-100 倍),生产环境使用 Rollup(JavaScript,但专注于 ESM 优化)。
- 模块加载:
- Webpack 通过打包生成 bundle,浏览器加载整个 bundle 文件。
- Vite 利用浏览器原生 ESM,动态加载模块,减少打包开销。
- HMR 实现:
- Webpack 的 HMR 需要重新编译受影响的模块链,效率较低。
- Vite 的 HMR 基于 ESM,只更新修改模块,效率极高。
- 缓存机制:
- Webpack 依赖文件系统缓存(如 cache 配置),但仍需全量打包。
- Vite 使用 HTTP 缓存(304 Not Modified 协商缓存、Cache-Control: max-age=31536000,immutable 强缓存)优化依赖加载。
三、Vite 在开发环境与生产环境的打包差异
Vite 在开发环境和生产环境的打包策略完全不同,这是其设计的核心优势之一。
1. 开发环境
- 无打包:Vite 不进行全量打包,而是启动一个基于 Koa 的开发服务器,直接服务源代码。
- 按需编译:利用浏览器原生 ESM,当浏览器请求某个模块(如 .vue、.tsx)时,Vite 实时编译该模块及其依赖。
- 依赖预构建:第三方依赖(如 React、Vue)由 esbuild 预构建为 ESM 格式,缓存到 node_modules/.vite,避免重复解析。
- HMR:基于 ESM 的 HMR 只更新修改模块,速度极快,通常在毫秒级别。
- 优势:启动快、HMR 高效、开发体验流畅,特别适合大型项目。
2. 生产环境
- Rollup 打包:Vite 使用 Rollup 进行打包,生成优化的 bundle 文件。
- Tree Shaking:Rollup 的静态分析能力优于 Webpack,移除未使用的代码更高效。
- 代码分割:Vite 自动支持动态导入(import())和 CSS 代码分割,优化加载性能。
- 压缩优化:Rollup 配合 terser 或 esbuild 进行代码压缩,生成更小的 bundle。
- 优势:生成的文件体积小,加载速度快,适合生产环境部署。
差异总结:
- 开发环境:无打包,按需编译,依赖 esbuild 和浏览器 ESM,注重速度和开发体验。
- 生产环境:全量打包,依赖 Rollup,注重代码优化和性能。
- 一致性:Vite 通过预构建依赖和统一的插件 API(基于 Rollup)确保开发和生产环境的一致性,但打包流程完全不同。
四、Webpack 和 Vite 的历史发展
1. Webpack 的历史
- 2012 年:Webpack 由 Tobias Koppers 创建,最初是为了解决 Browserify 的局限性(如缺乏对 CSS、图片等非 JS 资源的处理能力)。
- 2014 年:Webpack 1.0 发布,引入模块打包、Loader 和 Plugin 机制,成为 Grunt 和 Gulp 的替代品。当时 JavaScript 生态以 CommonJS 为主,Webpack 提供了强大的模块化支持。
- 2016-2017 年:Webpack 2 引入 Tree Shaking 和动态导入,支持 ES Modules,适应了前端框架(如 React、Vue)的快速发展。
- 2018 年:Webpack 4 优化性能,引入 mode(开发/生产模式),默认支持零配置。
- 2020 年:Webpack 5 发布,改进持久化缓存、模块联邦(Module Federation),并优化长期存在的性能问题。
- 现状:Webpack 拥有成熟的生态系统,广泛应用于大型项目,但其复杂配置和高性能开销推动了更轻量工具的出现。
2. Vite 的历史
- 2020 年:Vite 由尤雨溪在 Vue 3.0 开发期间推出,初衷是为 Vue 项目提供更快的构建工具。当时 Webpack 的启动和 HMR 速度在大型项目中成为瓶颈。
- 2021 年:Vite 2.0 发布,支持多框架(Vue、React、Svelte 等),引入 esbuild 预构建依赖,确立了"无打包开发、Rollup 生产打包"的模式。Vue 3 的默认脚手架从 vue-cli(基于 Webpack)切换到 create-vite。
- 2022-2023 年:Vite 生态快速发展,插件数量增加,支持更多框架和场景。ViteConf 2023 上,尤雨溪宣布 Rolldown(基于 Rust 的 Rollup 替代品)计划,旨在进一步提升构建性能。
- 现状:Vite 已成为现代前端开发的首选工具,尤其在 Vue 和 React 社区中流行。生态系统虽不如 Webpack 成熟,但快速增长。
历史对比:
- Webpack:起步早(2012 年),经历了前端模块化从 CommonJS 到 ESM 的演变,生态成熟但复杂。
- Vite:起步晚(2020 年),针对现代浏览器和 ESM 设计,强调速度和简单性,代表了下一代构建工具的方向。
五、详细分析与选择建议
1. 性能分析
- 启动速度:Vite 的无打包启动和 esbuild 预构建使其在开发环境中启动速度远超 Webpack(毫秒级 vs 秒级)。
- HMR 速度:Vite 的增量更新机制使其 HMR 速度几乎不受项目规模影响,而 Webpack 的全量更新在大项目中明显变慢。
- 生产打包:Vite 的 Rollup 打包生成更小的 bundle,且 Tree Shaking 更高效;Webpack 的打包更全面但体积可能较大。
2. 生态与扩展性
- Webpack:拥有庞大的 Loader 和 Plugin 生态,几乎支持所有场景,但需要复杂的配置和维护。
- Vite:插件生态基于 Rollup,数量较少,但足以覆盖常见需求,配置简单,适合快速开发。
3. 适用场景
- Webpack:
- 适合大型、复杂项目,需要高度定制化(如微前端、模块联邦)。
- 适合需要支持旧浏览器的项目(通过 polyfill 和 Loader)。
- 适合已有 Webpack 配置的遗留项目。
- Vite:
- 适合中小型项目、快速原型开发或现代化前端框架(如 Vue 3、React)。
- 适合追求开发体验和性能的团队。
- 不适合需要复杂自定义构建逻辑或支持旧浏览器的项目(除非使用插件)。
4. 未来趋势
- Webpack:仍在优化性能(如缓存、模块联邦),但受限于 Node.js 和全量打包模式,难以达到 Vite 的速度。
- Vite:随着 Rolldown 的开发(Rust 实现的 Rollup),Vite 的性能和生态将进一步提升,有望取代 Webpack 在更多场景中的地位。
六、总结
Webpack 是一个功能强大、生态成熟的模块打包工具,适合复杂的大型项目,但其启动和 HMR 速度较慢,配置复杂。Vite 利用浏览器原生 ESM 和 esbuild,提供了极快的开发体验和简单的配置,生产环境中通过 Rollup 优化输出,适合现代前端开发。两者的核心区别在于设计理念:Webpack 强调全面性和兼容性,Vite 追求速度和现代化。
选择建议:
- 如果你的项目需要高度定制、支持复杂场景或兼容旧浏览器,选择 Webpack。
- 如果你追求开发效率、快速迭代或使用现代框架(如 Vue 3、React),Vite 是更好的选择。
- 对于新项目,推荐优先尝试 Vite,尤其在中小型项目中;对于遗留项目,逐步迁移到 Vite 需评估生态兼容性。
历史趋势: Webpack 代表了前端构建工具的上一代,解决了模块化问题但性能逐渐成为瓶颈;Vite 代表了下一代工具,利用现代浏览器特性和高效语言(如 Go、Rust)推动了构建速度的革命。随着浏览器对 ESM 的支持增强和 Vite 生态的成熟,Vite 有望在未来占据更大市场份额。
参考资料:
- Vite 官方文档:https://cn.vite.dev
- Webpack 官方文档:https://webpack.js.org
- Rollup 官方文档:https://rollupjs.org
- esbuild 官方文档:https://esbuild.github.io
以下是对 npm run build 和 npm run dev 在 Webpack 和 Vite 环境下的详细内部操作流程分析,涵盖每个步骤的技术细节、工具链行为、文件处理流程,以及最终打包输出的过程。由于问题中提到 Webpack 和 Vite,我将分别分析两者的流程,并以 Vite 的开发与生产环境差异为重点,同时结合 Webpack 的对比,全面解析从命令执行到最终输出的全过程。
1.1 逆向目标
- 某花顺登录滑块逆向:提取登录过程中的加密参数(如
uname
、passwdSalt
)和滑块验证码验证逻辑,实现自动化登录。 - Webpack 代码抠取:将 Webpack 打包的浏览器端代码移植到 Node.js 环境,调用关键函数(如 MD5、RSA 加密)。
- 公私钥加密:分析 RSA 加密实现,探讨公钥指数固定的安全性。
- 滑块验证码:理解为何验证码可用数据表示,并实现自动化识别。
1.2 工具准备
浏览器开发者工具:
- Chrome/Firefox DevTools,分析网络请求和 JavaScript 代码
- 使用 Network 面板监控 API 请求
- 使用 Sources 面板进行代码调试
- 使用 Console 面板执行测试代码
反混淆工具:
- de4js:美化压缩代码
- JS Beautifier:格式化 JavaScript
- AST Explorer:分析代码结构
Source Map 工具:
unwebpack-sourcemap
:还原 Webpack Source Mapsource-map-explorer
:分析 bundle 结构webpack-bundle-analyzer
:可视化依赖关系
抓包工具:
- Fiddler:Windows 平台抓包
- Burp Suite:跨平台抓包,支持 HTTPS
- Charles:Mac 平台抓包
图像处理:
- Python 的
ddddocr
:OCR 识别 Pillow
:图像处理OpenCV
:计算机视觉
- Python 的
Node.js 环境:
- 运行逆向代码
- 复用 Webpack 模块
- 模拟浏览器环境
2. Webpack 与 Vite 打包代码的逆向
2.1 Webpack 打包特点
Webpack 是前端常用的模块打包工具,将 JavaScript、CSS 等资源打包为 bundle 文件(如 main.js
)。其特点包括:
模块化:
- 使用
__webpack_require__
加载模块 - 模块以数字 ID(如
1337
)组织 - 存储在
window.webpackChunk
或__webpack_modules__
中
- 使用
压缩与混淆:
- 生产模式下使用 Terser 压缩代码
- 变量名缩短
- 函数名重命名
- 移除注释和空白
Source Map:
- 开发模式生成
.map
文件 - 包含原始代码映射
- 支持调试和错误追踪
- 开发模式生成
动态导入:
- 支持代码分割
- 生成 chunk 文件(如
chunk-xxx.js
) - 按需加载优化性能
2.2 Vite 打包特点
Vite 基于 ES 模块(ESM)和 Rollup,特点如下:
ESM 驱动:
- 开发环境直接使用浏览器原生模块
- 生产环境由 Rollup 打包
- 更快的开发服务器启动
简洁 bundle:
- 相比 Webpack,代码结构更清晰
- 混淆程度较低
- 更好的可读性
依赖预打包:
- 将
node_modules
依赖打包到dist/assets
中 - 使用 esbuild 进行预构建
- 提高开发环境性能
- 将
2.3 逆向步骤
2.3.1 获取前端资源
打开 DevTools:
// 禁用 F12 检测 document.addEventListener('keydown', function(e) { if (e.key === 'F12') { e.preventDefault(); } });
提取 Source Map:
# 安装工具 npm install -g unwebpack-sourcemap # 还原代码 unwebpack-sourcemap main.js.map # 分析 bundle npx source-map-explorer main.js.map
2.3.2 反混淆代码
- 使用 de4js:
// 压缩代码 function a(b,c){return b+c} // 美化后 function add(num1, num2) { return num1 + num2; }
2.3.3 定位关键逻辑
搜索关键字:
// 在某花顺案例中搜索 thsencrypt passwdsalt
断点调试:
// 在 DevTools 中设置条件断点 if (plaintext === '[email protected]') { debugger; }
模块结构:
// Webpack 模块注册 (window.webpackChunk = window.webpackChunk || []).push([[245], { 245: (module, exports, __webpack_require__) => { module.exports = { encode: function(plaintext) { // 加密逻辑 } }; } }]);
2.3.4 提取 Webpack 运行时
定位 webpack_require:
function __webpack_require__(moduleId) { var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = __webpack_module_cache__[moduleId] = { exports: {} }; __webpack_modules__[moduleId].call( module.exports, module, module.exports, __webpack_require__ ); return module.exports; }
全局导出:
// 添加全局访问 globalThis.__exposedWebpackRequire = __webpack_require__;
2.3.5 收集依赖模块
- 设置日志断点:
// 在 __webpack_require__ 中添加日志 window.module_array += moduleId + ':' + __webpack_modules__[moduleId] + ',\n'; // 清空缓存强制加载 __webpack_module_cache__ = {};
2.3.6 补环境
- 模拟浏览器环境:
// Node.js 环境补丁 global.self = global; global.window = global; global.navigator = { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }; global.document = { createEvent: () => ({ timeStamp: Number(process.hrtime.bigint() / 1_000_000n) }) };
2.3.7 在 Node.js 中运行
- 编写运行脚本:
// run_encrypt.js global.self = global; require('./main.bundle.js'); require('./chunk-xxx.js'); let __webpack_require__ = globalThis.__exposedWebpackRequire; let module_xxx = __webpack_require__('xxx'); console.log(module_xxx.encode('[email protected]'));
3. 某花顺登录滑块逆向
3.1 背景
某花顺登录涉及账号密码加密和滑块验证码验证,核心目标是: 加密 uname 和 passwdSalt 参数,发送到 getGS 和 dologinreturnjson2 接口。 自动识别滑块验证码,生成验证参数(如 phrase 和 signature)。
3.2 加密逻辑
3.2.1 RSA 加密
前端实现:使用 thsencrypt.encode 函数,基于 RSA 算法加密账号和密码:
var thsencrypt = {
encode: function(plaintext, modulus_hex, exponent_hex) {
var rsa = new JSEncrypt();
rsa.setPublicKey(modulus_hex, exponent_hex);
return rsa.encrypt(plaintext);
}
};
var uname = thsencrypt.encode('[email protected]', 'YOUR_MODULUS', '10001');
Python 还原:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from base64 import b64encode
def encrypt_encode(plaintext: str) -> str:
modulus_hex = "YOUR_MODULUS_HERE" # 从 getGS 获取
exponent_hex = "10001"
modulus = int(modulus_hex, 16)
exponent = int(exponent_hex, 16)
key = RSA.construct((modulus, exponent))
cipher = PKCS1_v1_5.new(key)
plaintext_bytes = plaintext.encode('utf-8')
encrypted_bytes = cipher.encrypt(plaintext_bytes)
return b64encode(encrypted_bytes).decode('utf-8')
密码加密:密码先经过 MD5 加密:
import hashlib
def hex_md5(text: str) -> str:
return hashlib.md5(text.encode('utf-8')).hexdigest().lower()
passwd_md5 = hex_md5('mypassword')
passwd_encrypted = encrypt_encode(passwd_md5)
3.2.2 passwdSalt 生成
逻辑:涉及 MD5、HmacSHA256 和 XOR 操作:
import hmac
import hashlib
from base64 import b64decode, b64encode
def get_str_xor(e: str, t: str) -> str:
s = len(e)
r = len(t)
o = []
for d in range(s):
n = d % r
xor_char = chr(ord(e[d]) ^ ord(t[n]))
o.append(xor_char)
return ''.join(o)
def encode_data_salt_once(passwd: str, uname: str, crnd: str, dsk: str, ssv: str, dsv: str) -> str:
n = hashlib.sha256((crnd + dsk).encode('utf-8')).hexdigest()
ssv_decoded = b64decode(ssv).decode('utf-8')
n = get_str_xor(n, ssv_decoded)
passwd_md5 = hex_md5(passwd)
n = hmac.new(n.encode('utf-8'), passwd_md5.encode('utf-8'), hashlib.sha256).hexdigest()
dsv_sha256 = hashlib.sha256(dsv.encode('utf-8')).hexdigest()
n = get_str_xor(n, dsv_sha256)
n = b64encode(n.encode('utf-8')).decode('utf-8')
return encrypt_encode(n)
3.3 滑块验证码实现
3.3.1 验证码分析
滑块验证码的核心是验证用户滑动轨迹是否合法。主要验证点包括:
轨迹数据:
- 滑动距离
- 滑动时间
- 加速度变化
- 轨迹点分布
特征提取:
def extract_track_features(track_points): features = { 'distance': calculate_distance(track_points), 'duration': track_points[-1]['timestamp'] - track_points[0]['timestamp'], 'acceleration': calculate_acceleration(track_points), 'point_count': len(track_points) } return features
轨迹生成:
def generate_human_like_track(distance: int) -> List[Dict]: track = [] current_x = 0 current_time = int(time.time() * 1000) # 初始加速 for i in range(5): current_x += random.randint(2, 4) current_time += random.randint(10, 20) track.append({'x': current_x, 'y': 0, 'timestamp': current_time}) # 匀速滑动 while current_x < distance - 10: current_x += random.randint(1, 3) current_time += random.randint(15, 25) track.append({'x': current_x, 'y': 0, 'timestamp': current_time}) # 减速 while current_x < distance: current_x += random.randint(0, 2) current_time += random.randint(20, 30) track.append({'x': current_x, 'y': 0, 'timestamp': current_time}) return track
3.3.2 验证码绕过
图像识别:
import ddddocr def get_slider_distance(bg_image: bytes, slider_image: bytes) -> int: ocr = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False) res = ocr.slide_match(bg_image, slider_image, simple_target=True) return res['target'][0]
轨迹优化:
def optimize_track(track: List[Dict], target_distance: int) -> List[Dict]: # 调整轨迹点分布 optimized = [] for point in track: # 添加随机偏移 point['y'] = random.randint(-2, 2) # 调整时间间隔 point['timestamp'] += random.randint(-5, 5) optimized.append(point) return optimized
请求构造:
def construct_verify_request(track: List[Dict], distance: int) -> Dict: return { 'phrase': base64.b64encode(json.dumps(track).encode()).decode(), 'signature': calculate_signature(track, distance), 'distance': distance }
3.4 完整登录流程
async def login(username: str, password: str) -> Dict:
# 1. 获取加密参数
gs_response = await get_gs()
modulus = gs_response['modulus']
crnd = gs_response['crnd']
# 2. 加密用户名和密码
encrypted_username = encrypt_encode(username, modulus)
encrypted_password = encrypt_encode(hex_md5(password), modulus)
# 3. 生成 passwdSalt
passwd_salt = encode_data_salt_once(
password, username, crnd,
gs_response['dsk'],
gs_response['ssv'],
gs_response['dsv']
)
# 4. 处理滑块验证码
slider_data = await get_slider()
distance = get_slider_distance(slider_data['bg'], slider_data['slider'])
track = generate_human_like_track(distance)
verify_data = construct_verify_request(track, distance)
# 5. 发送登录请求
login_data = {
'uname': encrypted_username,
'passwd': encrypted_password,
'passwdSalt': passwd_salt,
**verify_data
}
return await send_login_request(login_data)
4. 安全建议
4.1 前端加密
避免固定公钥:
- 定期更换 RSA 密钥对
- 使用动态生成的密钥
- 考虑使用非对称加密的其他方案
增加验证复杂度:
- 添加时间戳验证
- 使用动态盐值
- 实现请求签名机制
混淆保护:
- 使用 JavaScript 混淆工具
- 实现代码自修改
- 添加反调试机制
4.2 验证码优化
轨迹验证:
- 增加轨迹点验证
- 添加加速度检测
- 实现轨迹特征分析
图像处理:
- 增加图像干扰
- 使用动态背景
- 实现多图验证
行为分析:
- 记录用户行为特征
- 实现风险评分
- 添加二次验证
5. 总结
前端逆向工程是一个复杂而有趣的技术领域,需要深入理解前端框架、加密算法和验证码机制。通过本文的案例,我们展示了:
- Webpack/Vite 打包代码的逆向方法
- RSA 加密算法的实现和安全性分析
- 滑块验证码的自动化解决方案
- 完整登录流程的实现
在实际应用中,我们需要在安全性和用户体验之间找到平衡,既要保护系统安全,又要确保良好的用户体验。同时,也要注意逆向工程的法律和道德边界,确保技术的合理使用。
注:本文仅用于技术研究和学习目的,请勿用于非法用途。在实际项目中,建议采用更安全的加密方案和验证机制。
- Table of Contents
- 前端逆向工程:从 Webpack/Vite 打包到滑块验证码与公私钥加密的全面解析
- Webpack 和 Vite 的详细对比
- 一、Webpack 和 Vite 的底层打包原理与架构
- 1. Webpack 的打包原理与架构
- 2. Vite 的打包原理与架构
- 二、Webpack 和 Vite 的技术与设计差异
- 三、Vite 在开发环境与生产环境的打包差异
- 1. 开发环境
- 2. 生产环境
- 四、Webpack 和 Vite 的历史发展
- 1. Webpack 的历史
- 2. Vite 的历史
- 五、详细分析与选择建议
- 1. 性能分析
- 2. 生态与扩展性
- 3. 适用场景
- 4. 未来趋势
- 六、总结
- 1.1 逆向目标
- 1.2 工具准备
- 2. Webpack 与 Vite 打包代码的逆向
- 2.1 Webpack 打包特点
- 2.2 Vite 打包特点
- 2.3 逆向步骤
- 2.3.1 获取前端资源
- 2.3.2 反混淆代码
- 2.3.3 定位关键逻辑
- 2.3.4 提取 Webpack 运行时
- 2.3.5 收集依赖模块
- 2.3.6 补环境
- 2.3.7 在 Node.js 中运行
- 3. 某花顺登录滑块逆向
- 3.1 背景
- 3.2 加密逻辑
- 3.2.1 RSA 加密
- 3.2.2 passwdSalt 生成
- 3.3 滑块验证码实现
- 3.3.1 验证码分析
- 3.3.2 验证码绕过
- 3.4 完整登录流程
- 4. 安全建议
- 4.1 前端加密
- 4.2 验证码优化
- 5. 总结