ELF32-i386 文件格式简要分析(2)
通过简单的一些 Case,通过实际操作对 ELF32-i386 文件做概要分析。
使用 Docker 来统一整体的开发、测试环境,适用于 Linux、Windows、MacOS(包括 Intel、M1 芯片)。
ELF Header 回顾
ELF 中,最核心的字段如上标注:
Program Header
的起始地址0x34
,其实和 ELF Header 的大小e_ehsize
是一样的,也就是说Pargram Header
是紧跟在ELF Header
之后的- 数量 * 大小 =
0x02
*0x20
= 64 字节 - 所以地址范围为:
0x34
~0x74
- 数量 * 大小 =
Section Header
的起始地址 0x1024- 数量 * 大小 =
0x03
*0x28
= 120 字节 - 所以地址范围为
0x1024
~0x109c
- 数量 * 大小 =
Program
从 ELF Header 中获取 Program Header 的位置之后,就可以得到以下 Header 的具体信息
- 第一个 Load 的 offset 为
0x0
,FileSiz 为0x74
,就是 ELF Header + Program Header 的总长度 - 第二个 Load 的 offset 为
0x1000
,FileSize 为0x11
,就是真实程序执行地址- 由于程序一般运行在保护模式下,所以会有虚拟地址的映射,页就是运行时的地址,即
0x804900
- 由于程序一般运行在保护模式下,所以会有虚拟地址的映射,页就是运行时的地址,即
$ readelf -l ./plus
Elf file type is EXEC (Executable file)
Entry point 0x8049000
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x00074 0x00074 R 0x1000
LOAD 0x001000 0x08049000 0x08049000 0x00011 0x00011 R E 0x1000
Section
从 ELF Header 中获取 Section Header 的位置之后,就可以得到以下 Header 的具体信息。
Section 的信息是从后往前引用的。
- 第一个 Section 为空
- 第二个 Section 指向真实的主程序代码地址
- 第三个 Section 指向 StringTable
- 地址范围
0x1011
~0x1022
- StringTable 的分别是给 Section Name 命名的
- 地址范围
$ readelf -S ./plus
There are 3 section headers, starting at offset 0x1024:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08049000 001000 000011 00 AX 0 0 16
[ 2] .shstrtab STRTAB 00000000 001011 000011 00 0 0 1
.data
使用 .data
section 来打印 Hello World
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov eax,4 ; system call number (sys_write),
; https://www.tutorialspoint.com/assembly_programming/assembly_system_calls.htm
; https://en.wikipedia.org/wiki/Write_(system_call)
mov ebx,1 ; file descriptor (stdout)
; https://en.wikipedia.org/wiki/File_descriptor
mov ecx,msg ;message to write
mov edx,len ;message length
int 0x80 ;call kernel
; https://en.wikipedia.org/wiki/X86_instruction_listings
; https://stackoverflow.com/questions/1817577/what-does-int-0x80-mean-in-assembly-code 80 是调用 Linux 内核
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!' ;string to be printed
len equ $ - msg ;length of the string, $ 表示当前地址 msg 表示 msg 的地址,相减即为 msg 的长度