Example #1
0
    def parse_content(self,
                      parse_resources=True,
                      parse_delay=True,
                      parse_reloc=True):
        h = struct.unpack("BB", self.content[:2])
        if h != (0x4d, 0x5a):  # magic number, MZ
            raise ValueError("Not a PE, no MZ magic number")
        of = 0
        self.sex = '<'
        self.wsize = 32
        self.DOShdr = pe.DOShdr(parent=self, content=self.content, start=of)
        of = self.DOShdr.lfanew
        if of > len(self.content):
            raise ValueError('Not a PE, NTsig offset after eof %#x', of)
        self.NTsig = pe.NTsig(parent=self, content=self.content, start=of)
        if self.NTsig.signature != 0x4550:  # PE\0\0
            raise ValueError('Not a PE, NTsig is %#x', self.NTsig.signature)

        of += self.NTsig.bytelen
        self.COFFhdr = pe.COFFhdr(parent=self, content=self.content, start=of)
        of += self.COFFhdr.bytelen
        magic, = struct.unpack('H', self.content[of:of + 2])
        self.wsize = (magic >> 8) * 32
        if not magic in (0x10b, 0x20b):
            # e.g. Ange Albertini's d_nonnull.dll d_tiny.dll
            log.warning('Opthdr magic %#x', magic)
            self.wsize = 32
        self.Opthdr = {
            32: pe.Opthdr32,
            64: pe.Opthdr64
        }[self.wsize](parent=self, content=self.content, start=of)
        l = self.Opthdr.bytelen
        self.NThdr = pe.NThdr(parent=self, content=self.content, start=of + l)
        of += self.COFFhdr.sizeofoptionalheader
        if self.NThdr.numberofrvaandsizes < 13:
            log.warning('Windows 8 needs at least 13 directories, %d found',
                        self.NThdr.numberofrvaandsizes)
        # Even if the NT header has 64-bit pointers, in 64-bit PE files
        # the Section headers have 32-bit pointers (it is a 32-bit COFF
        # in a 64-bit PE).
        self.SHList = pe.SHList(parent=self,
                                content=self.content,
                                start=of,
                                wsize=32)

        # Directory parsing.
        # 'start' is None, because the offset is computed from the RVA
        # in the NT header
        kargs = {'parent': self, 'content': self.content, 'start': None}
        self.DirImport = pe.DirImport(**kargs)
        self.DirExport = pe.DirExport(**kargs)
        if parse_delay: self.DirDelay = pe.DirDelay(**kargs)
        if parse_reloc: self.DirReloc = pe.DirReloc(**kargs)
        if parse_resources: self.DirRes = pe.DirRes(**kargs)

        if self.COFFhdr.pointertosymboltable != 0:
            if self.COFFhdr.pointertosymboltable + 18 * self.COFFhdr.numberofsymbols > len(
                    self.content):
                log.warning('Too many symbols: %d',
                            self.COFFhdr.numberofsymbols)
            self.Symbols = pe.CoffSymbols(**kargs)
        if hasattr(self, 'Symbols'):
            of = self.COFFhdr.pointertosymboltable + self.Symbols.bytelen
            sz, = struct.unpack(self.sex + 'I', self.content[of:of + 4])
            if len(self.content) < of + sz:
                log.warning('File too short for StrTable %#x != %#x' %
                            (len(self.content) - of, sz))
                sz = len(self.content) - of
            self.SymbolStrings = StrTable(self.content[of:of + sz])
