免杀专题

28、花指令的剔除

1. 课程目标

学习如何识别和剔除花指令,这是逆向分析的重要技能。


2. 识别花指令

2.1 常见特征

特征 说明
NOP序列 连续的0x90
无效跳转 跳转到下一条指令
自抵消操作 push/pop, add/sub相同值
死代码 跳转后的不可达代码
重复指令 相同操作重复多次

2.2 识别方法

1. 控制流分析
   - 找出永远不执行的代码块
   - 识别无条件跳转后的代码

2. 数据流分析
   - 找出对结果无影响的操作
   - 识别自抵消的指令序列

3. 模式匹配
   - 已知花指令模式库
   - 正则匹配识别

3. 手动剔除

3.1 使用IDA Pro

1. 找到花指令区域
2. Edit → Patch program → Change byte
3. 用NOP(0x90)替换花指令
4. 或直接删除并重新分析

3.2 使用x64dbg

1. 定位花指令
2. 右键 → Binary → Fill with NOPs
3. 或手动修改为有效指令

4. 自动剔除脚本

4.1 IDA Python脚本

# IDA Python花指令剔除
import idaapi
import idc

def remove_junk_code(start, end):
    """移除指定范围内的花指令"""
    addr = start
    while addr < end:
        # 获取指令
        mnem = idc.print_insn_mnem(addr)
        
        # 检查NOP
        if mnem == "nop":
            print(f"Found NOP at {hex(addr)}")
        
        # 检查无效跳转 (jmp next_instruction)
        if mnem == "jmp":
            target = idc.get_operand_value(addr, 0)
            next_addr = idc.next_head(addr)
            if target == next_addr:
                print(f"Found useless jmp at {hex(addr)}")
                # Patch为NOP
                idc.patch_byte(addr, 0x90)
                idc.patch_byte(addr + 1, 0x90)
        
        addr = idc.next_head(addr)

# 使用
remove_junk_code(0x401000, 0x402000)

4.2 通用识别模式

# 常见花指令模式
JUNK_PATTERNS = [
    # push reg; pop reg (无效操作)
    [0x50, 0x58],  # push eax; pop eax
    [0x51, 0x59],  # push ecx; pop ecx
    
    # xor reg, reg; add reg, val; sub reg, val
    # ... 更多模式
]

def detect_junk(data, offset):
    for pattern in JUNK_PATTERNS:
        if data[offset:offset+len(pattern)] == bytes(pattern):
            return len(pattern)
    return 0

5. 对抗花指令剔除

5.1 使用有意义的花指令

// 看起来像真实代码的花指令
volatile int dummy = 0;
dummy = GetTickCount();
dummy = dummy * 2;
if (dummy > 0) {
    dummy = 0;
}
// 实际dummy从未被使用

5.2 交织真实代码

int result = 0;
int junk = GetTickCount();  // 花指令
result = CalculateValue();  // 真实
junk ^= junk;               // 花指令
result += 10;               // 真实
junk++;                     // 花指令
return result;              // 真实

6. 课后作业

6.1、作业1:手动识别(必做)

  1. 使用IDA分析一个加花的程序
  2. 手动识别出花指令位置

6.2、作业2:脚本剔除(进阶)

  1. 编写IDA Python脚本自动识别花指令
  2. 测试脚本效果

7. 下一课预告

下一课我们将学习动态Patch函数技术。