Exemple #1
0
def loadPeIntoWorkspace(vw, pe, filename=None, baseaddr=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch is None:
        raise Exception("Machine %.4x is not supported for PE!" % mach )

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

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

    # Set ourselves up for extended windows binary analysis

    if baseaddr is None:
        baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase+codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname is None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    try:
        vs = pe.getVS_VERSIONINFO()
    except Exception, e:
        vs = None
        vw.vprint('Failed to load version info resource due to %s' % (repr(e),))
Exemple #2
0
def loadPeIntoWorkspace(vw, pe, filename=None, baseaddr=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch is None:
        raise Exception("Machine %.4x is not supported for PE!" % mach )

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

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

    # Set ourselves up for extended windows binary analysis

    if baseaddr is None:
        baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase+codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname is None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    try:
        vs = pe.getVS_VERSIONINFO()
    except Exception, e:
        vs = None
        vw.vprint('Failed to load version info resource due to %s' % (repr(e),))
Exemple #3
0
    def platformParseBinary(self, filename, baseaddr, normname):
        try:
            pe = PE.peFromMemoryObject(self, baseaddr)
            vhash = e_symcache.symCacheHashFromPe(pe)

            symcache = self.symcache.getCacheSyms(vhash)
            if symcache is None:
                # Symbol type 0 for now...
                symcache = [(rva, 0, name, e_resolv.SYMSTOR_SYM_SYMBOL)
                            for rva, ord, name in pe.getExports()]
                self.symcache.setCacheSyms(vhash, symcache)

            self.impSymCache(symcache, symfname=normname, baseaddr=baseaddr)

        except Exception as e:
            logger.error('Error Parsing Binary (%s): %s', normname, e)
Exemple #4
0
    def platformParseBinary(self, filename, baseaddr, normname):
        try:
            pe = PE.peFromMemoryObject(self, baseaddr)
            vhash = e_symcache.symCacheHashFromPe(pe)

            symcache = self.symcache.getCacheSyms(vhash)
            if symcache == None:
                # Symbol type 0 for now...
                symcache = [ ( rva, 0, name, e_resolv.SYMSTOR_SYM_SYMBOL ) for rva,ord,name in pe.getExports() ]
                self.symcache.setCacheSyms( vhash, symcache )

            self.impSymCache( symcache, symfname=normname, baseaddr=baseaddr )

        except Exception as e:
            import traceback;traceback.print_exc()
            print(('Error Parsing Binary (%s): %s' % (normname, e)))
Exemple #5
0
def loadPeIntoWorkspace(vw, pe, filename=None, baseaddr=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch is None:
        raise Exception("Machine %.4x is not supported for PE!" % mach)

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

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

    # Set ourselves up for extended windows binary analysis

    if baseaddr is None:
        baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase + codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname is not None:
        fvivname = dllname

    if fvivname is None:
        fvivname = "pe_%.8x" % baseaddr

    # grab the file bytes for hashing
    pe.fd.seek(0)
    bytez = pe.fd.read()
    fhash = v_parsers.md5Bytes(bytez)
    sha256 = v_parsers.sha256Bytes(bytez)

    # create the file and store md5 and sha256 hashes
    fname = vw.addFile(fvivname.lower(), baseaddr, fhash)
    vw.setFileMeta(fname, 'sha256', sha256)

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    try:
        vs = pe.getVS_VERSIONINFO()
    except Exception as e:
        vs = None
        vw.vprint('Failed to load version info resource due to %s' %
                  (repr(e), ))
    if vs is not None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver is not None and len(vsver):
            # add check to split seeing samples with spaces and nothing else..
            parts = vsver.split()
            if len(parts):
                vsver = vsver.split()[0]
                vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads",
                (("Address", VASET_ADDRESS), ("Library", VASET_STRING)))
    vw.addVaSet('pe:ordinals',
                (('Address', VASET_ADDRESS), ('Ordinal', VASET_INTEGER)))

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS)

    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))

    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(
        pe.IMAGE_NT_HEADERS.FileHeader
    ) + pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader

    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(
            pe.IMAGE_NT_HEADERS
        ) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)

    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment
    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    if secrem != 0:
        header += "\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != "PE":
        raise Exception("We only support PE exe's")

    if not vw.isLocation(baseaddr + magicaddr):
        padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = baseaddr + magicaddr + 4
    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")
    ohstruct = vw.makeStructure(ifhdr_va + len(ifstruct),
                                "pe.IMAGE_OPTIONAL_HEADER")
    nxcompat = ohstruct.DllCharacteristics & PE.IMAGE_DLLCHARACTERISTICS_NX_COMPAT

    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
    carvepes = vw.config.viv.parsers.pe.carvepes

    deaddirs = [
        PE.IMAGE_DIRECTORY_ENTRY_EXPORT, PE.IMAGE_DIRECTORY_ENTRY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_RESOURCE, PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION,
        PE.IMAGE_DIRECTORY_ENTRY_SECURITY, PE.IMAGE_DIRECTORY_ENTRY_BASERELOC,
        PE.IMAGE_DIRECTORY_ENTRY_DEBUG, PE.IMAGE_DIRECTORY_ENTRY_COPYRIGHT,
        PE.IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
        PE.IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
        PE.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
        PE.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, PE.IMAGE_DIRECTORY_ENTRY_IAT,
        PE.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
    ]
    deadvas = [ddir.VirtualAddress]
    for datadir in deaddirs:
        d = pe.getDataDirectory(datadir)
        if d.VirtualAddress:
            deadvas.append(d.VirtualAddress)

    for idx, sec in enumerate(pe.sections):
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = (sec.VirtualAddress == ddir.VirtualAddress)
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            # However, there is the DLLCHARACTERISTICS NXCOMPAT flag to take into account,
            # which works with the OS to prevent certain pages of memory from achieving
            # execution unless they're marked with the execute bit
            # so we can't just blindly mark these as executable quite yet.
            if not nxcompat:
                if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and not isrsrc:
                    mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC

        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize

        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if secrva >= codebase and secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva and entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if not nxcompat:
            if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and mapflags & e_mem.MM_READ:
                mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx + 1 >= len(pe.sections):
                continue
            # fill the gap with null bytes..
            nsec = pe.sections[idx + 1]
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))
            continue

        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize:
                continue

        plen = sec.VirtualSize - sec.SizeOfRawData

        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))

        except Exception as e:
            logger.warning(
                "Error Loading Section (%s size:%d rva:%.8x offset: %d): %s",
                secname, secfsize, secrva, secoff, e)

    vw.addExport(entry, EXP_FUNCTION, '__entry', fname)
    vw.addEntryPoint(entry)

    # store the actual reloc section virtual address
    reloc_va = pe.getDataDirectory(
        PE.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress
    if reloc_va:
        reloc_va += baseaddr
    vw.setFileMeta(fname, "reloc_va", reloc_va)

    for rva, rtype in pe.getRelocations():

        # map PE reloc to VIV reloc ( or dont... )
        vtype = relmap.get(rtype)
        if vtype is None:
            logger.info('Skipping PE Relocation type: %d at %d (no handler)',
                        rtype, rva)
            continue

        mapoffset = vw.readMemoryPtr(rva + baseaddr) - baseaddr
        vw.addRelocation(rva + baseaddr, vtype, mapoffset)

    for rva, lname, iname in pe.getImports():
        if vw.probeMemory(rva + baseaddr, 4, e_mem.MM_READ):
            vw.makeImport(rva + baseaddr, lname, iname)

    # Tell vivisect about ntdll functions that don't exit...
    vw.addNoReturnApi("ntdll.RtlExitUserThread")
    vw.addNoReturnApi("kernel32.ExitProcess")
    vw.addNoReturnApi("kernel32.ExitThread")
    vw.addNoReturnApi("kernel32.FatalExit")
    vw.addNoReturnApiRegex("^msvcr.*\._CxxThrowException$")
    vw.addNoReturnApiRegex("^msvcr.*\.abort$")
    vw.addNoReturnApiRegex("^msvcr.*\.exit$")
    vw.addNoReturnApiRegex("^msvcr.*\._exit$")
    vw.addNoReturnApiRegex("^msvcr.*\.quick_exit$")
    # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/invalid-parameter-functions?view=vs-2019
    # TODO: Again, there's a couple in there that have conditional termination that we should check for
    #vw.addNoReturnApiRegex("vcruntime140.__std_terminate")
    vw.addNoReturnApiRegex(
        "^api_ms_win_crt_runtime_.*\._invalid_parameter_noinfo_noreturn$")
    vw.addNoReturnApiRegex("^api_ms_win_crt_runtime_.*\.exit$")
    vw.addNoReturnApiRegex("^api_ms_win_crt_runtime_.*\._exit$")
    # TODO: we should add abort and terminate on the conditions that there are no signal handlers
    # registered
    # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/cexit-c-exit?view=vs-2019
    # vw.addNoReturnApiRegex("^msvcr.*\._cexit$")
    # vw.addNoReturnApiRegex("^msvcr.*\._c_exit$")
    vw.addNoReturnApi("ntoskrnl.KeBugCheckEx")

    exports = pe.getExports()
    for rva, ord, name in exports:
        eva = rva + baseaddr

        # Functions exported by ordinal only have no name
        if not name:
            name = "Ordinal_" + str(ord)

        try:
            vw.setVaSetRow('pe:ordinals', (eva, ord))
            vw.addExport(eva, EXP_UNTYPED, name, fname)
            if vw.probeMemory(eva, 1, e_mem.MM_EXEC):
                vw.addEntryPoint(eva)
        except Exception as e:
            vw.vprint('addExport Failed: %s.%s (0x%.8x): %s' %
                      (fname, name, eva, e))

    # Save off the ordinals...
    vw.setFileMeta(fname, 'ordinals', exports)

    fwds = pe.getForwarders()
    for rva, name, forwardname in fwds:
        vw.makeName(rva + baseaddr, "forwarder_%s.%s" % (fname, name))
        vw.makeString(rva + baseaddr)

    vw.setFileMeta(fname, 'forwarders', fwds)

    # Check For SafeSEH list...
    if pe.IMAGE_LOAD_CONFIG is not None:

        vw.setFileMeta(fname, "SafeSEH", True)

        va = pe.IMAGE_LOAD_CONFIG.SEHandlerTable
        if va != 0:
            vw.makeName(va, "%s.SEHandlerTable" % fname)
            count = pe.IMAGE_LOAD_CONFIG.SEHandlerCount
            # RP BUG FIX - sanity check the count
            if count * 4 < pe.filesize and vw.isValidPointer(va):
                # XXX - CHEAP HACK for some reason we have binaries still thorwing issues..

                try:
                    # Just cheat and use the workspace with memory maps in it already
                    for h in vw.readMemoryFormat(va, "<%dP" % count):
                        sehva = baseaddr + h
                        vw.addEntryPoint(sehva)
                        #vw.hintFunction(sehva, meta={'SafeSEH':True})
                except:
                    vw.vprint("SEHandlerTable parse error")

    # Last but not least, see if we have symbol support and use it if we do
    if vt_win32.dbghelp:

        s = vt_win32.Win32SymbolParser(-1, filename, baseaddr)

        # We don't want exports or whatever because we already have them
        s.symopts |= vt_win32.SYMOPT_EXACT_SYMBOLS
        s.parse()

        # Add names for any symbols which are missing them
        for symname, symva, size, flags in s.symbols:

            if not vw.isValidPointer(symva):
                continue

            try:

                if vw.getName(symva) is None:
                    vw.makeName(symva, symname, filelocal=True)

            except Exception as e:
                vw.vprint("Symbol Load Error: %s" % e)

        # Also, lets set the locals/args name hints if we found any
        vw.setFileMeta(fname, 'PELocalHints', s._sym_locals)

    # if it has an EXCEPTION directory parse if it has the pdata
    edir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION)
    if edir.VirtualAddress and arch == 'amd64':
        va = edir.VirtualAddress + baseaddr
        vamax = va + edir.Size
        while va < vamax:
            f = vw.makeStructure(va, 'pe.IMAGE_RUNTIME_FUNCTION_ENTRY')
            if not vw.isValidPointer(baseaddr + f.UnwindInfoAddress):
                break

            # FIXME UNWIND_INFO *requires* DWORD alignment, how is it enforced?
            fva = f.BeginAddress + baseaddr
            uiva = baseaddr + f.UnwindInfoAddress
            # Possible method 1...
            #uiva = baseaddr + (f.UnwindInfoAddress & 0xfffffffc )

            # Possible method 2...
            #uirem = f.UnwindInfoAddress % 4
            #if uirem:
            #uiva += ( 4 - uirem )
            uinfo = vw.getStructure(uiva, 'pe.UNWIND_INFO')
            ver = uinfo.VerFlags & 0x7
            if ver != 1:
                vw.vprint('Unwind Info Version: %d (bailing on .pdata)' % ver)
                break

            flags = uinfo.VerFlags >> 3
            # Check if it's a function *block* rather than a function *entry*
            if not (flags & PE.UNW_FLAG_CHAININFO):
                vw.addEntryPoint(fva)

            va += len(f)

    # auto-mark embedded PEs as "dead data" to prevent code flow...
    if carvepes:
        pe.fd.seek(0)
        fbytes = pe.fd.read()
        for offset, i in pe_carve.carve(fbytes, 1):
            # Found a sub-pe!
            subpe = pe_carve.CarvedPE(fbytes, offset, chr(i))
            pebytes = subpe.readAtOffset(0, subpe.getFileSize())
            rva = pe.offsetToRva(offset) + baseaddr
            vw.markDeadData(rva, rva + len(pebytes))

    return fname
