文章目录
前言
本博客是参考了诸多大佬的文章而成的,博主本人也是菜鸟,可以看作是博主的学习笔记,因此我也会尽量写的详细,希望可以对你(萌新)有所帮助。路过大佬给个大腿抱抱/(ㄒoㄒ)/~~
简介
花指令又名垃圾代码、脏字节,英文名是junk code。花指令就是在不影响程序运行的情况下,往真实代码中插入一些垃圾代码,从而影响反汇编器的正常运行;或是起到干扰逆向分析人员的静态分析,增加分析难度和分析时间。
有句话,花指令的目的是阻挠逆向人员的分析,并不是阻止。因此,我们在去除花指令的时候,要有耐心,因为这应该不会是什么难点,慢慢来一定可以解决的。
简单花指令
花指令分为俩种:
- 不可执行花指令
- 可执行花指令
可执行花指令
顾名思义,可以执行的花指令,这部分垃圾代码会在程序运行的时候执行,但是执行这些指令没有任何意义,并不会改变寄存器的值,同时反汇编器也可以正常的反汇编这些指令。目的是为了增加静态分析的难度,加大逆向分析人员的工作量。
不可执行花指令
不可以执行的花指令,这类花指令会使反编译器在反编译的时候出错,反汇编器可能错误的反汇编这些指令。根据反汇编的工作原理,只有花指令同正常指令的前几个字节被反汇编器识别成一组无用字节时,才能破坏反汇编的结果。因此,插入的花指令应当是一些不完整的指令,被插入的不完整指令可以是随机选择的。
为了能够有效迷惑反汇编器,同时又确保代码的正确运行,花指令必须满足两个基本特征,即:
- 垃圾数据必须是某个合法指令的一部分。
- 程序运行时,花指令必须位于实际不可执行的代码路径。
原理:反汇编算法的设计缺陷
反汇编算法主要可以分为俩类:递归下降算法和线性扫描算法。
1)线性扫描算法
线性扫描算法p1从程序的入口点开始反汇编,然后对整个代码段进行扫描,反汇编扫描过程中所遇到的每条指令。线性扫描算法的缺点在于在冯诺依曼体系结构下,无法区分数据与代码,从而导致将代码段中嵌入的数据误解释为指令的操作码,以致最后得到错误的反汇编结果。
2)递归下降算法
递归下降采取另外一种不同的方法来定位指令。递归下降算法强调控制流的概念。控制流根据一条指令是否被另一条指令引用来决定是否对其进行反汇编,遇到非控制转移指令时顺序进行反汇编,而遇到控制转移指令时则从转移地址处开始进行反汇编。通过构造必然条件或者互补条件,使得反汇编出错。
关于花指令的构造
永恒跳转
最简单的jmp指令
jmp LABEL1
db junk_code;
LABEL1:
这种jmp单次跳转只能骗过线性扫描算法,会被IDA识别(递归下降)。
多层跳转
__asm {
jmp LABEL1;
_emit 68h;
LABEL1:
jmp LABEL2;
_emit 0CDh;
_emit 20h;
LABEL2:
jmp LABEL3;
_emit 0E8h;
LABEL3:
}
和单次跳转一样,这种也会被IDA识别。
为了骗过IDA,我们将上面的花指令改写一下,
__asm {
_emit 0xE8
_emit 0xFF
//_emit 立即数:代表在这个位置插入一个数据,这里插入的是0xe8
}
查看反汇编后的结果

可以看到IDA错误的识别loc_411877处的代码,成功的实现了花指令的目的。那么我们知道了如何构造,自然也就明白了如何去除,只需要将插入的立即数nop掉即可,点击0xe8和0xff,点击右键,选择patching->change byte

也可以使用一个idapython脚本添加一个快捷键,
from idaapi import *
from idc import *
def nopIt():
start = get_screen_ea()
patch_byte(start,0x90)
refresh_idaview_anyway()
add_hotkey("ctrl-N",nopIt)
这个快捷键可以将选中的地方直接nop掉。(不太清楚,我看别的文章都是说可以直接ctrl+n,我没有找到/(ㄒoㄒ)/~~)(虽然这个脚本也是从别人文章扒的h)

idapython在File - Script commannd…处 也可以Shift+F2快捷键打开。

idapython需要python环境,未安装的萌新请自行搜索安装。
其它构造形式
jnz和jz互补跳转
__asm {
jz Label;
jnz Label;
_emit 0xC7;
Label:

本文介绍了花指令,一种在程序中插入干扰代码以增加逆向分析难度的技术。文章详细讲解了不可执行和可执行花指令的区别,以及利用反汇编算法的缺陷进行构造的方法,如永恒跳转和各种跳转指令的混淆。最后给出了相关CTF练习作为实践应用实例。

665

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