Example #2
0
    def parse_content(self,
                      parse_resources=True,
                      parse_delay=True,
                      parse_reloc=True):
        # Note that there is no "magic number" to recognize COFF files.
        # Therefore, the usual way to know if a file is COFF is to parse
        # its content with this method. If it is not a COFF, then an
        # exception is raised, of type ValueError
        of = 0
        # Detect specific cases of COFF Header format, without knowing
        # the endianess
        COFFmachineLE, = struct.unpack("<H", self.content[0:2])
        COFFmachineBE, = struct.unpack(">H", self.content[0:2])
        if pe.IMAGE_FILE_MACHINE_ALPHA_O in (COFFmachineLE, COFFmachineBE):
            self.wsize = 64
            COFFhdr = pe.COFFhdr
            sizeofoptionalheader = self.content[18:20]
        elif pe.IMAGE_FILE_MACHINE_XCOFF64 in (COFFmachineLE, COFFmachineBE):
            self.wsize = 64
            COFFhdr = pe.XCOFFhdr64
            sizeofoptionalheader = self.content[16:18]
        else:
            self.wsize = 32
            COFFhdr = pe.COFFhdr
            sizeofoptionalheader = self.content[16:18]
        # COFF endianess is tricky to determine, we use the fact
        # that sizeofoptionalheader should be less than 256
        sizeofoptionalheader = struct.unpack("BB", sizeofoptionalheader)
        if not 0 in sizeofoptionalheader:
            raise ValueError("Not COFF: OptHdr size too big")
        if sizeofoptionalheader[1] == 0: self.sex = '<'
        else: self.sex = '>'
        self.COFFhdr = COFFhdr(parent=self, content=self.content, start=of)
        of += self.COFFhdr.bytelen
        if self.COFFhdr.machine == pe.IMAGE_FILE_MACHINE_TI:
            m = struct.unpack('H', self.content[of:of + 2])[0]
            self.CPU = {
                # COFF for Texas Instruments
                # Cf. http://www.ti.com/lit/an/spraao8/spraao8.pdf
                # and https://gist.github.com/eliotb/1073231
                0x97: 'TMS470',
                0x98: 'TMS320C5400',
                0x99: 'TMS320C6000',
                0x9C: 'TMS320C5500',
                0x9D: 'TMS320C2800',
                0xA0: 'MSP430',
                0xA1: 'TMS320C5500+',
            }.get(m, 'unknown')
            of += 2
        kargs = {'parent': self, 'content': self.content, 'start': of}
        if self.COFFhdr.sizeofoptionalheader == 28:
            self.Opthdr = pe.Opthdr32(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 36:
            assert self.COFFhdr.machine == pe.IMAGE_FILE_MACHINE_CLIPPER
            self.Opthdr = pe.OpthdrClipper(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 44:
            assert self.COFFhdr.machine == pe.IMAGE_FILE_MACHINE_APOLLOM68K
            self.Opthdr = pe.OpthdrApollo(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 56:
            assert self.COFFhdr.machine in (pe.IMAGE_FILE_MACHINE_MIPSIII,
                                            pe.IMAGE_FILE_MACHINE_MIPSEB,
                                            pe.IMAGE_FILE_MACHINE_R3000,
                                            pe.IMAGE_FILE_MACHINE_R4000,
                                            pe.IMAGE_FILE_MACHINE_R10000)
            self.Opthdr = pe.OpthdrECOFF32(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 80:
            assert self.COFFhdr.machine == pe.IMAGE_FILE_MACHINE_ALPHA_O
            self.Opthdr = pe.OpthdrECOFF64(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 72:
            self.Opthdr = pe.OpthdrXCOFF32(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 110:
            self.Opthdr = pe.OpthdrXCOFF64(**kargs)
        elif self.COFFhdr.sizeofoptionalheader == 0:
            from elfesteem.pe import CStruct

            class NullHdr(CStruct):
                _fields = []

            self.Opthdr = NullHdr(**kargs)
        elif (self.COFFhdr.sizeofoptionalheader % 4) == 0:
            # All known OptHdr start with a 2-byte magic and 2-byte vstamp
            from elfesteem.pe import CStruct

            class OpthdrUnknown(CStruct):
                _fields = [ ("magic", "u16"), ("vstamp", "u16") ] \
                        + [ ("f%d"%_, "u32")
                    for _ in range(1, self.COFFhdr.sizeofoptionalheader // 4) ]

            self.Opthdr = OpthdrUnknown(**kargs)
        else:
            # Size of COFF optional header should probably be a multiple of 4
            raise ValueError("COFF SZOPT %d" %
                             self.COFFhdr.sizeofoptionalheader)

        of += self.COFFhdr.sizeofoptionalheader
        filesz = len(self.content)
        if self.COFFhdr.numberofsections == 0:
            raise ValueError("COFF cannot have no sections")
        if self.COFFhdr.numberofsections > 0x1000:
            raise ValueError("COFF too many sections %d" %
                             self.COFFhdr.numberofsections)
        if of + self.COFFhdr.numberofsections * 40 > filesz:
            raise ValueError("COFF too many sections %d, past end of file" %
                             self.COFFhdr.numberofsections)
        if self.COFFhdr.pointertosymboltable > filesz:
            raise ValueError("COFF invalid ptr to symbol table")
        self.SHList = pe.SHList(parent=self, content=self.content, start=of)

        of = self.COFFhdr.pointertosymboltable
        if self.COFFhdr.machine == pe.IMAGE_FILE_MACHINE_ALPHA_O \
                and of != 0 \
                and struct.unpack('<H',self.content[of:of+2])[0] == 0x1992:
            self.OSF1Symbols = pe.CoffOSF1Symbols(
                parent=self,
                content=self.content,
                start=self.COFFhdr.pointertosymboltable,
            )
        elif of != 0 and self.COFFhdr.numberofsymbols != 0:
            self.Symbols = pe.CoffSymbols(
                parent=self,
                content=self.content,
                start=None,
            )
        if hasattr(self, 'Symbols'):
            of = self.COFFhdr.pointertosymboltable + self.Symbols.bytelen
            sz, = struct.unpack(self.sex + 'I', self.content[of:of + 4])
            if len(self.content) < of + sz:
                log.warning('File too short for StrTable %#x != %#x' %
                            (len(self.content) - of, sz))
                sz = len(self.content) - of
            self.SymbolStrings = StrTable(self.content[of:of + sz])

        if self.Opthdr.__class__.__name__ == 'OpthdrUnknown':
            log.warning(
                "Unknown Option Header format of size %d for machine %s:",
                self.COFFhdr.sizeofoptionalheader,
                pe.constants['IMAGE_FILE_MACHINE'].get(
                    self.COFFhdr.machine, '%#x' % self.COFFhdr.machine))
            log.warning('%r', self.Opthdr)
Example #3
0
    def __init__(self,
                 pestr=None,
                 parse_resources=True,
                 parse_delay=True,
                 parse_reloc=True,
                 wsize=32):
        self._rva = ContentRVA(self)
        self._virt = ContentVirtual(self)
        if pestr == None:
            self.sex = '<'
            self.wsize = wsize
            self.DOShdr = pe.DOShdr(parent=self, wsize=32)
            self.NTsig = pe.NTsig(parent=self, wsize=32)
            self.COFFhdr = pe.COFFhdr(parent=self, wsize=32)
            self.Opthdr = {
                32: pe.Opthdr32,
                64: pe.Opthdr64
            }[wsize](parent=self)
            self.NThdr = pe.NThdr(parent=self)
            self.SHList = pe.SHList(parent=self, wsize=32)

            self.DirImport = pe.DirImport(parent=self)
            self.DirExport = pe.DirExport(parent=self)
            self.DirDelay = pe.DirDelay(parent=self)
            self.DirReloc = pe.DirReloc(parent=self)
            self.DirRes = pe.DirRes(parent=self)

            self.DOShdr.magic = 0x5a4d
            self.DOShdr.lfanew = 0xe0

            if wsize == 32:
                self.COFFhdr.machine = pe.IMAGE_FILE_MACHINE_I386
                self.COFFhdr.characteristics = 0x10f
                self.COFFhdr.sizeofoptionalheader = 0xe0
                self.Opthdr.magic = pe.IMAGE_NT_OPTIONAL_HDR32_MAGIC
            elif wsize == 64:
                self.COFFhdr.machine = pe.IMAGE_FILE_MACHINE_AMD64
                self.COFFhdr.characteristics = 0x22
                self.COFFhdr.sizeofoptionalheader = 0xf0
                self.Opthdr.magic = pe.IMAGE_NT_OPTIONAL_HDR64_MAGIC
            self.Opthdr.majorlinkerversion = 0x7
            self.Opthdr.minorlinkerversion = 0x0

            self.NThdr.ImageBase = 0x400000
            self.NThdr.sectionalignment = 0x1000
            self.NThdr.filealignment = 0x200
            self.NThdr.filealignment = 0x1000  # previous versions of elfesteem
            self.NThdr.majoroperatingsystemversion = 0x5
            self.NThdr.minoroperatingsystemversion = 0x1
            self.NThdr.MajorImageVersion = 0x5
            self.NThdr.MinorImageVersion = 0x1
            self.NThdr.majorsubsystemversion = 0x4
            self.NThdr.minorsubsystemversion = 0x0
            self.NThdr.subsystem = 0x3
            self.NThdr.dllcharacteristics = 0x8000
            self.NThdr.sizeofstackreserve = 0x200000
            self.NThdr.sizeofstackcommit = 0x1000
            self.NThdr.sizeofheapreserve = 0x100000
            self.NThdr.sizeofheapcommit = 0x1000
            self.NThdr.sizeofheaders = 0x1000
            self.NThdr.numberofrvaandsizes = 0x10
            self.NThdr.optentries = pe.OptNThdrs(parent=self.NThdr)
            for _ in range(self.NThdr.numberofrvaandsizes):
                self.NThdr.optentries.append(
                    pe.OptNThdr(parent=self.NThdr.optentries))
            self.NThdr._size += self.NThdr.optentries.bytelen
            self.NThdr.CheckSum = 0

            self.NTsig.signature = 0x4550
            self.content = StrPatchwork(self.pack())

        else:
            self.content = StrPatchwork(pestr)
            self.parse_content(parse_resources=parse_resources,
                               parse_delay=parse_delay,
                               parse_reloc=parse_reloc)
        # For API compatibility with previous versions of elfesteem
        self._sex = '<>'.index(self.sex)
        self._wsize = self.wsize