最小的可执行程序(x86-64) [英] Smallest executable program (x86-64)

查看:146
本文介绍了最小的可执行程序(x86-64)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I recently came across this post describing the smallest possible ELF executable, however the post was written for 32 bit and I was unable to get the final version to compile on my machine. This brings me to the question: what's the smallest x86-64 ELF executable it's possible to write that runs without error?

推荐答案

从我的答案开始 Linux上的ELF可执行文件的真实"入口点和原始"系统调用,我们可以将其简化为

Starting from an answer of mine about the "real" entrypoint of an ELF executable on Linux and "raw" syscalls, we can strip it down to

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个字节):

I don't think you can get it to be any smaller without going out of specs - in particular, the psABI doesn't guarantee anything about the state of eax. This gets assembled to precisely 10 bytes (as opposed to the 7 bytes of the 32 bit payload):

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


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


The straightforward way (assemble with nasm, link with ld) produces me a 352 bytes executable.

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

The first "real" transformation he does is building the ELF "by hand"; doing this (with some modifications, as the ELF header for x86_64 is a bit bigger)

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位.

we get down to 130 bytes. This is a tad bigger than the 91 bytes executable, but it comes from the fact that several fields become 64 bits instead of 32.

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

We can then apply some tricks similar to his; the partial overlap of phdr and ehdr can be done, although the order of fields in phdr is different, and we have to overlap p_flags with e_shnum (which however should be ignored due to e_shentsize being 0).

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

Moving the code inside the header is slightly more difficult, as it's 3 bytes larger, but that part of header is just as big as in the 32 bit case. We overcome this by starting 2 bytes earlier, overwriting the padding byte (ok) and the ABI version field (not ok, but still works).

因此,我们达到:

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位的相关修改,因此您只需尝试更大胆的重叠

Here I stop for the moment, as I don't have much time for this right now. You now have the basic layout with the relevant modifications for 64 bit, so you just have to experiment with more audacious overlaps

这篇关于最小的可执行程序(x86-64)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