# A minimal Linux i386 hex-undump program in assembly. # 22 instructions using 14 different opcode bytes, # 64 bytes of code, but the executable is 356 after # `strip hexd; objcopy -R .note.gnu.build-id hexd`. # This can probably be improved substantially, along the lines of # , # which packs an ELF executable into 45 bytes, # This version, based on some hacks of Dave Long’s, reads # fixed four-byte chunks; the first two bytes are # hex digits, and the other two are unused so far, so they can be, # say, space and newline. The “hex” digits are “ASCII hex”, just using # the low four bits of the character: so 0-9 work as expected, # but not a-f; # instead of a-f, you can use :;<=>?, *+,-.,, z{|}~DEL, # or most conveniently, jklmno or JKLMNO. # For example, given the input file # "68 65 6L 6L 6o 2L 20 77 6o 72 6L 64 2n 0J\n" # it says, "hello, world." You can also spell that as # "6h 6e 6L 6L 6o 2, 2 7w 6o 7r 6L 6d 2. 0J\n" # or # "fh fe fl fl fo ". " gw fo gr fl fd ". @J\n" # so maybe there is some mnemonic value to this extra freedom. # So it seems like it should be possible to fit a hex # undump ELF into less than 128 bytes. .equiv __NR_exit, 1 # linux/arch/x86/include/asm/unistd_32.h:9 .equiv __NR_read, 3 .equiv __NR_write, 4 .equiv stdin, 0 .equiv stdout, 1 .globl _start _start: push %ebx # Allocate an on-stack buffer. read: mov $__NR_read, %eax mov $stdin, %ebx mov %esp, %ecx # Use the on-stack buffer mov $4, %edx int $0x80 test %eax, %eax jz exit ## decode “ASCII hex”. pop %ebx and $0x0f, %bh shl $4, %bl add %bh, %bl ## output the decoded byte via the stack. push %ebx mov $__NR_write, %eax mov $stdout, %ebx mov %esp, %ecx mov $1, %edx int $0x80 jmp read exit: mov $__NR_exit, %eax xor %ebx, %ebx int $0x80