4 ms·
As it turns out, the idea of using the fixed header bytes in the instructions isn't so wacky after all! We can move the 0x00000001 at 0x18 into EDI, then use th
by LegionMammal978 3y ago
As it turns out, the idea of using the fixed header bytes in the instructions isn't so wacky after all! We can move the 0x00000001 at 0x18 into EDI, then use the next two bytes as a JMP to the next block. (Also, I'd totally forgotten that the SYSCALL instruction saves the return address in RCX, which lets us use a no-op read(2) to shave a byte off the address calculation and avoid the assumption that argc == 1.) This technique takes the program down to 86 bytes, the smallest it can become without breaking up the "Hello, world!\n" string:
00000000: 7f45 4c46 500f 05b0 01b1 4851 b20e eb04 .ELFP.....HQ....
00000010: 0200 3e00 5eb3 e7bf 0100 0000 eb12 0000 ..>.^...........
00000020: 1800 0000 0000 0000 1800 0000 eb12 0000 ................
00000030: 0f05 935f 0f05 3800 0100 0000 0000 0000 ..._..8.........
00000040: 0100 0000 0000 0000 4865 6c6c 6f2c 2077 ........Hello, w
00000050: 6f72 6c64 210a orld!.
0x01:
.ascii "ELF"
push rax
syscall
mov al, 1
mov cl, 0x48
push rcx
mov dl, 14
jmp 0x14
0x14:
pop rsi
mov bl, 231
mov edi, 1
jmp 0x30
0x30:
syscall
xchg ebx, eax
pop rdi
syscall
0x48:
.ascii "Hello, world!\n"
I can't think of any possible trick that would allow the string to be broken up while also saving bytes overall. Perhaps there exists some wild self-modifying code that somehow produces the correct behavior, or perhaps this program truly is the shortest.