Пример #1
0
 def _handle_relocation(self, container, section, rel):
     reloc_type = rel['type']
     if reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PC32"]:
         swbase = None
         for base in sorted(self.bases):
             if base > rel['offset']:
                 break
             swbase = base
         value = rel['st_value'] + rel['addend'] - (rel['offset'] - swbase)
         swlbl = ".LC%x-.LC%x" % (value, swbase)
         section.replace(rel['offset'], 4, swlbl)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_64"]:
         # C++ ABI functions, to be ignored
         # if not (rel["name"].startswith("_ZTV") or rel["name"] == "__gxx_personality_v0"):
         if rel['st_value']:
             value = rel['st_value'] + rel['addend']
             label = ".LC%x" % value
         else:
             label = "%s+%d" % (rel['name'], rel['addend'])
         section.replace(rel['offset'], 8, label)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_RELATIVE"]:
         value = rel['addend']
         label = ".LC%x" % value
         section.replace(rel['offset'], 8, label)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_COPY"]:
         # NOP
         pass
     else:
         print("[*] Unhandled relocation {}".format(
             describe_reloc_type(reloc_type, container.loader.elffile)))
Пример #2
0
 def _handle_relocation(self, container, section, rel):
     reloc_type = rel['type']
     if reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PC32"]:
         swbase = None
         for base in sorted(self.bases):
             if base > rel['offset']:
                 break
             swbase = base
         value = rel['st_value'] + rel['addend'] - (rel['offset'] - swbase)
         swlbl = ".LC%x-.LC%x" % (value, swbase)
         section.replace(rel['offset'], 4, swlbl)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_64"]:
         value = rel['st_value'] + rel['addend']
         label = ".LC%x" % value
         section.replace(rel['offset'], 8, label)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_RELATIVE"]:
         value = rel['addend']
         label = ".LC%x" % value
         section.replace(rel['offset'], 8, label)
     elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_COPY"]:
         # NOP
         pass
     else:
         print("[*] Unhandled relocation {}".format(
             describe_reloc_type(reloc_type, container.loader.elffile)))
Пример #3
0
    def get_relocations(self):
        relocations = []
        with open(self.filename, "rb") as elf_file:
            elf = ELFFile(elf_file)
            for section in elf.iter_sections():
                if not isinstance(section, RelocationSection):
                    continue
                symbols = elf.get_section(section["sh_link"])
                for relocation in section.iter_relocations():
                    if relocation["r_info_sym"] == 0:
                        continue
                    relocation_data = {}
                    relocation_data["offset"] = relocation["r_offset"]
                    relocation_data["info"] = relocation["r_info"]
                    relocation_data["info_type"] = describe_reloc_type(relocation["r_info_type"], elf)
                    relocation_data["symbol"] = relocation["r_info_sym"]
                    symbol = symbols.get_symbol(relocation_data["symbol"])
                    if symbol["st_name"] == 0:
                        symbol_section = elf.get_section(symbol["st_shndx"])
                        relocation_data["symbol_name"] = symbol_section.name
                    else:
                        relocation_data["symbol_name"] = symbol.name

                    relocation_data["symbol_value"] = symbol["st_value"]
                    relocation_data["section_index"] = symbol["st_shndx"]
                    relocations.append(relocation_data)
        return relocations
Пример #4
0
    def display_relocations(self):
        """ Display the relocations contained in the file
        """
        has_relocation_sections = False
        for section in self.elffile.iter_sections():
            if not isinstance(section, RelocationSection):
                continue

            has_relocation_sections = True
            self._emitline(
                "\nRelocation section '%s' at offset %s contains %s entries:" %
                (bytes2str(section.name), self._format_hex(
                    section['sh_offset']), section.num_relocations()))
            if section.is_RELA():
                self._emitline(
                    "  Offset          Info           Type           Sym. Value    Sym. Name + Addend"
                )
            else:
                self._emitline(
                    " Offset     Info    Type            Sym.Value  Sym. Name")

            # The symbol table section pointed to in sh_link
            symtable = self.elffile.get_section(section['sh_link'])

            for rel in section.iter_relocations():
                hexwidth = 8 if self.elffile.elfclass == 32 else 12
                self._emit(
                    '%s  %s %-17.17s' %
                    (self._format_hex(
                        rel['r_offset'], fieldsize=hexwidth, lead0x=False),
                     self._format_hex(
                         rel['r_info'], fieldsize=hexwidth, lead0x=False),
                     describe_reloc_type(rel['r_info_type'], self.elffile)))

                if rel['r_info_sym'] == 0:
                    self._emitline()
                    continue

                symbol = symtable.get_symbol(rel['r_info_sym'])
                # Some symbols have zero 'st_name', so instead what's used is
                # the name of the section they point at
                if symbol['st_name'] == 0:
                    symsec = self.elffile.get_section(symbol['st_shndx'])
                    symbol_name = symsec.name
                else:
                    symbol_name = symbol.name
                self._emit(' %s %s%22.22s' % (self._format_hex(
                    symbol['st_value'], fullhex=True,
                    lead0x=False), '  ' if self.elffile.elfclass == 32 else '',
                                              bytes2str(symbol_name)))
                if section.is_RELA():
                    self._emit(' %s %x' %
                               ('+' if rel['r_addend'] >= 0 else '-',
                                abs(rel['r_addend'])))
                self._emitline()

        if not has_relocation_sections:
            self._emitline('\nThere are no relocations in this file.')
