Mini Shell
"""
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)
Zerion Mini Shell 1.0