Ejemplo n.º 1
0
def makeRelocTable(vw, va, maxva, addbase, baseaddr, addend=False):
    if addend:
        sname = 'elf.Elf%dReloca' % (vw.getPointerSize() * 8)
    else:
        sname = 'elf.Elf%dReloc' % (vw.getPointerSize() * 8)

    while va < maxva:
        s = vw.makeStructure(va, sname)
        tname = Elf.r_types_386.get(Elf.getRelocType(s.r_info), "Unknown Type")
        vw.setComment(va, tname)
        va += len(s)
Ejemplo n.º 2
0
Archivo: elf.py Proyecto: BwRy/vivisect
def loadElfIntoWorkspace(vw, elf, filename=None):

    arch = arch_names.get(elf.e_machine)
    if arch == None:
       raise Exception("Unsupported Architecture: %d\n", elf.e_machine)

    platform = elf.getPlatform()

    # setup needed platform/format
    vw.setMeta('Architecture', arch)
    vw.setMeta('Platform', platform)
    vw.setMeta('Format', 'elf')

    vw.setMeta('DefaultCall', archcalls.get(arch,'unknown'))

    vw.addNoReturnApi("*.exit")

    # Base addr is earliest section address rounded to pagesize
    # NOTE: This is only for prelink'd so's and exe's.  Make something for old style so.
    addbase = False
    if not elf.isPreLinked() and elf.isSharedObject():
        addbase = True
    baseaddr = elf.getBaseAddress()

    #FIXME make filename come from dynamic's if present for shared object
    if filename == None:
        filename = "elf_%.8x" % baseaddr

    fhash = "unknown hash"
    if os.path.exists(filename):
        fhash = v_parsers.md5File(filename)

    fname = vw.addFile(filename.lower(), baseaddr, fhash)

    strtabs = {}
    secnames = []
    for sec in elf.getSections():
        secnames.append(sec.getName())

    pgms = elf.getPheaders()
    secs = elf.getSections()

    for pgm in pgms:
        if pgm.p_type == Elf.PT_LOAD:
            if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm)))
            bytez = elf.readAtOffset(pgm.p_offset, pgm.p_filesz)
            bytez += "\x00" * (pgm.p_memsz - pgm.p_filesz)
            pva = pgm.p_vaddr
            if addbase: pva += baseaddr
            vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytez) #FIXME perms
        else:
            if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm))

    if len(pgms) == 0:
        # fall back to loading sections as best we can...
        if vw.verbose: vw.vprint('elf: no program headers found!')

        maps = [ [s.sh_offset,s.sh_size] for s in secs if s.sh_offset and s.sh_size ]
        maps.sort()

        merged = []
        for i in xrange(len(maps)):

            if merged and maps[i][0] == (merged[-1][0] + merged[-1][1]):
                merged[-1][1] += maps[i][1]
                continue

            merged.append( maps[i] )

        baseaddr = 0x05000000
        for offset,size in merged:
            bytez = elf.readAtOffset(offset,size)
            vw.addMemoryMap(baseaddr + offset, 0x7, fname, bytez)

        for sec in secs:
            if sec.sh_offset and sec.sh_size:
                sec.sh_addr = baseaddr + sec.sh_offset

    # First add all section definitions so we have them
    for sec in secs:
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        vw.addSegment(sva, size, sname, fname)

    # Now trigger section specific analysis
    for sec in secs:
        #FIXME dup code here...
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        if sname == ".interp":
            vw.makeString(sva)

        elif sname == ".init":
            vw.makeName(sva, "init_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".fini":
            vw.makeName(sva, "fini_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".dynamic": # Imports
            makeDynamicTable(vw, sva, sva+size)

        # FIXME section names are optional, use dynamic info from .dynamic
        elif sname == ".dynstr": # String table for dynamics
            makeStringTable(vw, sva, sva+size)

        elif sname == ".dynsym":
            #print "LINK",sec.sh_link
            for s in makeSymbolTable(vw, sva, sva+size):
                pass
                #print "########################.dynsym",s

        # If the section is really a string table, do it
        if sec.sh_type == Elf.SHT_STRTAB:
            makeStringTable(vw, sva, sva+size)

        elif sec.sh_type == Elf.SHT_SYMTAB:
            makeSymbolTable(vw, sva, sva+size)

        elif sec.sh_type == Elf.SHT_REL:
            makeRelocTable(vw, sva, sva+size, addbase, baseaddr)

        if sec.sh_flags & Elf.SHF_STRINGS:
            print "FIXME HANDLE SHF STRINGS"

    # Let pyelf do all the stupid string parsing...
    for r in elf.getRelocs():
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase: rlva += baseaddr
        try:
            # If it has a name, it's an externally
            # resolved "import" entry, otherwise, just a regular reloc
            if arch in ('i386','amd64'):

                name = r.getName()
                if name:
                    if rtype == Elf.R_386_JMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    # FIXME elf has conflicting names for 2 relocs?
                    #elif rtype == Elf.R_386_GLOB_DAT:
                        #vw.makeImport(rlva, "*", name)

                    elif rtype == Elf.R_386_32:
                        pass

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva)))

            if arch == 'arm':
                name = r.getName()
                if name:
                    if rtype == Elf.R_ARM_JUMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva)))

        except vivisect.InvalidLocation, e:
            print "NOTE",e
