一个最小x86 ELF Hello World程序的诞生
来源:互联网 发布:mac下载iphone应用 编辑:程序博客网 时间:2024/06/05 16:06
注:这里的最小是指我能做到的
最终大小: 142字节
介绍
这篇文章可以算是我在Ubuntu Linux上尝试创建一个最小的x86 ELF二进制Hello World文件的记录,你也可以把它当作一篇指南,我的尝试先是从c开始,然后转向x86汇编,最后以16进制编辑器搞定,但我的最终成果实际上只能打印"Hi World",这纯粹是为了让最终的数字看着更顺眼一些而已,最终的x86 ELF二进制虽然已经被破坏的不成样子,但最重要的是它仍然可以照常运行。
开始
- 如果你也想跟我一起来试试,那你要做的第一件事就应该是先配置环境:
- 安装Ubuntu (或随便别的你喜欢的发行版)
- 运行: sudo apt-get install g++ gcc nasm
- 查看系统版本
user@computer:~$ lsb_release -aNo LSB modules are available.Distributor ID: UbuntuDescription: Ubuntu 8.04.1Release: 8.04Codename: hardyuser@computer:~$ uname -aLinux ryanh-desktop 2.6.24-19-generic #1 SMP Wed Jun 18 14:43:41 UTC 2008 i686 GNU/Linuxuser@computer:~$ gcc --versiongcc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)Copyright (C) 2007 Free Software Foundation, Inc.This is free software; see the source for copying conditions. There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.user@computer:~$ nasm -versionNASM version 0.99.06-20071101 compiled on Nov 15 2007
我的尝试从C开始,下面是我写的C程序,chello.c
- #include <STDIO.H>
- int main()
- {
- printf ("Hi World\n");
- return0;
- }
#includeint main(){ printf ("Hi World\n"); return0;}
编译:
user@computer:~$ gcc -o chello chello.cuser@computer:~$ ./chelloHi World
我最初得到的可执行文件大小为6363字节,你可以使用readelf来查看ELF文件的头信息,命令:
user@computer:~$ readelf -h chelloELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x80482f0 Start of program headers: 52 (bytes into file) Start of section headers: 3220 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 7 Size of section headers: 40 (bytes) Number of section headers: 36 Section header string table index: 33
ldd也是个很有用的命令,它可以显示这个c程序链接了哪些动态库:
user@computer:~$ ldd chello linux-gate.so.1 => (0xb7f77000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e18000) /lib/ld-linux.so.2 (0xb7f78000)
file命令可以告诉你这个文件的基本信息
user@computer:~$ file chellochello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped
我们看到file命令返回了"not stripped",这就是说这个二进制包含了用于调试的符号信息,让我们使用strip命令给它做个瘦身:
- user@computer:~$ strip -s chello
user@computer:~$ strip -s chello
经过瘦身之后,现在这个二进制的大小变成了2984字节,还是没法接受,是时候做出艰难决定了,于是我放弃了C以及printf,转而使用nasm x86汇编,下面是hello.asm:
SECTION .datamsg:db "Hi World",10len:equ $-msgSECTION .text global mainmain:movedx,lenmovecx,msgmovebx,1moveax,4int0x80movebx,0moveax,1int0x80
编译
user@computer:~$ nasm -f elf hello.asmuser@computer:~$ gcc -o hello hello.o -nostartfiles -nostdlib -nodefaultlibsuser@computer:~$ strip -s hellouser@computer:~$ ./helloHi World
strip之前是770字节,之后是448字节,但是这个二进制仍然包含一些无用的头部和section信息,现在找个你最顺手的16进制编辑器打开这个二进制,我一般用curses hexeditor和ghex2。
删掉0xAD后面的内容后,现在大小变成了173字节
可以看到0x7后面有一块无用空间,所有我们把保存Hi World字符串的数据块从0xA4-0xAC移到了0x7然后把0x86对字符串的引用从0xA4改为新的地址0x7,最后删除0xA2和0xA3.
现在文件大小应该变成了164字节,是时候进入最终环节了,剩下的部分我需要做些解释,基本上,我要做的就是不断尝试改变ELF的头部,但是避免出现segfault fault,我加了许多jmp并完全破坏了原本的可执行文件,尽管如此,它还是可以运行的,这里是一些有用的技巧: 在x86汇编中 0xD9D0,也就是nop操作符,如果你需要填充空白时这个指令很有用,另外0xEB后面跟一个有符号字节来完成相对跳转,你真的应该看看intel x86的汇编指令文档A-MN-Z。
- typedef struct {
- unsigned char e_ident[EI_NIDENT];
- Elf32_Half e_type;
- Elf32_Half e_machine;
- Elf32_Word e_version;
- Elf32_Addr e_entry;
- Elf32_Off e_phoff;
- Elf32_Off e_shoff;
- Elf32_Word e_flags;
- Elf32_Half e_ehsize;
- Elf32_Half e_phentsize;
- Elf32_Half e_phnum;
- Elf32_Half e_shentsize;
- Elf32_Half e_shnum;
- Elf32_Half e_shtrndx;
- } Elf32_Ehdr;
typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shtrndx;} Elf32_Ehdr;
结论
最终大小: 142 字节
helloworld.tar.gz
我确信肯定还有办法让它更小,应该还是可以从头部移掉一些没用的数据,但是我不想花太多时间钻研ELF的头部格式,另一个办法或许是使用a.out格式来代替ELF格式。
如果你有意见,建议或是批评欢迎给我邮件:henszey#gmail.com
-----------
本文来自:"Smallest x86 ELF Hello World",作者:henszey
- 一个最小x86 ELF Hello World程序的诞生
- Smallest x86 ELF Hello World
- 最小的C语言Hello,world程序
- 最小的hello world
- 一个Hello World程序
- 最小的ELF程序?
- 一个简单hello world程序
- 一个c++ Hello world程序
- 一个简单的Activiti的hello world程序
- socket编程的一个简单的hello world程序
- 一个面象对象的"hello world"程序
- 一个完整的struts 2 Hello World程序(5)
- 用Vim写一个简单的Hello,World程序
- 编写一个简单的内核模块程序Hello World!
- SDK的hello world程序!
- ACIS 的 hello world 程序
- 汇编语言的Hello world程序
- Hello world程序的生命周期
- 11.7 extract superclass (提炼超类)
- 在Vim(gvim)中使用cscope
- ADB学习
- HelloWorld模块加载--驱动
- 【局域网】解题报告
- 一个最小x86 ELF Hello World程序的诞生
- 咋办
- 【求先序遍历】解题报告
- 基于Android的WebService开发例子
- 存储过程的写法与不同
- Ubuntu下Android连接真实手机调试
- java 中变量存储位置的区别
- java 输出回环数(螺旋矩阵)
- ARM-Linux移植之(三)——init进程启动流程分析