Exemple #6
0
def loadPeIntoWorkspace(vw, pe, filename=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch == None:
        raise Exception("Machine %.4x is not supported for PE!" % mach)

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

    defcall = defcalls.get(arch)
    if defcall:
        vw.setMeta("DefaultCall", defcall)

    # Set ourselvs up for extended windows binary analysis

    baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase + codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname == None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    vs = pe.getVS_VERSIONINFO()
    if vs != None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver != None and len(vsver):
            vsver = vsver.split()[0]
            vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads",
                (("Address", VASET_ADDRESS), ("Library", VASET_STRING)))

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS)

    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))

    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(
        pe.IMAGE_NT_HEADERS.FileHeader
    ) + pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader

    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(
            pe.IMAGE_NT_HEADERS
        ) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)

    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment

    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    if secrem != 0:
        header += "\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != "PE":
        raise Exception("We only support PE exe's")

    if not vw.isLocation(baseaddr + magicaddr):
        padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = baseaddr + magicaddr + 4
    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")

    vw.makeStructure(ifhdr_va + len(ifstruct), "pe.IMAGE_OPTIONAL_HEADER")

    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
    carvepes = vw.config.viv.parsers.pe.carvepes

    deaddirs = [
        PE.IMAGE_DIRECTORY_ENTRY_EXPORT, PE.IMAGE_DIRECTORY_ENTRY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_RESOURCE, PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION,
        PE.IMAGE_DIRECTORY_ENTRY_SECURITY, PE.IMAGE_DIRECTORY_ENTRY_BASERELOC,
        PE.IMAGE_DIRECTORY_ENTRY_DEBUG, PE.IMAGE_DIRECTORY_ENTRY_COPYRIGHT,
        PE.IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
        PE.IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
        PE.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
        PE.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, PE.IMAGE_DIRECTORY_ENTRY_IAT,
        PE.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
    ]
    deadvas = [ddir.VirtualAddress]
    for datadir in deaddirs:
        d = pe.getDataDirectory(datadir)
        if d.VirtualAddress:
            deadvas.append(d.VirtualAddress)

    for idx, sec in enumerate(pe.sections):
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = (sec.VirtualAddress == ddir.VirtualAddress)
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and not isrsrc:
                mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC

        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize

        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if secrva >= codebase and secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva and entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and mapflags & e_mem.MM_READ:
            mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx + 1 >= len(pe.sections):
                continue
            # fill the gap with null bytes..
            nsec = pe.sections[idx + 1]
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))

            continue

        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize:
                continue

        plen = sec.VirtualSize - sec.SizeOfRawData

        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))

        except Exception, e:
            print "Error Loading Section (%s size:%d rva:%.8x offset: %d): %s" % (
                secname, secfsize, secrva, secoff, e)