Ejemplo n.º 3
0
Archivo: elf.py Proyecto: BwRy/vivisect
def makeRelocTable(vw, va, maxva, addbase, baseaddr):
    while va < maxva:
        s = vw.makeStructure(va, "elf.Elf32Reloc")
        tname = Elf.r_types_386.get(Elf.getRelocType(s.r_info), "Unknown Type")
        vw.setComment(va, tname)
        va += len(s)
Ejemplo n.º 4
0
def loadElfIntoWorkspace(vw, elf, filename=None):

    arch = arch_names.get(elf.e_machine)
    if arch == None:
       raise Exception("Unsupported Architecture: %d\n", elf.e_machine)

    # setup needed platform/format
    vw.setMeta('Architecture', arch)
    vw.setMeta('Platform', 'unknown')
    vw.setMeta('Format', 'elf')

    # FIXME try to determine *which* Elf system...
    if arch == 'i386':
        vw.setMeta("DefaultCall", "cdecl")

    elif arch == 'amd64':
        vw.setMeta("DefaultCall", "sysvamd64call")

    vw.addNoReturnApi("*.exit")

    # Base addr is earliest section address rounded to pagesize
    # NOTE: This is only for prelink'd so's and exe's.  Make something for old style so.
    addbase = False
    if not elf.isPreLinked() and elf.isSharedObject():
        addbase = True
    baseaddr = elf.getBaseAddress()

    #FIXME make filename come from dynamic's if present for shared object
    if filename == None:
        filename = "elf_%.8x" % baseaddr

    fname = vw.addFile(filename, baseaddr, v_parsers.md5File(filename))

    strtabs = {}
    secnames = []
    for sec in elf.getSections():
        secnames.append(sec.getName())

    for pgm in elf.getPheaders():
        if pgm.p_type == Elf.PT_LOAD:
            if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm)))
            bytes = elf.readAtOffset(pgm.p_offset, pgm.p_filesz)
            bytes += "\x00" * (pgm.p_memsz - pgm.p_filesz)
            pva = pgm.p_vaddr
            if addbase: pva += baseaddr
            vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytes) #FIXME perms
        else:
            if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm))

    # First add all section definitions so we have them
    for sec in elf.getSections():
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        vw.addSegment(sva, size, sname, fname)

    # Now trigger section specific analysis
    for sec in elf.getSections():
        #FIXME dup code here...
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        if sname == ".interp":
            vw.makeString(sva)

        elif sname == ".init":
            vw.makeName(sva, "init_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".fini":
            vw.makeName(sva, "fini_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".dynamic": # Imports
            makeDynamicTable(vw, sva, sva+size)

        # FIXME section names are optional, use dynamic info from .dynamic
        elif sname == ".dynstr": # String table for dynamics
            makeStringTable(vw, sva, sva+size)

        elif sname == ".dynsym":
            #print "LINK",sec.sh_link
            for s in makeSymbolTable(vw, sva, sva+size):
                pass
                #print "########################.dynsym",s

        # If the section is really a string table, do it
        if sec.sh_type == Elf.SHT_STRTAB:
            makeStringTable(vw, sva, sva+size)

        elif sec.sh_type == Elf.SHT_SYMTAB:
            # FIXME 32 bit specific!
            #print "FOUND A SYMBOL TABLE!"
            makeSymbolTable(vw, sva, sva+size)

        elif sec.sh_type == Elf.SHT_REL:
            makeRelocTable(vw, sva, sva+size, addbase, baseaddr)

        if sec.sh_flags & Elf.SHF_STRINGS:
            print "FIXME HANDLE SHF STRINGS"

    # Let pyelf do all the stupid string parsing...
    for r in elf.getRelocs():
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase: rlva += baseaddr
        try:
            # If it has a name, it's an externally
            # resolved "import" entry, otherwise, just a regular reloc
            if arch in ('i386','amd64'):

                name = r.getName()
                if name:
                    if rtype == Elf.R_386_JMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    # FIXME elf has conflicting names for 2 relocs?
                    #elif rtype == Elf.R_386_GLOB_DAT:
                        #vw.makeImport(rlva, "*", name)

                    elif rtype == Elf.R_386_32:
                        pass

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva)))

            if arch == 'arm':
                name = r.getName()
                if name:
                    if rtype == Elf.R_ARM_JUMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva)))

        except vivisect.InvalidLocation, e:
            print "NOTE",e
