详解ELF可执行文件格式:读取头部信息和程序表头
https://man7.org/linux/man-pages/man5/elf.5.html
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
ElfN_Addr e_entry;
ElfN_Off e_phoff;
ElfN_Off e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} ElfN_Ehdr;
https://pan.baidu.com/s/1YbApA8J_68E1UlLHpAtc9A
密码: ao1d
对应的是代码所解读的ELF文件,以下是解读ELF头的实现:
import struct
elf32_path = "/content/drive/My Drive/elf32/hello_world.o"
ET_REL = 1 #.o类型
ET_EXEC = 2 #可执行
ET_DYN = 3 #动态链接
ELFCLASSNONE = 0
ELFCLASS32 = 1
ELFCLASS64 = 2
LITTLE_ENDIAN = 1 #数据编码是大端还是小端
BIG_ENDIAN = 2
#支持的CPU类型
MACHINE_EM_386 = 3 #Intel 80386
MACHINE_EM_860 = 7 #Intel 80860
MACHINE_S570 = 9 #IBM System/370
VERSION_CURRENT = 1
PT_NONE = 0 #程序头表未定义
PT_LOAD = 1 #对应的段要被加载到内存中
PT_DYNAMIC = 2 #包含动态链接对应的信息
PT_INTERP = 3 #连接器二进制可执行文件对应路径
PT_NOTE = 4 #
PT_SHLIB = 5 #保留,不应该是该值
PT_PHDR = 6 #该程序头专门用于描述程序头表
PF_X = 1 #可执行
PF_W = 2 #可写
PF_R = 3 #可读
def read_elf_header(binary_data):
format = "@"+ "".join(['c']*16)
magic = struct.unpack(format, binary_data[0:16])
print("Magic: ", magic)
elf_class = int.from_bytes(magic[4], "little") #32位还是64位
if elf_class == ELFCLASS32:
print("class ELF32")
if elf_class == ELFCLASS64:
print("class ELF64")
endian = int.from_bytes(magic[5], "little")
if endian == LITTLE_ENDIAN:
print("little endian")
elif endian == BIG_ENDIAN:
print("big endian")
version = int.from_bytes(magic[6], "little")
if version == VERSION_CURRENT:
print("Version Current")
o_class = struct.unpack("h", binary_data[16:18])[0]
file_type = "type: "
if o_class == ET_REL:
file_type += "ET_REL"
if o_class == ET_EXEC:
file_type += "ET_EXEC"
if o_class == ET_DYN:
file_type += "ET_DYN"
print(file_type)
machine_type = struct.unpack("h", binary_data[18:20])[0]
if machine_type == MACHINE_EM_386:
print("Machine: Intel 80386")
obj_file_version = struct.unpack("I", binary_data[20: 24])[0]
print("object file version: ", obj_file_version)
virtual_entry = struct.unpack("i", binary_data[24:28])[0]
print("Entry point address: ", hex(virtual_entry))
program_header_offset = struct.unpack("i", binary_data[28:32])[0]
print("program header offset: ", program_header_offset) #程序头表在文件内部偏移
section_header_offset = struct.unpack("i", binary_data[32:36])[0]
print("section header offset: ", section_header_offset)#段头表在文件内部偏移
processor_flag = struct.unpack("i", binary_data[36:40])[0]
print("processor flag: ", processor_flag )
this_header_size = struct.unpack("h", binary_data[40:42])[0]
print("size of this header: ", this_header_size)
program_header_entry_size = struct.unpack("h", binary_data[42:44])[0] #程序头表中一条记录的大小
print("program header entry size: ", program_header_entry_size)
program_entry_count = struct.unpack("h", binary_data[44:46])[0] #程序头表中记录的数量
print("program header entry count: ", program_entry_count)
section_header_entry_size = struct.unpack("h", binary_data[46:48])[0] #段记录的大小
print("section header entry size: ", section_header_entry_size)
section_header_count = struct.unpack("h", binary_data[48:50])[0] #段表记录的数量
print("section header count: ", section_header_count)
section_string_table = struct.unpack("h", binary_data[50:52])[0]
print("section string table index: ", section_string_table)
return (program_header_offset, section_header_offset, program_header_entry_size, program_entry_count, section_header_entry_size, section_header_count)
typedef struct {
uint32_t p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
} Elf32_Phdr;
def readelf_program_header(binary_data, size, count):
print("there are {} program header entries".format(count))
for i in range(count):
binary_data = binary_data[size * i :]
program_type = struct.unpack("i", binary_data[0:4])[0]
if program_type == PT_NONE:
print("header type: PT_NONE")
if program_type == PT_LOAD:
print("header type: PT_LOAD") #可转载到内存里的程序段,对应代码和数据,这些段才是我们关心的
elif program_type == PT_DYNAMIC:
print("header type: PT_DYNAMIC")
elif program_type == PT_INTERP:
print("header type: PT_INTERP")
elif program_type == PT_NOTE:
print("header type: PT_NOTE")
elif program_type == PT_SHLIB:
print("header type: PT_SHLIB")
elif program_type == PT_PHDR:
print("header type: PT_PHDR")
else:
print("header type hex: ", hex(program_type))
header_offset = struct.unpack("i", binary_data[4:8])[0]
print("program header content offset: ", hex(header_offset))
virtual_addr = struct.unpack("i", binary_data[8:12])[0]
print("program header content virtual address: ", hex(virtual_addr))
pysical_addr = struct.unpack("i", binary_data[12:16])[0]
print("program header content pysical address: ", hex(pysical_addr))
header_file_size = struct.unpack("i", binary_data[16:20])[0]
print("program header file size: ", header_file_size)
header_memory_size = struct.unpack("i", binary_data[20:24])[0]
print("program header memory size: ", header_memory_size)
header_flags = struct.unpack("i", binary_data[24:28])[0]
if (header_flags & PF_X):
print("this segment can be execute")
if (header_flags & PF_R):
print("this segment can be read")
if (header_flags & PF_W):
print("this segment cab be write")
header_align = struct.unpack("i", binary_data[28:32])[0]
print("align value: ", header_align)
with open(elf32_path, 'rb') as f:
binary_data = f.read()
elf32_info = read_elf_header(binary_data)
program_header_offset = elf32_info[0]
program_header_entry_size = elf32_info[2]
program_header_entry_count = elf32_info[3]
print("header offset: ", program_header_offset)
readelf_program_header(binary_data[program_header_offset:], program_header_entry_size,
program_header_entry_count)
更多精彩内容请点击”阅读原文“
本文分享自微信公众号 - Coding迪斯尼(gh_c9f933e7765d)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
以上是 详解ELF可执行文件格式:读取头部信息和程序表头 的全部内容, 来源链接: utcz.com/z/509451.html