【翻译】如何让Linux ELF文件由4KB缩减至45B!
字数 973 2025-08-23 18:31:34

如何将Linux ELF文件从4KB缩减至45B - 深入解析与优化指南

1. 初始探索:从C语言到汇编

1.1 基础C程序分析

我们从最简单的C程序开始:

/* tiny.c */
int main(void) {
    return 42;
}

编译后文件大小:

  • 普通编译:3998字节
  • 使用-s去除符号表:2632字节
  • 添加-O3优化:2616字节

1.2 转向汇编语言

使用NASM编写等效汇编代码:

; tiny.asm
BITS 32
GLOBAL main
SECTION .text
main:
    mov eax, 42
    ret

编译后文件大小:2604字节(仅减少12字节)

1.3 绕过main()接口

直接使用_start入口点:

; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
    mov eax, 42
    ret

编译选项:

  • -nostartfiles:不使用标准系统启动文件
  • 但会导致段错误,因为_start不是函数,没有返回地址

2. 正确使用系统调用退出

2.1 使用_exit()函数

; tiny.asm
BITS 32
EXTERN _exit
GLOBAL _start
SECTION .text
_start:
    push dword 42
    call _exit

编译后文件大小:1340字节

2.2 完全脱离标准库

使用-nostdlib选项,但需要自己实现系统调用:

; tiny.asm
BITS 32
GLOBAL _start
SECTION .text
_start:
    mov eax, 1    ; exit系统调用号
    mov ebx, 42   ; 返回值
    int 0x80      ; 触发系统调用

编译后文件大小:372字节

3. 优化汇编代码

3.1 原始机器码分析

00000000 B801000000 mov eax, 1
00000005 BB2A000000 mov ebx, 42
0000000A CD80       int 0x80

3.2 优化后的代码

xor eax, eax  ; 清空eax
inc eax       ; eax = 1
mov bl, 42    ; 只设置bl寄存器
int 0x80

使用ld直接链接:

  • 文件大小:368字节(由于对齐填充)

4. 深入ELF文件格式

4.1 ELF文件结构

ELF文件由以下部分组成:

  1. ELF头(52字节)
  2. 程序头表(可选)
  3. 节头表(可选)
  4. 实际程序数据

4.2 手动构造最小ELF

BITS 32
org 0x08048000

ehdr: ; Elf32_Ehdr
    db 0x7F, "ELF", 1, 1, 1, 0 ; e_ident
    times 8 db 0
    dw 2       ; e_type
    dw 3       ; e_machine
    dd 1       ; e_version
    dd _start  ; e_entry
    dd phdr - 
$$
 ; e_phoff
    dd 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: ; Elf32_Phdr
    dd 1       ; p_type
    dd 0       ; p_offset
    dd 
$$
      ; p_vaddr
    dd 
$$
      ; p_paddr
    dd filesize ; p_filesz
    dd filesize ; p_memsz
    dd 5       ; p_flags
    dd 0x1000  ; p_align

phdrsize equ $ - phdr

_start:
    mov bl, 42
    xor eax, eax
    inc eax
    int 0x80

filesize equ $ - 
$$

编译后文件大小:91字节

5. 极限优化技巧

5.1 重叠ELF头和程序代码

将代码嵌入ELF头的未使用部分:

BITS 32
org 0x08048000

ehdr:
    db 0x7F, "ELF" ; e_ident
    db 1, 1, 1, 0, 0
_start:
    mov bl, 42
    xor eax, eax
    inc eax
    int 0x80
    dw 2       ; e_type
    ; ... 其余ELF头字段

文件大小:84字节

5.2 重叠ELF头和程序头表

BITS 32
org 0x08048000

ehdr:
    db 0x7F, "ELF" ; e_ident
    db 1, 1, 1, 0, 0
_start:
    mov bl, 42
    xor eax, eax
    inc eax
    int 0x80
    dw 2       ; e_type
    dw 3       ; e_machine
    dd 1       ; e_version
    dd _start  ; e_entry
    dd phdr - 
$$
 ; e_phoff
phdr:
    dd 1       ; e_shoff ; p_type
    ; ... 重叠的字段