Пример #5
0
    def display_relocations(self):
        """ Display the relocations contained in the file
        """
        has_relocation_sections = False
        for section in self.elffile.iter_sections():
            if not isinstance(section, RelocationSection):
                continue

            has_relocation_sections = True
            self._emitline("\nRelocation section '%s' at offset %s contains %s entries:" % (
                bytes2str(section.name),
                self._format_hex(section['sh_offset']),
                section.num_relocations()))
            if section.is_RELA():
                self._emitline("  Offset          Info           Type           Sym. Value    Sym. Name + Addend")
            else:
                self._emitline(" Offset     Info    Type            Sym.Value  Sym. Name")

            # The symbol table section pointed to in sh_link
            symtable = self.elffile.get_section(section['sh_link'])

            for rel in section.iter_relocations():
                hexwidth = 8 if self.elffile.elfclass == 32 else 12
                self._emit('%s  %s %-17.17s' % (
                    self._format_hex(rel['r_offset'],
                        fieldsize=hexwidth, lead0x=False),
                    self._format_hex(rel['r_info'],
                        fieldsize=hexwidth, lead0x=False),
                    describe_reloc_type(
                        rel['r_info_type'], self.elffile)))

                if rel['r_info_sym'] == 0:
                    self._emitline()
                    continue

                symbol = symtable.get_symbol(rel['r_info_sym'])
                # Some symbols have zero 'st_name', so instead what's used is
                # the name of the section they point at
                if symbol['st_name'] == 0:
                    symsec = self.elffile.get_section(symbol['st_shndx'])
                    symbol_name = symsec.name
                else:
                    symbol_name = symbol.name
                self._emit(' %s %s%22.22s' % (
                    self._format_hex(
                        symbol['st_value'],
                        fullhex=True, lead0x=False),
                    '  ' if self.elffile.elfclass == 32 else '',
                    bytes2str(symbol_name)))
                if section.is_RELA():
                    self._emit(' %s %x' % (
                        '+' if rel['r_addend'] >= 0 else '-',
                        abs(rel['r_addend'])))
                self._emitline()

        if not has_relocation_sections:
            self._emitline('\nThere are no relocations in this file.')
Пример #6
0
    def _handle_relocation(self, container, section, all_symbols, rel):
        reloc_type = rel['type']
        if reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PC32"]:
            swbase = None
            for base in sorted(self.bases):
                if base > rel['offset']:
                    break
                swbase = base
            value = rel['st_value'] + rel['addend'] - (rel['offset'] - swbase)
            swlbl = ".LC%x-.LC%x" % (value, swbase)
            section.replace(rel['offset'], 4, swlbl)

        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_64"]:
            value = rel['st_value'] + rel['addend']
            label = ".LC%x" % value
          
            #relocation already has a name
            if rel['st_value']  == 0 and  rel['name'] != None:
                label = rel['name']
                if  rel['addend'] != 0:
                     label += " + 0x%x" %  rel['addend']

            #internal symbol
            #we use name from symbols
            elif rel['st_value'] and  rel['st_value'] in all_symbols:
                    #if not, then use "sym + offset"
                    label = container.loader.adjust_sym_name(all_symbols[rel['st_value']])
                    if  rel['addend'] != 0:
                        label += " + 0x%x" %  rel['addend']

            section.replace(rel['offset'], 8, label)

            #end by JX

        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_RELATIVE"]:
            value = rel['addend']
            label = ".LC%x" % value
          
            if rel['addend'] in all_symbols:
                label = container.loader.adjust_sym_name(all_symbols[rel['addend']])

            section.replace(rel['offset'], 8, label)
            #end by JX

        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_COPY"]:
            # NOP
            pass
        else:
            print("[*] Unhandled relocation {}".format(
                describe_reloc_type(reloc_type, container.loader.elffile)))
