SickRage/lib/hachoir_parser/program/elf.py

188 lines
7.0 KiB
Python

"""
ELF (Unix/BSD executable file format) parser.
Author: Victor Stinner
Creation date: 08 may 2006
"""
from lib.hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, ParserError,
UInt8, UInt16, UInt32, Enum,
String, Bytes)
from lib.hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
class ElfHeader(FieldSet):
static_size = 52*8
LITTLE_ENDIAN_ID = 1
BIG_ENDIAN_ID = 2
MACHINE_NAME = {
1: u"AT&T WE 32100",
2: u"SPARC",
3: u"Intel 80386",
4: u"Motorola 68000",
5: u"Motorola 88000",
7: u"Intel 80860",
8: u"MIPS RS3000"
}
CLASS_NAME = {
1: u"32 bits",
2: u"64 bits"
}
TYPE_NAME = {
0: u"No file type",
1: u"Relocatable file",
2: u"Executable file",
3: u"Shared object file",
4: u"Core file",
0xFF00: u"Processor-specific (0xFF00)",
0xFFFF: u"Processor-specific (0xFFFF)"
}
ENDIAN_NAME = {
LITTLE_ENDIAN_ID: "Little endian",
BIG_ENDIAN_ID: "Big endian",
}
def createFields(self):
yield Bytes(self, "signature", 4, r'ELF signature ("\x7fELF")')
yield Enum(UInt8(self, "class", "Class"), self.CLASS_NAME)
yield Enum(UInt8(self, "endian", "Endian"), self.ENDIAN_NAME)
yield UInt8(self, "file_version", "File version")
yield String(self, "pad", 8, "Pad")
yield UInt8(self, "nb_ident", "Size of ident[]")
yield Enum(UInt16(self, "type", "File type"), self.TYPE_NAME)
yield Enum(UInt16(self, "machine", "Machine type"), self.MACHINE_NAME)
yield UInt32(self, "version", "ELF format version")
yield UInt32(self, "entry", "Number of entries")
yield UInt32(self, "phoff", "Program header offset")
yield UInt32(self, "shoff", "Section header offset")
yield UInt32(self, "flags", "Flags")
yield UInt16(self, "ehsize", "Elf header size (this header)")
yield UInt16(self, "phentsize", "Program header entry size")
yield UInt16(self, "phnum", "Program header entry count")
yield UInt16(self, "shentsize", "Section header entry size")
yield UInt16(self, "shnum", "Section header entre count")
yield UInt16(self, "shstrndx", "Section header strtab index")
def isValid(self):
if self["signature"].value != "\x7FELF":
return "Wrong ELF signature"
if self["class"].value not in self.CLASS_NAME:
return "Unknown class"
if self["endian"].value not in self.ENDIAN_NAME:
return "Unknown endian (%s)" % self["endian"].value
return ""
class SectionHeader32(FieldSet):
static_size = 40*8
TYPE_NAME = {
8: "BSS"
}
def createFields(self):
yield UInt32(self, "name", "Name")
yield Enum(UInt32(self, "type", "Type"), self.TYPE_NAME)
yield UInt32(self, "flags", "Flags")
yield textHandler(UInt32(self, "VMA", "Virtual memory address"), hexadecimal)
yield textHandler(UInt32(self, "LMA", "Logical memory address (in file)"), hexadecimal)
yield textHandler(UInt32(self, "size", "Size"), hexadecimal)
yield UInt32(self, "link", "Link")
yield UInt32(self, "info", "Information")
yield UInt32(self, "addr_align", "Address alignment")
yield UInt32(self, "entry_size", "Entry size")
def createDescription(self):
return "Section header (name: %s, type: %s)" % \
(self["name"].value, self["type"].display)
class ProgramHeader32(FieldSet):
TYPE_NAME = {
3: "Dynamic library"
}
static_size = 32*8
def createFields(self):
yield Enum(UInt16(self, "type", "Type"), ProgramHeader32.TYPE_NAME)
yield UInt16(self, "flags", "Flags")
yield UInt32(self, "offset", "Offset")
yield textHandler(UInt32(self, "vaddr", "V. address"), hexadecimal)
yield textHandler(UInt32(self, "paddr", "P. address"), hexadecimal)
yield UInt32(self, "file_size", "File size")
yield UInt32(self, "mem_size", "Memory size")
yield UInt32(self, "align", "Alignment")
yield UInt32(self, "xxx", "???")
def createDescription(self):
return "Program Header (%s)" % self["type"].display
def sortSection(a, b):
return int(a["offset"] - b["offset"])
#class Sections(FieldSet):
# def createFields?(self, stream, parent, sections):
# for section in sections:
# ofs = section["offset"]
# size = section["file_size"]
# if size != 0:
# sub = stream.createSub(ofs, size)
# #yield DeflateFilter(self, "section[]", sub, size, Section, "Section"))
# chunk = self.doRead("section[]", "Section", (Section,), {"stream": sub})
# else:
# chunk = self.doRead("section[]", "Section", (FormatChunk, "string[0]"))
# chunk.description = "ELF section (in file: %s..%s)" % (ofs, ofs+size)
class ElfFile(Parser):
PARSER_TAGS = {
"id": "elf",
"category": "program",
"file_ext": ("so", ""),
"min_size": ElfHeader.static_size, # At least one program header
"mime": (
u"application/x-executable",
u"application/x-object",
u"application/x-sharedlib",
u"application/x-executable-file",
u"application/x-coredump"),
"magic": (("\x7FELF", 0),),
"description": "ELF Unix/BSD program/library"
}
endian = LITTLE_ENDIAN
def validate(self):
err = self["header"].isValid()
if err:
return err
return True
def createFields(self):
# Choose the right endian depending on endian specified in header
if self.stream.readBits(5*8, 8, BIG_ENDIAN) == ElfHeader.BIG_ENDIAN_ID:
self.endian = BIG_ENDIAN
else:
self.endian = LITTLE_ENDIAN
# Parse header and program headers
yield ElfHeader(self, "header", "Header")
for index in xrange(self["header/phnum"].value):
yield ProgramHeader32(self, "prg_header[]")
if False:
raise ParserError("TODO: Parse sections...")
#sections = self.array("prg_header")
#size = self["header/shoff"].value - self.current_size//8
#chunk = self.doRead("data", "Data", (DeflateFilter, stream, size, Sections, sections))
#chunk.description = "Sections (use an evil hack to manage share same data on differents parts)"
#assert self.current_size//8 == self["header/shoff"].value
else:
raw = self.seekByte(self["header/shoff"].value, "raw[]", relative=False)
if raw:
yield raw
for index in xrange(self["header/shnum"].value):
yield SectionHeader32(self, "section_header[]")
def createDescription(self):
return "ELF Unix/BSD program/library: %s" % (
self["header/class"].display)