The code in question:
mov ebx, fs:30h
Consequent shellcode:
648b1d30000000
I can't seem to figure out how to write this without null bytes.
Your own answer (of using the destination register to construct the offset for the load) works but wastes some bytes.
The 30h
can fit in a disp8
in an addressing mode instead of an imm8
in a separate instruction.
xor ebx, ebx
mov ebx, fs:[ebx+30h] ; or [rbx+30h] in 64-bit code.
Some register is needed as part of the addressing mode; there's no way to use a disp8
without a register.
In 64-bit code, RIP-relative addressing doesn't help for shellcode (which could end up injected at any unknown absolute address). But it is possible to generate a 30h
offset as RIP+rel32 == 30h if you know the absolute address the code will run from, and it's within +-2GiB of 30h
.
YASM allows relative references to absolute addresses. (NASM doesn't like it.)
mov ebx, [fs: rel 30h]
Disassembly of yasm -felf64 foo.asm && ld foo.o
on Linux, which makes a non-PIE executable (not position-independent, can only run with .text
at the address it's linked for.) objdump -drwC -Mintel
output:
401000: 64 8b 1d 29 f0 bf ff mov ebx,DWORD PTR fs:[rip+0xffffffffffbff029] # 30
But NASM makes the cowardly complaint: "foo.asm:1: warning: absolute address can not be RIP-relative [-w+ea-absolute]" and assembles it to a [disp32]
absolute address (which in x86-64 requires a SIB byte to encode.)
401000: 64 8b 1c 25 30 00 00 00 mov ebx,DWORD PTR fs:0x30
IIRC, with some trickery one can convince GAS to emit RIP-relative addressing of an absolute address.
If Windows has a relocation-entry type for reaching an absolute address via a relative reference, it could also support what YASM does, in code that isn't LargeAddressAware so the rel32 can reach.