Public reminder to add some tricks sometime
1. XOR Instruction
Setting a register to null is usually a problem when writing shellcode due to couple of reasons:
- It contains null characters, will fuck up your string.
- Size limitations.
Example:
nasm > mov al, 0
00000000 B000 ; 2 bytes
nasm > mov ax, 0
00000000 66B80000 ; 4 bytes
nasm > mov eax, 0
00000000 B800000000 ; 5 bytes
Instead, XORing a register with itself 1) clears it out as well, 2) is null-free and 3) generates less shellcode.
nasm > xor al,al
00000000 30C0 ; 2 bytes
nasm > xor ax,ax
00000000 6631C0 ; 4 bytes
nasm > xor eax,eax
00000000 31C0 ; 2 bytes
Although xor ax,ax
didn’t generate less shellcode, it doesn’t contain a null character.
2. CBW, CWD, CDQ Instructions
CBW
, CWD
and CDQ
extends the sign bit of al
/ax
/eax
to ah
/dx
/edx
. This is particularly useful due to a couple of reasons:
EAX
is essential in system calls.- Many times you’ll need a register zeroed out. As most system calls won’t “set” the flag bit in
EAX
, calling C{B/W/D}Q is an easy way to useEDX
when NULL is needed.
Example:
mov al, 5 ; al's sign bit is 0 (positive)
cbw ; ah is now 0x00
mov ax, -5
cbd ; dx is now 0xffff
mov eax, 1337
cdq ; eax is now 0x00000000
A common way to set a register to zero is by XORing itself (tip 1). This is 2-4 bytes long, while using any of the previous commands knowing/controlling the value of the corresponding register, we can reduce it to a single byte, cutting down the size to 50-75%.
nasm > xor eax, eax
00000000 31C0
nasm > xor edx, edx
00000000 31D2
nasm > xor ah,ah
00000000 30E4
nasm > cbw
00000000 6698
nasm > cwd
00000000 6699
nasm > cdq
00000000 99
3. Push, POP Reg32
XORing (Tip 1) is great to zero out a register, but what if we want to initialize it with a certain value?
nasm > xor eax, eax
00000000 31C0
nasm > mov al, 0x1
00000000 B001
How about we utilize the stack? Pushing 0x1 for example will be automatically aligned as a DWORD.
nasm > push byte 0x1
00000000 6A01 push byte +0x1
nasm > pop eax
00000000 58 pop eax
- Abatchy