Ejemplo n.º 5
0
def applyRelocs(elf, vw, addbase=False, baseaddr=0):
    '''
    process relocations / strings (relocs use Dynamic Symbols)
    '''
    arch = arch_names.get(elf.e_machine)
    relocs = elf.getRelocs()
    logger.debug("reloc len: %d", len(relocs))
    for r in relocs:
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase:
            rlva += baseaddr
        try:
            # If it has a name, it's an externally resolved "import" entry,
            # otherwise, just a regular reloc
            name = r.getName()
            dmglname = demangle(name)
            logger.debug('relocs: 0x%x: %s (%s)', rlva, dmglname, name)
            if arch in ('i386', 'amd64'):
                if name:
                    if rtype == Elf.R_X86_64_IRELATIVE:
                        # before making import, let's fix up the pointer as a BASEPTR Relocation
                        ptr = r.r_addend
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        logger.info('Reloc: R_X86_64_IRELATIVE 0x%x', rlva)

                    if rtype in (Elf.R_386_JMP_SLOT, Elf.R_X86_64_GLOB_DAT,
                                 Elf.R_X86_64_IRELATIVE):
                        logger.info('Reloc: making Import 0x%x (name: %s/%s) ',
                                    rlva, name, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                    elif rtype in (Elf.R_386_32, Elf.R_386_COPY,
                                   Elf.R_X86_64_TPOFF64):
                        pass

                    else:
                        logger.warning('unknown reloc type: %d %s (at %s)',
                                       rtype, name, hex(rlva))
                        logger.info(r.tree())

                else:
                    if rtype == Elf.R_386_RELATIVE:  # R_X86_64_RELATIVE is the same number
                        ptr = vw.readMemoryPtr(rlva)
                        logger.info(
                            'R_386_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ',
                            rlva, ptr, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)

                    elif rtype == Elf.R_X86_64_IRELATIVE:
                        # first make it a relocation that is based on the imagebase
                        ptr = r.r_addend
                        logger.info(
                            'R_X86_64_IRELATIVE: adding Relocation 0x%x -> 0x%x (name: %r %r) ',
                            rlva, ptr, name, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)

                        # next get the target and find a name, since the reloc itself doesn't have one
                        tgt = vw.readMemoryPtr(rlva)
                        tgtname = vw.getName(tgt)
                        if tgtname is not None:
                            logger.info('   name(0x%x): %r', tgt, tgtname)
                            fn, symname = tgtname.split('.', 1)
                            logger.info(
                                'Reloc: making Import 0x%x (name: %s.%s) ',
                                rlva, fn, symname)
                            vw.makeImport(rlva, fn, symname)

                    else:
                        logger.warning('unknown reloc type: %d %s (at %s)',
                                       rtype, name, hex(rlva))
                        logger.info(r.tree())

            if arch in ('arm', 'thumb', 'thumb16'):
                # ARM REL entries require an addend that could be stored as a
                # number or an instruction!
                import envi.archs.arm.const as eaac
                if r.vsHasField('addend'):
                    # this is a RELA object, bringing its own addend field!
                    addend = r.addend
                else:
                    # otherwise, we have to check the stored value for number or instruction
                    # if it's an instruction, we have to use the immediate value and then
                    # figure out if it's negative based on the instruction!
                    try:
                        temp = vw.readMemoryPtr(rlva)
                        if rtype in Elf.r_armclasses[
                                Elf.
                                R_ARMCLASS_DATA] or rtype in Elf.r_armclasses[
                                    Elf.R_ARMCLASS_MISC]:
                            # relocation points to a DATA or MISCELLANEOUS location
                            addend = temp
                        else:
                            # relocation points to a CODE location (ARM, THUMB16, THUMB32)
                            op = vw.parseOpcode(rlva)
                            for oper in op.opers:
                                if hasattr(oper, 'val'):
                                    addend = oper.val
                                    break

                                elif hasattr(oper, 'offset'):
                                    addend = oper.offset
                                    break

                            lastoper = op.opers[-1]
                            if op.mnem.startswith('sub') or \
                                    op.mnem in ('ldr', 'str') and \
                                    hasattr(lastoper, 'pubwl') and \
                                    not (lastoper.pubwl & eaac.PUxWL_ADD):
                                addend = -addend
                    except Exception as e:
                        logger.exception("ELF: Reloc Addend determination: %s",
                                         e)
                        addend = temp

                logger.debug('addend: 0x%x', addend)

                if rtype == Elf.R_ARM_JUMP_SLOT:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    # quick check to make sure we don't provide this symbol
                    # some toolchains like to point the GOT back at it's PLT entry
                    # that does *not* mean it's not an IMPORT
                    if ptr and not isPLT(vw, ptr):
                        logger.info(
                            'R_ARM_JUMP_SLOT: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        if addbase:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        else:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC,
                                             ptr)
                        pname = "ptr_%s_%.8x" % (name, rlva)
                        if vw.vaByName(pname) is None:
                            vw.makeName(rlva, pname)

                        # name the target as well
                        if addbase:
                            ptr += baseaddr
                        # normalize thumb addresses
                        ptr &= -2
                        vw.makeName(ptr, name)
                        vw.setComment(ptr, dmglname)

                    else:
                        logger.info(
                            'R_ARM_JUMP_SLOT: adding Import 0x%x (%s) ', rlva,
                            dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                elif rtype == Elf.R_ARM_GLOB_DAT:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    if ptr:
                        logger.info(
                            'R_ARM_GLOB_DAT: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        if addbase:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        else:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC,
                                             ptr)
                        pname = "ptr_%s" % name

                        if vw.vaByName(pname) is None:
                            vw.makeName(rlva, pname)

                        if addbase:
                            ptr += baseaddr
                        vw.makeImport(ptr, "*", dmglname)
                        vw.setComment(ptr, name)

                    else:
                        logger.info('R_ARM_GLOB_DAT: adding Import 0x%x (%s) ',
                                    rlva, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                elif rtype == Elf.R_ARM_ABS32:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    if ptr:
                        logger.info(
                            'R_ARM_ABS32: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        pname = "ptr_%s" % name
                        if vw.vaByName(pname) is None and len(name):
                            vw.makeName(rlva, pname)

                    else:
                        logger.info('R_ARM_ABS32: adding Import 0x%x (%s) ',
                                    rlva, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                    vw.setComment(rlva, dmglname)

                elif rtype == Elf.R_ARM_RELATIVE:  # Adjust locations for the rebasing
                    ptr = vw.readMemoryPtr(rlva)
                    logger.info(
                        'R_ARM_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ',
                        rlva, ptr, dmglname)
                    vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                    if len(name):
                        vw.makeName(rlva, dmglname, makeuniq=True)
                        vw.setComment(rlva, name)

                elif rtype == Elf.R_ARM_COPY:
                    pass

                else:
                    logger.warning('unknown reloc type: %d %s (at %s)', rtype,
                                   name, hex(rlva))
                    logger.info(r.tree())

        except vivisect.InvalidLocation as e:
            logger.warning("NOTE\t%r", e)
Ejemplo n.º 6
0
def loadElfIntoWorkspace(vw, elf, filename=None):

    arch = arch_names.get(elf.e_machine)
    if arch == None:
        raise Exception("Unsupported Architecture: %d\n", elf.e_machine)

    platform = elf.getPlatform()

    # setup needed platform/format
    vw.setMeta('Architecture', arch)
    vw.setMeta('Platform', platform)
    vw.setMeta('Format', 'elf')

    vw.setMeta('DefaultCall', archcalls.get(arch, 'unknown'))

    vw.addNoReturnApi("*.exit")

    # Base addr is earliest section address rounded to pagesize
    # NOTE: This is only for prelink'd so's and exe's.  Make something for old style so.
    addbase = False
    if not elf.isPreLinked() and elf.isSharedObject():
        addbase = True
    baseaddr = elf.getBaseAddress()

    #FIXME make filename come from dynamic's if present for shared object
    if filename == None:
        filename = "elf_%.8x" % baseaddr

    fhash = "unknown hash"
    if os.path.exists(filename):
        fhash = v_parsers.md5File(filename)

    fname = vw.addFile(filename.lower(), baseaddr, fhash)

    strtabs = {}
    secnames = []
    for sec in elf.getSections():
        secnames.append(sec.getName())

    pgms = elf.getPheaders()
    secs = elf.getSections()

    for pgm in pgms:
        if pgm.p_type == Elf.PT_LOAD:
            if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm)))
            bytez = elf.readAtOffset(pgm.p_offset, pgm.p_filesz)
            bytez += "\x00" * (pgm.p_memsz - pgm.p_filesz)
            pva = pgm.p_vaddr
            if addbase: pva += baseaddr
            vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytez)  #FIXME perms
        else:
            if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm))

    if len(pgms) == 0:
        # fall back to loading sections as best we can...
        if vw.verbose: vw.vprint('elf: no program headers found!')

        maps = [[s.sh_offset, s.sh_size] for s in secs
                if s.sh_offset and s.sh_size]
        maps.sort()

        merged = []
        for i in xrange(len(maps)):

            if merged and maps[i][0] == (merged[-1][0] + merged[-1][1]):
                merged[-1][1] += maps[i][1]
                continue

            merged.append(maps[i])

        baseaddr = 0x05000000
        for offset, size in merged:
            bytez = elf.readAtOffset(offset, size)
            vw.addMemoryMap(baseaddr + offset, 0x7, fname, bytez)

        for sec in secs:
            if sec.sh_offset and sec.sh_size:
                sec.sh_addr = baseaddr + sec.sh_offset

    # First add all section definitions so we have them
    for sec in secs:
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue  # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        vw.addSegment(sva, size, sname, fname)

    # Now trigger section specific analysis
    for sec in secs:
        #FIXME dup code here...
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue  # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        if sname == ".interp":
            vw.makeString(sva)

        elif sname == ".init":
            vw.makeName(sva, "init_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".fini":
            vw.makeName(sva, "fini_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".dynamic":  # Imports
            makeDynamicTable(vw, sva, sva + size)

        # FIXME section names are optional, use dynamic info from .dynamic
        elif sname == ".dynstr":  # String table for dynamics
            makeStringTable(vw, sva, sva + size)

        elif sname == ".dynsym":
            #print "LINK",sec.sh_link
            for s in makeSymbolTable(vw, sva, sva + size):
                pass
                #print "########################.dynsym",s

        # If the section is really a string table, do it
        if sec.sh_type == Elf.SHT_STRTAB:
            makeStringTable(vw, sva, sva + size)

        elif sec.sh_type == Elf.SHT_SYMTAB:
            makeSymbolTable(vw, sva, sva + size)

        elif sec.sh_type == Elf.SHT_REL:
            makeRelocTable(vw, sva, sva + size, addbase, baseaddr)

        if sec.sh_flags & Elf.SHF_STRINGS:
            print "FIXME HANDLE SHF STRINGS"

    # Let pyelf do all the stupid string parsing...
    for r in elf.getRelocs():
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase: rlva += baseaddr
        try:
            # If it has a name, it's an externally
            # resolved "import" entry, otherwise, just a regular reloc
            if arch in ('i386', 'amd64'):

                name = r.getName()
                if name:
                    if rtype == Elf.R_386_JMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    # FIXME elf has conflicting names for 2 relocs?
                    #elif rtype == Elf.R_386_GLOB_DAT:
                    #vw.makeImport(rlva, "*", name)

                    elif rtype == Elf.R_386_32:
                        pass

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' %
                                     (rtype, name, hex(rlva)))

            if arch == 'arm':
                name = r.getName()
                if name:
                    if rtype == Elf.R_ARM_JUMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' %
                                     (rtype, name, hex(rlva)))

        except vivisect.InvalidLocation, e:
            print "NOTE", e