Exemple #7
0
def loadPeIntoWorkspace(vw, pe, filename=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch == None:
        raise Exception("Machine %.4x is not supported for PE!" % mach )

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

    defcall = defcalls.get(arch)
    if defcall:
        vw.setMeta("DefaultCall", defcall)

    # Set ourselvs up for extended windows binary analysis

    baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase+codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname == None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    vs = pe.getVS_VERSIONINFO()
    if vs != None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver != None:
            vsver = vsver.split()[0]
            vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads", (("Address", VASET_ADDRESS),("Library", VASET_STRING)))

    # Tell vivisect about ntdll functions that don't exit...
    vw.addNoReturnApi("ntdll.RtlExitUserThread")
    vw.addNoReturnApi("kernel32.ExitProcess")
    vw.addNoReturnApi("kernel32.ExitThread")
    vw.addNoReturnApi("kernel32.FatalExit")
    vw.addNoReturnApi("msvcrt._CxxThrowException")
    vw.addNoReturnApi("msvcrt.abort")
    vw.addNoReturnApi("ntoskrnl.KeBugCheckEx")
    

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS) 
    
    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))
    
    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(pe.IMAGE_NT_HEADERS.FileHeader) +  pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader 
    
    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)


    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment

    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    if secrem != 0:
        header += "\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != "PE":
        raise Exception("We only support PE exe's")

    padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = padloc[L_VA] + padloc[L_SIZE]

    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")

    vw.makeStructure(ifhdr_va + len(ifstruct), "pe.IMAGE_OPTIONAL_HEADER")


    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
            
    for idx, sec in enumerate(pe.sections):
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = ( sec.VirtualAddress == ddir.VirtualAddress )
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            if subsys_majver < 6 and not isrsrc:
                mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC

        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize

        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if secrva >= codebase and secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva and entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if subsys_majver < 6 and mapflags & e_mem.MM_READ:
            mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx+1 > len(pe.sections):
                continue
            # fill the gap with null bytes.. 
            nsec = pe.sections[idx+1] 
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase 
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            continue
        
        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize: 
                continue
    
        plen = sec.VirtualSize - sec.SizeOfRawData          
    
        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)
        except Exception, e:
            print "Error Loading Section (%s size:%d rva:%.8x offset: %d): %s" % (secname,secfsize,secrva,secoff,e)
