GLP-1s need not apply.
There may be situations where you wish to conditionally run 32-bit or 64-bit shellcode from the same codebase. One such scenario is if you are bootstrapping some code into an ILONLY assembly.
Below is valid x86 and x86-64 code that can be used for that purpose.
xor eax, eax
db 048h
db 0ffh
db 0c0h
test eax, eax
jnz lbl_64
lbl_32:
int 3
lbl_64:
int 3
The interesting bit is how the sequence 0x48, 0xff, 0xc0 is encoded differently between the two architectures.
On x86 it is encoded to:
dec eax
inc eax
And on x86-64 it gets encoded to:
[rex] inc rax
There are alternative variations to this trick, but I feel this iteration strikes a good balance of simplicity and readability.
Additionally, here’s a Python utility function to join x86 and x86-64 shellcode together using this trick.
def create_fat_loader(shellcode_32: bytes, shellcode_64: bytes) -> bytes:
stub: bytearray = bytearray()
stub += b"\x31\xC0\x48\xFF\xC0\x85\xC0\x0F\x85"
offset_patch_64_jne: int = len(stub)
stub += b"\x00\x00\x00\x00"
stub.extend(shellcode_32)
offset_64: bytes = len(shellcode_32).to_bytes(length=4, byteorder='little', signed=False)
stub.extend(shellcode_64)
stub[offset_patch_64_jne:offset_patch_64_jne + 4] = offset_64
return bytes(stub)