Пример #7
0
    def __init__(self, elf: Any, section: Any, symtable: Any, symbol_objects: Any, r):
        self.offset = int(r["r_offset"])
        stype = describe_reloc_type(r["r_info_type"], elf)
        if stype == "R_ARM_GOT_BREL":
            self.type = lief.ELF.RELOCATION_ARM.GOT_BREL
        elif stype == "R_ARM_ABS32":
            self.type = lief.ELF.RELOCATION_ARM.ABS32
        elif stype == "R_ARM_THM_CALL":
            self.type = lief.ELF.RELOCATION_ARM.THM_CALL
        elif stype == "R_ARM_THM_JUMP24":
            self.type = lief.ELF.RELOCATION_ARM.THM_JUMP24
        elif stype == "R_ARM_TARGET1":
            self.type = lief.ELF.RELOCATION_ARM.TARGET1
        elif stype == "R_ARM_PREL31":
            self.type = lief.ELF.RELOCATION_ARM.PREL31
        elif stype == "R_ARM_REL32":
            self.type = lief.ELF.RELOCATION_ARM.REL32
        elif stype == "R_ARM_JUMP_SLOT":
            self.type = lief.ELF.RELOCATION_ARM.JUMP_SLOT
        elif stype == "R_ARM_GLOB_DAT":
            self.type = lief.ELF.RELOCATION_ARM.GLOB_DAT
        else:
            raise Exception("Unknown rel type: '%s'" % (stype))

        symbol_index = r["r_info_sym"]
        s = symtable.get_symbol(symbol_index)
        if s["st_name"] != 0:
            self.name = str(s.name)
            self.symbol = symbol_objects[symbol_index]
            self.has_symbol = True
        else:
            self.symbol = None
            self.has_symbol = False

        try:
            symsec = elf.get_section(s["st_shndx"])
            self.section = Section(symsec)
            self.name = self.section.name
        except:
            self.section = Section(section)
            self.name = self.section.name

        self.debug = "debug_" in self.section.name

        self.value = s["st_value"]
        self.address = s["st_value"]
Пример #8
0
    def apply_data_relocation(self, container, section, relocation):
        reloc_type = relocation['type']
        if reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_COPY"]:
            # NOP
            return

        relocation_size = Symbolizer.RELOCATION_SIZES[relocation['type']]
        relocation_target = None

        if relocation['symbol_address'] is None:
            # This relocation refers to an imported symbol
            relocation_target = '{} + {}'.format(relocation['name'], relocation['addend'])

        # PC32 and PLT32 are more or less the same in the kernel, but not in user space
        if reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PC32"] or reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PLT32"]:
            if not relocation_target:
                value = relocation['symbol_address'].offset + relocation['addend']
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
            relocation_target += ' - .'
        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_PC64"]:
            if not relocation_target:
                value = relocation['symbol_address'].offset + relocation['addend']
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
            relocation_target += ' - .'
        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_32S"]:
            if not relocation_target:
                value = relocation['symbol_address'].offset + relocation['addend']
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_64"]:
            if not relocation_target:
                value = relocation['symbol_address'].offset + relocation['addend']
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_RELATIVE"]:
            if not relocation_target:
                value = relocation['addend']
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
        elif reloc_type == ENUM_RELOC_TYPE_x64["R_X86_64_JUMP_SLOT"]:
            if not relocation_target:
                value = relocation['symbol_address'].offset
                relocation_target = self.label_for_address(container, Address(relocation['symbol_address'].section, value))
        else:
            print("[*] Unhandled relocation {}".format(
                describe_reloc_type(reloc_type, container.loader.elffile)))

        if relocation_size:
            section.replace(relocation['address'].offset, relocation_size, relocation_target)
Пример #9
0
def main():
    if len(sys.argv) < 2:
        print("usage: python3 {} elf [data symbol]".format(sys.argv[0]))
        sys.exit(1)

    elf = sys.argv[1]
    item = sys.argv[2] if len(sys.argv) > 2 else ""

    counters = {}
    reloc_types = {}
    elf = ELFFile(open(elf, "rb"))

    for sec in elf.iter_sections():
        if not isinstance(sec, RelocationSection):
            continue

        symtab = elf.get_section(sec["sh_link"])
        for reloc in sec.iter_relocations():
            ref_sym = symtab.get_symbol(reloc["r_info_sym"])
            name = ref_sym.name

            if item in name:
                if name in counters:
                    counters[name] += 1
                else:
                    counters[name] = 1
                    reloc_types[name] = {}

                reloc_type = describe_reloc_type(reloc["r_info_type"], elf)
                if reloc_type in reloc_types[name]:
                    reloc_types[name][reloc_type] += 1
                else:
                    reloc_types[name][reloc_type] = 1

    counters_list = [(v, k) for (k, v) in counters.items()]
    for count, name in sorted(counters_list, reverse=True):
        print("{}: {}".format(name, count))
        reloc_list = [(v, k) for (k, v) in reloc_types[name].items()]
        for count, reloc_type in sorted(reloc_list, reverse=True):
            print("\t{}: {}".format(reloc_type, count))
Пример #10
0
    def _get_relocations(self) -> List[Dict[str, str]]:
        relocations = []
        for section in self.elf.iter_sections():
            if not isinstance(section, RelocationSection):
                continue
            section_relocations = set()
            for rel in section.iter_relocations():
                relocation = {
                    "offset": self._print_addr(rel["r_offset"]),
                    "info": self._print_addr(rel["r_info"]),
                    "type": describe_reloc_type(rel["r_info_type"], self.elf),
                    "value": "",
                    "name": "",
                }

                if rel["r_info_sym"] != 0:
                    symtable = self.elf.get_section(section["sh_link"])
                    symbol = symtable.get_symbol(rel["r_info_sym"])
                    # Some symbols have zero "st_name", so instead use
                    # the name of the section they point at
                    if symbol["st_name"] == 0:
                        symsec = self.elf.get_section(symbol["st_shndx"])
                        symbol_name = symsec.name
                    else:
                        symbol_name = symbol.name

                    relocation["value"] = self._print_addr(symbol["st_value"])
                    relocation["name"] = symbol_name

                section_relocations.add(relocation)

            relocations.append(
                {
                    "name": section.name,
                    "entries": section_relocations,
                }
            )
        return relocations