Ejemplo n.º 7
0
def makeRelocTable(vw, va, maxva, addbase, baseaddr):
    while va < maxva:
        s = vw.makeStructure(va, "elf.Elf32Reloc")
        tname = Elf.r_types_386.get(Elf.getRelocType(s.r_info), "Unknown Type")
        vw.setComment(va, tname)
        va += len(s)
def loadElfIntoWorkspace(vw, elf, filename=None):

    arch = arch_names.get(elf.e_machine)
    if arch == None:
        raise Exception("Unsupported Architecture: %d\n", elf.e_machine)

    # setup needed platform/format
    vw.setMeta('Architecture', arch)
    vw.setMeta('Platform', 'unknown')
    vw.setMeta('Format', 'elf')

    # FIXME try to determine *which* Elf system...
    if arch == 'i386':
        vw.setMeta("DefaultCall", "cdecl")

    elif arch == 'amd64':
        vw.setMeta("DefaultCall", "sysvamd64call")

    vw.addNoReturnApi("*.exit")

    # Base addr is earliest section address rounded to pagesize
    # NOTE: This is only for prelink'd so's and exe's.  Make something for old style so.
    addbase = False
    if not elf.isPreLinked() and elf.isSharedObject():
        addbase = True
    baseaddr = elf.getBaseAddress()

    #FIXME make filename come from dynamic's if present for shared object
    if filename == None:
        filename = "elf_%.8x" % baseaddr

    fname = vw.addFile(filename, baseaddr, v_parsers.md5File(filename))

    strtabs = {}
    secnames = []
    for sec in elf.getSections():
        secnames.append(sec.getName())

    for pgm in elf.getPheaders():
        if pgm.p_type == Elf.PT_LOAD:
            if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm)))
            bytes = elf.readAtOffset(pgm.p_offset, pgm.p_filesz)
            bytes += "\x00" * (pgm.p_memsz - pgm.p_filesz)
            pva = pgm.p_vaddr
            if addbase: pva += baseaddr
            vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytes)  #FIXME perms
        else:
            if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm))

    # First add all section definitions so we have them
    for sec in elf.getSections():
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue  # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        vw.addSegment(sva, size, sname, fname)

    # Now trigger section specific analysis
    for sec in elf.getSections():
        #FIXME dup code here...
        sname = sec.getName()
        size = sec.sh_size
        if sec.sh_addr == 0:
            continue  # Skip non-memory mapped sections

        sva = sec.sh_addr
        if addbase: sva += baseaddr

        if sname == ".interp":
            vw.makeString(sva)

        elif sname == ".init":
            vw.makeName(sva, "init_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".fini":
            vw.makeName(sva, "fini_function", filelocal=True)
            vw.addEntryPoint(sva)

        elif sname == ".dynamic":  # Imports
            makeDynamicTable(vw, sva, sva + size)

        # FIXME section names are optional, use dynamic info from .dynamic
        elif sname == ".dynstr":  # String table for dynamics
            makeStringTable(vw, sva, sva + size)

        elif sname == ".dynsym":
            #print "LINK",sec.sh_link
            for s in makeSymbolTable(vw, sva, sva + size):
                pass
                #print "########################.dynsym",s

        # If the section is really a string table, do it
        if sec.sh_type == Elf.SHT_STRTAB:
            makeStringTable(vw, sva, sva + size)

        elif sec.sh_type == Elf.SHT_SYMTAB:
            # FIXME 32 bit specific!
            #print "FOUND A SYMBOL TABLE!"
            makeSymbolTable(vw, sva, sva + size)

        elif sec.sh_type == Elf.SHT_REL:
            makeRelocTable(vw, sva, sva + size, addbase, baseaddr)

        if sec.sh_flags & Elf.SHF_STRINGS:
            print "FIXME HANDLE SHF STRINGS"

    # Let pyelf do all the stupid string parsing...
    for r in elf.getRelocs():
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase: rlva += baseaddr
        try:
            # If it has a name, it's an externally
            # resolved "import" entry, otherwise, just a regular reloc
            if arch in ('i386', 'amd64'):

                name = r.getName()
                if name:
                    if rtype == Elf.R_386_JMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    # FIXME elf has conflicting names for 2 relocs?
                    #elif rtype == Elf.R_386_GLOB_DAT:
                    #vw.makeImport(rlva, "*", name)

                    elif rtype == Elf.R_386_32:
                        pass

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' %
                                     (rtype, name, hex(rlva)))

            if arch == 'arm':
                name = r.getName()
                if name:
                    if rtype == Elf.R_ARM_JUMP_SLOT:
                        vw.makeImport(rlva, "*", name)

                    else:
                        vw.verbprint('unknown reloc type: %d %s (at %s)' %
                                     (rtype, name, hex(rlva)))

        except vivisect.InvalidLocation, e:
            print "NOTE", e
