花指令

一、花指令概述

1.概念:花指令是,由设计者特别构思,希望使静态反汇编的时候出错,让破解者无法清楚正确地反汇编程序的内容,迷失方向。

2.分类:分为可执行式与不可执行式

可执行式:就是能够执行这些花指令,但执行这些代码没有任何意义,执行前后不改变任何寄存器的值(当然eip这种除外),同时这部分代码也会被反汇编器正常识别。

这种花指令的目的就是:

(1)增大逆向者的工作量,可能一串代码看了很久,到最后分析出来没有任何用处。

(2)然后,这种花指令可以破坏反编译的分析,使得栈指针在反编译引擎中出现异常例如

sub_411880      endp ; sp-analysis failed

不可执行类:是这部分花指令代码在程序的正常执行过程中不会被执行

目的:

就是会导致在IDA里面查看是看到一些不正确的汇编指令

3.实现原理:或者说是为什么加了某些花指令,就会反编译不了,主要还是因为,一些反编译工具,如IDA采用的是线性反编译。文件都是二进制构成的,一部分二进制转换为十六进制,就是所谓的机器码,而机器码就可以转换为对应的汇编指令,如

55就相当于push ebp
8B EC就相当于mov ebp,esp
E8 ??????就相当于跳转指令

而现在IDA采用线性扫描,就是一个个读取机器码,或者读取几个机器码然后输出其对应的汇编指令。现在思考,如果我向一串机器码中插入一个垃圾机器码,是不是IDA就可能输出错误的汇编代码,导致反编译失败。而这些垃圾机器码就是我们加上的花指令。

4.添加花指令原则:

(1)一定不会影响整个程序的运作。

(2)构造永恒跳转,添加垃圾数据!

二、一些准备工作

1.什么是内敛汇编

_asm
{
    push ebp
    mov ebp,esp
    sub esp,3D
}

大括号里面就用来写汇编代码。

2._emit 立即数

_emit e8
_emit c3

这个就是用来插入垃圾代码的。

3.一些IDA的功能使用

(1)查看机器码和栈顶指针


(2)改机器码或者栈顶,这个就调试的时候在介绍了。

(3)d键,c键,p键,这个也在调试的时候说了。

三、开始调试各种含有花指令的文件

1.样本1

源代码如下

#include<stdio.h>
#include<windows.h>

int main()
{
    printf("hello!");
    __asm {
        xor eax,eax
        test eax,eax 
        je LABEL1 
        jne LABEL2
LABEL2:   
        _emit 0x5e
        and eax,ebx
        _emit 0x50
        xor eax,ebx
        _emit 0x74
        add eax,edx
LABEL1:
    }
    printf("world");
    return 0;
}

放到IDA里面分析。


按d键后。

nop机器码,圈住机器码的开头然后点击Edit—Patch program—change byte

注意还要,将原来d键后的位置,按c键重新分析一下,才能在函数开头按p键。

去花后

2.样本2

源代码如下

#include<stdio.h>

int main(void)
{
    int a=1;
    printf("hello ");
    if(a==0)
    {
        _asm
        {
            _emit 0xe8;
            _emit 0xc3;
        }
    }
    else
    printf("world");
    return 0;
}

调试过程如下

按了d键,c键展开,重新布局之后

nop后,按p键,就可以f5看伪代码了。

3.样本3

源代码如下

#include<stdio.h>
#include<windows.h>
int a=1;
int main()
{
    printf("hello!");
        __asm {
        push eax;
        xor eax, eax;
        test eax, eax;
        jnz  LABEL1;
        jz LABEL2;
    LABEL1:
        _emit 0xE8;
    LABEL2:
        mov byte ptr[a], 0;
        call LABEL3;
        _emit 0xFF;
    LABEL3:
        add dword ptr ss : [esp] , 8;//这里的8是经过调试而得,使执行ret指令时正好到达mov byte ptr[a], 2;,而掩盖_emit 0xFF;__emit 0x11;这两个垃圾值。
        ret;
        __emit 0x11;
        mov byte ptr[a], 2;
        pop eax;
    }
    printf("world");
    return 0;
}

调试过程

看机器码

然后用d键和c键使整个逻辑看起来清晰一些。这个过程可以用另一个软件dbg来看一些垃圾代码,因为在dbg里面每执行一步就可以看到正确的语句,就可以看到正确的机器码,然后挑出垃圾代码。

然后c键重新分析,然后p键,发现下半段会有个sp-analysis failed

既然这样就直接把那个call loc_40104C后面一部分全部nop了,也不会对整个流程产生影响。

然后p键,就发现可以f5看伪代码了。