ELF文件分析
ELF文件概述
1. 什么是ELF文件
ELF(Executable and Linkable Format)是Linux和其他类Unix系统下的可执行文件、目标代码、共享库和核心转储的标准文件格式。ELF文件包含了程序运行所需的所有信息,如代码、数据、符号表、重定位信息等。理解ELF文件结构对于逆向工程、安全分析和软件开发都至关重要。
ELF文件类型
- ET_REL (1): 可重定位文件,如.o文件
- ET_EXEC (2): 可执行文件,如/bin/ls
- ET_DYN (3): 共享目标文件,如.so文件
- ET_CORE (4): 核心转储文件
ELF文件标识
e_ident[0-3]: 魔数 (0x7F, 'E', 'L', 'F')
e_ident[4]: 文件类 (1=32位, 2=64位)
e_ident[5]: 数据编码 (1=小端, 2=大端)
e_ident[6]: ELF版本 (1=当前版本)
e_ident[7-15]: 保留字节
实际例题:识别ELF文件
# 使用hexdump查看ELF文件头
$ hexdump -C -n 16 /bin/ls
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
# 分析结果:
# 7f 45 4c 46: ELF魔数
# 02: 64位文件
# 01: 小端序
# 01: ELF版本1
2. ELF文件的特点
- 跨平台兼容:支持多种CPU架构和操作系统
- x86, x86-64, ARM, MIPS等架构
- Linux, FreeBSD, Android等系统
- 动态链接:支持动态链接库(.so文件)
- 运行时加载共享库
- 支持符号版本控制
- 支持延迟绑定
- 可重定位:支持代码和数据在不同内存地址加载
- 支持地址无关代码(PIC)
- 支持基址重定位
- 支持符号重定位
- 符号表:包含丰富的调试和符号信息
- 全局符号和局部符号
- 弱符号和强符号
- 调试符号信息
- 节表:灵活的数据组织方式
- 代码段和数据段分离
- 支持自定义节
- 支持节对齐和权限控制
- 程序头表:描述段(Segment)信息
- 可加载段
- 动态链接信息
- 程序解释器
实际例题:查看ELF文件段信息
# 使用readelf查看程序头表
$ readelf -l /bin/ls
Elf file type is DYN (Shared object file)
Entry point 0x5850
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 0x8
INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000001e4a8 0x000000000001e4a8 R E 0x200000
LOAD 0x000000000001e4b0 0x000000000021e4b0 0x000000000021e4b0
0x00000000000013b8 0x00000000000013b8 RW 0x200000
DYNAMIC 0x000000000001e4e0 0x000000000021e4e0 0x000000000021e4e0
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000254 0x0000000000000254 0x0000000000000254
0x0000000000000044 0x0000000000000044 R 0x4
GNU_EH_FRAME 0x000000000001b6a0 0x000000000001b6a0 0x000000000001b6a0
0x0000000000000844 0x0000000000000844 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x000000000001e4b0 0x000000000021e4b0 0x000000000021e4b0
0x0000000000001350 0x0000000000001350 R 0x1
3. ELF文件的应用场景
- 程序分析:分析程序的结构和行为
- 函数调用关系分析
- 控制流分析
- 数据流分析
- 漏洞挖掘:发现程序中的安全漏洞
- 缓冲区溢出检测
- 格式化字符串漏洞
- 整数溢出检测
- 恶意软件分析:分析病毒、木马等恶意程序
- 行为分析
- 特征提取
- 家族分类
- 软件保护:实现软件加密和保护机制
- 代码混淆
- 反调试技术
- 完整性校验
- 性能优化:分析程序的资源使用和性能特征
- 内存使用分析
- 函数调用开销
- 热点代码识别
- 兼容性研究:分析不同版本程序之间的差异
- ABI兼容性
- API变化分析
- 版本迁移
实际例题:分析ELF文件符号表
# 使用nm查看符号表
$ nm -D /bin/ls
0000000000000000 A _IO_stdin_used
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main
U __stack_chk_fail
U abort
U acl_extended_file
U acl_get_entry
U acl_get_tag_type
U acl_to_text
U bindtextdomain
U calloc
U clock_gettime
U closedir
U dcgettext
U dirfd
U dprintf
U endgrent
U endpwent
U error
U exit
U fchdir
U fchownat
U fclose
U fcntl
U fflush
U fgetfilecon
U fgetxattr
U fnmatch
U fopen
U fprintftime
U fprintf
U fputs
U freadlinkat
U free
U fstatat
U fts_children
U fts_close
U fts_open
U fts_read
U fts_set
U getenv
U getgrgid
U getgrnam
U getopt_long
U getpwnam
U getpwuid
U getxattr
U hash_get_n_entries
U hash_get_n_buckets
U hash_get_max_bucket_length
U hash_string
U iconv_open
U iswprint
U lchown
U lgetfilecon
U linkat
U llistxattr
U localeconv
U localtime
U lstat
U malloc
U mbrtowc
U mbsinit
U mbsrtowcs
U memcmp
U memcpy
U mempcpy
U memset
U mknodat
U mktime
U mmap
U mprotect
U mremap
U newlocale
U nl_langinfo
U openat
U opendir
U parse_gnu_standard_options_only
U posix_fadvise
U posix_openpt
U pread
U printf
U putchar
U puts
U qsort
U raise
U readdir
U readlink
U readlinkat
U realloc
U regcomp
U regexec
U regfree
U removexattr
U renameat
U rmdir
U setenv
U setlocale
U setvbuf
U sigaction
U siginterrupt
U stat
U strcasecmp
U strchr
U strcmp
U strcoll
U strcpy
U strcspn
U strdup
U strerror
U strftime
U strlen
U strncasecmp
U strncmp
U strncpy
U strndup
U strnlen
U strpbrk
U strrchr
U strspn
U strstr
U strtod
U strtol
U strtoul
U strverscmp
U symlinkat
U sysconf
U time
U tzset
U uname
U unlinkat
U unsetenv
U utime
U utimensat
U vfprintf
U vprintf
U wcrtomb
U wcscoll
U wcslen
U wcsnrtombs
U wcsrtombs
U wcstombs
U wctob
U wctomb
U wcwidth
U write
4. ELF文件分析的基本概念
文件头
- 魔数:标识ELF文件格式
- 固定值:0x7F 0x45 0x4C 0x46
- 用于快速识别文件类型
- 文件类型:可执行文件、可重定位文件、共享目标文件等
- ET_REL (1): 可重定位文件
- ET_EXEC (2): 可执行文件
- ET_DYN (3): 共享目标文件
- ET_CORE (4): 核心转储文件
- 机器类型:支持的CPU架构
- EM_386 (3): Intel 80386
- EM_X86_64 (62): AMD x86-64
- EM_ARM (40): ARM
- EM_MIPS (8): MIPS
- 入口点:程序执行的起始地址
- 可执行文件的代码入口
- 相对于基址的偏移
节表
- .text:代码段
- 包含可执行代码
- 只读属性
- 可执行属性
- .data:已初始化数据段
- 包含已初始化的全局变量
- 读写属性
- .bss:未初始化数据段
- 包含未初始化的全局变量
- 读写属性
- 不占用文件空间
- .rodata:只读数据段
- 包含常量数据
- 只读属性
- .symtab:符号表
- 包含所有符号信息
- 用于链接和调试
- .strtab:字符串表
- 存储符号名称
- 存储节名称
- .rel:重定位表
- 包含重定位信息
- 用于动态链接
程序头表
- LOAD:可加载段
- 包含代码和数据
- 指定内存权限
- 指定文件偏移
- DYNAMIC:动态链接信息
- 包含动态链接库列表
- 包含重定位信息
- 包含符号表信息
- INTERP:程序解释器
- 指定动态链接器路径
- 用于加载共享库
- NOTE:注释信息
- 包含版本信息
- 包含ABI信息
实际例题:分析ELF文件节表
# 使用readelf查看节表
$ readelf -S /bin/ls
There are 31 section headers, starting at offset 0x1b168:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000000254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-id NOTE 0000000000000274 00000274
0000000000000024 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000298 00000298
00000000000000a4 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 0000000000000340 00000340
0000000000000c48 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000f88 00000f88
00000000000005c2 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 000000000000154a 0000154a
0000000000000108 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000001658 00001658
00000000000000f0 0000000000000000 A 6 2 8
[ 9] .rela.dyn RELA 0000000000001748 00001748
0000000000000c18 0000000000000018 A 5 0 8
[10] .rela.plt RELA 0000000000002360 00002360
0000000000000a08 0000000000000018 AI 5 24 8
[11] .init PROGBITS 0000000000003000 00003000
0000000000000017 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000003020 00003020
00000000000006b0 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 00000000000036d0 000036d0
0000000000000008 0000000000000008 AX 0 0 8
[14] .text PROGBITS 00000000000036e0 000036e0
0000000000017f2a 0000000000000000 AX 0 0 16
[15] .fini PROGBITS 000000000001b60c 0001b60c
0000000000000009 0000000000000000 AX 0 0 4
[16] .rodata PROGBITS 000000000001b620 0001b620
0000000000003f20 0000000000000000 A 0 0 32
[17] .eh_frame_hdr PROGBITS 000000000001f540 0001f540
0000000000000844 0000000000000000 A 0 0 4
[18] .eh_frame PROGBITS 000000000001fd88 0001fd88
0000000000002c24 0000000000000000 A 0 0 8
[19] .init_array INIT_ARRAY 00000000000229b0 000229b0
0000000000000008 0000000000000008 WA 0 0 8
[20] .fini_array FINI_ARRAY 00000000000229b8 000229b8
0000000000000008 0000000000000008 WA 0 0 8
[21] .data.rel.ro PROGBITS 00000000000229c0 000229c0
0000000000000b20 0000000000000000 WA 0 0 32
[22] .dynamic DYNAMIC 00000000000234e0 000234e0
00000000000001f0 0000000000000010 WA 6 0 8
[23] .got PROGBITS 00000000000236d0 000236d0
0000000000000330 0000000000000008 WA 0 0 8
[24] .data PROGBITS 0000000000023a00 00023a00
0000000000000a60 0000000000000000 WA 0 0 32
[25] .bss NOBITS 0000000000024460 00024460
0000000000001a68 0000000000000000 WA 0 0 32
[26] .comment PROGBITS 0000000000000000 00024460
0000000000000029 0000000000000001 MS 0 0 1
[27] .symtab SYMTAB 0000000000000000 00024490
0000000000000c48 0000000000000018 28 47 8
[28] .strtab STRTAB 0000000000000000 000250d8
00000000000004c2 0000000000000000 0 0 1
[29] .shstrtab STRTAB 0000000000000000 0002559a
0000000000000109 0000000000000000 0 0 1
[30] .gnu_debuglink PROGBITS 0000000000000000 000256a4
0000000000000034 0000000000000000 0 0 4