利用 Chrome devTools Source Override 实现JS逆向破解案例
之前讲解 Chrome 一大强势技术 override 时,给的案例貌似没有给大家留下多深的印象
浏览器本地替换(local overrides)快速定位前端样式问题的案例详解(也是hook js的手段)_浏览器的 overrides 替换功能-CSDN博客
其实这个超厉害的,任何一项小技术在 buffer 叠加的基础下才能发挥威力,若单单看到这一项技术,就局限了。
注意
实际测试时,最新版本的 Chrome 的 override 已经不好用了,原因未知,用的 360 极速浏览器搞得,不过神奇的时,Chrome 开启 override 公用极速浏览器的文件夹时,竟然也可以,后经排查,应该是谷歌浏览器的自动格式化问题导致,细节不深究。
结合 xhr 的监听
Chrome 浏览器是能监听到 XHR 请求的,一般我们逆向的突破点都在 XHR 这里,因为所谓的逆向就是为了捕捉传输过程中的数据,因为 Chrome 浏览器就帮我们解决了这个问题。
在 network 中监听 fetch/xhr 请求,发现每次点击页码时都是调用这个接口,于是我们以这个接口特征进行 xhr 断点

设置 xhr 断点

再次点击页码时,会停在一个位置

xhr 返回的数据是加密的
-
一般企业都会将信息进行加密,或者混淆,以避免这么简单就被你获取数据了,既然数据被加密,自然有解密函数,只要你耐心调试一下,往下游去找,定能找到被解密的数据结构,找到后,再对所有 js 进行回搜,就能快速定位解密函数,例如这里解密后,我们会发现数据结构中有个 nodes,且这个 nodes 是另外一个大对象里面的 key,那无非有两种赋值方式['nodes'] 或者 .nodes,我们搜搜后者,发现还在这个 js 文件中,那就没跑了

我们回到这个 js,再进行搜索,可以精确定位到这个数据的解析来源,把整个代码,让 grok 帮我们重新写一下,让我们理解得更彻底

grok 重写后的代码,完美重写的代码,一目了然,核心点就在 o(l),经过 grok 重写后,我们知道 o 就是 resolve,l 就是返回数据 parsedData
async function le(t, n) {// 构造 URLconst e = new URL(t);e.pathname = be(t.pathname);if (t.pathname.endsWith("/")) {e.searchParams.append(Be, "1");}e.searchParams.append(He, n.map(o => (o ? "1" : "0")).join(""));// 发起 HTTP 请求const a = await Ht(e.href);if (!a.ok) {const contentType = a.headers.get("content-type");let errorMessage;if (contentType?.includes("application/json")) {errorMessage = await a.json();} else if (a.status === 404) {errorMessage = "Not Found";} else if (a.status === 500) {errorMessage = "Internal Error";}throw new st(a.status, errorMessage);}// 处理流式数据return new Promise((resolve, reject) => {const i = new Map();const s = a.body.getReader();const c = new TextDecoder();// 自定义函数,用于处理数据转换function f(g) {return Me(g, {Promise: d =>new Promise((fulfil, reject) => {i.set(d, { fulfil, reject });}),});}let buffer = "";async function processStream() {while (true) {const { done, value } = await s.read();if (done && !buffer) {break;}buffer += value ? c.decode(value, { stream: true }) : "\n";while (true) {const lineEndIndex = buffer.indexOf("\n");if (lineEndIndex === -1) {break;}const line = buffer.slice(0, lineEndIndex);buffer = buffer.slice(lineEndIndex + 1);const parsedData = JSON.parse(line);if (parsedData.type === "redirect") {return resolve(parsedData); // 直接解析并返回} else if (parsedData.type === "data") {if (parsedData.nodes) {parsedData.nodes.forEach(node => {if (node?.type === "data") {node.uses = fe(node.uses);node.data = f(node.data);}});}resolve(parsedData); // 解析第一个 data 数据return; // 避免多次 resolve} else if (parsedData.type === "chunk") {const { id, data, error } = parsedData;const promiseHandler = i.get(id);i.delete(id);if (error) {promiseHandler.reject(f(error));} else {promiseHandler.fulfil(f(data));}}}}// 如果流结束且没有返回任何数据,可以选择 reject 或 resolve 一个默认值reject(new Error("Stream ended without redirect or data"));}processStream().catch(reject);});
}
把这个 js 给 override 了,怎么 override,参考以前我写得链接吧,这里不赘述了

然后在 override 的文件里追加一个 fetch 代码,发到我们本地代码去

