elf文件的解释和解析

1.首先把android 64位的so拖进010 editor

在这里插入图片描述
可以看到这里有4个struct,这些struct怎么去看,这里我们重点关注 elf_header, program_header_table, section_header_table

  1. elf_header就是elf文件的头文件,里面涵盖了各种信息说明 这里主要解释几个字段的意思,其实你查010 editor
    注释里的英文字母也能看懂各个字段的意思
 1.16个字节是elf标识
 2. 2个字节.dynsym表示该节区包含了要动态连接的符号
3.e_mechine表示arm版本
4.e_version表示文件版本
5.表示so的开始地址一般为0x000000
6.program_header_offset,程序头位移 52 段头表
7.section_header_offset,节区位移    节头表
8.elf header size elf头的大小
9.paogram_header_entry_size 每个paramitem的大小
10.number of program_header_entries program的个数
11.section_header_size 节的个数
12.numver_of_section_header_entry_size, 每个节的大小
13.e_shtrndx_string_table_index, shtrndx在setion的index
  1. 那么program_header和section_header又是干嘛的
这又要说elf的两种视图
1.program视图 段视图, 执行视频
2.section视图 节视图,ida视图,加载so的时候会把节变为段
  1. 那么节又是怎么把section(节)加载为program(段)的呢
分三步
1.装载
2.分配数据块
3.连接 (重点)

大概理清了他们之间的关系,那么怎么去写一个elf文件的解析

  1. 首先我们读取elf里的header字段
import mmap  # 将一个文件或者其它对象映射到进程的地址空间
import struct

endian_prefix = ""

def is_elf(f):
    magic_code = f.read(4).decode()
    if magic_code.find("ELF") == -1:
        raise ValueError("not a valid elf file")


def get_ei_data(mm):
    # 判断大小端
    ei_data = struct.unpack("<B", mm.read(1))[0]
    # 其他没啥用
    endian_prefix = '<' if ei_data == 1 else '>'
    return endian_prefix

# elf头
class ElfHeader:
    e_type = ""
    e_machine = ""
    e_version = ""
    e_entry = ""
    e_phoff = ""
    e_shoff = ""
    e_flags = ""
    e_ehsize = ""
    e_phentsize = ""
    e_phnum = ""
    e_shentsize = ""
    e_shnum = ""
    e_shtrndx = ""


def read_elf_header(f):
    is_elf(f)
    global endian_prefix
    endian_prefix = get_ei_data(f)
    f.seek(16)
    ElfHeader.e_type = unpack_data("H", 2, f)
    ElfHeader.e_machine = unpack_data("H", 2, f)
    ElfHeader.e_version = unpack_data("I", 4, f)
    ElfHeader.e_entry = unpack_data("I", 4, f)
    ElfHeader.e_phoff = unpack_data("I", 4, f)
    ElfHeader.e_shoff = unpack_data("I", 4, f)
    ElfHeader.e_flags = unpack_data("I", 4, f)
    ElfHeader.e_ehsize = unpack_data("H", 2, f)
    ElfHeader.e_phentsize = unpack_data("H", 2, f)
    ElfHeader.e_phnum = unpack_data("H", 2, f)
    ElfHeader.e_shentsize = unpack_data("H", 2, f)
    ElfHeader.e_shnum = unpack_data("H", 2, f)
    ElfHeader.e_shtrndx = unpack_data("H", 2, f)


def main(so_path):
    with open(so_path, "r+b") as f:
        with mmap.mmap(f.fileno(), 0) as mm:
            mm = mm
            read_elf_header(mm)    
  1. 读取program数据
def read_data(f, off, size):
    print("off", off)
    f.seek(off)
    return b''.join([t[0] for t in struct.iter_unpack('<s', f.read(size))])


def unpack_data(data_type, size, f):
    return struct.unpack(endian_prefix + data_type, f.read(size))[0]


def read_program_header_table(f, off, size):
    """
    读取程序视图
    :param f:
    :param off:
    :param size:
    :return:
    """
    f.seek(off)
    for _ in range(size):
        info = ProgramInfo()
        info.p_type = unpack_data("I", 4, f)
        info.p_elf_begin = unpack_data("I", 4, f)
        info.p_var_addr = unpack_data("I", 4, f)
        info.p_p_addr = unpack_data("I", 4, f)
        info.p_seg_length = unpack_data("I", 4, f)
        info.p_memsz = unpack_data("I", 4, f)
        info.p_flag = unpack_data("I", 4, f)
        info.p_align = unpack_data("I", 4, f)
        current = f.tell()
        data = read_data(f, info.p_elf_begin, info.p_seg_length)
        info.data = data
        f.seek(current)
  1. 读取节区数据
def read_section_header(f, off, size):
    """
    节区视图
    :param f:
    :param off:
    :param size:
    :return:
    """
    f.seek(off)
    for _ in range(size):
        info = SectionInfo()
        info.s_name = unpack_data("I", 4, f)
        info.p_elf_begin = unpack_data("I", 4, f)
        info.s_type = unpack_data("I", 4, f)
        info.s_flag = unpack_data("I", 4, f)
        info.s_addr = unpack_data("I", 4, f)
        info.s_size = unpack_data("I", 4, f)
        info.s_link = unpack_data("I", 4, f)
        info.s_info = unpack_data("I", 4, f)
        info.s_addr_align = unpack_data("I", 4, f)
        info.s_ent_size = unpack_data("I", 4, f)
        current = f.tell()
        char_data = read_data(f, info.s_addr, info.s_size)
        print("char_data", char_data.decode('utf-8', errors='ignore'))
        f.seek(current)

注意

1.字段的大小怎么看,可以根据010editor里的size字段去看
2.需要注意大端小端的数据怎么去取

猜你喜欢

转载自blog.csdn.net/esabeny/article/details/112288146