Пример #11
0
    def _get_relocations(self):
        relocations = []
        for section in self.elf.iter_sections():
            if not isinstance(section, RelocationSection):
                continue
            section_relocations = []
            for rel in section.iter_relocations():
                relocation = {
                    "offset": self._print_addr(rel["r_offset"]),
                    "info": self._print_addr(rel["r_info"]),
                    "type": describe_reloc_type(rel["r_info_type"], self.elf),
                    "value": "",
                    "name": ""
                }

                if rel["r_info_sym"] != 0:
                    symtable = self.elf.get_section(section["sh_link"])
                    symbol = symtable.get_symbol(rel["r_info_sym"])
                    # Some symbols have zero "st_name", so instead use
                    # the name of the section they point at
                    if symbol["st_name"] == 0:
                        symsec = self.elf.get_section(symbol["st_shndx"])
                        symbol_name = symsec.name
                    else:
                        symbol_name = symbol.name

                    relocation["value"] = self._print_addr(symbol["st_value"])
                    relocation["name"] = symbol_name

                if relocation not in section_relocations:
                    section_relocations.append(relocation)

            relocations.append({
                "name": section.name,
                "entries": section_relocations,
            })
        return relocations
Пример #12
0
def get_relocations_in_elf(obj):
    rels = []
    with open(obj, "rb") as f:
        elf = ELFFile(f)
        for section in elf.iter_sections():
            if not isinstance(section, RelocationSection):
                continue
            symtable = elf.get_section(section['sh_link'])
            for rel in section.iter_relocations():
                if rel['r_info_sym'] == 0:
                    continue
                rdata = {}
                rdata["offset"] = int(rel['r_offset'])
                rdata["info"] = rel['r_info']
                rdata["type"] = describe_reloc_type(rel['r_info_type'], elf)
                symbol = symtable.get_symbol(rel['r_info_sym'])
                if symbol['st_name'] == 0:
                    symsec = elf.get_section(symbol['st_shndx'])
                    rdata["name"] = str(symsec.name)
                else:
                    rdata["name"] = str(symbol.name)
                rdata["value"] = symbol["st_value"]
                rels.append(rdata)
    return rels
