Esempio n. 1
0
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
Esempio n. 2
0
 def test_parse(self):
     s = CString("foo", encoding="utf8")
     self.assertEqual(s.parse(six.b("hello\x00")), six.u("hello"))
Esempio n. 3
0
 def test_parse_terminator(self):
     s = CString("foo", terminators=six.b("XYZ"), encoding="utf8")
     self.assertEqual(s.parse(six.b("helloX")), six.u("hello"))
     self.assertEqual(s.parse(six.b("helloY")), six.u("hello"))
     self.assertEqual(s.parse(six.b("helloZ")), six.u("hello"))
Esempio n. 4
0
 def test_parse(self):
     s = CString("foo", encoding="utf8")
     self.assertEqual(s.parse(six.b("hello\x00")), six.u("hello"))
Esempio n. 5
0
 def test_parse_terminator(self):
     s = CString("foo", terminators=six.b("XYZ"), encoding="utf8")
     self.assertEqual(s.parse(six.b("helloX")), six.u("hello"))
     self.assertEqual(s.parse(six.b("helloY")), six.u("hello"))
     self.assertEqual(s.parse(six.b("helloZ")), six.u("hello"))
Esempio n. 6
0
 def test_parse_terminator(self):
     s = CString("foo", terminators=b"XYZ")
     self.assertEqual(s.parse(b"helloX"), b"hello")
     self.assertEqual(s.parse(b"helloY"), b"hello")
     self.assertEqual(s.parse(b"helloZ"), b"hello")
Esempio n. 7
0
 def test_parse(self):
     s = CString("foo")
     self.assertEqual(s.parse(b"hello\x00"), b"hello")
Esempio n. 8
0
 def test_parse(self):
     s = CString("s", encoding="utf8")
     self.assertEqual(s.parse(b"hello\x00"), u"hello")
     s = CString("s")
     self.assertEqual(s.parse(b"hello\x00"), b"hello")
Esempio n. 9
0
 def test_parse_terminator(self):
     s = CString("s", terminators=b"XYZ", encoding="utf8")
     self.assertEqual(s.parse(b"helloX"), u"hello")
     self.assertEqual(s.parse(b"helloY"), u"hello")
     self.assertEqual(s.parse(b"helloZ"), u"hello")
Esempio n. 10
0
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']