HackPluto's Blog

反静态调试总结

字数统计: 1.8k阅读时长: 6 min
2019/09/24 Share

花指令

花指令就是一串没有任何实际意义的指令。为什么会产生花指令呢,因为反汇编器并不知道某一个地方的数据到底是数据还是指令的机器码,所以就会将某些花指令反汇编成真正的汇编指令,由于X86平台的指令是密集编码的,所以很多指令都是一个字节编码的,例如生成一个16kb的随即数据,并对其进行了反汇编。效果如下:

可以通过_EMIT指令实现花指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream.h>
#include <windows.h>
void main()
{
_asm
{
jmp l2
_EMIT 0x1//这里就是花指令
_EMIT 0x2//这里就是花指令
_EMIT 0x3//这里就是花指令
_EMIT 0x4//这里就是花指令
l2:
mov eax,0x11111111
}
}

可以看到,程序直接跳转到标签l2了,在jmp指令和l2之间的就是花指令.

花指令不光是能够用jmp指令来设计,还可以用call指令配合ret指令来进行设计,
1.call一个地址,在call下面随便写一点花指令,但是要注意一点与jmp版花指令不同的,我们要记得自己写的花指令占了多少个字节,比如,占了2字节
2.在call里面,也就是函数里面,首先pop出压入的地址,然后把这个地址减去花指令占用的字节数,这里是2字节,再重新push进堆栈,然后就ret
这样,call结束以后执行的下一条指令就是我们想要去的位置了,也就是花指令下面的正常的指令了
其实用call来做的话起到的也就是jmp的作用,道理是一样的,只不过手法不同

判断花指令

特权指令
x86处理器有四个保护环(常用Ring0和Ring3)。某些指令只能在Ring0中运行。这些特殊的特权指令也碰巧是单字节操作码,并且经常发生在反汇编花指令中。比如下面这个使用“Lorem ipsum”反汇编出来的指令:

标红的是单字节指令,如果你知道你正在查看的代码不是作为操作系统引导加载程序、内核或设备驱动程序运行的,那么当查看到这些特权指令时我们应该意识到这些反汇编不是真正有效的代码。

常见Ring0指令的列表:
IN (INS, INSB, INSW, INSD)
OUT (OUTS, OUTSB, OUTSW, OUTSD)
IRET
IRETD
ARPL
ICEBP / INT 1
CLI
STI
HLT

罕见的指令
在用户模式代码中有许多Ring3指令是有效的,但是在编译代码中非常少见。 我们可以将这些指令分为三类:便利指令,不太可能的数学指令和远指针指令。

便利指令

便利指令就是将多条基本汇编语句整合成一句汇编指令
ENTER
LEAVE
LOOP (LOOPE/LOOPZ, LOOPNE/LOOPNZ)
PUSHA
POPA

汇编语言程序员可以使用ENTER和LEAVE指令来获得函数序言和结语,这两个指令可以手动的使用PUSH,MOV和SUB来完成。
ENTER相当于

1
2
push ebp;
mov ebp,esp;

LEAVE相当于

1
2
mov esp,ebp;
pop ebp;

现代编译器倾向于避免使用ENTER和LEAVE,因此大多数程序员也不会使用它们。因为他们一起占据了操作码范围的近1%,所以它们在花指令代码中的出现是非常普遍的。

LOOP指令及其条件同类的LOOPZ和LOOPNZ提供了一种用汇编语言编写循环的非常直观且有用的方法。 编译器通常选择不使用这些,而是使用JMP和条件跳转指令来制作自己的循环。

PUSHA和POPA指令提供了将所有寄存器的状态保存到堆栈的机制。这为汇编语言程序员提供了一个可能方便的类宏指令。由于它也存储和恢复堆栈指针本身,这使得一个懒惰的编码器在函数启动时盲目地存储寄存器信息,并在函数结束时恢复它们的潜在用途变得复杂了。你不会在编译代码中找到这些指令,但是它们也占据了可用操作码范围的近1%,所以它们经常出现在花指令中。

以上这些只是花指令可能出现的情况,并不绝对,并不是说出现了上述指令就一定是花指令,还需要做进一步的分析才可以。

不太可能的数学指令

浮点指令
F*
WAIT/FWAIT

浮点指令通常以字母“F”开始。虽然有些程序使用浮点数学,但大部分程序都不使用浮点数学。浮点指令占用操作码范围的很大一部分,所以它们在花指令中的是普遍存在的。

SAHF
LAHF
SAHF和LAHF指令将AH寄存器的内容复制到标志寄存器EFLAGS中。这是一种编程行为,不会从高级语言转换下来,因此编译器通常不会输出这些指令。如果不是手动编写汇编代码,那么这些指令将会很少出现。由于这些是单操作码范围内的单字节指令,所以它们经常在反汇编花指令中出现。

ASCII调整指令
AAA
AAS
AAM
AAD
“AA”系列指令涉及以二进制编码的十进制形式处理数据。这是一个比较早的编码方式,基本很难再现代计算中遇到。但是,您将经常在反汇编花指令中遇到这些指令,因为它们是单字节指令。

CLC
STC
CLD
STD
这些指令清除并设置进位和目标标志。 它们可能在流操作附近的编译器生成的代码中找到(通常会在REP前缀的地方)。尽管如此,由于它们都是单字节指令,它们在花指令中出现的可能性非常高

远指针指令

LDS
LSS
LES
LFS
LGS
在英特尔架构中,远指针的使用并不存在于16位时代。但是,设置远指针的指令仍然占用两个单字节操作码和两个字节操作码范围中的三个值。因此,你会看到这些指令经常出现在反汇编花指令中。

指令前缀

x86中的指令可以有前缀。前缀字节通常会修改后续指令的行为。前缀的常用用法是改变操作数的大小。有许多这样的前缀,不幸的是,其中许多都落在ASCII表的字母范围内。这意味着,当反汇编ASCII文本(如我们的lorem ipsum),指令前缀将是非常普遍的。这些指令前缀会出现在正常指令中,但没有在花指令中出现的频繁。
如果正在拆解32位代码,并且看到大量使用的16位寄存器(AX,BX,CX,DX,SP,BP等,而不是EAX,EBX,ECX,EDX,ESP和EBP
),你可能正在看花指令。






















CATALOG
  1. 1. 花指令
    1. 1.1. 判断花指令
      1. 1.1.1. 便利指令
      2. 1.1.2. 不太可能的数学指令
      3. 1.1.3. 远指针指令
      4. 1.1.4. 指令前缀