Exemple #8
0
def loadPeIntoWorkspace(vw, pe, filename=None, baseaddr=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch is None:
        raise Exception("Machine %.4x is not supported for PE!" % mach)

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

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

    # Set ourselves up for extended windows binary analysis

    if baseaddr is None:
        baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase + codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname is None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    try:
        vs = pe.getVS_VERSIONINFO()
    except Exception as e:
        vs = None
        vw.vprint('Failed to load version info resource due to %s' %
                  (repr(e), ))
    if vs is not None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver is not None and len(vsver):
            # add check to split seeing samples with spaces and nothing else..
            parts = vsver.split()
            if len(parts):
                vsver = vsver.split()[0]
                vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads",
                (("Address", VASET_ADDRESS), ("Library", VASET_STRING)))
    vw.addVaSet('pe:ordinals',
                (('Address', VASET_ADDRESS), ('Ordinal', VASET_INTEGER)))

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS)

    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))

    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(
        pe.IMAGE_NT_HEADERS.FileHeader
    ) + pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader

    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(
            pe.IMAGE_NT_HEADERS
        ) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)

    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment
    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    # Lines below will extend the header to one page.  In reality, some
    # samples put code after the header but in the same page, so it is better
    # to stick with header_size.  See FLARE-662.
    #if secrem != 0:
    #    header += "\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != "PE":
        raise Exception("We only support PE exe's")

    if not vw.isLocation(baseaddr + magicaddr):
        padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = baseaddr + magicaddr + 4
    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")

    vw.makeStructure(ifhdr_va + len(ifstruct), "pe.IMAGE_OPTIONAL_HEADER")

    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
    carvepes = vw.config.viv.parsers.pe.carvepes

    deaddirs = [
        PE.IMAGE_DIRECTORY_ENTRY_EXPORT, PE.IMAGE_DIRECTORY_ENTRY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_RESOURCE, PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION,
        PE.IMAGE_DIRECTORY_ENTRY_SECURITY, PE.IMAGE_DIRECTORY_ENTRY_BASERELOC,
        PE.IMAGE_DIRECTORY_ENTRY_DEBUG, PE.IMAGE_DIRECTORY_ENTRY_COPYRIGHT,
        PE.IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
        PE.IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
        PE.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
        PE.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, PE.IMAGE_DIRECTORY_ENTRY_IAT,
        PE.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
        PE.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
    ]
    deadvas = [ddir.VirtualAddress]
    for datadir in deaddirs:
        d = pe.getDataDirectory(datadir)
        if d.VirtualAddress:
            deadvas.append(d.VirtualAddress)

    for idx, sec in enumerate(pe.sections):
        logger.debug('loading section number %d', idx)
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = (sec.VirtualAddress == ddir.VirtualAddress)
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and not isrsrc:
                mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC

        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize

        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if secrva >= codebase and secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva and entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and mapflags & e_mem.MM_READ:
            mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx + 1 >= len(pe.sections):
                continue
            # fill the gap with null bytes..
            nsec = pe.sections[idx + 1]
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))
            continue

        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize:
                continue

        plen = sec.VirtualSize - sec.SizeOfRawData

        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            if secname and (secname == '.data'):
                # Allow truncated .data segment.
                secbytes = pe.readAtOffset(secoff, readsize, shortok=True)
            else:
                secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            logger.debug('mapping section: %d %s', idx, secname)
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (
                    chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))

        except Exception as e:
            logging.getLogger("parsers.pe.loadPE").warning(
                "Error Loading Section (%s size:%d rva:%.8x offset: %d): %s",
                secname, secfsize, secrva, secoff, e)

    vw.addExport(entry, EXP_FUNCTION, '__entry', fname)
    vw.addEntryPoint(entry)

    # store the actual reloc section virtual address
    reloc_va = pe.getDataDirectory(
        PE.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress
    if reloc_va:
        reloc_va += baseaddr
    vw.setFileMeta(fname, "reloc_va", reloc_va)

    for rva, rtype in pe.getRelocations():

        # map PE reloc to VIV reloc ( or dont... )
        vtype = relmap.get(rtype)
        if vtype is None:
            logger.info('Skipping PE Relocation type: %d at %d (no handler)',
                        rtype, rva)
            continue

        mapoffset = vw.readMemoryPtr(rva + baseaddr) - baseaddr
        vw.addRelocation(rva + baseaddr, vtype, mapoffset)

    for rva, lname, iname in pe.getImports():
        if vw.probeMemory(rva + baseaddr, 4, e_mem.MM_READ):
            vw.makeImport(rva + baseaddr, lname, iname)

    # Tell vivisect about ntdll functions that don't exit...
    vw.addNoReturnApi("ntdll.RtlExitUserThread")
    vw.addNoReturnApi("kernel32.ExitProcess")
    vw.addNoReturnApi("kernel32.ExitThread")
    vw.addNoReturnApi("kernel32.FatalExit")
    vw.addNoReturnApiRegex("^msvcr.*\._CxxThrowException$")
    vw.addNoReturnApiRegex("^msvcr.*\.abort$")
    vw.addNoReturnApiRegex("^msvcr.*\.exit$")
    vw.addNoReturnApiRegex("^msvcr.*\._exit$")
    vw.addNoReturnApiRegex("^msvcr.*\._exit$")
    vw.addNoReturnApiRegex("^msvcr.*\.quick_exit$")
    # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/cexit-c-exit?view=vs-2019
    # vw.addNoReturnApiRegex("^msvcr.*\._cexit$")
    # vw.addNoReturnApiRegex("^msvcr.*\._c_exit$")
    vw.addNoReturnApi("ntoskrnl.KeBugCheckEx")

    exports = pe.getExports()
    for rva, ord, name in exports:
        eva = rva + baseaddr

        # Functions exported by ordinal only have no name
        if not name:
            name = "Ordinal_" + str(ord)

        try:
            vw.setVaSetRow('pe:ordinals', (eva, ord))
            vw.addExport(eva, EXP_UNTYPED, name, fname)
            if vw.probeMemory(eva, 1, e_mem.MM_EXEC):
                vw.addEntryPoint(eva)
        except Exception as e:
            vw.vprint('addExport Failed: %s.%s (0x%.8x): %s' %
                      (fname, name, eva, e))

    # Save off the ordinals...
    vw.setFileMeta(fname, 'ordinals', exports)

    fwds = pe.getForwarders()
    for rva, name, forwardname in fwds:
        vw.makeName(rva + baseaddr, "forwarder_%s.%s" % (fname, name))
        vw.makeString(rva + baseaddr)

    vw.setFileMeta(fname, 'forwarders', fwds)

    # Check For SafeSEH list...
    if pe.IMAGE_LOAD_CONFIG != None:

        vw.setFileMeta(fname, "SafeSEH", True)

        va = pe.IMAGE_LOAD_CONFIG.SEHandlerTable
        if va != 0:
            vw.makeName(va, "%s.SEHandlerTable" % fname)
            count = pe.IMAGE_LOAD_CONFIG.SEHandlerCount
            # RP BUG FIX - sanity check the count
            if count * 4 < pe.filesize and vw.isValidPointer(va):
                # XXX - CHEAP HACK for some reason we have binaries still thorwing issues..

                try:
                    # Just cheat and use the workspace with memory maps in it already
                    for h in vw.readMemoryFormat(va, "<%dP" % count):
                        sehva = baseaddr + h
                        vw.addEntryPoint(sehva)
                        #vw.hintFunction(sehva, meta={'SafeSEH':True})
                except:
                    vw.vprint("SEHandlerTable parse error")

    # Last but not least, see if we have symbol support and use it if we do
    if vt_win32.dbghelp:

        s = vt_win32.Win32SymbolParser(-1, filename, baseaddr)

        # We don't want exports or whatever because we already have them
        s.symopts |= vt_win32.SYMOPT_EXACT_SYMBOLS
        s.parse()

        # Add names for any symbols which are missing them
        for symname, symva, size, flags in s.symbols:

            if not vw.isValidPointer(symva):
                continue

            try:

                if vw.getName(symva) is None:
                    vw.makeName(symva, symname, filelocal=True)

            except Exception, e:
                vw.vprint("Symbol Load Error: %s" % e)

        # Also, lets set the locals/args name hints if we found any
        vw.setFileMeta(fname, 'PELocalHints', s._sym_locals)
Exemple #9
0
def loadPeIntoWorkspace(vw, pe, filename=None):
    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch is None:
        raise Exception("Machine %.4x is not supported for PE!" % mach)

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

    defcall = defcalls.get(arch)
    if defcall:
        vw.setMeta("DefaultCall", defcall)

    # Set ourselvs up for extended windows binary analysis

    baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase + codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname == None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    vs = pe.getVS_VERSIONINFO()
    if vs != None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver != None and len(vsver):
            # add check to split seeing samples with spaces and nothing else..
            parts = vsver.split()
            if len(parts):
                vsver = vsver.split()[0]
                vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads", (("Address", VASET_ADDRESS), ("Library", VASET_STRING)))
    vw.addVaSet('pe:ordinals', (('Address', VASET_ADDRESS), ('Ordinal', VASET_INTEGER)))

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS)

    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))

    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(
        pe.IMAGE_NT_HEADERS.FileHeader) + pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader

    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(
            pe.IMAGE_NT_HEADERS) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)

    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment

    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    if secrem != 0:
        header += b"\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != b"PE":
        raise Exception("We only support PE exe's")

    if not vw.isLocation(baseaddr + magicaddr):
        padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = baseaddr + magicaddr + 4
    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")

    vw.makeStructure(ifhdr_va + len(ifstruct), "pe.IMAGE_OPTIONAL_HEADER")

    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
    carvepes = vw.config.viv.parsers.pe.carvepes

    deaddirs = [PE.IMAGE_DIRECTORY_ENTRY_EXPORT,
                PE.IMAGE_DIRECTORY_ENTRY_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_RESOURCE,
                PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION,
                PE.IMAGE_DIRECTORY_ENTRY_SECURITY,
                PE.IMAGE_DIRECTORY_ENTRY_BASERELOC,
                PE.IMAGE_DIRECTORY_ENTRY_DEBUG,
                PE.IMAGE_DIRECTORY_ENTRY_COPYRIGHT,
                PE.IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
                PE.IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
                PE.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
                PE.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_IAT,
                PE.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
    deadvas = [ddir.VirtualAddress]
    for datadir in deaddirs:
        d = pe.getDataDirectory(datadir)
        if d.VirtualAddress:
            deadvas.append(d.VirtualAddress)

    for idx, sec in enumerate(pe.sections):
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = (sec.VirtualAddress == ddir.VirtualAddress)
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and not isrsrc:
                mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC

        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize

        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if codebase <= secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and mapflags & e_mem.MM_READ:
            mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx + 1 >= len(pe.sections):
                continue
            # fill the gap with null bytes.. 
            nsec = pe.sections[idx + 1]
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += b"\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            # FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))
            continue

        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize:
                continue

        plen = sec.VirtualSize - sec.SizeOfRawData

        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is
            # larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += b"\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase + len(secbytes))

            # FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (
                        chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase + len(secbytes))

        except Exception as e:
            print(("Error Loading Section (%s size:%d rva:%.8x offset: %d): %s" % (secname, secfsize, secrva, secoff, e)))
            raise e

    vw.addExport(entry, EXP_FUNCTION, '__entry', fname)
    vw.addEntryPoint(entry)

    # store the actual reloc section virtual address
    reloc_va = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress
    if reloc_va:
        reloc_va += baseaddr
    vw.setFileMeta(fname, "reloc_va", reloc_va)

    for rva, rtype in pe.getRelocations():

        # map PE reloc to VIV reloc ( or dont... )
        vtype = relmap.get(rtype)
        if vtype == None:
            continue

        vw.addRelocation(rva + baseaddr, vtype)

    for rva, lname, iname in pe.getImports():
        if vw.probeMemory(rva + baseaddr, 4, e_mem.MM_READ):
            vw.makeImport(rva + baseaddr, lname, iname)

    # Tell vivisect about ntdll functions that don't exit...
    vw.addNoReturnApi("ntdll.RtlExitUserThread")
    vw.addNoReturnApi("kernel32.ExitProcess")
    vw.addNoReturnApi("kernel32.ExitThread")
    vw.addNoReturnApi("kernel32.FatalExit")
    vw.addNoReturnApiRegex("^msvcr.*\._CxxThrowException$")
    vw.addNoReturnApiRegex("^msvcr.*\.abort$")
    vw.addNoReturnApi("ntoskrnl.KeBugCheckEx")

    exports = pe.getExports()
    for rva, ord, name in exports:
        eva = rva + baseaddr
        try:
            vw.setVaSetRow('pe:ordinals', (eva, ord))
            vw.addExport(eva, EXP_UNTYPED, name, fname)
            if vw.probeMemory(eva, 1, e_mem.MM_EXEC):
                vw.addEntryPoint(eva)
        except Exception as e:
            vw.vprint('addExport Failed: %s.%s (0x%.8x): %s' % (fname, name, eva, e))

    # Save off the ordinals...
    vw.setFileMeta(fname, 'ordinals', exports)

    fwds = pe.getForwarders()
    for rva, name, forwardname in fwds:
        vw.makeName(rva + baseaddr, "forwarder_%s.%s" % (fname, name))
        vw.makeString(rva + baseaddr)

    vw.setFileMeta(fname, 'forwarders', fwds)

    # Check For SafeSEH list...
    if pe.IMAGE_LOAD_CONFIG != None:

        vw.setFileMeta(fname, "SafeSEH", True)

        va = pe.IMAGE_LOAD_CONFIG.SEHandlerTable
        if va != 0:
            vw.makeName(va, "%s.SEHandlerTable" % fname)
            count = pe.IMAGE_LOAD_CONFIG.SEHandlerCount
            # RP BUG FIX - sanity check the count
            if count * 4 < pe.filesize and vw.isValidPointer(va):
                # XXX - CHEAP HACK for some reason we have binaries still thorwing issues.. 

                try:
                    # Just cheat and use the workspace with memory maps in it already
                    for h in vw.readMemoryFormat(va, "<%dP" % count):
                        sehva = baseaddr + h
                        vw.addEntryPoint(sehva)
                        # vw.hintFunction(sehva, meta={'SafeSEH':True})
                except:
                    vw.vprint("SEHandlerTable parse error")

    # Last but not least, see if we have symbol support and use it if we do
    if vt_win32.dbghelp:

        s = vt_win32.Win32SymbolParser(-1, filename, baseaddr)

        # We don't want exports or whatever because we already have them
        s.symopts |= vt_win32.SYMOPT_EXACT_SYMBOLS
        s.parse()

        # Add names for any symbols which are missing them
        for symname, symva, size, flags in s.symbols:

            if not vw.isValidPointer(symva):
                continue

            try:

                if vw.getName(symva) == None:
                    vw.makeName(symva, symname, filelocal=True)

            except Exception as e:
                vw.vprint("Symbol Load Error: %s" % e)

        # Also, lets set the locals/args name hints if we found any
        vw.setFileMeta(fname, 'PELocalHints', s._sym_locals)

    # if it has an EXCEPTION directory parse if it has the pdata
    edir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION)
    if edir.VirtualAddress and arch == 'amd64':
        va = edir.VirtualAddress + baseaddr
        vamax = va + edir.Size
        while va < vamax:
            f = vw.makeStructure(va, 'pe.IMAGE_RUNTIME_FUNCTION_ENTRY')
            if not vw.isValidPointer(baseaddr + f.UnwindInfoAddress):
                break

            # FIXME UNWIND_INFO *requires* DWORD alignment, how is it enforced?
            fva = f.BeginAddress + baseaddr
            uiva = baseaddr + f.UnwindInfoAddress
            # Possible method 1...
            # uiva = baseaddr + (f.UnwindInfoAddress & 0xfffffffc )

            # Possible method 2...
            #uirem = f.UnwindInfoAddress % 4
            #if uirem:
                #uiva += ( 4 - uirem )
            uinfo = vw.getStructure(uiva, 'pe.UNWIND_INFO')
            ver = uinfo.VerFlags & 0x7
            if ver != 1:
                vw.vprint('Unwind Info Version: %d (bailing on .pdata)' % ver)
                break

            flags = uinfo.VerFlags >> 3
            # Check if it's a function *block* rather than a function *entry*
            if not (flags & PE.UNW_FLAG_CHAININFO):
                vw.addEntryPoint(fva)

            va += len(f)

    # auto-mark embedded PEs as "dead data" to prevent code flow...
    if carvepes:
        pe.fd.seek(0)
        fbytes = pe.fd.read()
        for offset, i in pe_carve.carve(fbytes, 1):
            # Found a sub-pe!
            subpe = pe_carve.CarvedPE(fbytes, offset, chr(i))
            pebytes = subpe.readAtOffset(0, subpe.getFileSize())
            rva = pe.offsetToRva(offset)
            vw.markDeadData(rva, rva + len(pebytes))

    return fname
