最小的可执行程序(x86-64)

时间:2018-11-19 21:03:55

标签: assembly x86-64 elf

我最近遇到this post,它描述了可能的最小ELF可执行文件,但是该帖子是用32位编写的,因此我无法在计算机上获得最终版本进行编译。这使我想到一个问题:可以编写出无错误运行的最小x86-64 ELF可执行文件是什么?

1 个答案:

答案 0 :(得分:3)

from an answer of mine开始,讨论Linux上ELF可执行文件的“真实”入口点和“原始”系统调用,我们可以将其简化为

bits 64
global _start
_start:
   mov di,42        ; only the low byte of the exit code is kept,
                    ; so we can use di instead of the full edi/rdi
   xor eax,eax
   mov al,60        ; shorter than mov eax,60
   syscall          ; perform the syscall

我认为您可以在不超出规格的情况下将其缩小到任何较小的大小-特别是psABI不保证有关eax状态的任何信息。它将精确地组装为10个字节(与32位有效负载的7个字节相对):

66 bf 2a 00 31 c0 b0 3c 0f 05

直接的方法(与nasm组合,与ld链接)产生了352个字节的可执行文件。

他进行的第一个“实际”转换是“手工”构建ELF。这样做(做一些修改,因为x86_64的ELF标头要大一些)

bits 64
            org 0x08048000

ehdr:                                           ; Elf64_Ehdr
            db  0x7F, "ELF", 2, 1, 1, 0         ;   e_ident
    times 8 db  0
            dw  2                               ;   e_type
            dw  62                              ;   e_machine
            dd  1                               ;   e_version
            dq  _start                          ;   e_entry
            dq  phdr - $$                       ;   e_phoff
            dq  0                               ;   e_shoff
            dd  0                               ;   e_flags
            dw  ehdrsize                        ;   e_ehsize
            dw  phdrsize                        ;   e_phentsize
            dw  1                               ;   e_phnum
            dw  0                               ;   e_shentsize
            dw  0                               ;   e_shnum
            dw  0                               ;   e_shstrndx

ehdrsize    equ $ - ehdr

phdr:                                           ; Elf64_Phdr
            dd  1                               ;   p_type
            dd  5                               ;   p_flags
            dq  0                               ;   p_offset
            dq  $$                              ;   p_vaddr
            dq  $$                              ;   p_paddr
            dq  filesize                        ;   p_filesz
            dq  filesize                        ;   p_memsz
            dq  0x1000                          ;   p_align

phdrsize    equ     $ - phdr

_start:
   mov di,42        ; only the low byte of the exit code is kept,
                    ; so we can use di instead of the full edi/rdi
   xor eax,eax
   mov al,60        ; shorter than mov eax,60
   syscall          ; perform the syscall

filesize      equ     $ - $$

我们减少到130个字节。这比91字节的可执行文件要大一些,但这是因为多个字段变为64位而不是32位。


然后我们可以应用一些与他相似的技巧; phdrehdr的部分重叠可以完成,尽管phdr中字段的顺序不同,并且我们必须将p_flagse_shnum重叠(但是,由于e_shentsize为0),应将其忽略。

在标头中移动代码要困难一些,因为它要大3个字节,但是标头的那部分与32位情况下一样大。我们通过提前开始2个字节,覆盖填充字节(确定)和ABI版本字段(不是确定,但仍然有效)克服了这一问题。

因此,我们达到:

bits 64
            org 0x08048000

ehdr:                                           ; Elf64_Ehdr
            db  0x7F, "ELF", 2, 1,              ;   e_ident
_start:
            mov di,42        ; only the low byte of the exit code is kept,
                            ; so we can use di instead of the full edi/rdi
            xor eax,eax
            mov al,60        ; shorter than mov eax,60
            syscall          ; perform the syscall
            dw  2                               ;   e_type
            dw  62                              ;   e_machine
            dd  1                               ;   e_version
            dq  _start                          ;   e_entry
            dq  phdr - $$                       ;   e_phoff
            dq  0                               ;   e_shoff
            dd  0                               ;   e_flags
            dw  ehdrsize                        ;   e_ehsize
            dw  phdrsize                        ;   e_phentsize
phdr:                                           ; Elf64_Phdr
            dw  1                               ;   e_phnum         p_type
            dw  0                               ;   e_shentsize
            dw  5                               ;   e_shnum         p_flags
            dw  0                               ;   e_shstrndx
ehdrsize    equ $ - ehdr
            dq  0                               ;   p_offset
            dq  $$                              ;   p_vaddr
            dq  $$                              ;   p_paddr
            dq  filesize                        ;   p_filesz
            dq  filesize                        ;   p_memsz
            dq  0x1000                          ;   p_align

phdrsize    equ     $ - phdr
filesize    equ     $ - $$

这是112个字节长。

此刻我停下来,因为我现在没有太多时间进行此操作。现在,您已经有了基本布局,并进行了64位的相关修改,因此您只需要尝试更大胆的重叠