Пример #13
0
    def lkm_dynlinker(self, ql, mem_start):
        def get_symbol(elffile, name):
            section = elffile.get_section_by_name('.symtab')
            for symbol in section.iter_symbols():
                if symbol.name == name:
                    return symbol
            return None

        elffile = ELFFile(open(ql.path, 'rb'))

        all_symbols = []
        self.ql.os.hook_addr = API_HOOK_MEM
        # map address to symbol name
        ql.import_symbols = {}
        # reverse dictionary to map symbol name -> address
        rev_reloc_symbols = {}

        # dump_mem("XX Original code at 15a1 = ", ql.mem.read(0x15a1, 8))
        for section in elffile.iter_sections():
            # only care about reloc section
            if not isinstance(section, RelocationSection):
                continue

            # ignore reloc for module section
            if section.name == ".rela.gnu.linkonce.this_module":
                continue

            # The symbol table section pointed to in sh_link
            symtable = elffile.get_section(section['sh_link'])

            for rel in section.iter_relocations():
                if rel['r_info_sym'] == 0:
                    continue

                symbol = symtable.get_symbol(rel['r_info_sym'])

                # Some symbols have zero 'st_name', so instead what's used is
                # the name of the section they point at.
                if symbol['st_name'] == 0:
                    symsec = elffile.get_section(
                        symbol['st_shndx'])  # save sh_addr of this section
                    symbol_name = symsec.name
                    sym_offset = symsec['sh_offset']
                    # we need to do reverse lookup from symbol to address
                    rev_reloc_symbols[symbol_name] = sym_offset + mem_start
                else:
                    symbol_name = symbol.name
                    # get info about related section to be patched
                    info_section = elffile.get_section(section['sh_info'])
                    sym_offset = info_section['sh_offset']

                    if not symbol_name in all_symbols:
                        _symbol = get_symbol(elffile, symbol_name)
                        if _symbol['st_shndx'] == 'SHN_UNDEF':
                            # external symbol
                            # only save symbols of APIs
                            all_symbols.append(symbol_name)
                            # we need to lookup from address to symbol, so we can find the right callback
                            # for sys_xxx handler for syscall, the address must be aligned to 8
                            if symbol_name.startswith('sys_'):
                                if self.ql.os.hook_addr % self.ql.pointersize != 0:
                                    self.ql.os.hook_addr = (
                                        int(self.ql.os.hook_addr /
                                            self.ql.pointersize) +
                                        1) * self.ql.pointersize
                                    # print("hook_addr = %x" %self.ql.os.hook_addr)
                            ql.import_symbols[
                                self.ql.os.hook_addr] = symbol_name
                            # ql.nprint(":: Demigod is hooking %s(), at slot %x" %(symbol_name, self.ql.os.hook_addr))

                            if symbol_name == "page_offset_base":
                                # FIXME: this is for rootkit to scan for syscall table from page_offset_base
                                # write address of syscall table to this slot,
                                # so syscall scanner can quickly find it
                                ql.mem.write(self.ql.os.hook_addr,
                                             self.ql.pack(SYSCALL_MEM))

                            # we also need to do reverse lookup from symbol to address
                            rev_reloc_symbols[
                                symbol_name] = self.ql.os.hook_addr
                            sym_offset = self.ql.os.hook_addr - mem_start
                            self.ql.os.hook_addr += self.ql.pointersize
                        else:
                            # local symbol
                            all_symbols.append(symbol_name)
                            _section = elffile.get_section(_symbol['st_shndx'])
                            rev_reloc_symbols[symbol_name] = _section[
                                'sh_offset'] + _symbol['st_value'] + mem_start
                            # ql.nprint(":: Add reverse lookup for %s to %x (%x, %x)" %(symbol_name, rev_reloc_symbols[symbol_name], _section['sh_offset'], _symbol['st_value']))
                            # ql.nprint(":: Add reverse lookup for %s to %x" %(symbol_name, rev_reloc_symbols[symbol_name]))
                    else:
                        sym_offset = rev_reloc_symbols[symbol_name] - mem_start

                # ql.nprint("Relocating symbol %s -> 0x%x" %(symbol_name, rev_reloc_symbols[symbol_name]))

                loc = elffile.get_section(
                    section['sh_info'])['sh_offset'] + rel['r_offset']
                loc += mem_start

                if describe_reloc_type(rel['r_info_type'],
                                       elffile) == 'R_X86_64_32S':
                    # patch this reloc
                    if rel['r_addend']:
                        val = sym_offset + rel['r_addend']
                        val += mem_start
                        # ql.nprint('R_X86_64_32S %s: [0x%x] = 0x%x' %(symbol_name, loc, val & 0xFFFFFFFF))
                        ql.mem.write(loc, ql.pack32(val & 0xFFFFFFFF))
                    else:
                        # print("sym_offset = %x, rel = %x" %(sym_offset, rel['r_addend']))
                        # ql.nprint('R_X86_64_32S %s: [0x%x] = 0x%x' %(symbol_name, loc, rev_reloc_symbols[symbol_name] & 0xFFFFFFFF))
                        ql.mem.write(
                            loc,
                            ql.pack32(rev_reloc_symbols[symbol_name]
                                      & 0xFFFFFFFF))

                elif describe_reloc_type(rel['r_info_type'],
                                         elffile) == 'R_X86_64_64':
                    # patch this function?
                    val = sym_offset + rel['r_addend']
                    val += 0x2000000  # init_module position: FIXME
                    # finally patch this reloc
                    # ql.nprint('R_X86_64_64 %s: [0x%x] = 0x%x' %(symbol_name, loc, val))
                    ql.mem.write(loc, ql.pack64(val))

                elif describe_reloc_type(rel['r_info_type'],
                                         elffile) == 'R_X86_64_PC32':
                    # patch branch address: X86 case
                    val = rel['r_addend'] - loc
                    val += rev_reloc_symbols[symbol_name]
                    # finally patch this reloc
                    # ql.nprint('R_X86_64_PC32 %s: [0x%x] = 0x%x' %(symbol_name, loc, val & 0xFFFFFFFF))
                    ql.mem.write(loc, ql.pack32(val & 0xFFFFFFFF))

                elif describe_reloc_type(rel['r_info_type'],
                                         elffile) == 'R_386_PC32':
                    val = ql.unpack(ql.mem.read(loc, 4))
                    val = rev_reloc_symbols[symbol_name] + val - loc
                    ql.mem.write(loc, ql.pack32(val & 0xFFFFFFFF))

                elif describe_reloc_type(rel['r_info_type'],
                                         elffile) == 'R_386_32':
                    val = ql.unpack(ql.mem.read(loc, 4))
                    val = rev_reloc_symbols[symbol_name] + val
                    ql.mem.write(loc, ql.pack32(val & 0xFFFFFFFF))

        return rev_reloc_symbols
