花指令原理小结

小结

         常见的花指令构造方法主要有:

  • 0x1 垃圾指令:这些垃圾指令并不影响程序的执行结果和过程,对寄存器也没有影响,但是大量重复的辣鸡指令可以有效阻碍逆向过程
  • 0x2 指令膨胀(等价替换):通过使用多条指令替换一条执行,或者起到同样的效果的方法来阻碍逆向分析
  • 0x3 绝对执行分支:反汇编器优先反汇编错误分支,使用绝对执行分支插入花指令可以干扰反汇编器反汇编。
  • 0x4 打乱执行流:通过打乱执行流,再向中间插入辣鸡指令干扰分析

绝对分支执行

         所谓绝对分支执行:就是虽然是一条条件跳转,但是其结果是已知确定的。是一个必然发生或者必然不发生的事情。常见的构造方法就是JZ-JNZ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Junk1()
{
_asm
{
jz l1
jnz l1
_EMIT 0xE8//这里就是花指令
_EMIT 0x14//这里就是花指令
_EMIT 0x56//这里就是花指令
_EMIT 0x40//这里就是花指令
l2:
mov eax, 0x11111111
}
MessageBox(NULL, "Junk1", "Test", MB_OK);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Junk4()
{
_asm
{
pushad
xor eax,1
cmp eax,1
jnz L1
_EMIT 0xE8
L1:
call Message
popad
}
}

打乱执行流

         跳来跳去,你说晕不晕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Junk2()
{
DWORD pAdress;
_asm
{
jmp L1
L1:
pop eax //保存这条指令地址到eax
call Fun1
_EMIT 0xEA
jmp L2
Fun1:
pop ebx //ebx保存的是_EMIT 0xEA的地址
inc ebx //ebx保存的是jmp L2的地址
push ebx //将jmp L2 地址压栈
ret //跳转到jmp L2
L2:
call Fun2
_EMIT 0xE8
Fun2:
pop ebx //为了保持栈平衡
mov ebx,offset Fun3
push ebx
ret //跳转到Fun3
Fun3:
}
MessageBox(NULL, "Junk2", "Test", MB_OK);
}

进阶花指令

         利用条件跳转是很容易被分析察觉出来的。执行流的更改除了使用跳转以外还是可以使用调用函数的。由于函数调用比跳转来的复杂所以增加了反汇编器识别的难度。

         目的,隐藏那些字符串。我们首先思考一件事:花指令是不被执行的,如何在函数调用后返回的时候准确的落到花指令的后面也就是程序执行的地方。

         方案:结合Hook技术中跳转Detour的方法,代码执行处F-减去函数地址$-代码大小。其实跳跃的就是那些花指令的地方,但是这些地方不能直接计算。用函数调用处(也就是函数返回地址)作为参照。加上之间的距离就是代码执行处F。

1
2
3
4
5
6
7
8
9
10
11
myjmp proc
pop eax
add eax,ecx
push eax
ret
myjmp endp
start:
mov ecx,offset @F- $ -10
call myjmp
db '花指令乱码'
@F:;.........正常指令继续

         适配一下VS就是下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void Junk6()
{
char* Str1;
_asm
{
jmp L1
myjmp :
pop eax //保存这条指令地址到eax
//栈顶保存的是返回地址
add eax, ecx
push eax
ret
L1:
//mov ecx, offset (F -$- 20)
//是为了算出F到EMIT的距离,但是不能直接算,只能间接算F-L距离,减去代码长度
//从而ret到F
mov edx,offset L1
mov ecx,offset F
sub ecx,edx
sub ecx,20
call myjmp
_EMIT 0xE9
//正常执行的指令
F:
mov byte ptr[ebx], 'h'
mov byte ptr[ebx + 1], 'e'
mov byte ptr[ebx + 2], 'l'
mov byte ptr[ebx + 3], 'l'
mov byte ptr[ebx + 4], 'o'
mov byte ptr[ebx + 5], ' '
mov byte ptr[ebx + 6], 'w'
mov byte ptr[ebx + 7], 'o'
mov byte ptr[ebx + 8], 'r'
mov byte ptr[ebx + 9], 'l'
mov byte ptr[ebx + 10], 'd'
mov byte ptr[ebx + 11], '\0'
mov Str1, ebx;
}
MessageBox(NULL, Str1, "OK", MB_OK);
}