让 Grok 用 flask 写一个本地 http 协议的服务承接内容,并写到 excel 中去
-
注意 http 服务要允许跨域,因为发过来的 origin 是其他域名,不允许就会被拒绝
-
如果网页本身采用 CSP 的方式阻止浏览器发出跨域请求,不过 localhost 一般不会,若被拒绝,可以下载一个 CSP 扩展开启后就行了,这个可以重写 xhr 的 response headers
from flask import Flask, request, jsonify
from flask_cors import CORS
import openpyxl
from openpyxl import load_workbook
import osapp = Flask(__name__)# 启用 CORS,允许所有来源访问
CORS(app)# Excel 文件路径
EXCEL_FILE = 'WhatsApp.xlsx'# 常驻缓存:存储已经写入的 id
ID_CACHE = set()# 检查 Excel 文件是否存在,如果不存在则创建并添加表头
# 如果存在,则加载现有数据到缓存
if not os.path.exists(EXCEL_FILE):wb = openpyxl.Workbook()ws = wb.activews.title = "Data"headers = ["id", "name", "version", "description", "userCount", "lastUpdate", "email", "author", "ratingValue","ratingCount", "logo", "creationDate"]ws.append(headers)wb.save(EXCEL_FILE)
else:# 加载 Excel 文件中的 id 到缓存try:wb = load_workbook(EXCEL_FILE)ws = wb["Data"]for row in ws.iter_rows(min_row=2, values_only=True): # 从第二行开始(跳过表头)if row[0]: # 确保 id 不为空ID_CACHE.add(row[0])print(f"Loaded {len(ID_CACHE)} IDs into cache from {EXCEL_FILE}")except Exception as e:print(f"Error loading IDs from Excel: {e}")# 定义一个 POST 路由来接收 JSON 数据
@app.route('/extract', methods=['POST'])
def extract_fields():try:# 获取请求中的 JSON 数据data = request.get_json()# 如果数据不是列表,直接转换为列表以统一处理if not isinstance(data, list):data = [data]# 提取指定字段,并检查缓存extracted_data = []new_data_to_save = [] # 存储需要写入 Excel 的新数据for item in data:item_id = item.get("id")if item_id in ID_CACHE:# 如果 id 已存在,跳过写入,但仍返回该数据extracted_item = {"id": item_id,"name": item.get("name"),"version": item.get("version"),"description": item.get("description"),"userCount": item.get("userCount"),"lastUpdate": item.get("lastUpdate"),"email": item.get("email"),"author": item.get("author"),"ratingValue": item.get("ratingValue"),"ratingCount": item.get("ratingCount"),"logo": item.get("logo"),"creationDate": item.get("creationDate")}extracted_data.append(extracted_item)continue# 如果 id 不存在,添加到缓存并准备写入 ExcelID_CACHE.add(item_id)extracted_item = {"id": item_id,"name": item.get("name"),"version": item.get("version"),"description": item.get("description"),"userCount": item.get("userCount"),"lastUpdate": item.get("lastUpdate"),"email": item.get("email"),"author": item.get("author"),"ratingValue": item.get("ratingValue"),"ratingCount": item.get("ratingCount"),"logo": item.get("logo"),"creationDate": item.get("creationDate")}extracted_data.append(extracted_item)new_data_to_save.append(extracted_item)# 将新数据保存到 Excelif new_data_to_save: # 只有当有新数据时才写入 Excelsave_to_excel(new_data_to_save)# 返回提取后的数据(包括已存在和新增的数据)return jsonify(extracted_data), 200except Exception as e:return jsonify({"error": str(e)}), 400# 函数:将数据保存到 Excel
def save_to_excel(data):wb = load_workbook(EXCEL_FILE)ws = wb["Data"]for item in data:row = [item["id"],item["name"],item["version"],item["description"],item["userCount"],item["lastUpdate"],item["email"],item["author"],item["ratingValue"],item["ratingCount"],item["logo"],item["creationDate"]]ws.append(row)wb.save(EXCEL_FILE)# 启动服务
if __name__ == '__main__':app.run(host='0.0.0.0', port=5000, debug=False)
CSP 谷歌扩展
这玩意是啥?不懂就自行谷歌学习一下吧,给浏览器用的东西

跨域搞定后,数据就能发送过去了
network 记得勾选预留日志和关闭缓存,否则有些东西看不到,完美处理

