免杀专题

27、花指令

1. 课程目标

学习花指令技术,通过插入垃圾代码干扰静态分析和特征匹配。


2. 名词解释

名词 英文 解释
花指令 Junk Code / Garbage Code 不影响程序逻辑的无用指令
死代码 Dead Code 永远不会执行的代码
不透明谓词 Opaque Predicate 结果恒定但难以分析的条件

3. 花指令类型

3.1 NOP填充

; 最简单的花指令
nop                    ; 90
nop
nop

; 多字节NOP
db 0x66, 0x90         ; xchg ax, ax
db 0x0F, 0x1F, 0x00   ; nop dword [eax]

3.2 等价指令替换

; 原始
mov eax, 0

; 等价替换
xor eax, eax
sub eax, eax
and eax, 0

; 原始
add eax, 1

; 等价替换
inc eax
sub eax, -1
lea eax, [eax+1]

3.3 死代码插入

; 永远不执行的代码
    jmp real_code
    db 'This is junk data...'
    int 3
    ret
real_code:
    ; 真正的代码

3.4 不透明谓词

// 结果恒为真,但静态分析难以判断
int x = GetTickCount();
if ((x * x) >= 0) {  // 恒为真
    // 真正代码
} else {
    // 永远不执行的代码
    ExitProcess(0);
}

4. 代码实现

4.1 C语言花指令宏

// 花指令宏
#define JUNK_CODE_1 \
    __asm { push eax } \
    __asm { xor eax, eax } \
    __asm { add eax, 1 } \
    __asm { sub eax, 1 } \
    __asm { pop eax }

#define JUNK_CODE_2 \
    __asm { pushfd } \
    __asm { pushad } \
    __asm { popad } \
    __asm { popfd }

// 使用
void MyFunction() {
    JUNK_CODE_1
    // 真正代码
    JUNK_CODE_2
}

4.2 x64内联汇编

由于MSVC x64不支持内联汇编,需要单独的.asm文件:

; junk.asm
.code

JunkCode proc
    push rax
    xor rax, rax
    add rax, 12345678h
    sub rax, 12345678h
    pop rax
    ret
JunkCode endp

end

4.3 自动花指令插入

// 随机插入花指令
void InsertJunkCode() {
    volatile int junk = 0;
    junk += GetTickCount() & 0xF;
    junk ^= junk;
    junk = junk * 2 - junk * 2;
}

#define JUNK InsertJunkCode();

void RealFunction() {
    JUNK
    // 代码1
    JUNK
    // 代码2
    JUNK
}

5. 高级技术

5.1 跳转花指令

    jmp label1
db 0xE8             ; call的操作码,会干扰反汇编
label1:
    jmp label2
db 0xFF             ; 无效操作码
label2:
    ; 真正代码

5.2 条件花指令

// 恒真条件
if (((unsigned int)-1) > 0) {
    // 真正代码
}

// 恒假条件包裹垃圾代码
if (sizeof(int) > 100) {
    MessageBoxA(NULL, "Never", "Never", 0);
}

6. 课后作业

6.1、作业1:手动花指令(必做)

  1. 在ShellCode Loader中插入花指令
  2. 观察对反汇编的影响

6.2、作业2:自动化(进阶)

  1. 编写花指令自动插入工具
  2. 随机化花指令内容

7. 下一课预告

下一课我们将学习花指令的剔除技术。