""" Executable and Linkable Format (ELF), 32 bit, big or little endian Used on *nix systems as a replacement of the older a.out format Big-endian support kindly submitted by Craig McQueen (mcqueen-c#edsrd1!yzk!co!jp) """ from construct import * import six def elf32_body(ElfInt16, ElfInt32): elf32_program_header = Struct("program_header", Enum(ElfInt32("type"), NULL = 0, LOAD = 1, DYNAMIC = 2, INTERP = 3, NOTE = 4, SHLIB = 5, PHDR = 6, _default_ = Pass, ), ElfInt32("offset"), ElfInt32("vaddr"), ElfInt32("paddr"), ElfInt32("file_size"), ElfInt32("mem_size"), ElfInt32("flags"), ElfInt32("align"), ) elf32_section_header = Struct("section_header", ElfInt32("name_offset"), Pointer(lambda ctx: ctx._.strtab_data_offset + ctx.name_offset, CString("name") ), Enum(ElfInt32("type"), NULL = 0, PROGBITS = 1, SYMTAB = 2, STRTAB = 3, RELA = 4, HASH = 5, DYNAMIC = 6, NOTE = 7, NOBITS = 8, REL = 9, SHLIB = 10, DYNSYM = 11, _default_ = Pass, ), ElfInt32("flags"), ElfInt32("addr"), ElfInt32("offset"), ElfInt32("size"), ElfInt32("link"), ElfInt32("info"), ElfInt32("align"), ElfInt32("entry_size"), OnDemandPointer(lambda ctx: ctx.offset, HexDumpAdapter(Field("data", lambda ctx: ctx.size)) ), ) return Struct("body", Enum(ElfInt16("type"), NONE = 0, RELOCATABLE = 1, EXECUTABLE = 2, SHARED = 3, CORE = 4, ), Enum(ElfInt16("machine"), NONE = 0, M32 = 1, SPARC = 2, I386 = 3, Motorolla68K = 4, Motorolla88K = 5, Intel860 = 7, MIPS = 8, _default_ = Pass ), ElfInt32("version"), ElfInt32("entry"), ElfInt32("ph_offset"), ElfInt32("sh_offset"), ElfInt32("flags"), ElfInt16("header_size"), ElfInt16("ph_entry_size"), ElfInt16("ph_count"), ElfInt16("sh_entry_size"), ElfInt16("sh_count"), ElfInt16("strtab_section_index"), # calculate the string table data offset (pointer arithmetics) # ugh... anyway, we need it in order to read the section names, later on Pointer(lambda ctx: ctx.sh_offset + ctx.strtab_section_index * ctx.sh_entry_size + 16, ElfInt32("strtab_data_offset"), ), # program header table Rename("program_table", Pointer(lambda ctx: ctx.ph_offset, Array(lambda ctx: ctx.ph_count, elf32_program_header ) ) ), # section table Rename("sections", Pointer(lambda ctx: ctx.sh_offset, Array(lambda ctx: ctx.sh_count, elf32_section_header ) ) ), ) elf32_body_little_endian = elf32_body(ULInt16, ULInt32) elf32_body_big_endian = elf32_body(UBInt16, UBInt32) elf32_file = Struct("elf32_file", Struct("identifier", Magic(six.b("\x7fELF")), Enum(Byte("file_class"), NONE = 0, CLASS32 = 1, CLASS64 = 2, ), Enum(Byte("encoding"), NONE = 0, LSB = 1, MSB = 2, ), Byte("version"), Padding(9), ), Embedded(IfThenElse("body", lambda ctx: ctx.identifier.encoding == "LSB", elf32_body_little_endian, elf32_body_big_endian, )), ) if __name__ == "__main__": obj = elf32_file.parse_stream(open("../../../tests/_ctypes_test.so", "rb")) #[s.data.value for s in obj.sections] print(obj)