后续
你想全自动化采集?那就自学个谷歌插件吧,或者用 python 的 puppeteer 来进行替换处理,所以的加解密,只要是网页端能被你眼睛看到的,基本都可以采用以上方式解决。
相关文章:
利用 Chrome devTools Source Override 实现JS逆向破解案例
之前讲解 Chrome 一大强势技术 override 时,给的案例貌似没有给大家留下多深的印象 浏览器本地替换(local overrides)快速定位前端样式问题的案例详解(也是hook js的手段)_浏览器的 overrides 替换功能-CSDN博客 其实…...
Springboot 中使用 List<Integer> 与 JSONArray 处理 JSON 数组的性能与实践
深入对比:Springboot 中使用 List 与 JSONArray 处理 JSON 数组的性能与实践 引言 在现代 Web 开发中,处理 JSON 格式的数据是常见需求。当面对 POST 请求中的 JSON 数组时,开发者常需在 List<Integer> 和 JSONArray 两种方案间抉择。…...
容器C++ ——STL常用容器
string容器 string构造函数 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默认构造const char* str "hello world";string s2(str);//传入char*cout << "s2" << s2 << endl;s…...
npu踩坑记录
之前使用qwen系列模型在ascend 910a卡进行了一些生成任务, 贴出踩坑过程也许对遇到类似问题的同学有帮助: ) 目录 千问 qwq32环境配置 代码部署 生成内容清洗 已生成内容清洗 生成过程优化 Failed to initialize the HCCP process问题 assistant 的历史回答丢失 推理执…...
Linux信号——信号的产生(1)
注:信号vs信号量:两者没有任何关系! 信号是什么? Linux系统提供的,让用户(进程)给其他进程发送异步信息的一种方式。 进程看待信号的方式: 1.信号在没有发生的时候,进…...
【机器学习】——机器学习思考总结
摘要 这篇文章深入探讨了机器学习中的数据相关问题,重点分析了神经网络(DNN)的学习机制,包括层级特征提取、非线性激活函数、反向传播和梯度下降等关键机制。同时,文章还讨论了数据集大小的标准、机器学习训练数据量的…...
html处理Base文件流
处理步骤 从服务返回的字符串中提取文件流数据,可能是Base64或二进制。将数据转换为Blob对象。创建对象URL。创建<a>元素,设置href和download属性。触发点击事件以下载文件。删除缓存数据 代码 // 假设这是从服务返回的Base64字符串(…...
力扣每日一题:2712——使所有字符相等的最小成本
使所有字符相等的最小成本 题目示例示例1示例2 题解这些话乍一看可能看不懂,但是多读两遍就明白了。很神奇的解法,像魔术一样。 题目 给你一个下标从 0 开始、长度为 n 的二进制字符串 s ,你可以对其执行两种操作: 选中一个下标…...
在MFC中使用Qt(六):深入了解QMfcApp
前言 此前系列文章回顾: 在MFC中使用Qt(一):玩腻了MFC,试试在MFC中使用Qt!(手动配置编译Qt) 在MFC中使用Qt(二):实现Qt文件的自动编译流程 在M…...
JMeter进行分布式压测
从机: 1、确认防火墙是否关闭; 2、打开网络设置,关闭多余端口;(避免远程访问不到) 3、打开JMeter/bin 目录底下的jmeter.properties; remove_hosts设置当前访问地址,192.XXXXX&…...
Python实现音频数字水印方法
数字水印技术可以将隐藏信息嵌入到音频文件中而不明显影响音频质量。下面我将介绍几种在Python中实现音频数字水印的方法。 方法一:LSB (最低有效位) 水印 import numpy as np from scipy.io import wavfile def embed_watermark_lsb(audio_path, watermark, ou…...
快速入手-基于Django-rest-framework的第三方认证插件(SimpleJWT)权限认证扩展返回用户等其他信息(十一)
1、修改serializer.py,增加自定义类 # 自定义用户登录token等返回信息 class MyTokenObtainPair(TokenObtainPairView): def post(self, request, *args, **kwargs): serializer self.get_serializer(datarequest.data) try: serializer.is_valid(raise_exceptio…...
关于IP免实名的那些事
IP技术已成为个人与企业保护隐私、提升网络效率的重要工具。其核心原理是通过中介服务器转发用户请求,隐藏真实IP地址,从而实现匿名访问、突破地域限制等目标。而“免实名”代理IP的出现,进一步简化了使用流程,用户无需提交身份信…...
【SQL性能优化】预编译SQL:从注入防御到性能飞跃
🔥 开篇:直面SQL的"阿喀琉斯之踵" 假设你正在开发电商系统🛒,当用户搜索商品时: -- 普通SQL拼接(危险!) String sql "SELECT * FROM products WHERE name "…...
Spring容器从启动到关闭的注解使用顺序及说明
Spring容器从启动到关闭的注解使用顺序及说明 1. 容器启动阶段 注解:Configuration、ComponentScan 作用: Configuration:标记配置类,声明Spring应用上下文的配置源。ComponentScan:扫描指定包下的组件(B…...
UVM概念面试题100问
1-10:UVM概述 Q1: 什么是UVM? A1: UVM是Universal Verification Methodology的缩写,它是由Accellera标准化的一种用于IC验证的方法学。它提供了一个基类库(BCL),包含通用工具如组件层次结构、事务级模型(TLM)和配置数据库等,使用户能够创建结构化、可重用的验证环境。 Q2:…...
SQL Server从安装到入门一文掌握应用能力。
本篇文章主要讲解,SQL Server的安装教程及入门使用的基础知识,通过本篇文章你可以快速掌握SQL Server的建库、建表、增加、查询、删除、修改等基本数据库操作能力。 作者:任聪聪 日期:2025年3月31日 一、SQL Server 介绍: SQL Server 是微软旗下的一款主流且优质的数据库…...
力扣HOT100之矩阵:54. 螺旋矩阵
这道题之前在代码随想录里刷过类似的,还有印象,我就按照当初代码随想录的思路做了一下,结果怎么都做不对,因为按照代码随想录的边界条件设置,当行数和列数都为奇数时,最后一个元素无法被添加到数组中&#…...
5.1 WPF路由事件以及文本样式
一、路由事件 WPF中存在一种路由事件(routed event),该事件将发送到包含该控件所在层次的所有控件,如果不希望继续向更高的方向传递,只要设置e.Handled true即可。 这种从本控件-->父控件->父的父控件的事件&am…...
Python数据可视化-第1章-数据可视化与matplotlib
环境 开发工具 VSCode库的版本 numpy1.26.4 matplotlib3.10.1 ipympl0.9.7教材 本书为《Python数据可视化》一书的配套内容,本章为第1章 数据可视化与matplotlib 本文主要介绍了什么是数据集可视化,数据可视化的目的,常见的数据可视化方式…...
Flutter敏感词过滤实战:基于AC自动机的高效解决方案
Flutter敏感词过滤实战:基于AC自动机的高效解决方案 在社交、直播、论坛等UGC场景中,敏感词过滤是保障平台安全的关键防线。本文将深入解析基于AC自动机的Flutter敏感词过滤实现方案,通过原理剖析实战代码性能对比,带你打造毫秒级…...
20250331-vue-组件事件1触发与监听事件
触发与监听事件 1 在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件(例如:在 v-on 的处理函数中): 子组件代码 <template><button click"$emit(someEvent)">点击</button> </template><…...
Odoo/OpenERP 和 psql 命令行的快速参考总结
Odoo/OpenERP 和 psql 命令行的快速参考总结 psql 命令行选项 选项意义-a从脚本中响应所有输入-A取消表数据输出的对齐模式-c <查询>仅运行一个简单的查询,然后退出-d <数据库名>指定连接的数据库名(默认为当前登录用户名)-e回显…...
Vue中使用antd-table组件时,树形表格展开配置不生效-defaultExpandedRowKeys-默认展开配置不生效
defaultExpandedRowKeys属性 defaultExpandAllRows这个属性仅仅是用来设置默认值的,只在第一次渲染的时候起作用,后续再去改变,无法实现响应式 解决方案一 a-table表格添加key属性,当每次获取值时,动态改变key,以达到重新渲染的效果 <a-table:key="tableKey"…...
VRRP交换机三层架构综合实验
题目要求: 1,内网Ip地址使用172.16.0.0/16分配 说明可以划分多个子网,图中有2个VLAN,可以根据VLAN划分 2,sw1和SW2之间互为备份 互为备份通常通过VRRP(虚拟路由冗余协议)来实现。VRRP会在两个…...
基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)
更多图像分类、图像识别、目标检测、图像分割等项目可从主页查看 功能演示: 眼疾识别系统resnet50,efficentnet,卷积神经网络(pytorch框架,python代码)_哔哩哔哩_bilibili (一)简介…...
基于srpingboot智慧校园管理服务平台的设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...
【力扣hot100题】(026)合并两个有序链表
可以创建一个新链表记录答案: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *…...
TCP网络编程与多进程并发实践
一、引言 在网络编程中,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。而多进程并发则是一种提高服务器处理能力的有效手段,允许服务器同时处理多个客户端的请求。本文将详细介绍如何使用 TCP 协议进…...
【前端】一文掌握 Vue 3 指令用法(vue3 备忘清单)
文章目录 入门介绍创建应用应用实例通过 CDN 使用 Vue使用 ES 模块构建版本模板语法文本插值原始 HTMLAttribute 绑定布尔型 Attribute动态绑定多个值使用 JavaScript 表达式仅支持表达式(例子都是无效)调用函数指令 Directives参数 Arguments绑定事件动态参数动态的事件名称修…...
