mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
864 字
2 分钟
某音乐解密流程
2026-06-16

浏览器控制台日志爆炸问题解决方案#

主要是针对某音乐解密那一类的,密钥buffer几万的长度,解密的过程中就能把浏览器爆炸了。

解密没啥好说的,拿到日志就行,他就是固定的密钥,然后长度是21位。

用buffer里的数字对长度取模拿到索引值,然后做异或操作得到真实数据。

我们主要来聊一下日志的问题吧。

问题背景#

在 JS 逆向分析过程中,对 VM/混淆代码进行插桩时,日志量可能达到数万甚至数十万条。直接在浏览器控制台输出会导致:

  • 浏览器卡顿/死机:console.log 输出过多,浏览器渲染线程被阻塞
  • 内存溢出:大量日志堆积在控制台缓冲区
  • 调试器无响应:DevTools 无法处理海量日志

核心解决方案:WebSocket 远程日志传输#

将日志从浏览器实时传输到本地 Python 服务器,避免浏览器内存占用。

架构设计#

┌─────────────────┐ WebSocket ┌─────────────────┐
│ 浏览器插桩代码 │ ──────────────────► │ Python 日志服务器 │
│ (sign插桩.js) │ 顺序发送日志 │ (log_server_ws.py) │
└─────────────────┘ └─────────────────┘
│ │
▼ ▼
console.log(少量) 批量写入 vm_logs.txt

服务端实现(Python)#

关键代码#

import asyncio
import websockets
LOG_FILE = "vm_logs.txt"
BATCH_SIZE = 100 # 每 100 条批量写入
async def handle_log(websocket):
batch = []
try:
with open(LOG_FILE, 'a', encoding='utf-8') as f:
async for message in websocket:
batch.append(message)
# 批量写入优化:减少 IO 次数
if len(batch) >= BATCH_SIZE:
f.write('\n'.join(batch) + '\n')
f.flush()
batch = []
# 发送确认,保证顺序
await websocket.send("ok")
except websockets.exceptions.ConnectionClosed:
if batch:
with open(LOG_FILE, 'a', encoding='utf-8') as f:
f.write('\n'.join(batch) + '\n')
async with websockets.serve(handle_log, "127.0.0.1", 9999):
await asyncio.Future()

服务端启动#

python log_server_ws.py

浏览器端实现#

核心策略#

  1. 限制日志总量:设置 MAX_LOGS 上限
  2. 顺序发送:每条日志发送后等待服务端确认,再发送下一条
  3. 队列缓冲:网络延迟时使用队列暂存
  4. 重连机制:连接断开后自动重连

关键代码#

const MAX_LOGS = 5000; // 限制最多输出 5000 条
const WS_SERVER = 'ws://127.0.0.1:9999';
let wsSocket = null;
let wsQueue = [];
let wsConnected = false;
let logCounter = 0;
function initWebSocket() {
wsSocket = new WebSocket(WS_SERVER);
wsSocket.onopen = () => {
wsConnected = true;
flushWsQueue(); // 发送队列中的日志
};
wsSocket.onmessage = (event) => {
if (event.data === 'ok') {
wsQueue.shift(); // 确认后移除已发送的日志
flushWsQueue(); // 发送下一条
}
};
}
function vmLog(...args) {
if (logCounter >= MAX_LOGS) return; // 限制日志数量
const logLine = `[${++logCounter}] ${args.join(' ')}`;
// 方式1:少量控制台输出(可选)
// console.log(logLine);
// 方式2:WebSocket 发送到服务端
wsQueue.push(logLine);
if (wsConnected) flushWsQueue();
}
function flushWsQueue() {
if (!wsConnected || wsQueue.length === 0) return;
wsSocket.send(wsQueue[0]); // 只发送第一条,等待确认
}

完整配置流程#

步骤 1:启动日志服务器#

cd "D:\大胖狗的学习\逆向\胖狗逆向集\扣扣音乐纯算"
python log_server_ws.py

步骤 2:在浏览器控制台运行插桩代码#

确保插桩代码中 USE_WS = true,浏览器会自动连接到 ws://127.0.0.1:9999

步骤 3:触发目标函数#

执行加密/解密操作,日志会自动传输到服务端并写入 vm_logs.txt

步骤 4:查看日志文件#

# 实时查看日志
tail -f vm_logs.txt
# 搜索关键信息
grep "key" vm_logs.txt

关键优化点#

1. 日志数量限制#

const MAX_LOGS = 5000;
function vmLog(...args) {
if (logCounter >= MAX_LOGS) return; // 达到上限后停止输出
// ...
}

2. 数组内容完整显示#

当需要查看完整密钥数组时,修改 pretty 函数:

function pretty(value) {
if (Array.isArray(value)) {
// 完整显示所有元素,不截断
return '[' + value.map(x => typeof x === 'number' ? x : pretty(x)).join(', ') + ']';
}
// ...
}

3. 批量写入优化#

服务端每 100 条写入一次文件,减少磁盘 IO:

if len(batch) >= BATCH_SIZE:
f.write('\n'.join(batch) + '\n')
f.flush()
batch = []

4. 顺序保证#

使用确认机制确保日志顺序正确:

wsSocket.onmessage = (event) => {
if (event.data === 'ok') {
wsQueue.shift();
flushWsQueue();
}
};

常见问题#

Q1: WebSocket 连接失败#

  • 确保 Python 服务器已启动
  • 检查端口是否被占用(默认 9999)
  • 浏览器控制台查看连接状态

Q2: 日志不完整#

  • 检查 MAX_LOGS 是否设置过低
  • 确保页面关闭前等待日志发送完毕
  • 服务端会在连接断开时写入剩余日志

Q3: 日志顺序混乱#

  • 确保每条日志发送后等待确认
  • 不要并发发送多条日志

Q4: 浏览器仍然卡顿#

  • 关闭 console.log 输出,仅保留 WebSocket 传输
  • 进一步降低 MAX_LOGS
  • 使用更轻量的日志格式

对比方案#

方案优点缺点
直接 console.log简单日志爆炸,浏览器卡死
WebSocket 传输无内存压力,可存储需要启动服务端
本地文件下载无需服务端需要等待执行完成才能下载
内存缓存后下载简单大量日志导致内存溢出

推荐配置#

针对不同场景的配置建议:

快速调试(少量日志)#

const MAX_LOGS = 1000;
// 仅控制台输出,不启用 WebSocket

详细分析(中等日志)#

const MAX_LOGS = 5000;
// 启用 WebSocket,控制台同步输出

完整追踪(大量日志)#

const MAX_LOGS = 50000;
// 启用 WebSocket,关闭控制台输出
// 服务端批量写入
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

某音乐解密流程
https://fatdog.20060113.xyz/posts/qqmusic-decrypt/
作者
神秘大胖狗
发布于
2026-06-16
许可协议
MIT

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00