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])
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)
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