Exemple #10
0
def loadPeIntoWorkspace(vw, pe, filename=None):

    mach = pe.IMAGE_NT_HEADERS.FileHeader.Machine

    arch = arch_names.get(mach)
    if arch == None:
        raise Exception("Machine %.4x is not supported for PE!" % mach )

    vw.setMeta('Architecture', arch)
    vw.setMeta('Format', 'pe')

    platform = 'windows'

    # Drivers are platform "winkern" so impapi etc works
    subsys = pe.IMAGE_NT_HEADERS.OptionalHeader.Subsystem
    if subsys == PE.IMAGE_SUBSYSTEM_NATIVE:
        platform = 'winkern'

    vw.setMeta('Platform', platform)

    defcall = defcalls.get(arch)
    if defcall:
        vw.setMeta("DefaultCall", defcall)

    # Set ourselvs up for extended windows binary analysis

    baseaddr = pe.IMAGE_NT_HEADERS.OptionalHeader.ImageBase
    entry = pe.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint + baseaddr
    entryrva = entry - baseaddr

    codebase = pe.IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode
    codesize = pe.IMAGE_NT_HEADERS.OptionalHeader.SizeOfCode
    codervamax = codebase+codesize

    fvivname = filename

    # This will help linkers with files that are re-named
    dllname = pe.getDllName()
    if dllname != None:
        fvivname = dllname

    if fvivname == None:
        fvivname = "pe_%.8x" % baseaddr

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

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

    symhash = e_symcache.symCacheHashFromPe(pe)
    vw.setFileMeta(fname, 'SymbolCacheHash', symhash)

    # Add file version info if VS_VERSIONINFO has it
    vs = pe.getVS_VERSIONINFO()
    if vs != None:
        vsver = vs.getVersionValue('FileVersion')
        if vsver != None and len(vsver):
            # add check to split seeing samples with spaces and nothing else..
            parts = vsver.split()
            if len(parts):
                vsver = vsver.split()[0]
                vw.setFileMeta(fname, 'Version', vsver)

    # Setup some va sets used by windows analysis modules
    vw.addVaSet("Library Loads", (("Address", VASET_ADDRESS),("Library", VASET_STRING)))
    vw.addVaSet('pe:ordinals', (('Address', VASET_ADDRESS),('Ordinal',VASET_INTEGER)))

    # SizeOfHeaders spoofable...
    curr_offset = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS) 
    
    secsize = len(vstruct.getStructure("pe.IMAGE_SECTION_HEADER"))
    
    sec_offset = pe.IMAGE_DOS_HEADER.e_lfanew + 4 + len(pe.IMAGE_NT_HEADERS.FileHeader) +  pe.IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader 
    
    if sec_offset != curr_offset:
        header_size = sec_offset + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize
    else:
        header_size = pe.IMAGE_DOS_HEADER.e_lfanew + len(pe.IMAGE_NT_HEADERS) + pe.IMAGE_NT_HEADERS.FileHeader.NumberOfSections * secsize

    # Add the first page mapped in from the PE header.
    header = pe.readAtOffset(0, header_size)


    secalign = pe.IMAGE_NT_HEADERS.OptionalHeader.SectionAlignment

    subsys_majver = pe.IMAGE_NT_HEADERS.OptionalHeader.MajorSubsystemVersion
    subsys_minver = pe.IMAGE_NT_HEADERS.OptionalHeader.MinorSubsystemVersion

    secrem = len(header) % secalign
    if secrem != 0:
        header += "\x00" * (secalign - secrem)

    vw.addMemoryMap(baseaddr, e_mem.MM_READ, fname, header)
    vw.addSegment(baseaddr, len(header), "PE_Header", fname)

    hstruct = vw.makeStructure(baseaddr, "pe.IMAGE_DOS_HEADER")
    magicaddr = hstruct.e_lfanew
    if vw.readMemory(baseaddr + magicaddr, 2) != "PE":
        raise Exception("We only support PE exe's")

    if not vw.isLocation( baseaddr + magicaddr ):
        padloc = vw.makePad(baseaddr + magicaddr, 4)

    ifhdr_va = baseaddr + magicaddr + 4
    ifstruct = vw.makeStructure(ifhdr_va, "pe.IMAGE_FILE_HEADER")

    vw.makeStructure(ifhdr_va + len(ifstruct), "pe.IMAGE_OPTIONAL_HEADER")

    # get resource data directory
    ddir = pe.getDataDirectory(PE.IMAGE_DIRECTORY_ENTRY_RESOURCE)
    loadrsrc = vw.config.viv.parsers.pe.loadresources
    carvepes = vw.config.viv.parsers.pe.carvepes

    deaddirs = [PE.IMAGE_DIRECTORY_ENTRY_EXPORT,
                PE.IMAGE_DIRECTORY_ENTRY_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_RESOURCE,
                PE.IMAGE_DIRECTORY_ENTRY_EXCEPTION,
                PE.IMAGE_DIRECTORY_ENTRY_SECURITY,
                PE.IMAGE_DIRECTORY_ENTRY_BASERELOC,
                PE.IMAGE_DIRECTORY_ENTRY_DEBUG,
                PE.IMAGE_DIRECTORY_ENTRY_COPYRIGHT,
                PE.IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
                PE.IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
                PE.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
                PE.IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_IAT,
                PE.IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
                PE.IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
    deadvas = [ddir.VirtualAddress]
    for datadir in deaddirs:
        d = pe.getDataDirectory(datadir)
        if d.VirtualAddress:
            deadvas.append(d.VirtualAddress)

    for idx, sec in enumerate(pe.sections):
        mapflags = 0

        chars = sec.Characteristics
        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ

            isrsrc = ( sec.VirtualAddress == ddir.VirtualAddress )
            if isrsrc and not loadrsrc:
                continue

            # If it's for an older system, just about anything
            # is executable...
            if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and not isrsrc:
                mapflags |= e_mem.MM_EXEC

        if chars & PE.IMAGE_SCN_MEM_READ:
            mapflags |= e_mem.MM_READ
        if chars & PE.IMAGE_SCN_MEM_WRITE:
            mapflags |= e_mem.MM_WRITE
        if chars & PE.IMAGE_SCN_MEM_EXECUTE:
            mapflags |= e_mem.MM_EXEC
        if chars & PE.IMAGE_SCN_CNT_CODE:
            mapflags |= e_mem.MM_EXEC


        secrva = sec.VirtualAddress
        secvsize = sec.VirtualSize
        secfsize = sec.SizeOfRawData
        secbase = secrva + baseaddr
        secname = sec.Name.strip("\x00")
        secrvamax = secrva + secvsize
    
        # If the section is part of BaseOfCode->SizeOfCode
        # force execute perms...
        if secrva >= codebase and secrva < codervamax:
            mapflags |= e_mem.MM_EXEC

        # If the entry point is in this section, force execute
        # permissions.
        if secrva <= entryrva and entryrva < secrvamax:
            mapflags |= e_mem.MM_EXEC

        if not vw.config.viv.parsers.pe.nx and subsys_majver < 6 and mapflags & e_mem.MM_READ:
            mapflags |= e_mem.MM_EXEC

        if sec.VirtualSize == 0 or sec.SizeOfRawData == 0:
            if idx+1 >= len(pe.sections):
                continue
            # fill the gap with null bytes.. 
            nsec = pe.sections[idx+1] 
            nbase = nsec.VirtualAddress + baseaddr

            plen = nbase - secbase 
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize
            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase+len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase+len(secbytes))
            continue
        
        # if SizeOfRawData is greater than VirtualSize we'll end up using VS in our read..
        if sec.SizeOfRawData < sec.VirtualSize:
            if sec.SizeOfRawData > pe.filesize: 
                continue
    
        plen = sec.VirtualSize - sec.SizeOfRawData          
    
        try:
            # According to http://code.google.com/p/corkami/wiki/PE#section_table if SizeOfRawData is larger than VirtualSize, VS is used..
            readsize = sec.SizeOfRawData if sec.SizeOfRawData < sec.VirtualSize else sec.VirtualSize

            secoff = pe.rvaToOffset(secrva)
            secbytes = pe.readAtOffset(secoff, readsize)
            secbytes += "\x00" * plen
            vw.addMemoryMap(secbase, mapflags, fname, secbytes)
            vw.addSegment(secbase, len(secbytes), secname, fname)

            # Mark dead data on resource and import data directories
            if sec.VirtualAddress in deadvas:
                vw.markDeadData(secbase, secbase+len(secbytes))

            #FIXME create a mask for this
            if not (chars & PE.IMAGE_SCN_CNT_CODE) and not (chars & PE.IMAGE_SCN_MEM_EXECUTE) and not (chars & PE.IMAGE_SCN_MEM_WRITE):
                vw.markDeadData(secbase, secbase+len(secbytes))

        except Exception, e:
            logging.getLogger("parsers.pe.loadPE").warning("Error Loading Section (%s size:%d rva:%.8x offset: %d): %s", secname, secfsize, secrva, secoff, e)