Linux二进制分析入门

碎碎念

常用工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
objdump -D <elf_object> #ELF文件所有节的数据或代码
objdump -d <elf_object> #ELF文件程序代码
objdump -tT <elf_object> #所有符号
objcopy -only-section=.data <infile> <outfile> #把某文件.data段复制到另一个文件中
strace /bin/ls -o ./ls.out #跟踪ls系统调用
strace -p <pid> -o daemon.out #附加的现存进程上
strace -e read=3 /bin/ls #对每个SYS_read(3,buf,sizeof(buf))其中文件描述符3内容查看
ltrace <program> -o program.out #打印共享库/静态库符号
readelf -S <object> #查询节头表
readelf -l <object> #查询程序头表
readelf -s <object> #查询符号表
readelf -e <object> #查询ELF文件头数据
readelf -r <object> #查询重定位入口
readelf -d <object> #查询动态段
cat /proc/<pid>/maps #进程地址空间分布
#/proc/kcore为内核动态核心文件
#/proc/kallsyms为内核符号
#/proc/iomem

ELF文件格式

文件头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;

对于e_type字段有:

类型 描述
ET_NONE 未知
ET_REL 重定位文件.o
ET_EXEC 可执行文件
ET_DYN 共享目标文件dynamic
ET_CORN 核心文件

e_phoff字段指向程序头结构:

1
2
3
4
5
6
7
8
9
10
typedef struct {
Elf64_Word p_type; /* Segment type 段类型*/
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;

例如text和data段为PT_LOAD类型的段,表示可装载,映射时根据p_align在内存中对对齐。p_flags字段为权限,例如text段为PF_X|PF_R,data段为PF_W|PF_R。

PT_DYNAMIC类型的段为动态段,动态链接可执行文件特有,内容有运行时需链接的共享库、GOT表地址、重定位条目信息等。

PT_NOTE类型的段保存与特定供应商或系统相关的附加信息。PT_INTERP类型的段描述程序解释器位置,如/lib64/ld-linux-x86-64.so.2。PT_PHDR类型的段保存程序头本身位置和大小。

ELF节头如下:

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;

常见节如下:

节类型 所属段 描述
text SHT_PROGBITS text
rodata SHT_PROGBITS text
plt SHT_PROGBITS text
data SHT_PROGBITS data
bss SHT_NOBITS data
got.plt SHT_PROGBITS
dynsym SHT_DYNSYM text 从共享库导入的动态符号信息
dynstr 动态符号字符串表
rel.* SHT_REL 重定位信息
hash或gnu.hash 查找符号的散列表
symtab SHT_SYMTAB 符号信息
strtab SHT_STRTAB 符号字符串表
shstrtab SHT_STRTAB 节头字符串表
ctors与dtors