Пример #14
0
    def get_sections(self):
        sections = []
        for nsec, section in enumerate(self._elf.iter_sections()):
            result = {}
            result['nsec'] = nsec
            result['name'] = section.name
            result['sh_type'] = describe_sh_type(section['sh_type'])
            if self._elf.elfclass == 32:
                result['sh_addr'] = section['sh_addr']
                result['shoffset'] = section['sh_offset']
                result['sh_size'] = section['sh_size']
                result['sh_entsize'] = section['sh_entsize']
                result['sh_flags'] = describe_sh_flags(section['sh_flags'])
                result['sh_link'] = section['sh_link']
                result['sh_info'] = section['sh_info']
                result['sh_addralign'] = section['sh_addralign']
            else:  # 64
                result['sh_addr'] = section['sh_addr']
                result['sh_offset'] = section['sh_offset']
                result['sh_size'] = section['sh_size']
                result['sh_entsize'] = section['sh_entsize']
                result['sh_flags'] = describe_sh_flags(section['sh_flags'])
                result['sh_link'] = section['sh_link'], section['sh_info']
                result['sh_addralign'] = section['sh_addralign']

            # Dynamic Section
            if isinstance(section, DynamicSection):
                result['special_type'] = 'dynamic'
                result['dynamic'] = []
                has_dynamic_sections = True
                for tag in section.iter_tags():
                    dynamic = {}
                    if tag.entry.d_tag == 'DT_NEEDED':
                        parsed = 'Shared library: [%s]' % tag.needed
                    elif tag.entry.d_tag == 'DT_RPATH':
                        parsed = 'Library rpath: [%s]' % tag.rpath
                    elif tag.entry.d_tag == 'DT_RUNPATH':
                        parsed = 'Library runpath: [%s]' % tag.runpath
                    elif tag.entry.d_tag == 'DT_SONAME':
                        parsed = 'Library soname: [%s]' % tag.soname
                    elif tag.entry.d_tag.endswith(('SZ', 'ENT')):
                        parsed = '%i (bytes)' % tag['d_val']
                    elif tag.entry.d_tag.endswith(('NUM', 'COUNT')):
                        parsed = '%i' % tag['d_val']
                    elif tag.entry.d_tag == 'DT_PLTREL':
                        s = describe_dyn_tag(tag.entry.d_val)
                        if s.startswith('DT_'):
                            s = s[3:]
                        parsed = '%s' % s
                    else:
                        parsed = '%#x' % tag['d_val']
                        dynamic['tag'] = ENUM_D_TAG.get(
                            tag.entry.d_tag, tag.entry.d_tag)
                        dynamic['tag_type'] = tag.entry.d_tag[3:]
                        dynamic['tag_value'] = parsed
                    result['dynamic'].append(dynamic)

            #Relocation Section
            if isinstance(section, RelocationSection):
                result['special_type'] = 'relocation'
                result['relocation'] = []
                has_relocation_sections = True
                # The symbol table section pointed to in sh_link
                symtable = self._elf.get_section(section['sh_link'])

                for rel in section.iter_relocations():
                    relocation = {}
                    relocation['r_offset'] = rel['r_offset']
                    relocation['r_info'] = rel['r_info']
                    relocation['r_info_type'] = describe_reloc_type(
                        rel['r_info_type'], self._elf)

                    if rel['r_info_sym'] == 0:
                        continue

                    symbol = symtable.get_symbol(rel['r_info_sym'])
                    # Some symbols have zero 'st_name', so instead what's used is
                    # the name of the section they point at
                    if symbol['st_name'] == 0:
                        symsec = self._elf.get_section(symbol['st_shndx'])
                        relocation['symbol_name'] = symbol_name = symsec.name
                    else:
                        symbol_name = symbol.name
                        relocation['st_value'] = symbol['st_value']
                        relocation['symbol_name'] = symbol_name
                    if section.is_RELA():
                        relocation['r_addend'] = rel['r_addend']
                    result['relocation'].append(relocation)

            #Symbol Section
            if isinstance(section, SymbolTableSection):
                self._init_versioninfo()

                if section['sh_entsize'] == 0:
                    continue
                result['special_type'] = 'symbol'
                result['symbol'] = []
                for nsym, symbol in enumerate(section.iter_symbols()):
                    sym_dic = {}
                    version_info = ''
                    # readelf doesn't display version info for Solaris versioning
                    if (section['sh_type'] == 'SHT_DYNSYM'
                            and self._versioninfo['type'] == 'GNU'):
                        version = self._symbol_version(nsym)
                        if (version['name'] != symbol.name and version['index']
                                not in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL')):
                            if version['filename']:
                                # external symbol
                                version_info = '@%(name)s (%(index)i)' % version
                            else:
                                # internal symbol
                                if version['hidden']:
                                    version_info = '@%(name)s' % version
                                else:
                                    version_info = '@@%(name)s' % version

                        # symbol names are truncated to 25 chars, similarly to readelf
                        sym_dic['nsym'] = nsym
                        sym_dic['st_value'] = symbol['st_value']
                        sym_dic['st_size'] = symbol['st_size']
                        sym_dic['st_type'] = describe_symbol_type(
                            symbol['st_info']['type'])
                        sym_dic['bind'] = describe_symbol_bind(
                            symbol['st_info']['bind'])
                        sym_dic['vis'] = describe_symbol_visibility(
                            symbol['st_other']['visibility'])
                        sym_dic['ndx'] = describe_symbol_shndx(
                            symbol['st_shndx'])
                        sym_dic['name'] = symbol.name
                        sym_dic['version'] = version_info
                        result['symbol'].append(sym_dic)
            sections.append(result)
        return sections
Пример #15
0
def parse_elf_file(f, file_type, pkg):
  is_shlib = 'shared object' in file_type \
    and '.so' in file_type  # Detect PIEs

  with open(f, 'rb') as stream:
    elf_file = ELFFile(stream)
    f = os.path.basename(f)

    # First collect dependency info
    dynsect = elf_file.get_section_by_name('.dynamic')
    if not dynsect:
      error("%s: no .dynamic section" % f)
    elif not isinstance(dynsect, DynamicSection):
      # TODO: investigate
      error("%s: unexpected type of .dynamic" % f)
    soname = None
    deps = []
    is_symbolic = False
    for tag in dynsect.iter_tags():
      if tag.entry.d_tag == 'DT_NEEDED':
        deps.append(tag.needed)
      elif tag.entry.d_tag == 'DT_SONAME':
        if soname is not None:
          error("%s: multiple DT_SONAME in .dynamic section" % f)
        soname = tag.soname
      elif tag.entry.d_tag == 'DT_SYMBOLIC' \
          or (tag.entry.d_tag == 'DT_FLAGS' and (tag.entry.d_val & 0x2)):
        is_symbolic = True
    if not deps and not linker.is_dynamic_linker(f):
      warn("%s: no DT_NEEDED in .dynamic section" % f)

    # Get copy relocs (they are not real exports)
    copy_relocated_addresses = set()
    reladyn_name = '.rela.dyn'
    reladyn = elf_file.get_section_by_name(reladyn_name)
    if not isinstance(reladyn, RelocationSection):
        warn("%s: unexpected type of .rela.dyn" % f)
    else:
      # The symbol table section pointed to in sh_link
      for rel in reladyn.iter_relocations():
        rel_type = describe_reloc_type(rel['r_info_type'], elf_file)
        if rel_type == 'R_X86_64_COPY':
          copy_relocated_addresses.add(rel['r_offset'])

    # Get version names
    verdef = elf_file.get_section_by_name('.gnu.version_d')
    ver_names = set()
    if verdef:
      if not isinstance(verdef, GNUVerDefSection):
        error("%s: unexpected type of .gnu.version_d" % f)
      else:
        for verdef, verdaux_iter in verdef.iter_versions():
          verdaux = next(verdaux_iter)
          ver_names.add(verdaux.name)

    # Now analyze interface
    # TODO: versions
    symtab = elf_file.get_section_by_name('.dynsym')
    if not symtab:
      error("%s: no symbol table in %s")
      return False
    if not isinstance(symtab, SymbolTableSection):
      error("%s: unexpected type of .dynsym" % f)
      return False

    obj = Object(f, soname, pkg, deps, [], [], is_shlib, is_symbolic)

    for ndx, elf_symbol in enumerate(symtab.iter_symbols()):
      bind = elf_symbol['st_info']['bind']
      vis = elf_symbol['st_other']['visibility']
      # STB_LOOS means STB_GNU_UNIQUE
      if bind in ('STB_GLOBAL', 'STB_WEAK', 'STB_LOOS') \
          and vis in ('STV_DEFAULT', 'STV_PROTECTED'):
        if elf_symbol.name in ver_names:
          continue
        symbol = Symbol(elf_symbol.name, obj, bind == 'STB_WEAK', vis == 'STV_PROTECTED')
        if elf_symbol['st_shndx'] == 'SHN_UNDEF' \
            or elf_symbol['st_value'] in copy_relocated_addresses:
          obj.imports.append(symbol)
        else:
          obj.exports.append(symbol)

  return obj
Пример #16
0
    def lkm_dynlinker(self, elffile: ELFFile,
                      mem_start: int) -> Mapping[str, int]:
        def __get_symbol(name: str) -> Optional[Symbol]:
            _symtab = elffile.get_section_by_name('.symtab')
            _sym = _symtab.get_symbol_by_name(name)

            return _sym[0] if _sym else None

        ql = self.ql

        all_symbols = []
        self.ql.os.hook_addr = API_HOOK_MEM
        # map address to symbol name
        self.import_symbols = {}
        # reverse dictionary to map symbol name -> address
        rev_reloc_symbols = {}

        rh = RelocationHandler(elffile)
        sections = [
            sec for sec in elffile.iter_sections()
            if sec['sh_flags'] & SH_FLAGS.SHF_ALLOC
        ]

        for sec in sections:
            reloc_sec = rh.find_relocations_for_section(sec)

            if reloc_sec and reloc_sec.name != '.rela.gnu.linkonce.this_module':
                # get the symbol table section pointed in sh_link
                symtab = elffile.get_section(reloc_sec['sh_link'])
                assert isinstance(symtab, SymbolTableSection)

                for rel in reloc_sec.iter_relocations():
                    # if reloc['r_info_sym'] == 0:
                    #     continue

                    symbol = symtab.get_symbol(rel['r_info_sym'])
                    assert symbol

                    # Some symbols have zero 'st_name', so instead what's used is
                    # the name of the section they point at.
                    if symbol['st_name'] == 0:
                        symsec = elffile.get_section(symbol['st_shndx'])
                        symbol_name = symsec.name
                        sym_offset = symsec['sh_offset']

                        rev_reloc_symbols[symbol_name] = sym_offset + mem_start
                    else:
                        symbol_name = symbol.name
                        # get info about related section to be patched
                        info_section = elffile.get_section(
                            reloc_sec['sh_info'])
                        sym_offset = info_section['sh_offset']

                        if symbol_name in all_symbols:
                            sym_offset = rev_reloc_symbols[
                                symbol_name] - mem_start
                        else:
                            all_symbols.append(symbol_name)
                            _symbol = __get_symbol(symbol_name)

                            if _symbol['st_shndx'] == 'SHN_UNDEF':
                                # external symbol
                                # only save symbols of APIs

                                # we need to lookup from address to symbol, so we can find the right callback
                                # for sys_xxx handler for syscall, the address must be aligned to pointer size
                                if symbol_name.startswith('sys_'):
                                    self.ql.os.hook_addr = self.ql.mem.align_up(
                                        self.ql.os.hook_addr,
                                        self.ql.arch.pointersize)

                                self.import_symbols[
                                    self.ql.os.hook_addr] = symbol_name

                                # FIXME: this is for rootkit to scan for syscall table from page_offset_base
                                # write address of syscall table to this slot, so syscall scanner can quickly find it
                                if symbol_name == "page_offset_base":
                                    ql.mem.write_ptr(self.ql.os.hook_addr,
                                                     SYSCALL_MEM)

                                # we also need to do reverse lookup from symbol to address
                                rev_reloc_symbols[
                                    symbol_name] = self.ql.os.hook_addr
                                sym_offset = self.ql.os.hook_addr - mem_start
                                self.ql.os.hook_addr += self.ql.arch.pointersize
                            else:
                                # local symbol
                                _section = elffile.get_section(
                                    _symbol['st_shndx'])
                                rev_reloc_symbols[symbol_name] = _section[
                                    'sh_offset'] + _symbol[
                                        'st_value'] + mem_start

                    # ql.log.info(f'relocating: {symbol_name} -> {rev_reloc_symbols[symbol_name]:#010x}')

                    # FIXME: using the rh.apply_section_relocations method for the following relocation work
                    # seems to be cleaner.

                    loc = elffile.get_section(
                        reloc_sec['sh_info'])['sh_offset'] + rel['r_offset']
                    loc += mem_start

                    desc = describe_reloc_type(rel['r_info_type'], elffile)

                    if desc in ('R_X86_64_32S', 'R_X86_64_32'):
                        # patch this reloc
                        if rel['r_addend']:
                            val = sym_offset + rel['r_addend']
                            val += mem_start
                        else:
                            val = rev_reloc_symbols[symbol_name]

                        ql.mem.write_ptr(loc, (val & 0xFFFFFFFF), 4)

                    elif desc == 'R_X86_64_64':
                        val = sym_offset + rel['r_addend']
                        val += 0x2000000  # init_module position: FIXME
                        ql.mem.write_ptr(loc, val, 8)

                    elif desc == 'R_X86_64_PC64':
                        val = rel['r_addend'] - loc
                        val += rev_reloc_symbols[symbol_name]
                        ql.mem.write_ptr(loc, val, 8)

                    elif desc in ('R_X86_64_PC32', 'R_X86_64_PLT32'):
                        val = rel['r_addend'] - loc
                        val += rev_reloc_symbols[symbol_name]
                        ql.mem.write_ptr(loc, (val & 0xFFFFFFFF), 4)

                    elif desc in ('R_386_PC32', 'R_386_PLT32'):
                        val = ql.mem.read_ptr(loc, 4)
                        val = rev_reloc_symbols[symbol_name] + val - loc
                        ql.mem.write_ptr(loc, (val & 0xFFFFFFFF), 4)

                    elif desc in ('R_386_32', 'R_MIPS_32'):
                        val = ql.mem.read_ptr(loc, 4)
                        val = rev_reloc_symbols[symbol_name] + val
                        ql.mem.write_ptr(loc, (val & 0xFFFFFFFF), 4)

                    elif desc == 'R_MIPS_HI16':
                        # actual relocation is done in R_MIPS_LO16
                        prev_mips_hi16_loc = loc

                    elif desc == 'R_MIPS_LO16':
                        val = ql.mem.read_ptr(prev_mips_hi16_loc + 2,
                                              2) << 16 | ql.mem.read_ptr(
                                                  loc + 2, 2)
                        val = rev_reloc_symbols[symbol_name] + val
                        # *(word)(mips_lo16_loc + 2) is treated as signed
                        if (val & 0xFFFF) >= 0x8000:
                            val += (1 << 16)

                        ql.mem.write_ptr(prev_mips_hi16_loc + 2, (val >> 16),
                                         2)
                        ql.mem.write_ptr(loc + 2, (val & 0xFFFF), 2)

                    else:
                        raise NotImplementedError(
                            f'Relocation type {desc} not implemented')

        return rev_reloc_symbols