Explicación y análisis de archivos elf

1. Primero arrastre el Android de 64 bits al editor 010

Inserte la descripción de la imagen aquí
Puede ver que hay 4 estructuras, cómo mirar estas estructuras, aquí nos enfocamos en elf_header, program_header_table, section_header_table

  1. elf_header es el archivo de encabezado del archivo elf, que cubre una variedad de información para explicar el significado de varios campos aquí. De hecho,
    puede comprender el significado de cada campo al verificar las letras en inglés en el comentario del editor 010 .
 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. Entonces, ¿qué hacen program_header y section_header?
这又要说elf的两种视图
1.program视图 段视图, 执行视频
2.section视图 节视图,ida视图,加载so的时候会把节变为段
  1. Entonces, ¿cómo se carga la sección sección (sección) como programa (sección)?
分三步
1.装载
2.分配数据块
3.连接 (重点)

Probablemente aclaró la relación entre ellos, luego cómo escribir un análisis de archivo elf

  1. Primero leemos el campo del encabezado en elf
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. Leer datos del programa
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. Leer datos de la sección
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)

Nota

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

Supongo que te gusta

Origin blog.csdn.net/esabeny/article/details/112288146
Recomendado
Clasificación