引言
在當今Web安全領域,JavaScript虛擬機保護(JSVMP)技術被廣泛應用于前端代碼的保護和反爬機制中。作為前端逆向工程師,掌握JSVMP逆向技術已成為必備技能。本文將深入剖析JSVMP的工作原理,并分享實用的逆向破解思路。
什么是JSVMP?
JSVMP(JavaScript Virtual Machine Protection)是一種通過自定義虛擬機執行JavaScript代碼的保護技術。它將原始JavaScript代碼編譯為自定義的字節碼,然后通過解釋器執行,從而:
-
隱藏原始業務邏輯
-
增加逆向分析難度
-
防止直接調試和Hook
JSVMP的核心組成
1. 字節碼編譯器
將原始JS代碼轉換為自定義字節碼序列:
// 原始JS
function add(a, b) {return a + b;
}// 編譯后字節碼可能類似
[0x01, 0x02, 0x03, 0x04, ...]
2. 虛擬機解釋器
解釋執行自定義字節碼的虛擬機核心:
function VM(bytecode) {this.pc = 0; // 程序計數器this.stack = []; // 操作數棧this.registers = {}; // 寄存器this.run = function() {while(this.pc < bytecode.length) {const opcode = bytecode[this.pc++];this.execute(opcode);}}this.execute = function(opcode) {switch(opcode) {case 0x01: // PUSHthis.stack.push(bytecode[this.pc++]);break;case 0x02: // ADDconst a = this.stack.pop();const b = this.stack.pop();this.stack.push(a + b);break;// ...其他操作碼}}
}
3. 運行時環境
提供與原生JavaScript環境的交互接口:
const runtime = {getCookie: function(name) {// 獲取cookie的實現},sendRequest: function(url, data) {// 發送請求的實現}// ...其他運行時方法
};
JSVMP逆向分析步驟
1. 識別JSVMP結構
通過特征識別目標是否使用JSVMP:
-
存在大量
switch-case
結構 -
有明顯的字節碼序列
-
代碼包含解釋執行循環
-
使用
eval
或Function
動態執行
2. 定位關鍵入口
尋找字節碼加載和解釋器初始化的位置:
// 常見初始化模式
const bytecode = [0x01, 0x02, ...];
const vm = new VM(bytecode);
vm.run();
3. 分析字節碼結構
確定字節碼的編碼方式和指令集:
操作碼 | 指令 | 描述 |
---|---|---|
0x01 | PUSH | 壓棧 |
0x02 | ADD | 加法 |
0x03 | CALL | 調用函數 |
... | ... | ... |
4. 動態調試技巧
使用Chrome DevTools進行動態分析:
// 在關鍵位置插入調試語句
console.log("PC:", vm.pc, "Opcode:", opcode, "Stack:", vm.stack);// 或使用debugger語句
if(vm.pc === targetPC) debugger;
實戰破解案例
案例1:某網站加密參數分析
目標:破解_signature
參數生成算法
步驟:
-
通過XHR斷點定位加密位置
-
回溯調用棧找到VM入口
-
分析字節碼中的加密邏輯
-
提取關鍵操作模擬執行
// 還原后的加密邏輯
function generateSign(params) {const vm = new VM(encryptBytecode);vm.registers.input = JSON.stringify(params);vm.run();return vm.stack.pop();
}
案例2:某JSVMP反爬破解
挑戰:
-
動態變化的操作碼映射表
-
自修改字節碼
-
反調試檢測
解決方案:
-
使用
Object.defineProperty
Hook關鍵函數 -
記錄操作碼執行軌跡
-
構建操作碼到原始JS的映射關系
// Hook示例
const originalRun = VM.prototype.run;
VM.prototype.run = function() {console.log("VM started with bytecode:", this.bytecode);return originalRun.apply(this, arguments);
};
高級逆向技術
1. 符號執行分析
通過符號執行還原原始邏輯:
# 使用PyExZ3等符號執行工具
from pyexz3 import *def analyze_bytecode(bytecode):vm = VM(bytecode)vm.run()return vm.stack
2. 字節碼反編譯
將字節碼轉換回高級JavaScript代碼:
function decompile(bytecode) {let jsCode = "";for(let i = 0; i < bytecode.length; ) {const opcode = bytecode[i++];switch(opcode) {case 0x01: jsCode += `stack.push(${bytecode[i++]});\n`;break;// 其他操作碼轉換...}}return jsCode;
}
3. 內存快照分析
通過內存dump獲取運行時信息:
// 獲取VM內存狀態
function dumpVM(vm) {return {pc: vm.pc,stack: [...vm.stack],registers: {...vm.registers}};
}
反反爬對策
應對JSVMP的反逆向措施:
反爬技術 | 破解方法 |
---|---|
代碼混淆 | AST分析 |
環境檢測 | 純凈環境 |
動態加載 | 請求攔截 |
定時檢測 | 斷點繞過 |
工具推薦
-
靜態分析工具:
-
AST Explorer
-
Babel Parser
-
WebStorm
-
-
動態調試工具:
-
Chrome DevTools
-
Fiddler
-
Charles
-
-
專用逆向工具:
-
WasmDec
-
JEB JavaScript
-
Node.js VM
-
學習資源
-
《JavaScript高級程序設計》- VM實現章節
-
Chrome V8引擎源碼
-
WebAssembly虛擬機規范
-
Babel插件開發手冊
結語
JSVMP逆向是一個需要耐心和技術積累的過程。通過本文介紹的方法論和實戰案例,相信讀者已經對JSVMP逆向有了系統性的認識。記住,逆向工程的本質是與開發者的智力博弈,保持學習和技術更新才是制勝關鍵。
重要聲明:本文所有技術僅限學習交流,請勿用于非法用途。實際逆向操作前請確保已獲得相關授權。