Alternatives to NOP for shellcode nop sleds
Does anyone know of any online source that provides instruction alternatives to a NOP opcode ?
Like 'xchg ax, ax' and the likes. I'm pretty sure that there is also a tool for it开发者_StackOverflow中文版, can someone point me to that direction please ?
Some shellcode engines contain nop
sled generators, if that is what you're looking for.
Though there are an infinite variety of nop
-equivalents of various lengths, so an exhaustive listing is impractical.
For instance, push eax; pop eax
is effectively a nop
. (assuming a valid esp
, etc, etc)
Or inc eax; dec eax
(assuming no overflow or you test then reset the overflow flag).
This page has a nice list of NOP alternatives with increasing encoding lengths: http://www.asmpedia.org/index.php?title=NOP
An alternative to NOP that's useless for nop sleds, but useful for performance: What methods can be used to efficiently extend instruction length on modern x86? (e.g. add extra prefixes to make instructions longer).
Normally your exploit payload doesn't care about register values (other than the stack pointer), so you can freely destroy them with things like inc eax
(single-byte in 32-bit code). There are lots of single-byte instructions that only modify registers and won't fault. e.g. cld
/std
, stc
/clc
/cmc
, cwde
, cdq
are all single-byte. Again in 32-bit code, even BCD instructions like AAA
or DAA
are usable, but those will stick out like a sore thumb because compilers never use them. (Compilers do in practice use cdq
and maybe cwde
, but typically not cld
or std
.)
Also the other xchg-with-eax one-byte 0x91..7 instructions, other than 0x90 nop
which uses the same encoding that xchg eax,eax
would have, and could in 32-bit mode. (But note that xchg eax,eax
in 64-bit mode isn't a NOP; it has to use the other encoding so it can truncate RAX to EAX.)
With any multi-byte instruction like mov eax,eax
, make sure to check how it decodes if execution starts at something other than the first byte. The whole point of a sled is that execution has to land somewhere inside the buffer but you don't know where.
You can use optional prefixes to make multi-byte instructions that still decode ok if execution starts after the prefix. cbw
is 0x66 cwde
(operand-size prefix). Or REX prefixes (0x40..4f
), so xchg rax,rcx
for example.
rep
prefixes are typically ignored safely on instructions they don't apply to, but may run differently on future CPUs. (e.g. rep nop
used to just be NOP, but now it's pause
. rep bsr
is now lzcnt
, which produces a different result.) This is fine for shellcode, you're trying to exploit one system now, not be future-proof for future CPUs.
If you know the target buffer alignment, then you control (via the low bits of the instruction pointer) which possible offsets you can jump to. If the buffer is 4-byte aligned (or more specifically that your payload will end up a 4-byte aligned location), then only every 4th byte needs to be a valid starting point for decoding, so you can use pairs of 2-byte instructions like xor eax, ebx
/ add ecx, edx
.
4-byte instructions include addss xmm0, xmm1
and other SSE1/SSE2 instructions. Unless the code you're exploiting is running in kernel mode with SSE disabled, you can normally assume that whatever machine you're exploiting has SSE1.
You could even use a 5-byte instruction like mov eax, 0x90345612
starting at a 4-byte aligned address. Note that the last byte of the little-endian immediate is 0x90
nop, so it's ok if decoding starts there.
My understanding is that techniques like this are widely used to work around intrusion-detection systems / virus scanners that find long strings of 0x90
suspicious. (And/or because 0x90
is not printable ASCII, and not valid UTF-8).
The intel optimization manual and the instruction manuals for intel and AMD should have listing of all the no op equivalent functions. It should be noted that most of them are multi byte no ops, to be used for aligning branch and code cache targets etc.
From the internet archive of the dead link in the top answer.
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]
just think through the different operations that dont change anything (other than flags). add zero to a register, or the register with itself and the register with itself, move the register to itself. subtract 0, or with zero, and with ~0. A bit test type instruction, usually an and but the destination is not modified.
精彩评论