def RRName(name): ''' A Resource Record Name structure. Supports DNS pointer compression through the MovingPointer class ''' return Struct( name, Anchor('_start'), Union( 'length_or_offset', UBInt8('length'), # regular label UBInt16('offset'), # compression pointer ), IfThenElse( 'name', this.length_or_offset.length & 0xc0 == 0xc0, # compression pointer MovingPointer( lambda ctx: ctx.length_or_offset.offset & ~0xc000, Label(name), offset=1, whence=os.SEEK_CUR, ), # regular label MovingPointer(this._start, Label(name)), ), )
def FourByteUnion(name): return name / Union( 'u32' / Int32ul, 'u16' / Struct( 'a' / Int16ul, 'b' / Int16ul, ), )
class ElfParser(object): """ """ EI_NIDENT = 16 DATATYPES32 = { "Addr": (Int32ul, Int32ub), # 4 - Unsigned program address "Half": (Int16ul, Int16ub), # 2 - Unsigned medium integer "Off": (Int32ul, Int32ub), # 4 - Unsigned file offset "Sword": (Int32sl, Int32sb), # 4 - Signed large integer "Word": (Int32ul, Int32ub), # 4 - Unsigned large integer "Xword": (Int32ul, Int32ub), # 8 - Unsigned long integer "Sxword": (None, None), # 8 - Signed long integer } DATATYPES64 = { "Addr": (Int64ul, Int64ub), # 8 - Unsigned program address "Off": (Int64ul, Int64ub), # 8 - Unsigned file offset "Half": (Int16ul, Int16ub), # 2 - Unsigned medium integer "Word": (Int32ul, Int32ub), # 4 - Unsigned integer "Sword": (Int32sl, Int32sb), # 4 - Signed integer "Xword": (Int64ul, Int64ub), # 8 - Unsigned long integer "Sxword": (Int64sl, Int64sb), # 8 - Signed long integer } BasicHeader = Struct( "header" / Union( None, "fields" / Struct( Const(MAGIC), "ei_class" / Int8ul, "ei_data" / Int8ul, "ei_version" / Int8ul, "ei_osabi" / Int8ul, "ei_abiversion" / Int8ul, Padding(7), ), "bytes" / Bytes(EI_NIDENT)), ) def __init__(self, filename): self.fp = create_memorymapped_fileview(filename) sha = calculate_crypto_hash(self.fp.tobytes()) self.db = model.Model() self.session = self.db.session self.symbols = SymbolAPI(self) self.sections = SectionAPI(self) self._images = dict() self._sections_by_name = OrderedDict() self.asciiCString = CString(encoding="ascii") self._basic_header = ElfParser.BasicHeader.parse(self.fp) self.b64 = (self.ei_class == 2) if self.ei_data == 1: # Little-Endian offset = 0 elif self.ei_data == 2: # Big-Endian offset = 1 else: raise ValueError("EI_DATA has an invalid value. Got: {}".format( self.ei_data)) self._endianess = "<" if self.ei_data == 1 else ">" datatypes = ElfParser.DATATYPES64.items( ) if self.b64 else ElfParser.DATATYPES32.items() for key, value in datatypes: setattr(self, key, value[offset]) self._parser_extended_header() self._parse_section_headers() self._parse_program_headers() self.create_section_to_segment_mapping() for section in self._symbol_sections: self._parse_symbol_section(section) self.session.commit() def _parser_extended_header(self): ExtendedHeader = Struct( "e_type" / self.Half, # Object file type "e_machine" / self.Half, # Machine type "e_version" / self.Word, # Object file version "e_entry" / self.Addr, # Entry point address "e_phoff" / self.Off, # Program header offset "e_shoff" / self.Off, # Section header offset "e_flags" / self.Word, # Processor-specific flags "e_ehsize" / self.Half, # ELF header size "e_phentsize" / self.Half, # Size of program header entry "e_phnum" / self.Half, # Number of program header entries "e_shentsize" / self.Half, # Size of section header entry "e_shnum" / self.Half, # Number of section header entries "e_shstrndx" / self.Half, # Section name string table index ) self._extended_header = ExtendedHeader.parse(self.fp[self.EI_NIDENT:]) def _parse_section_headers(self): SectionHeaders = Struct("sections" / Array( lambda ctx: self.e_shnum, "section" / Struct( "sh_name" / self.Word, "sh_type" / self.Word, "sh_flags" / self.Xword, "sh_addr" / self.Addr, "sh_offset" / self.Off, "sh_size" / self.Xword, "sh_link" / self.Word, "sh_info" / self.Word, "sh_addralign" / self.Xword, "sh_entsize" / self.Xword, "allocate" / Computed(lambda ctx: (ctx.sh_type not in (0, 8) and ctx.sh_size > 0)), ))) sections = [] self._symbol_sections = [] if hasattr(self, 'e_shnum'): self._section_headers = SectionHeaders.parse( self.fp[self.e_shoff:]) for idx, section in enumerate(self._section_headers.sections): if section.allocate: image = self.fp[section.sh_offset:section.sh_offset + section.sh_size] else: image = None if image is not None: image = image.tobytes() self._images[idx] = image section.image = image for idx, section in enumerate(self._section_headers.sections): name = self.get_string(self.e_shstrndx, section.sh_name) section.name = name self._sections_by_name[name] = section image = self._images[idx] if section.sh_type == defs.SectionType.SHT_NOTE: note_obj = self._parse_note(image) if note_obj: note = model.Elf_Note(section_name=name, type=note_obj.type, name=note_obj.name, desc=note_obj.desc) sections.append(note) elif section.sh_type in (defs.SectionType.SHT_SYMTAB, defs.SectionType.SHT_DYNSYM): self._symbol_sections.append(section) elif name == ".comment": cmt_text = self._parse_comment(image) if cmt_text: comment = model.Elf_Comment(text=cmt_text) sections.append(comment) db_sec = model.Elf_Section(index=idx, section_name=name, sh_name=section.sh_name, sh_type=section.sh_type, sh_flags=section.sh_flags, sh_addr=section.sh_addr, sh_offset=section.sh_offset, sh_size=section.sh_size, sh_link=section.sh_link, sh_info=section.sh_info, sh_addralign=section.sh_addralign, sh_entsize=section.sh_entsize, section_image=image) sections.append(db_sec) self.session.bulk_save_objects(sections) def get_string(self, table_index, entry): if entry > len(self._images[table_index]): return "" name = self.asciiCString.parse(self._images[table_index][entry:]) return name def _parse_program_headers(self): ProgramHeaders = Struct("segments" / Array( lambda ctx: self.e_phnum, "segment" / IfThenElse( lambda ctx: self.b64, Struct( "p_type" / self.Word, "p_flags" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Xword, "p_memsz" / self.Xword, "p_align" / self.Xword, ), Struct( "p_type" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Word, "p_memsz" / self.Word, "p_flags" / self.Word, "p_align" / self.Word, )), )) if hasattr(self, 'e_shnum'): #if self.e_shnum: # print("PG_size: {}".format(ProgramHeaders.sizeof() / self.e_phnum)) self._program_headers = ProgramHeaders.parse( self.fp[self.e_phoff:]) def _parse_symbol_section(self, section): sh_link = section.sh_link symbols = [] Symbol = Struct( "st_name" / self.Word, "st_value" / self.Addr, "st_size" / self.Word, "st_info" / BitStruct( "st_bind" / BitsInteger(4), "st_type" / BitsInteger(4), ), "st_other" / Int8ul, "symbol_name" / Computed(lambda ctx: self.get_string(sh_link, ctx.st_name)), "st_shndx" / self.Half, ) symbol_cache = {} num_symbols = len(section.image) // Symbol.sizeof() for offset in range(0, len(section.image), Symbol.sizeof()): sym = Symbol.parse(section.image[offset:offset + Symbol.sizeof()]) section_header = None if sym.st_shndx in defs.SpecialSections: section_name = defs.special_section_name(sym.st_shndx) else: if not sym.st_shndx in symbol_cache: section_header = self.session.query(model.Elf_Section).\ filter(model.Elf_Section.index == sym.st_shndx).first() if section_header: section_name = section_header.section_name else: section_name = str(sym.st_shndx) db_sym = model.Elf_Symbol( st_name=sym.st_name, st_value=sym.st_value, st_size=sym.st_size, st_bind=sym.st_info.st_bind, st_type=sym.st_info.st_type, st_other=sym.st_other, st_shndx=sym.st_shndx, symbol_name=sym.symbol_name, section_name=section_name, access=section_header.sh_flags if section_header else 0) symbols.append(db_sym) self.session.bulk_save_objects(symbols) self.session.commit() def _parse_comment(self, data): Line = Struct("line" / CString("ascii"), "pos" / Tell) if not data: return "" length = len(data) result = [] i = 0 if data.find(b"\x00") == -1: return str(data, "ascii") while i < length: #print("*** LINE", data[i : ]) line = Line.parse(data[i:]) if line.line: result.append(line.line) i += line.pos return '\n'.join(result) def _parse_note(self, data): Note = Struct("namesz" / self.Word, "descsz" / self.Word, "type" / self.Word, "name" / Bytes(this.namesz), "desc" / Bytes(this.descsz)) if not data: return None result = Note.parse(data) result.desc = binascii.b2a_hex(result.desc).decode() result.name = self.asciiCString.parse(result.name) return result def debug_sections(self): ds = OrderedDict() for idx, section in enumerate(self.sections.fetch()): name = section.section_name if name.startswith('.debug'): if name == '.debug_abbrev': pass ds[name] = section result = OrderedDict() for name, section in ds.items(): result[name] = DebugInfo(section, section.section_image) return result def section_in_segment1(self, section_header, segment, check_vma, strict): has_offset = False valid_segment = False has_VMA = False has_dynamic_size = False valid_segment = ((section_header.sh_flags & defs.SectionFlags.SHF_TLS) != 0) and (segment.p_type == defs.PT_TLS or \ segment.p_type == defs.PT_GNU_RELRO or segment.p_type == defs.PT_LOAD) or \ ((section_header.sh_flags & defs.SectionFlags.SHF_TLS) == 0 and segment.p_type != defs.PT_TLS and \ segment.p_type != defs.PT_PHDR) has_offset = section_header.sh_type == defs.SectionType.SHT_NOBITS or (section_header.sh_offset >= segment.p_offset \ and (not strict or (section_header.sh_offset - segment.p_offset <= segment.p_filesz - 1)) \ and ((section_header.sh_offset - segment.p_offset + self.section_size(section_header, segment)) <= \ (segment.p_filesz))) has_VMA = (not check_vma or (section_header.sh_flags & defs.SectionFlags.SHF_ALLOC) == 0 or (section_header.sh_addr >= \ segment.p_vaddr and (not strict or (section_header.sh_addr - segment.p_vaddr <= segment.p_memsz - 1)) \ and ((section_header.sh_addr - segment.p_vaddr + self.section_size(section_header, segment)) <= segment.p_memsz)) ) has_dynamic_size = (segment.p_type != defs.PT_DYNAMIC or section_header.sh_size != 0 or segment.p_memsz == 0 \ or ((section_header.sh_type == defs.SectionType.SHT_NOBITS or (section_header.sh_offset > segment.p_offset \ and (section_header.sh_offset - segment.p_offset < segment.p_filesz))) \ and ((section_header.sh_flags & defs.SectionFlags.SHF_ALLOC) == 0 \ or (section_header.sh_addr > segment.p_vaddr \ and (section_header.sh_addr - segment.p_vaddr < segment.p_memsz)))) \ ) return (valid_segment and has_offset and has_VMA and has_dynamic_size) def section_in_segment(self, section_header, segment): return self.section_in_segment1(section_header, segment, 1, 0) def section_in_segment_strict(self, section_header, segment): return self.section_in_segment1(section_header, segment, 1, 1) def create_section_to_segment_mapping(self): mapping = OrderedDict() for idx in range(self.e_phnum): segment = self.segments[idx] mapping[idx] = [] ## ## for j in range(self.e_shnum): ## section = self.sections[j] ## if not self.tbss_special(section, segment) and self.section_in_segment_strict(section, segment): ## mapping[idx].append(j) ## self.sections_to_segments = mapping return self.sections_to_segments def tbss_special(self, section_header, segment): return ((section_header.sh_flags & defs.SectionFlags.SHF_TLS) != 0 and section_header.sh_type == defs.SectionType.SHT_NOBITS and segment.p_type != defs.PT_TLS) def section_size(self, section_header, segment): return 0 if self.tbss_special(section_header, segment) else section_header.sh_size def get_basic_header_field(self, name): return getattr(self._basic_header.header.fields, name) def get_extended_header_field(self, name): return getattr(self._extended_header, name) @property def ei_class(self): return self.get_basic_header_field('ei_class') @property def ei_data(self): return self.get_basic_header_field('ei_data') @property def ei_version(self): return self.get_basic_header_field('ei_version') @property def ei_osabi(self): return self.get_basic_header_field('ei_osabi') @property def ei_abiversion(self): return self.get_basic_header_field('ei_abiversion') @property def header_bytes(self): return self._basic_header.header.bytes @property def e_type(self): return self.get_extended_header_field('e_type') @property def e_machine(self): return self.get_extended_header_field('e_machine') @property def e_version(self): return self.get_extended_header_field('e_version') @property def e_entry(self): return self.get_extended_header_field('e_entry') @property def e_phoff(self): return self.get_extended_header_field('e_phoff') @property def e_shoff(self): return self.get_extended_header_field('e_shoff') @property def e_flags(self): return self.get_extended_header_field('e_flags') @property def e_ehsize(self): return self.get_extended_header_field('e_ehsize') @property def e_phentsize(self): return self.get_extended_header_field('e_phentsize') @property def e_phnum(self): return self.get_extended_header_field('e_phnum') @property def e_shentsize(self): return self.get_extended_header_field('e_shentsize') @property def e_shnum(self): return self.get_extended_header_field('e_shnum') @property def e_shstrndx(self): return self.get_extended_header_field('e_shstrndx') @property def endianess(self): return self._endianess @property def segments(self): return self._program_headers['segments'] @property def arm_attributes(self): res = self.query(model.Elf_Section).filter( model.Elf_Section.section_name == ".ARM.attributes").first() if res: return attributes.parse(res.section_image, byteorder=self.endianess) else: return {} @property def comment(self): comment = self.query(model.Elf_Comment).first() if comment: return comment.text else: return None @property def notes(self): notes = self.query(model.Elf_Note).order_by( model.Elf_Note.section_name).all() if notes: return notes else: return [] @property def query(self): return self.session.query def create_image(self, join: bool = True, include_pattern: str = None, exclude_pattern: str = None, callback: callable = None): """ Parameters ---------- join: bool Try to join/merge sections. include_pattern: str Include only sections matching a Python RegEx exclude_pattern: str Exclude sections matching a Python RegEx callback: callable Could be used to generate output for your command-line tools. Called with: - state: "start" | "stop" | "section" - section -- current section (only applicable to state "section"). Returns ------- `objutils.Image` Note ---- `include_pattern` and `exclude_pattern` should be used mutually exclusive, unless you know what you are doing. Note ---- Look at `scripts/oj_elf_extract.py` to see `create_image()` in action. """ query = sections = self.query(model.Elf_Section) query = query.filter( model.Elf_Section.flag_alloc == True, model.Elf_Section.has_content == True, ) if include_pattern: query = query.filter( func.regexp(model.Elf_Section.section_name, include_pattern)) if exclude_pattern: query = query.filter( not_( func.regexp(model.Elf_Section.section_name, exclude_pattern))) query = query.order_by(model.Elf_Section.sh_addr) result = [] if callback: callback("start", None) for section in query.all(): if callback: callback("section", section) result.append(Section(section.sh_addr, section.section_image)) img = Image(result, join=join) if callback: callback("stop", None) return img
Single[(this.chunk_length - (this.title_length * 2) - 2 - 4 - 2) / Single.sizeof()], "swatch_type_index" / Short, # Two bytes ) end_palette = Struct( "chunk_type" / Const(b"\xc0\x02"), "chunk_length" / Int, ) palette = Struct( "chunk_type" / Const(b"\xc0\x01"), "chunk_length" / Int, "title_length" / Short, "title" / String(this.title_length * 2, encoding="utf-16be"), "colors" / color[1:], "_end" / end_palette, ) header = Struct( "datatype" / Const(b"ASEF"), "major_version" / Short, "minor_version" / Short, "bugfix_version" / Short, "chunk_count" / Short, ) ase_file = Struct( "header" / header, "data" / Union(0, "palette" / Optional(palette), "colors" / Optional(color[1:])))
from construct import Struct, Union, Enum, SLInt32 announcement_type = Enum( SLInt32("type"), LAUNCH=0, EXIT=1, ) announcement = Struct( "announcement", announcement_type, Union( "args", SLInt32("rank"), ), ) ANNOUNCEMENT_PACKET_LEN = announcement.sizeof()
def create_control_record_struct(self): little_endian = self.endianness == "little" min_mod = self.min_modulus control_len = self.control_len # Data types for integer values Int16s, Int16u, Int32s, Int32u = { "big": (Int16sb, Int16ub, Int32sb, Int32ub), "little": (Int16sl, Int16ul, Int32sl, Int32ul), }[self.endianness] # The 16 bytes that used to have the legacy MFTYPE field # has both the actual MFTYPE and the MSTXL, # and their order is affected by the endianness mftype = "mftype" / Default(Byte, 0) mstxl = "mstxl" / Rebuild( Byte, lambda this: this.mstxl if "mstxl" in this and this.mstxl is not None else this.get( "shift", this.modulus.bit_length() - 1 if "modulus" in this else self.default_shift, ), ) # MFCXX2 and MFCXX3 are used for locking the file on updating if self.lockable: mfcxx2 = "_mfcxx2" / Union( 0, "mfcxx2" / Default(Int32s, 0), "delock_count" / Int32u, # Data entry lock ) mfcxx3 = "_mfcxx3" / Union( 0, "mfcxx3" / Default(Int32s, 0), "ewlock" / ExprAdapter( Int32u, # Exclusive write lock lambda obj, ctx: bool(obj), lambda obj, ctx: int(obj)), ) else: mfcxx2 = "mfcxx2" / Default(Int32s, 0) mfcxx3 = "mfcxx3" / Default(Int32s, 0) # Legacy shift replacement if self.shift4is3: shift = "shift" / Computed(lambda this: 3 if this.mstxl == 4 else this.mstxl) else: shift = "shift" / Computed(lambda this: this.mstxl) # The control record struct for all cases nested_unpadded_struct = Struct( # First 4 fields, including information about the whole file "mfn" / Default(Int32s, 0), # CTLMFN Check(lambda this: this.mfn == 0), "next_mfn" / Default(Int32s, 1), # NXTMFN "next_block" / Default(Int32s, 1), # NXTMFB "next_offset" / Default(Int16u, self.control_len), # NXTMFP *([mftype, mstxl] if little_endian else [mstxl, mftype]), # Get the MST (modulus) and XRF (shift) alignment/shift values # from the MSTXL field, fixing the "legacy" replacements shift, "modulus" / Computed(lambda this: max(min_mod, 1 << this.shift)), Check(lambda this: control_len % this.modulus == 0), # Fields used for "statistics during backup/restore", # where the last two fields are also used for multi-user locking "reccnt" / Default(Int32s, 0), "mfcxx1" / Default(Int32s, 0), mfcxx2, mfcxx3, ) return Padded( length=control_len, subcon=Unnest(["_mfcxx2", "_mfcxx3"], nested_unpadded_struct) if self.lockable else nested_unpadded_struct, pattern=self.control_filler, )
class ElfParser(object): EI_NIDENT = 16 DATATYPES32 = { "Addr": (Int32ul, Int32ub), # 4 - Unsigned program address "Half": (Int16ul, Int16ub), # 2 - Unsigned medium integer "Off": (Int32ul, Int32ub), # 4 - Unsigned file offset "Sword": (Int32sl, Int32sb), # 4 - Signed large integer "Word": (Int32ul, Int32ub), # 4 - Unsigned large integer "Xword": (Int32ul, Int32ub), # 8 - Unsigned long integer "Sxword": (None, None), # 8 - Signed long integer } DATATYPES64 = { "Addr": (Int64ul, Int64ub), # 8 - Unsigned program address "Off": (Int64ul, Int64ub), # 8 - Unsigned file offset "Half": (Int16ul, Int16ub), # 2 - Unsigned medium integer "Word": (Int32ul, Int32ub), # 4 - Unsigned integer "Sword": (Int32sl, Int32sb), # 4 - Signed integer "Xword": (Int64ul, Int64ub), # 8 - Unsigned long integer "Sxword": (Int64sl, Int64sb), # 8 - Signed long integer } BasicHeader = Struct( "header" / Union(None, "fields"/ Struct( Const(MAGIC), "ei_class" / Int8ul, "ei_data" / Int8ul, "ei_version" / Int8ul, "ei_osabi" / Int8ul, "ei_abiversion" / Int8ul, Padding(7), ), "bytes" / Bytes(EI_NIDENT) ), ) def __init__(self, filename): self.db = sqa.Model(Base) self.session = self.db.session self._images = dict() self._sections_by_name = OrderedDict() self.asciiCString = CString(encoding = "ascii") self.fp = create_memorymapped_fileview(filename) print(filename, flush = True) self._basic_header = ElfParser.BasicHeader.parse(self.fp) self.b64 = (self.ei_class == 2) self.endianess = self.ei_data if self.ei_data == 1: # Little-Endian offset = 0 elif self.ei_data == 2: # Big-Endian offset = 1 else: offset = 0 # TODO: Error!!! datatypes = ElfParser.DATATYPES64.items() if self.b64 else ElfParser.DATATYPES32.items() for key, value in datatypes: setattr(self, key, value[offset]) print(self._basic_header) self._parser_extended_header() self._parse_section_headers() self._parse_program_headers() self.create_section_to_segment_mapping() self.session.commit() def _parser_extended_header(self): ExtendedHeader = Struct( "e_type" / self.Half, # Object file type "e_machine" / self.Half, # Machine type "e_version" / self.Word, # Object file version "e_entry" / self.Addr, # Entry point address "e_phoff" / self.Off, # Program header offset "e_shoff" / self.Off, # Section header offset "e_flags" / self.Word, # Processor-specific flags "e_ehsize" / self.Half, # ELF header size "e_phentsize" / self.Half, # Size of program header entry "e_phnum" / self.Half, # Number of program header entries "e_shentsize" / self.Half, # Size of section header entry "e_shnum" / self.Half, # Number of section header entries "e_shstrndx" / self.Half, # Section name string table index ) self._extended_header = ExtendedHeader.parse(self.fp[self.EI_NIDENT : ]) def _parse_section_headers(self): SectionHeaders = Struct( "sections" / Array(lambda ctx: self.e_shnum, "section" / Struct( "sh_name" / self.Word, "sh_type" / self.Word, "sh_flags" / self.Xword, "sh_addr" / self.Addr, "sh_offset" / self.Off, "sh_size" / self.Xword, "sh_link" / self.Word, "sh_info" / self.Word, "sh_addralign" / self.Xword, "sh_entsize" /self.Xword, "allocate" / Computed(lambda ctx: (ctx.sh_type not in (0, 8) and ctx.sh_size > 0)), ) ) ) if hasattr(self, 'e_shnum'): if self.e_shnum: print("SH_size: {}".format(SectionHeaders.sizeof() / self.e_shnum)) self._section_headers = SectionHeaders.parse(self.fp[self.e_shoff : ]) for idx, section in enumerate(self._section_headers.sections): if section.allocate: image = self.fp[section.sh_offset : section.sh_offset + section.sh_size] else: image = None self._images[idx] = image section.image = image for section in self._section_headers.sections: name = self.get_string(self.e_shstrndx, section.sh_name) section.name = name self._sections_by_name[name] = section if section.sh_type == defs.SectionType.SHT_NOTE: print("NOTE!!! {:08X} {:04X}".format(section.sh_offset, section.sh_size)) self._parse_note(self.fp[section.sh_offset : section.sh_offset + section.sh_size]) elif section.sh_type in (defs.SectionType.SHT_SYMTAB, defs.SectionType.SHT_DYNSYM): self._parse_symbol_section(section) def get_string(self, table_index, entry): name = self.asciiCString.parse(self._images[table_index][entry : ]) return name def _parse_program_headers(self): ProgramHeaders = Struct( "segments" / Array(lambda ctx: self.e_phnum, "segment" / IfThenElse(lambda ctx: self.b64, Struct( "p_type" / self.Word, "p_flags" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Xword, "p_memsz" / self.Xword, "p_align" / self.Xword, ), Struct( "p_type" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Word, "p_memsz" / self.Word, "p_flags" / self.Word, "p_align" / self.Word, ) ), ) ) if hasattr(self, 'e_shnum'): if self.e_shnum: print("PG_size: {}".format(ProgramHeaders.sizeof() / self.e_phnum)) self._program_headers = ProgramHeaders.parse(self.fp[self.e_phoff : ]) def _parse_symbol_section(self, section): sh_link = section.sh_link if self.b64: pass else: pass Symbol = Struct( "st_name" / self.Word, "st_value" / self.Addr, "st_size" / self.Word, "st_info" / BitStruct( "st_bind" / BitsInteger(4), "st_type" / BitsInteger(4), ), "st_other" / Int8ul, "symbol_name" / Computed(lambda ctx: self.get_string(sh_link, ctx.st_name)), "st_shndx" / self.Half, "section_name" / Computed(lambda ctx: defs.section_name(ctx.st_shndx)), "hidden" / Computed(lambda ctx: ctx.st_other in (defs.SymbolVisibility.STV_HIDDEN, defs.SymbolVisibility.STV_INTERNAL)), ) """ typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym; """ num_symbols = len(section.image) // Symbol.sizeof() for offset in range(0, len(section.image), Symbol.sizeof()): sym = Symbol.parse(section.image[offset : offset + Symbol.sizeof()]) db_sym = Elf_Symbol(st_name = sym.st_name, st_value = sym.st_value, st_size = sym.st_size, st_bind = sym.st_info.st_bind, st_type = sym.st_info.st_type, st_other = sym.st_other, st_shndx = sym.st_shndx, symbol_name = sym.symbol_name, section_name = sym.section_name, hidden = sym.hidden) self.session.add(db_sym) #print(db_sym) self.session.commit() query = self.session.query(Elf_Symbol) aaa = query.filter(Elf_Symbol.section_name == "SHN_ABS").all() print("SECTIONS", [a.symbol_name for a in aaa]) def _parse_note(self, data): Note = Struct( "namesz" / self.Word, "descsz" / self.Word, "type" / self.Word, "name" / Bytes(this.namesz), "desc" / Bytes(this.descsz) ) print(len(data), data.tobytes()) result = Note.parse(data) result.desc = binascii.b2a_hex(result.desc).decode() print(result.desc) print(result) def debug_sections(self): ds = OrderedDict() for idx, section in enumerate(self.sections): name = section.name if name.startswith('.debug'): print(name) if name == '.debug_abbrev': pass ds[name] = section result = OrderedDict() for name, section in ds.items(): result[name]= DebugInfo(section, section.image) return result def section_in_segment1(self, section_header, segment, check_vma, strict): has_offset = False valid_segment = False has_VMA = False has_dynamic_size = False valid_segment = ((section_header.sh_flags & defs.SHF_TLS) != 0) and (segment.p_type == defs.PT_TLS or \ segment.p_type == defs.PT_GNU_RELRO or segment.p_type == defs.PT_LOAD) or \ ((section_header.sh_flags & defs.SHF_TLS) == 0 and segment.p_type != defs.PT_TLS and \ segment.p_type != defs.PT_PHDR) has_offset = section_header.sh_type == defs.SectionType.SHT_NOBITS or (section_header.sh_offset >= segment.p_offset \ and (not strict or (section_header.sh_offset - segment.p_offset <= segment.p_filesz - 1)) \ and ((section_header.sh_offset - segment.p_offset + self.section_size(section_header, segment)) <= \ (segment.p_filesz))) has_VMA = (not check_vma or (section_header.sh_flags & defs.SHF_ALLOC) == 0 or (section_header.sh_addr >= \ segment.p_vaddr and (not strict or (section_header.sh_addr - segment.p_vaddr <= segment.p_memsz - 1)) \ and ((section_header.sh_addr - segment.p_vaddr + self.section_size(section_header, segment)) <= segment.p_memsz)) ) has_dynamic_size = (segment.p_type != defs.PT_DYNAMIC or section_header.sh_size != 0 or segment.p_memsz == 0 \ or ((section_header.sh_type == defs.SectionType.SHT_NOBITS or (section_header.sh_offset > segment.p_offset \ and (section_header.sh_offset - segment.p_offset < segment.p_filesz))) \ and ((section_header.sh_flags & defs.SHF_ALLOC) == 0 \ or (section_header.sh_addr > segment.p_vaddr \ and (section_header.sh_addr - segment.p_vaddr < segment.p_memsz)))) \ ) return (valid_segment and has_offset and has_VMA and has_dynamic_size) def section_in_segment(self, section_header, segment): return self.section_in_segment1(section_header, segment, 1, 0) def section_in_segment_strict(self, section_header, segment): return self.section_in_segment1(section_header, segment, 1, 1) def create_section_to_segment_mapping(self): mapping = OrderedDict() for idx in range(self.e_phnum): segment = self.segments[idx] mapping[idx] = [] for j in range(self.e_shnum): section = self.sections[j] if not self.tbss_special(section, segment) and self.section_in_segment_strict(section, segment): mapping[idx].append(j) print(section) self.sections_to_segments = mapping return self.sections_to_segments def tbss_special(self, section_header, segment): return ((section_header.sh_flags & defs.SHF_TLS) != 0 and section_header.sh_type == defs.SectionType.SHT_NOBITS and segment.p_type != defs.PT_TLS ) def buildSymbols(self): for section in self.sectionHeaders: if section.shType in (defs.SectionType.SHT_SYMTAB, defs.SectionType.SHT_DYNSYM): syms = [] for idx, symbol in section.symbols.items(): # sym = Symbol(self.getString(section.shLink, symbol.st_name), symbol.st_value, symbol.st_size, # self.getSymbolType(symbol.st_info & 0x0f), # self.getSymbolBinding(symbol.st_info >> 4), self.getSymbolVisibility(symbol.st_other), # self.getSymbolIndexType(self.header, symbol.st_shndx)) syms.append(sym) self.symbols[section.shName] = syms def section_size(self, section_header, segment): return 0 if self.tbss_special(section_header, segment) else section_header.sh_size def get_basic_header_field(self, name): return getattr(self._basic_header.header.fields, name) def get_extended_header_field(self, name): return getattr(self._extended_header, name) @property def ei_class(self): return self.get_basic_header_field('ei_class') @property def ei_data(self): return self.get_basic_header_field('ei_data') @property def ei_version(self): return self.get_basic_header_field('ei_version') @property def ei_osabi(self): return self.get_basic_header_field('ei_osabi') @property def ei_abiversion(self): return self.get_basic_header_field('ei_abiversion') @property def header_bytes(self): return self._basic_header.header.bytes @property def e_type(self): return self.get_extended_header_field('e_type') @property def e_machine(self): return self.get_extended_header_field('e_machine') @property def e_version(self): return self.get_extended_header_field('e_version') @property def e_entry(self): return self.get_extended_header_field('e_entry') @property def e_phoff(self): return self.get_extended_header_field('e_phoff') @property def e_shoff(self): return self.get_extended_header_field('e_shoff') @property def e_flags(self): return self.get_extended_header_field('e_flags') @property def e_ehsize(self): return self.get_extended_header_field('e_ehsize') @property def e_phentsize(self): return self.get_extended_header_field('e_phentsize') @property def e_phnum(self): return self.get_extended_header_field('e_phnum') @property def e_shentsize(self): return self.get_extended_header_field('e_shentsize') @property def e_shnum(self): return self.get_extended_header_field('e_shnum') @property def e_shstrndx(self): return self.get_extended_header_field('e_shstrndx') @property def sections(self): return self._section_headers.sections @property def segments(self): return self._program_headers['segments']