原理及意义: 花指令(也称为“空操作指令”)是计算机指令集架构(ISA)中的一种指令,它在执行时不会做任何有用的操作,只是占据一个指令周期。其作用主要是为了对齐指令流,使得程序在执行时能够更加高效地利用高处机硬件
场景
- 指令的大小不一。如果指令的长度不是固定的,处理器在读取指令时就需要额外的时间来确定指令的长度,这样会降低程序的执行效率。通过在指令流中添加一些长度为1字节且没有实际操作的花指令,可以使得指令流的长度变得更加规整,从而提高程序的执行效率
- 用于加密、防止代码注入等方面。通过在程序中加入一些花指令,可以使得程序的指令序列变得更加难以分析和理解,从而增强程序的安全性
花指令有两种类型
- 不可执行的花指令
- 在跳转指令之后插入一个多字节指令的字节,欺骗反汇编器将这个字节之后的几个字节当成一个多字节指令解释,进而造成后续指令反汇编出错
- 可执行的花指令
- 将指令的组成部分重新解释执行
一个2字节的跳转指令,第二个字节是操作数,但操作数可以是
0xff
,也就是带符号的-1
,使 EIP 落在0xff
这个字节上,将0xff
作为指令继续执行
- 将指令的组成部分重新解释执行
常见的花指令
- NOP指令(No Operation)
该指令在大多数计算机体系结构中都存在,它不执行任何实际操作,只是等待下一条指令的到来
- XCHG指令(Exchange)
该指令交换两个寄存器的值,但是如果指定的两个寄存器相同,则不做任何实际操作,相当于一条花指令
- INT3指令(Interrupt 3)
该指令用于调试,它会生成一个中断信号,使得调试器能够在这里中断程序的执行,但是在非调试模式下,该指令不做任何实际操作,也可以看作是一条花指令
- HLT指令(Halt)
该指令使得CPU停止工作,直到有中断信号到来。在某些情况下,可以将该指令用作花指令
- XOR
这条指令将寄存器和它自己进行异或操作,结果等于0,实际上也什么都没做
- XCHG(Exchange)
该指令交换两个寄存器或内存单元的值,但如果指定的两个操作数是同一个,则不执行实际操作,相当于一条花指令
- MOV(Move)
该指令将数据从一个寄存器或内存单元复制到另一个寄存器或内存单元,但如果源和目标操作数是同一个,则不执行实际操作,也可以看作是一条花指令
- ADD R0, R0, #0
这条指令将R0寄存器的值加上0,实际上什么都没做,但是可以占据一个指令周期
- SLL R0, R0, #0
这条指令将R0寄存器向左移动0个位,也没有实际操作
- call和ret利用来实现破坏栈帧分析
- push+jmp ⇒ call
- pop+jmp ⇒ ret
- CLC,CLD,FNOP
- 特点:在执行push ss,pop ss语句后,会自动执行下一条语句,当下一条为jmp或着Call是就会跑飞/关键功能丢失
push ss pop ss 待执行指令
创意花指令(过多的花指令可能会影响程序的性能)
- 循环移位:利用多个移位指令组合成一条花指令。例如,可以将多个 SHL 和 SHR 指令交替执行,实现一个循环移位的效果。
shift: shl eax, 1 shr eax, 1 jmp shift
- 逻辑操作:将多个逻辑指令组合成一条花指令。例如,可以将 AND、OR 和 XOR 指令交替执行,或者利用多个逻辑指令来模拟一个条件判断语句。
if: cmp eax, ebx jz true jmp false true: ; true branch jmp end false: ; false branch end: ; rest of the code
- 数据处理:将多个数据处理指令组合成一条花指令。例如,可以将 ADD 和 SUB 指令交替执行,或者将多个数据处理指令用来模拟一些算法。
encrypt: xchg eax, ebx add eax, 0x12345678 add ebx, 0x87654321 xchg eax, ebx ret
- 跳转指令:将多个跳转指令组合成一条花指令。例如,可以将多个条件跳转指令用来模拟一个循环或者条件语句
loop: nop nop nop nop nop nop nop nop nop nop jmp loop