文件大小:76字节

5.3 最终优化版本

BITS 32
org 0x00010000

    db 0x7F, "ELF" ; e_ident
    dd 1           ; p_type
    dd 0           ; p_offset
    dd 
$$
          ; p_vaddr
    dw 2           ; e_type ; p_paddr
    dw 3           ; e_machine
    dd _start      ; e_version ; p_filesz
    dd _start      ; e_entry ; p_memsz
    dd 4           ; e_phoff ; p_flags
_start:
    mov bl, 42     ; e_shoff ; p_align
    xor eax, eax
    inc eax        ; e_flags
    int 0x80
    db 0
    dw 0x34        ; e_ehsize
    dw 0x20        ; e_phentsize
    db 1           ; e_phnum ; e_shentsize ; e_shnum ; e_shstrndx

文件大小:45字节(绝对最小值)

6. 关键优化技术总结

  1. 绕过标准启动代码:使用-nostartfiles-nostdlib
  2. 直接系统调用:避免链接任何库
  3. 寄存器优化:使用部分寄存器(如bl而非ebx)
  4. ELF结构重叠
    • 代码嵌入ELF头
    • 程序头表与ELF头重叠
  5. 利用未检查字段
    • 使用非标准加载地址
    • 利用p_flags的可选位
  6. 文件截断:依赖Linux的零填充行为

7. 实际应用注意事项

  1. 这种极端优化主要用于研究目的
  2. 实际应用中应考虑:
    • 可读性和可维护性
    • 兼容性(不同Linux版本可能有不同行为)
    • 安全性(过度紧凑可能被误认为恶意代码)

通过这种方法,我们成功将Linux ELF可执行文件从最初的4KB缩减到了仅45字节,同时保持其完整功能。

如何将Linux ELF文件从4KB缩减至45B - 深入解析与优化指南 1. 初始探索:从C语言到汇编 1.1 基础C程序分析 我们从最简单的C程序开始: 编译后文件大小: 普通编译:3998字节 使用 -s 去除符号表:2632字节 添加 -O3 优化:2616字节 1.2 转向汇编语言 使用NASM编写等效汇编代码: 编译后文件大小:2604字节(仅减少12字节) 1.3 绕过main()接口 直接使用 _start 入口点: 编译选项: -nostartfiles :不使用标准系统启动文件 但会导致段错误,因为 _start 不是函数,没有返回地址 2. 正确使用系统调用退出 2.1 使用_ exit()函数 编译后文件大小:1340字节 2.2 完全脱离标准库 使用 -nostdlib 选项,但需要自己实现系统调用: 编译后文件大小:372字节 3. 优化汇编代码 3.1 原始机器码分析 3.2 优化后的代码 使用ld直接链接: 文件大小:368字节(由于对齐填充) 4. 深入ELF文件格式 4.1 ELF文件结构 ELF文件由以下部分组成: ELF头(52字节) 程序头表(可选) 节头表(可选) 实际程序数据 4.2 手动构造最小ELF 编译后文件大小:91字节 5. 极限优化技巧 5.1 重叠ELF头和程序代码 将代码嵌入ELF头的未使用部分: 文件大小:84字节 5.2 重叠ELF头和程序头表 文件大小:76字节 5.3 最终优化版本 文件大小:45字节(绝对最小值) 6. 关键优化技术总结 绕过标准启动代码 :使用 -nostartfiles 和 -nostdlib 直接系统调用 :避免链接任何库 寄存器优化 :使用部分寄存器(如bl而非ebx) ELF结构重叠 : 代码嵌入ELF头 程序头表与ELF头重叠 利用未检查字段 : 使用非标准加载地址 利用p_ flags的可选位 文件截断 :依赖Linux的零填充行为 7. 实际应用注意事项 这种极端优化主要用于研究目的 实际应用中应考虑: 可读性和可维护性 兼容性(不同Linux版本可能有不同行为) 安全性(过度紧凑可能被误认为恶意代码) 通过这种方法,我们成功将Linux ELF可执行文件从最初的4KB缩减到了仅45字节,同时保持其完整功能。