【发布时间】:2011-09-29 16:13:17
【问题描述】:
有谁知道任何提供 NOP 操作码替代指令的在线资源?
像 'xchg ax, ax' 之类的。我很确定还有一个工具,有人可以指点我那个方向吗?
【问题讨论】:
-
能否产生nop替代品?
-
出于好奇,您寻找 nop 替代品的目的是什么?
标签: security assembly x86 shellcode
有谁知道任何提供 NOP 操作码替代指令的在线资源?
像 'xchg ax, ax' 之类的。我很确定还有一个工具,有人可以指点我那个方向吗?
【问题讨论】:
标签: security assembly x86 shellcode
此页面有一个不错的 NOP 替代列表,编码长度增加:http://www.asmpedia.org/index.php?title=NOP
【讨论】:
一些 shellcode 引擎包含 nop sled 生成器,如果您正在寻找的话。
虽然nop-等价物有无数种长度,但详尽列出是不切实际的。
例如,push eax; pop eax 实际上是 nop。 (假设一个有效的esp等)
或者inc eax; dec eax(假设没有溢出或者你测试然后重置溢出标志)。
【讨论】:
intel 优化手册以及 intel 和 AMD 的说明手册应该列出所有 no op 等效功能。需要注意的是,它们大多是多字节无操作,用于对齐分支和代码缓存目标等。
【讨论】:
NOP 的替代方案,对 nop 雪橇无用,但对性能很有用:What methods can be used to efficiently extend instruction length on modern x86?(例如,添加额外的前缀以使指令更长)。
通常,您的漏洞利用负载不关心寄存器值(堆栈指针除外),因此您可以使用 inc eax(32 位代码中的单字节)之类的东西随意销毁它们。 有很多单字节指令只修改寄存器不会出错。例如cld/std, stc/clc/cmc, cwde, cdq 都是单字节的。 同样是 32 位代码,甚至是 BCD 指令像 AAA 或 DAA 是可以使用的,但它们会像大拇指一样突出,因为编译器从不使用它们。 (编译器在实践中会使用cdq 和cwde,但通常不会使用cld 或std。)
还有其他 xchg-with-eax 单字节 0x91..7 指令,而不是 0x90 nop,它使用与 xchg eax,eax 相同的编码,并且可以在 32 位模式下使用。 (但请注意,64 位模式下的 xchg eax,eax 不是 NOP;它必须使用其他编码才能将 RAX 截断为 EAX。)
对于像mov eax,eax 这样的任何多字节指令,请确保检查它是否从第一个字节以外的位置开始执行解码。 sled 的全部意义在于执行必须在缓冲区内的某个地方着陆,但您不知道在哪里。
您可以使用可选前缀来制作多字节指令,如果在前缀之后开始执行,这些指令仍然可以解码。 cbw 是 0x66 cwde(操作数大小前缀)。或 REX 前缀 (0x40..4f),例如 xchg rax,rcx。
rep 前缀通常在它们不适用的指令上被安全地忽略,但在未来的 CPU 上可能会以不同的方式运行。 (例如,rep nop 以前只是 NOP,但现在是 pause。rep bsr 现在是 lzcnt,这会产生不同的结果。)这对于 shellcode 来说很好,你现在正试图利用一个系统,不是面向未来的 CPU。
如果您知道目标缓冲区对齐方式,那么您可以控制(通过指令指针的低位)可以跳转到哪些可能的偏移量。如果缓冲区是 4 字节对齐的(或者更具体地说,您的有效负载将以 4 字节对齐的位置结束),那么只有每 4 个字节需要作为解码的有效起点,因此您可以使用成对的 2 字节xor eax, ebx / add ecx, edx 之类的指令。
4字节指令包括addss xmm0, xmm1和其他SSE1/SSE2指令。除非您正在利用的代码在禁用 SSE 的内核模式下运行,否则您通常可以假设您正在利用的任何机器都有 SSE1。
您甚至可以使用从 4 字节对齐地址开始的 5 字节指令,例如 mov eax, 0x90345612。请注意,小端立即数的最后一个字节是0x90 nop,所以如果从那里开始解码就可以了。
我的理解是,像这样的技术被广泛用于解决入侵检测系统/病毒扫描程序,这些系统发现长字符串 0x90 可疑。 (和/或因为 0x90 不是可打印的 ASCII,也不是有效的 UTF-8)。
【讨论】:
来自顶部答案中死链接的互联网档案。
90 nop
6690 xchg ax,ax ; 66: switch to 16-bit operand 90: opcode
0f1f00 nop dword ptr [eax] ; 0f1f: 2-byte opcode 00: mod=00 reg=000 rm=000 [EAX]
0f1f4000 nop dword ptr [eax] ; 0f1f: 2-byte opcode 40: mod=01 reg=000 rm=000 [EAX+0x00]
0f1f440000 nop dword ptr [eax+eax] ; 0f1f: 2-byte opcode 44: mod=01 reg=000 rm=100 SIB + 0x00
660f1f440000 nop word ptr [eax+eax] ; 66: switch to 16-bit operand 0f1f: 2-byte opcode 44: mod=01 reg=000 rm=100 SIB + 0x00
0f1f8000000000 nop dword ptr [eax] ; 0f1f: 2-byte opcode 80: mod=10 reg=000 rm=000 [EAX+0x00000000]
【讨论】:
00 00 是 add [rax], al
只需考虑不会改变任何东西(除了标志)的不同操作。将零添加到寄存器,或将寄存器与自身和寄存器与自身相加,将寄存器移动到自身。减去 0,或用零和 ~0。位测试类型的指令,通常是and,但目标没有被修改。
【讨论】: