前言
在 Web 逆向工程领域,定位、Hook、跟值分析与混淆对抗是核心技能栈。本文结合实际场景,系统性梳理逆向流程中的关键策略与技术细节,帮助读者建立结构化的逆向思维体系。
一、定位策略:从攻击到稳定的逆向流程
1. 重放攻击优先原则
目标:快速验证接口可用性
步骤:
- 通过抓包工具(如 Charles)获取原始请求
- 直接重放请求,验证响应有效性(状态码、业务逻辑)
- 理想场景:重放成功后直接进入参数精简阶段
2. 参数精简与稳定性测试
| 场景分类 | 核心流程 | 关键操作 |
|---|---|---|
| 理想情况 | 重放有效 → 参数精简 → 稳定性测试(几小时) | 保留必要参数,忽略非关键值 |
| 复杂情况 | 重放无效 → 关键参数逆向(JS/Set-Cookie)→ 测试 → 参数精简 → 稳定性测试 | 优先处理会话相关参数 |
| 异常崩溃 | 稳定性测试中突发失败 → 回滚参数 → 重新验证 | 记录参数组合变化历史 |
核心思想:通过最少必要参数降低暴露风险,优先处理Set-Cookie等会话关键参数。
二、Hook 技术:函数与对象的拦截实战
1. 函数 Hook 深度解析
a. 基础函数 Hook(非对象场景)
javascript
// 拦截eval函数,监控代码执行
const originalEval = window.eval;
window.eval = function(code) {
console.log(`[Hooked] Eval: ${code}`);
return originalEval.call(this, code);
};
b. 对象方法 Hook(原型链修改)
javascript
// 拦截数组push操作,记录参数
Array.prototype.push = (function(originalPush) {
return function(...args) {
console.log(`[Hooked] Push: ${JSON.stringify(args)}`);
return originalPush.apply(this, args);
};
})(Array.prototype.push);
c. 对抗检测方案
- 检测手段:通过
fn.toString()检测 Hook 痕迹 - 反制措施:
javascript
// 伪造函数toString方法 function hookedFn() { /* 实际逻辑 */ } hookedFn.toString = () => "function() { /* original code */ }";
2. 对象属性 Hook 高级技巧
a. Cookie 监控(描述符劫持)
javascript
// 监控document.cookie读写
let _cookie = document.cookie;
Object.defineProperty(document, 'cookie', {
get: () => _cookie,
set: (value) => {
console.log(`[Hooked] Cookie Set: ${value}`);
_cookie = value;
}
});
b. 全局对象代理(Proxy)
javascript
// 代理window对象,监控所有属性访问
const windowProxy = new Proxy(window, {
get(target, key) {
console.log(`[Proxy] Access: ${String(key)}`);
return target[key];
}
});
三、跟值分析:从同步到异步的追踪策略
1. 同步跟值核心逻辑
步骤:
- 在密文出现处设置断点(如 XHR 响应回调)
- 通过调用堆栈(Call Stack)向上追溯参数来源
- 重点关注函数参数(Arguments)与闭包变量
工具技巧:利用 Chrome DevTools 的Step Into和Step Over逐步追踪。
2. 异步跟值难点突破
挑战:事件循环导致堆栈断裂
解决方案:
- 在异步入口(如
setTimeout、Promise)设置断点 - 使用
debugger语句强制中断微任务执行 - 监控
EventEmitter事件触发点
实战技巧:在异步回调中临时插入console.trace()打印调用栈。
3. 特殊场景经验总结
| 特征标识 | 可能加密方式 | 处理策略 |
|---|---|---|
hex_md5函数 | MD5 哈希 | 替换为 JS-md5 库验证 |
| 大数组 + 移位 | 位运算加密 | 记录数组索引与运算模式 |
RC4关键词 | 对称加密 | 搜索 JS 文件头部的密钥定义 |
| 自执行函数传参 | 字符串解码 | 打印参数值并分析编码格式 |
四、混淆对抗:从基础到 JSVMP 的突破
1. 常见混淆手段解析
a. 变量名混淆
- 青铜级:
a,b,c→ 王者级:_0x4f3a = String.fromCharCode(97, 98, 99) - 应对:利用 IDE 重命名功能或调试器 watch 表达式映射变量。
b. 控制流平坦化
原始逻辑:
javascript
a = 1; b = 2; c = a + b;
混淆后:
javascript
var _step = 0;
while(true) {
switch(_step) {
case 0: a=1; _step=1; break;
case 1: b=2; _step=2; break;
case 2: c=a+b; return;
}
}
应对:使用 AST 工具(如 AST Explorer)还原控制流。
c. 死代码注入
特征:存在未调用函数或冗余变量赋值
javascript
function unused() { var temp = "dead code"; }
unused(); // 无实际作用的调用
应对:通过代码覆盖率工具标记无效代码。
2. JSVMP(JavaScript 虚拟化保护)
核心原理:
- 将原始代码编译为自定义指令数组(如
[110, 'var', 'a']表示声明变量) - 通过解释器逐指令执行,模拟寄存器和变量存储
简化示例:
javascript
// 指令数组(等价于a=1+b)
const instructions = [
[110, 'var', 'a'], // 声明变量
[66, 'b', 2], // 赋值
[88, 'a', 'b'] // 加法运算
];
// 解释器
function JSVMP(instructions) {
let reg = 0, vars = {};
for (const [op, arg1, arg2] of instructions) {
if (op === 110) vars[arg2] = 0; // 声明
if (op === 66) vars[arg1] = arg2; // 赋值
if (op === 88) reg = vars[arg1] + vars[arg2]; // 计算
}
return reg; // 返回3
}
应对思路:
- 分析指令集映射关系(操作码→实际功能)
- 跟踪寄存器与变量的映射关系
- 利用动态调试工具逐指令模拟执行
五、实战方法论总结
- 定位阶段:先验证重放攻击,再逐步精简参数,避免过早陷入逆向细节
- Hook 阶段:优先使用 Proxy 进行对象拦截,函数 Hook 需注意对抗检测
- 跟值阶段:同步依赖堆栈追踪,异步依赖事件断点,JSVMP 需指令集分析
- 混淆处理:先格式化代码,再移除死代码,最后分析控制流逻辑
关键认知:逆向工程是经验驱动的决策过程,需根据实际场景动态调整策略,同时遵守法律边界,确保技术的合理应用。
声明:本文仅用于技术交流,严禁用于非法用途。
2172

被折叠的 条评论
为什么被折叠?