Ejemplo n.º 9
0
def applyRelocs(elf, vw, addbase=False, baseaddr=0):
    # process relocations / strings (relocs use Dynamic Symbols)
    arch = arch_names.get(elf.e_machine)
    relocs = elf.getRelocs()
    logger.debug("reloc len: %d", len(relocs))
    for r in relocs:
        rtype = Elf.getRelocType(r.r_info)
        rlva = r.r_offset
        if addbase:
            rlva += baseaddr
        try:
            # If it has a name, it's an externally resolved "import" entry,
            # otherwise, just a regular reloc
            name = r.getName()
            dmglname = demangle(name)
            logger.debug('relocs: 0x%x: %r  (%r)', rlva, dmglname, name)
            if arch in ('i386', 'amd64'):
                if name:
                    if rtype == Elf.R_X86_64_IRELATIVE:
                        # before making import, let's fix up the pointer as a BASEPTR Relocation
                        ptr = r.r_addend
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        logger.info('Reloc: R_X86_64_IRELATIVE 0x%x', rlva)

                    if rtype in (Elf.R_386_JMP_SLOT, Elf.R_X86_64_GLOB_DAT,
                                 Elf.R_X86_64_IRELATIVE):
                        logger.info('Reloc: making Import 0x%x (name: %s/%s) ',
                                    rlva, name, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                    elif rtype in (Elf.R_386_32, Elf.R_386_COPY):
                        pass

                    else:
                        logger.warn('unknown reloc type: %d %s (at %s)', rtype,
                                    name, hex(rlva))
                        logger.info(r.tree())

                else:
                    if rtype == Elf.R_386_RELATIVE:  # R_X86_64_RELATIVE is the same number
                        ptr = vw.readMemoryPtr(rlva)
                        logger.info(
                            'R_386_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ',
                            rlva, ptr, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)

                    elif rtype == Elf.R_X86_64_IRELATIVE:
                        # first make it a relocation that is based on the imagebase
                        ptr = r.r_addend
                        logger.info(
                            'R_X86_64_IRELATIVE: adding Relocation 0x%x -> 0x%x (name: %r %r) ',
                            rlva, ptr, name, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)

                        # next get the target and find a name, since the reloc itself doesn't have one
                        tgt = vw.readMemoryPtr(rlva)
                        tgtname = vw.getName(tgt)
                        if tgtname is not None:
                            logger.info('   name(0x%x): %r', tgt, tgtname)
                            fn, symname = tgtname.split('.', 1)
                            logger.info(
                                'Reloc: making Import 0x%x (name: %s.%s) ',
                                rlva, fn, symname)
                            vw.makeImport(rlva, fn, symname)

                    else:
                        logger.warn('unknown reloc type: %d %s (at %s)', rtype,
                                    name, hex(rlva))
                        logger.info(r.tree())

            if arch in ('arm', 'thumb', 'thumb16'):
                if rtype == Elf.R_ARM_JUMP_SLOT:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    #quick check to make sure we don't provide this symbol
                    if ptr:
                        logger.info(
                            'R_ARM_JUMP_SLOT: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        if addbase:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        else:
                            vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC,
                                             ptr)
                        pname = "ptr_%s_%.8x" % (name, rlva)
                        if vw.vaByName(pname) is None:
                            vw.makeName(rlva, pname)

                        if addbase:
                            ptr += baseaddr
                        vw.makeName(ptr, name)
                        vw.setComment(ptr, dmglname)

                    else:
                        logger.info(
                            'R_ARM_JUMP_SLOT: adding Import 0x%x (%s) ', rlva,
                            dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                elif rtype == Elf.R_ARM_GLOB_DAT:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    #quick check to make sure we don't provide this symbol
                    if ptr:
                        logger.info(
                            'R_ARM_GLOB_DAT: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        pname = "ptr_%s" % name
                        if vw.vaByName(pname) is None:
                            vw.makeName(rlva, pname)

                        if addbase:
                            ptr += baseaddr
                        vw.makeImport(ptr, "*", dmglname)
                        vw.setComment(ptr, name)

                    else:
                        logger.info('R_ARM_GLOB_DAT: adding Import 0x%x (%s) ',
                                    rlva, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                elif rtype == Elf.R_ARM_ABS32:
                    symidx = r.getSymTabIndex()
                    sym = elf.getDynSymbol(symidx)
                    ptr = sym.st_value

                    if ptr:
                        logger.info(
                            'R_ARM_ABS32: adding Relocation 0x%x -> 0x%x (%s) ',
                            rlva, ptr, dmglname)
                        vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                        pname = "ptr_%s" % name
                        if vw.vaByName(pname) is None and len(name):
                            vw.makeName(rlva, pname)

                    else:
                        logger.info('R_ARM_ABS32: adding Import 0x%x (%s) ',
                                    rlva, dmglname)
                        vw.makeImport(rlva, "*", dmglname)
                        vw.setComment(rlva, name)

                    vw.setComment(rlva, dmglname)

                elif rtype == Elf.R_ARM_RELATIVE:  # Adjust locations for the rebasing
                    ptr = vw.readMemoryPtr(rlva)
                    logger.info(
                        'R_ARM_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ',
                        rlva, ptr, dmglname)
                    vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr)
                    if len(name):
                        vw.makeName(rlva, dmglname, makeuniq=True)
                        vw.setComment(rlva, name)

                else:
                    logger.warn('unknown reloc type: %d %s (at %s)', rtype,
                                name, hex(rlva))
                    logger.info(r.tree())

        except vivisect.InvalidLocation as e:
            logger.warn("NOTE\t%r", e)