Remove submodule, just put Dependencies in ./libs

This commit is contained in:
Ruud
2011-02-28 15:25:42 +01:00
parent 2fb578d4de
commit 6888798ef6
541 changed files with 173394 additions and 4 deletions
+6
View File
@@ -0,0 +1,6 @@
from hachoir_parser.program.elf import ElfFile
from hachoir_parser.program.exe import ExeFile
from hachoir_parser.program.python import PythonCompiledFile
from hachoir_parser.program.java import JavaCompiledClassFile
from hachoir_parser.program.prc import PRCFile
+187
View File
@@ -0,0 +1,187 @@
"""
ELF (Unix/BSD executable file format) parser.
Author: Victor Stinner
Creation date: 08 may 2006
"""
from hachoir_parser import Parser
from hachoir_core.field import (FieldSet, ParserError,
UInt8, UInt16, UInt32, Enum,
String, Bytes)
from hachoir_core.text_handler import textHandler, hexadecimal
from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
class ElfHeader(FieldSet):
static_size = 52*8
LITTLE_ENDIAN_ID = 1
BIG_ENDIAN_ID = 2
MACHINE_NAME = {
1: u"AT&T WE 32100",
2: u"SPARC",
3: u"Intel 80386",
4: u"Motorola 68000",
5: u"Motorola 88000",
7: u"Intel 80860",
8: u"MIPS RS3000"
}
CLASS_NAME = {
1: u"32 bits",
2: u"64 bits"
}
TYPE_NAME = {
0: u"No file type",
1: u"Relocatable file",
2: u"Executable file",
3: u"Shared object file",
4: u"Core file",
0xFF00: u"Processor-specific (0xFF00)",
0xFFFF: u"Processor-specific (0xFFFF)"
}
ENDIAN_NAME = {
LITTLE_ENDIAN_ID: "Little endian",
BIG_ENDIAN_ID: "Big endian",
}
def createFields(self):
yield Bytes(self, "signature", 4, r'ELF signature ("\x7fELF")')
yield Enum(UInt8(self, "class", "Class"), self.CLASS_NAME)
yield Enum(UInt8(self, "endian", "Endian"), self.ENDIAN_NAME)
yield UInt8(self, "file_version", "File version")
yield String(self, "pad", 8, "Pad")
yield UInt8(self, "nb_ident", "Size of ident[]")
yield Enum(UInt16(self, "type", "File type"), self.TYPE_NAME)
yield Enum(UInt16(self, "machine", "Machine type"), self.MACHINE_NAME)
yield UInt32(self, "version", "ELF format version")
yield UInt32(self, "entry", "Number of entries")
yield UInt32(self, "phoff", "Program header offset")
yield UInt32(self, "shoff", "Section header offset")
yield UInt32(self, "flags", "Flags")
yield UInt16(self, "ehsize", "Elf header size (this header)")
yield UInt16(self, "phentsize", "Program header entry size")
yield UInt16(self, "phnum", "Program header entry count")
yield UInt16(self, "shentsize", "Section header entry size")
yield UInt16(self, "shnum", "Section header entre count")
yield UInt16(self, "shstrndx", "Section header strtab index")
def isValid(self):
if self["signature"].value != "\x7FELF":
return "Wrong ELF signature"
if self["class"].value not in self.CLASS_NAME:
return "Unknown class"
if self["endian"].value not in self.ENDIAN_NAME:
return "Unknown endian (%s)" % self["endian"].value
return ""
class SectionHeader32(FieldSet):
static_size = 40*8
TYPE_NAME = {
8: "BSS"
}
def createFields(self):
yield UInt32(self, "name", "Name")
yield Enum(UInt32(self, "type", "Type"), self.TYPE_NAME)
yield UInt32(self, "flags", "Flags")
yield textHandler(UInt32(self, "VMA", "Virtual memory address"), hexadecimal)
yield textHandler(UInt32(self, "LMA", "Logical memory address (in file)"), hexadecimal)
yield textHandler(UInt32(self, "size", "Size"), hexadecimal)
yield UInt32(self, "link", "Link")
yield UInt32(self, "info", "Information")
yield UInt32(self, "addr_align", "Address alignment")
yield UInt32(self, "entry_size", "Entry size")
def createDescription(self):
return "Section header (name: %s, type: %s)" % \
(self["name"].value, self["type"].display)
class ProgramHeader32(FieldSet):
TYPE_NAME = {
3: "Dynamic library"
}
static_size = 32*8
def createFields(self):
yield Enum(UInt16(self, "type", "Type"), ProgramHeader32.TYPE_NAME)
yield UInt16(self, "flags", "Flags")
yield UInt32(self, "offset", "Offset")
yield textHandler(UInt32(self, "vaddr", "V. address"), hexadecimal)
yield textHandler(UInt32(self, "paddr", "P. address"), hexadecimal)
yield UInt32(self, "file_size", "File size")
yield UInt32(self, "mem_size", "Memory size")
yield UInt32(self, "align", "Alignment")
yield UInt32(self, "xxx", "???")
def createDescription(self):
return "Program Header (%s)" % self["type"].display
def sortSection(a, b):
return int(a["offset"] - b["offset"])
#class Sections(FieldSet):
# def createFields?(self, stream, parent, sections):
# for section in sections:
# ofs = section["offset"]
# size = section["file_size"]
# if size != 0:
# sub = stream.createSub(ofs, size)
# #yield DeflateFilter(self, "section[]", sub, size, Section, "Section"))
# chunk = self.doRead("section[]", "Section", (Section,), {"stream": sub})
# else:
# chunk = self.doRead("section[]", "Section", (FormatChunk, "string[0]"))
# chunk.description = "ELF section (in file: %s..%s)" % (ofs, ofs+size)
class ElfFile(Parser):
PARSER_TAGS = {
"id": "elf",
"category": "program",
"file_ext": ("so", ""),
"min_size": ElfHeader.static_size, # At least one program header
"mime": (
u"application/x-executable",
u"application/x-object",
u"application/x-sharedlib",
u"application/x-executable-file",
u"application/x-coredump"),
"magic": (("\x7FELF", 0),),
"description": "ELF Unix/BSD program/library"
}
endian = LITTLE_ENDIAN
def validate(self):
err = self["header"].isValid()
if err:
return err
return True
def createFields(self):
# Choose the right endian depending on endian specified in header
if self.stream.readBits(5*8, 8, BIG_ENDIAN) == ElfHeader.BIG_ENDIAN_ID:
self.endian = BIG_ENDIAN
else:
self.endian = LITTLE_ENDIAN
# Parse header and program headers
yield ElfHeader(self, "header", "Header")
for index in xrange(self["header/phnum"].value):
yield ProgramHeader32(self, "prg_header[]")
if False:
raise ParserError("TODO: Parse sections...")
#sections = self.array("prg_header")
#size = self["header/shoff"].value - self.current_size//8
#chunk = self.doRead("data", "Data", (DeflateFilter, stream, size, Sections, sections))
#chunk.description = "Sections (use an evil hack to manage share same data on differents parts)"
#assert self.current_size//8 == self["header/shoff"].value
else:
raw = self.seekByte(self["header/shoff"].value, "raw[]", relative=False)
if raw:
yield raw
for index in xrange(self["header/shnum"].value):
yield SectionHeader32(self, "section_header[]")
def createDescription(self):
return "ELF Unix/BSD program/library: %s" % (
self["header/class"].display)
+224
View File
@@ -0,0 +1,224 @@
"""
Microsoft Windows Portable Executable (PE) file parser.
Informations:
- Microsoft Portable Executable and Common Object File Format Specification:
http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
Author: Victor Stinner
Creation date: 2006-08-13
"""
from hachoir_parser import HachoirParser
from hachoir_core.endian import LITTLE_ENDIAN
from hachoir_core.field import (FieldSet, RootSeekableFieldSet,
UInt16, UInt32, String,
RawBytes, PaddingBytes)
from hachoir_core.text_handler import textHandler, hexadecimal
from hachoir_parser.program.exe_ne import NE_Header
from hachoir_parser.program.exe_pe import PE_Header, PE_OptHeader, SectionHeader
from hachoir_parser.program.exe_res import PE_Resource, NE_VersionInfoNode
MAX_NB_SECTION = 50
class MSDosHeader(FieldSet):
static_size = 64*8
def createFields(self):
yield String(self, "header", 2, "File header (MZ)", charset="ASCII")
yield UInt16(self, "size_mod_512", "File size in bytes modulo 512")
yield UInt16(self, "size_div_512", "File size in bytes divide by 512")
yield UInt16(self, "reloc_entries", "Number of relocation entries")
yield UInt16(self, "code_offset", "Offset to the code in the file (divided by 16)")
yield UInt16(self, "needed_memory", "Memory needed to run (divided by 16)")
yield UInt16(self, "max_memory", "Maximum memory needed to run (divided by 16)")
yield textHandler(UInt32(self, "init_ss_sp", "Initial value of SP:SS registers"), hexadecimal)
yield UInt16(self, "checksum", "Checksum")
yield textHandler(UInt32(self, "init_cs_ip", "Initial value of CS:IP registers"), hexadecimal)
yield UInt16(self, "reloc_offset", "Offset in file to relocation table")
yield UInt16(self, "overlay_number", "Overlay number")
yield PaddingBytes(self, "reserved[]", 8, "Reserved")
yield UInt16(self, "oem_id", "OEM id")
yield UInt16(self, "oem_info", "OEM info")
yield PaddingBytes(self, "reserved[]", 20, "Reserved")
yield UInt32(self, "next_offset", "Offset to next header (PE or NE)")
def isValid(self):
if 512 <= self["size_mod_512"].value:
return "Invalid field 'size_mod_512' value"
if self["code_offset"].value < 4:
return "Invalid code offset"
looks_pe = self["size_div_512"].value < 4
if looks_pe:
if self["checksum"].value != 0:
return "Invalid value of checksum"
if not (80 <= self["next_offset"].value <= 1024):
return "Invalid value of next_offset"
return ""
class ExeFile(HachoirParser, RootSeekableFieldSet):
PARSER_TAGS = {
"id": "exe",
"category": "program",
"file_ext": ("exe", "dll", "ocx"),
"mime": (u"application/x-dosexec",),
"min_size": 64*8,
#"magic": (("MZ", 0),),
"magic_regex": (("MZ.[\0\1].{4}[^\0\1\2\3]", 0),),
"description": "Microsoft Windows Portable Executable"
}
endian = LITTLE_ENDIAN
def __init__(self, stream, **args):
RootSeekableFieldSet.__init__(self, None, "root", stream, None, stream.askSize(self))
HachoirParser.__init__(self, stream, **args)
def validate(self):
if self.stream.readBytes(0, 2) != 'MZ':
return "Wrong header"
err = self["msdos"].isValid()
if err:
return "Invalid MSDOS header: "+err
if self.isPE():
if MAX_NB_SECTION < self["pe_header/nb_section"].value:
return "Invalid number of section (%s)" \
% self["pe_header/nb_section"].value
return True
def createFields(self):
yield MSDosHeader(self, "msdos", "MS-DOS program header")
if self.isPE() or self.isNE():
offset = self["msdos/next_offset"].value
self.seekByte(offset, relative=False)
if self.isPE():
for field in self.parsePortableExecutable():
yield field
elif self.isNE():
for field in self.parseNE_Executable():
yield field
else:
offset = self["msdos/code_offset"].value * 16
self.seekByte(offset, relative=False)
def parseNE_Executable(self):
yield NE_Header(self, "ne_header")
# FIXME: Compute resource offset instead of using searchBytes()
# Ugly hack to get find version info structure
start = self.current_size
addr = self.stream.searchBytes('VS_VERSION_INFO', start)
if addr:
self.seekBit(addr-32)
yield NE_VersionInfoNode(self, "info")
def parsePortableExecutable(self):
# Read PE header
yield PE_Header(self, "pe_header")
# Read PE optional header
size = self["pe_header/opt_hdr_size"].value
rsrc_rva = None
if size:
yield PE_OptHeader(self, "pe_opt_header", size=size*8)
if "pe_opt_header/resource/rva" in self:
rsrc_rva = self["pe_opt_header/resource/rva"].value
# Read section headers
sections = []
for index in xrange(self["pe_header/nb_section"].value):
section = SectionHeader(self, "section_hdr[]")
yield section
if section["phys_size"].value:
sections.append(section)
# Read sections
sections.sort(key=lambda field: field["phys_off"].value)
for section in sections:
self.seekByte(section["phys_off"].value)
size = section["phys_size"].value
if size:
name = section.createSectionName()
if rsrc_rva is not None and section["rva"].value == rsrc_rva:
yield PE_Resource(self, name, section, size=size*8)
else:
yield RawBytes(self, name, size)
def isPE(self):
if not hasattr(self, "_is_pe"):
self._is_pe = False
offset = self["msdos/next_offset"].value * 8
if 2*8 <= offset \
and (offset+PE_Header.static_size) <= self.size \
and self.stream.readBytes(offset, 4) == 'PE\0\0':
self._is_pe = True
return self._is_pe
def isNE(self):
if not hasattr(self, "_is_ne"):
self._is_ne = False
offset = self["msdos/next_offset"].value * 8
if 64*8 <= offset \
and (offset+NE_Header.static_size) <= self.size \
and self.stream.readBytes(offset, 2) == 'NE':
self._is_ne = True
return self._is_ne
def getResource(self):
# MS-DOS program: no resource
if not self.isPE():
return None
# Check if PE has resource or not
if "pe_opt_header/resource/size" in self:
if not self["pe_opt_header/resource/size"].value:
return None
if "section_rsrc" in self:
return self["section_rsrc"]
return None
def createDescription(self):
if self.isPE():
if self["pe_header/is_dll"].value:
text = u"Microsoft Windows DLL"
else:
text = u"Microsoft Windows Portable Executable"
info = [self["pe_header/cpu"].display]
if "pe_opt_header" in self:
hdr = self["pe_opt_header"]
info.append(hdr["subsystem"].display)
if self["pe_header/is_stripped"].value:
info.append(u"stripped")
return u"%s: %s" % (text, ", ".join(info))
elif self.isNE():
return u"New-style Executable (NE) for Microsoft MS Windows 3.x"
else:
return u"MS-DOS executable"
def createContentSize(self):
if self.isPE():
size = 0
for index in xrange(self["pe_header/nb_section"].value):
section = self["section_hdr[%u]" % index]
section_size = section["phys_size"].value
if not section_size:
continue
section_size = (section_size + section["phys_off"].value) * 8
if size:
size = max(size, section_size)
else:
size = section_size
if size:
return size
else:
return None
elif self.isNE():
# TODO: Guess NE size
return None
else:
size = self["msdos/size_mod_512"].value + (self["msdos/size_div_512"].value-1) * 512
if size < 0:
return None
return size*8
+60
View File
@@ -0,0 +1,60 @@
from hachoir_core.field import (FieldSet,
Bit, UInt8, UInt16, UInt32, Bytes,
PaddingBits, PaddingBytes, NullBits, NullBytes)
from hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
class NE_Header(FieldSet):
static_size = 64*8
def createFields(self):
yield Bytes(self, "signature", 2, "New executable signature (NE)")
yield UInt8(self, "link_ver", "Linker version number")
yield UInt8(self, "link_rev", "Linker revision number")
yield UInt16(self, "entry_table_ofst", "Offset to the entry table")
yield UInt16(self, "entry_table_size", "Length (in bytes) of the entry table")
yield PaddingBytes(self, "reserved[]", 4)
yield Bit(self, "is_dll", "Is a dynamic-link library (DLL)?")
yield Bit(self, "is_win_app", "Is a Windows application?")
yield PaddingBits(self, "reserved[]", 9)
yield Bit(self, "first_seg_code", "First segment contains code that loads the application?")
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "link_error", "Load even if linker detects errors?")
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "is_lib", "Is a library module?")
yield UInt16(self, "auto_data_seg", "Automatic data segment number")
yield filesizeHandler(UInt16(self, "local_heap_size", "Initial size (in bytes) of the local heap"))
yield filesizeHandler(UInt16(self, "stack_size", "Initial size (in bytes) of the stack"))
yield textHandler(UInt32(self, "cs_ip", "Value of CS:IP"), hexadecimal)
yield textHandler(UInt32(self, "ss_sp", "Value of SS:SP"), hexadecimal)
yield UInt16(self, "nb_entry_seg_tab", "Number of entries in the segment table")
yield UInt16(self, "nb_entry_modref_tab", "Number of entries in the module-reference table")
yield filesizeHandler(UInt16(self, "size_nonres_name_tab", "Number of bytes in the nonresident-name table"))
yield UInt16(self, "seg_tab_ofs", "Segment table offset")
yield UInt16(self, "rsrc_ofs", "Resource offset")
yield UInt16(self, "res_name_tab_ofs", "Resident-name table offset")
yield UInt16(self, "mod_ref_tab_ofs", "Module-reference table offset")
yield UInt16(self, "import_tab_ofs", "Imported-name table offset")
yield UInt32(self, "non_res_name_tab_ofs", "Nonresident-name table offset")
yield UInt16(self, "nb_mov_ent_pt", "Number of movable entry points")
yield UInt16(self, "log2_sector_size", "Log2 of the segment sector size")
yield UInt16(self, "nb_rsrc_seg", "Number of resource segments")
yield Bit(self, "unknown_os_format", "Operating system format is unknown")
yield PaddingBits(self, "reserved[]", 1)
yield Bit(self, "os_windows", "Operating system is Microsoft Windows")
yield NullBits(self, "reserved[]", 6)
yield Bit(self, "is_win20_prot", "Is Windows 2.x application running in version 3.x protected mode")
yield Bit(self, "is_win20_font", "Is Windows 2.x application supporting proportional fonts")
yield Bit(self, "fast_load", "Contains a fast-load area?")
yield NullBits(self, "reserved[]", 4)
yield UInt16(self, "fastload_ofs", "Fast-load area offset (in sector)")
yield UInt16(self, "fastload_size", "Fast-load area length (in sector)")
yield NullBytes(self, "reserved[]", 2)
yield textHandler(UInt16(self, "win_version", "Expected Windows version number"), hexadecimal)
+221
View File
@@ -0,0 +1,221 @@
from hachoir_core.field import (FieldSet, ParserError,
Bit, UInt8, UInt16, UInt32, TimestampUnix32,
Bytes, String, Enum,
PaddingBytes, PaddingBits, NullBytes, NullBits)
from hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
from hachoir_core.error import HACHOIR_ERRORS
class SectionHeader(FieldSet):
static_size = 40 * 8
def createFields(self):
yield String(self, "name", 8, charset="ASCII", strip="\0 ")
yield filesizeHandler(UInt32(self, "mem_size", "Size in memory"))
yield textHandler(UInt32(self, "rva", "RVA (location) in memory"), hexadecimal)
yield filesizeHandler(UInt32(self, "phys_size", "Physical size (on disk)"))
yield filesizeHandler(UInt32(self, "phys_off", "Physical location (on disk)"))
yield PaddingBytes(self, "reserved", 12)
# 0x0000000#
yield NullBits(self, "reserved[]", 4)
# 0x000000#0
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "has_code", "Contains code")
yield Bit(self, "has_init_data", "Contains initialized data")
yield Bit(self, "has_uninit_data", "Contains uninitialized data")
# 0x00000#00
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "has_comment", "Contains comments?")
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "remove", "Contents will not become part of image")
# 0x0000#000
yield Bit(self, "has_comdata", "Contains comdat?")
yield NullBits(self, "reserved[]", 1)
yield Bit(self, "no_defer_spec_exc", "Reset speculative exceptions handling bits in the TLB entries")
yield Bit(self, "gp_rel", "Content can be accessed relative to GP")
# 0x000#0000
yield NullBits(self, "reserved[]", 4)
# 0x00#00000
yield NullBits(self, "reserved[]", 4)
# 0x0#000000
yield Bit(self, "ext_reloc", "Contains extended relocations?")
yield Bit(self, "discarded", "Can be discarded?")
yield Bit(self, "is_not_cached", "Is not cachable?")
yield Bit(self, "is_not_paged", "Is not pageable?")
# 0x#0000000
yield Bit(self, "is_shareable", "Is shareable?")
yield Bit(self, "is_executable", "Is executable?")
yield Bit(self, "is_readable", "Is readable?")
yield Bit(self, "is_writable", "Is writable?")
def rva2file(self, rva):
return self["phys_off"].value + (rva - self["rva"].value)
def createDescription(self):
rva = self["rva"].value
size = self["mem_size"].value
info = [
"rva=0x%08x..0x%08x" % (rva, rva+size),
"size=%s" % self["mem_size"].display,
]
if self["is_executable"].value:
info.append("exec")
if self["is_readable"].value:
info.append("read")
if self["is_writable"].value:
info.append("write")
return 'Section "%s": %s' % (self["name"].value, ", ".join(info))
def createSectionName(self):
try:
name = str(self["name"].value.strip("."))
if name:
return "section_%s" % name
except HACHOIR_ERRORS, err:
self.warning(unicode(err))
return "section[]"
class DataDirectory(FieldSet):
def createFields(self):
yield textHandler(UInt32(self, "rva", "Virtual address"), hexadecimal)
yield filesizeHandler(UInt32(self, "size"))
def createDescription(self):
if self["size"].value:
return "Directory at %s (%s)" % (
self["rva"].display, self["size"].display)
else:
return "(empty directory)"
class PE_Header(FieldSet):
static_size = 24*8
cpu_name = {
0x0184: u"Alpha AXP",
0x01c0: u"ARM",
0x014C: u"Intel 80386",
0x014D: u"Intel 80486",
0x014E: u"Intel Pentium",
0x0200: u"Intel IA64",
0x0268: u"Motorola 68000",
0x0266: u"MIPS",
0x0284: u"Alpha AXP 64 bits",
0x0366: u"MIPS with FPU",
0x0466: u"MIPS16 with FPU",
0x01f0: u"PowerPC little endian",
0x0162: u"R3000",
0x0166: u"MIPS little endian (R4000)",
0x0168: u"R10000",
0x01a2: u"Hitachi SH3",
0x01a6: u"Hitachi SH4",
0x0160: u"R3000 (MIPS), big endian",
0x0162: u"R3000 (MIPS), little endian",
0x0166: u"R4000 (MIPS), little endian",
0x0168: u"R10000 (MIPS), little endian",
0x0184: u"DEC Alpha AXP",
0x01F0: u"IBM Power PC, little endian",
}
def createFields(self):
yield Bytes(self, "header", 4, r"PE header signature (PE\0\0)")
if self["header"].value != "PE\0\0":
raise ParserError("Invalid PE header signature")
yield Enum(UInt16(self, "cpu", "CPU type"), self.cpu_name)
yield UInt16(self, "nb_section", "Number of sections")
yield TimestampUnix32(self, "creation_date", "Creation date")
yield UInt32(self, "ptr_to_sym", "Pointer to symbol table")
yield UInt32(self, "nb_symbols", "Number of symbols")
yield UInt16(self, "opt_hdr_size", "Optional header size")
yield Bit(self, "reloc_stripped", "If true, don't contain base relocations.")
yield Bit(self, "exec_image", "Executable image?")
yield Bit(self, "line_nb_stripped", "COFF line numbers stripped?")
yield Bit(self, "local_sym_stripped", "COFF symbol table entries stripped?")
yield Bit(self, "aggr_ws", "Aggressively trim working set")
yield Bit(self, "large_addr", "Application can handle addresses greater than 2 GB")
yield NullBits(self, "reserved", 1)
yield Bit(self, "reverse_lo", "Little endian: LSB precedes MSB in memory")
yield Bit(self, "32bit", "Machine based on 32-bit-word architecture")
yield Bit(self, "is_stripped", "Debugging information removed?")
yield Bit(self, "swap", "If image is on removable media, copy and run from swap file")
yield PaddingBits(self, "reserved2", 1)
yield Bit(self, "is_system", "It's a system file")
yield Bit(self, "is_dll", "It's a dynamic-link library (DLL)")
yield Bit(self, "up", "File should be run only on a UP machine")
yield Bit(self, "reverse_hi", "Big endian: MSB precedes LSB in memory")
class PE_OptHeader(FieldSet):
SUBSYSTEM_NAME = {
1: u"Native",
2: u"Windows GUI",
3: u"Windows CUI",
5: u"OS/2 CUI",
7: u"POSIX CUI",
8: u"Native Windows",
9: u"Windows CE GUI",
10: u"EFI application",
11: u"EFI boot service driver",
12: u"EFI runtime driver",
13: u"EFI ROM",
14: u"XBOX",
16: u"Windows boot application",
}
DIRECTORY_NAME = {
0: "export",
1: "import",
2: "resource",
3: "exception",
4: "certificate",
5: "relocation",
6: "debug",
7: "description",
8: "global_ptr",
9: "tls", # Thread local storage
10: "load_config",
11: "bound_import",
12: "import_address",
}
def createFields(self):
yield UInt16(self, "signature", "PE optional header signature (0x010b)")
# TODO: Support PE32+ (signature=0x020b)
if self["signature"].value != 0x010b:
raise ParserError("Invalid PE optional header signature")
yield UInt8(self, "maj_lnk_ver", "Major linker version")
yield UInt8(self, "min_lnk_ver", "Minor linker version")
yield filesizeHandler(UInt32(self, "size_code", "Size of code"))
yield filesizeHandler(UInt32(self, "size_init_data", "Size of initialized data"))
yield filesizeHandler(UInt32(self, "size_uninit_data", "Size of uninitialized data"))
yield textHandler(UInt32(self, "entry_point", "Address (RVA) of the code entry point"), hexadecimal)
yield textHandler(UInt32(self, "base_code", "Base (RVA) of code"), hexadecimal)
yield textHandler(UInt32(self, "base_data", "Base (RVA) of data"), hexadecimal)
yield textHandler(UInt32(self, "image_base", "Image base (RVA)"), hexadecimal)
yield filesizeHandler(UInt32(self, "sect_align", "Section alignment"))
yield filesizeHandler(UInt32(self, "file_align", "File alignment"))
yield UInt16(self, "maj_os_ver", "Major OS version")
yield UInt16(self, "min_os_ver", "Minor OS version")
yield UInt16(self, "maj_img_ver", "Major image version")
yield UInt16(self, "min_img_ver", "Minor image version")
yield UInt16(self, "maj_subsys_ver", "Major subsystem version")
yield UInt16(self, "min_subsys_ver", "Minor subsystem version")
yield NullBytes(self, "reserved", 4)
yield filesizeHandler(UInt32(self, "size_img", "Size of image"))
yield filesizeHandler(UInt32(self, "size_hdr", "Size of headers"))
yield textHandler(UInt32(self, "checksum"), hexadecimal)
yield Enum(UInt16(self, "subsystem"), self.SUBSYSTEM_NAME)
yield UInt16(self, "dll_flags")
yield filesizeHandler(UInt32(self, "size_stack_reserve"))
yield filesizeHandler(UInt32(self, "size_stack_commit"))
yield filesizeHandler(UInt32(self, "size_heap_reserve"))
yield filesizeHandler(UInt32(self, "size_heap_commit"))
yield UInt32(self, "loader_flags")
yield UInt32(self, "nb_directory", "Number of RVA and sizes")
for index in xrange(self["nb_directory"].value):
try:
name = self.DIRECTORY_NAME[index]
except KeyError:
name = "data_dir[%u]" % index
yield DataDirectory(self, name)
def createDescription(self):
return "PE optional header: %s, entry point %s" % (
self["subsystem"].display,
self["entry_point"].display)
+445
View File
@@ -0,0 +1,445 @@
"""
Parser for resource of Microsoft Windows Portable Executable (PE).
Documentation:
- Wine project
VS_FIXEDFILEINFO structure, file include/winver.h
Author: Victor Stinner
Creation date: 2007-01-19
"""
from hachoir_core.field import (FieldSet, ParserError, Enum,
Bit, Bits, SeekableFieldSet,
UInt16, UInt32, TimestampUnix32,
RawBytes, PaddingBytes, NullBytes, NullBits,
CString, String)
from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
from hachoir_core.tools import createDict, paddingSize, alignValue, makePrintable
from hachoir_core.error import HACHOIR_ERRORS
from hachoir_parser.common.win32 import BitmapInfoHeader
MAX_DEPTH = 5
MAX_INDEX_PER_HEADER = 300
MAX_NAME_PER_HEADER = MAX_INDEX_PER_HEADER
class Version(FieldSet):
static_size = 32
def createFields(self):
yield textHandler(UInt16(self, "minor", "Minor version number"), hexadecimal)
yield textHandler(UInt16(self, "major", "Major version number"), hexadecimal)
def createValue(self):
return self["major"].value + float(self["minor"].value) / 10000
MAJOR_OS_NAME = {
1: "DOS",
2: "OS/2 16-bit",
3: "OS/2 32-bit",
4: "Windows NT",
}
MINOR_OS_BASE = 0
MINOR_OS_NAME = {
0: "Base",
1: "Windows 16-bit",
2: "Presentation Manager 16-bit",
3: "Presentation Manager 32-bit",
4: "Windows 32-bit",
}
FILETYPE_DRIVER = 3
FILETYPE_FONT = 4
FILETYPE_NAME = {
1: "Application",
2: "DLL",
3: "Driver",
4: "Font",
5: "VXD",
7: "Static library",
}
DRIVER_SUBTYPE_NAME = {
1: "Printer",
2: "Keyboard",
3: "Language",
4: "Display",
5: "Mouse",
6: "Network",
7: "System",
8: "Installable",
9: "Sound",
10: "Communications",
}
FONT_SUBTYPE_NAME = {
1: "Raster",
2: "Vector",
3: "TrueType",
}
class VersionInfoBinary(FieldSet):
def createFields(self):
yield textHandler(UInt32(self, "magic", "File information magic (0xFEEF04BD)"), hexadecimal)
if self["magic"].value != 0xFEEF04BD:
raise ParserError("EXE resource: invalid file info magic")
yield Version(self, "struct_ver", "Structure version (1.0)")
yield Version(self, "file_ver_ms", "File version MS")
yield Version(self, "file_ver_ls", "File version LS")
yield Version(self, "product_ver_ms", "Product version MS")
yield Version(self, "product_ver_ls", "Product version LS")
yield textHandler(UInt32(self, "file_flags_mask"), hexadecimal)
yield Bit(self, "debug")
yield Bit(self, "prerelease")
yield Bit(self, "patched")
yield Bit(self, "private_build")
yield Bit(self, "info_inferred")
yield Bit(self, "special_build")
yield NullBits(self, "reserved", 26)
yield Enum(textHandler(UInt16(self, "file_os_major"), hexadecimal), MAJOR_OS_NAME)
yield Enum(textHandler(UInt16(self, "file_os_minor"), hexadecimal), MINOR_OS_NAME)
yield Enum(textHandler(UInt32(self, "file_type"), hexadecimal), FILETYPE_NAME)
field = textHandler(UInt32(self, "file_subfile"), hexadecimal)
if field.value == FILETYPE_DRIVER:
field = Enum(field, DRIVER_SUBTYPE_NAME)
elif field.value == FILETYPE_FONT:
field = Enum(field, FONT_SUBTYPE_NAME)
yield field
yield TimestampUnix32(self, "date_ms")
yield TimestampUnix32(self, "date_ls")
class VersionInfoNode(FieldSet):
TYPE_STRING = 1
TYPE_NAME = {
0: "binary",
1: "string",
}
def __init__(self, parent, name, is_32bit=True):
FieldSet.__init__(self, parent, name)
self._size = alignValue(self["size"].value, 4) * 8
self.is_32bit = is_32bit
def createFields(self):
yield UInt16(self, "size", "Node size (in bytes)")
yield UInt16(self, "data_size")
yield Enum(UInt16(self, "type"), self.TYPE_NAME)
yield CString(self, "name", charset="UTF-16-LE")
size = paddingSize(self.current_size//8, 4)
if size:
yield NullBytes(self, "padding[]", size)
size = self["data_size"].value
if size:
if self["type"].value == self.TYPE_STRING:
if self.is_32bit:
size *= 2
yield String(self, "value", size, charset="UTF-16-LE", truncate="\0")
elif self["name"].value == "VS_VERSION_INFO":
yield VersionInfoBinary(self, "value", size=size*8)
if self["value/file_flags_mask"].value == 0:
self.is_32bit = False
else:
yield RawBytes(self, "value", size)
while 12 <= (self.size - self.current_size) // 8:
yield VersionInfoNode(self, "node[]", self.is_32bit)
size = (self.size - self.current_size) // 8
if size:
yield NullBytes(self, "padding[]", size)
def createDescription(self):
text = "Version info node: %s" % self["name"].value
if self["type"].value == self.TYPE_STRING and "value" in self:
text += "=%s" % self["value"].value
return text
def parseVersionInfo(parent):
yield VersionInfoNode(parent, "node[]")
def parseIcon(parent):
yield BitmapInfoHeader(parent, "bmp_header")
size = (parent.size - parent.current_size) // 8
if size:
yield RawBytes(parent, "raw", size)
class WindowsString(FieldSet):
def createFields(self):
yield UInt16(self, "length", "Number of 16-bit characters")
size = self["length"].value * 2
if size:
yield String(self, "text", size, charset="UTF-16-LE")
def createValue(self):
if "text" in self:
return self["text"].value
else:
return u""
def createDisplay(self):
return makePrintable(self.value, "UTF-8", to_unicode=True, quote='"')
def parseStringTable(parent):
while not parent.eof:
yield WindowsString(parent, "string[]")
RESOURCE_TYPE = {
1: ("cursor[]", "Cursor", None),
2: ("bitmap[]", "Bitmap", None),
3: ("icon[]", "Icon", parseIcon),
4: ("menu[]", "Menu", None),
5: ("dialog[]", "Dialog", None),
6: ("string_table[]", "String table", parseStringTable),
7: ("font_dir[]", "Font directory", None),
8: ("font[]", "Font", None),
9: ("accelerators[]", "Accelerators", None),
10: ("raw_res[]", "Unformatted resource data", None),
11: ("message_table[]", "Message table", None),
12: ("group_cursor[]", "Group cursor", None),
14: ("group_icon[]", "Group icon", None),
16: ("version_info", "Version information", parseVersionInfo),
}
class Entry(FieldSet):
static_size = 16*8
def __init__(self, parent, name, inode=None):
FieldSet.__init__(self, parent, name)
self.inode = inode
def createFields(self):
yield textHandler(UInt32(self, "rva"), hexadecimal)
yield filesizeHandler(UInt32(self, "size"))
yield UInt32(self, "codepage")
yield NullBytes(self, "reserved", 4)
def createDescription(self):
return "Entry #%u: offset=%s size=%s" % (
self.inode["offset"].value, self["rva"].display, self["size"].display)
class NameOffset(FieldSet):
def createFields(self):
yield UInt32(self, "name")
yield Bits(self, "offset", 31)
yield Bit(self, "is_name")
class IndexOffset(FieldSet):
TYPE_DESC = createDict(RESOURCE_TYPE, 1)
def __init__(self, parent, name, res_type=None):
FieldSet.__init__(self, parent, name)
self.res_type = res_type
def createFields(self):
yield Enum(UInt32(self, "type"), self.TYPE_DESC)
yield Bits(self, "offset", 31)
yield Bit(self, "is_subdir")
def createDescription(self):
if self["is_subdir"].value:
return "Sub-directory: %s at %s" % (self["type"].display, self["offset"].value)
else:
return "Index: ID %s at %s" % (self["type"].display, self["offset"].value)
class ResourceContent(FieldSet):
def __init__(self, parent, name, entry, size=None):
FieldSet.__init__(self, parent, name, size=entry["size"].value*8)
self.entry = entry
res_type = self.getResType()
if res_type in RESOURCE_TYPE:
self._name, description, self._parser = RESOURCE_TYPE[res_type]
else:
self._parser = None
def getResID(self):
return self.entry.inode["offset"].value
def getResType(self):
return self.entry.inode.res_type
def createFields(self):
if self._parser:
for field in self._parser(self):
yield field
else:
yield RawBytes(self, "content", self.size//8)
def createDescription(self):
return "Resource #%u content: type=%s" % (
self.getResID(), self.getResType())
class Header(FieldSet):
static_size = 16*8
def createFields(self):
yield NullBytes(self, "options", 4)
yield TimestampUnix32(self, "creation_date")
yield UInt16(self, "maj_ver", "Major version")
yield UInt16(self, "min_ver", "Minor version")
yield UInt16(self, "nb_name", "Number of named entries")
yield UInt16(self, "nb_index", "Number of indexed entries")
def createDescription(self):
text = "Resource header"
info = []
if self["nb_name"].value:
info.append("%u name" % self["nb_name"].value)
if self["nb_index"].value:
info.append("%u index" % self["nb_index"].value)
if self["creation_date"].value:
info.append(self["creation_date"].display)
if info:
return "%s: %s" % (text, ", ".join(info))
else:
return text
class Name(FieldSet):
def createFields(self):
yield UInt16(self, "length")
size = min(self["length"].value, 255)
if size:
yield String(self, "name", size, charset="UTF-16LE")
class Directory(FieldSet):
def __init__(self, parent, name, res_type=None):
FieldSet.__init__(self, parent, name)
nb_entries = self["header/nb_name"].value + self["header/nb_index"].value
self._size = Header.static_size + nb_entries * 64
self.res_type = res_type
def createFields(self):
yield Header(self, "header")
if MAX_NAME_PER_HEADER < self["header/nb_name"].value:
raise ParserError("EXE resource: invalid number of name (%s)"
% self["header/nb_name"].value)
if MAX_INDEX_PER_HEADER < self["header/nb_index"].value:
raise ParserError("EXE resource: invalid number of index (%s)"
% self["header/nb_index"].value)
hdr = self["header"]
for index in xrange(hdr["nb_name"].value):
yield NameOffset(self, "name[]")
for index in xrange(hdr["nb_index"].value):
yield IndexOffset(self, "index[]", self.res_type)
def createDescription(self):
return self["header"].description
class PE_Resource(SeekableFieldSet):
def __init__(self, parent, name, section, size):
SeekableFieldSet.__init__(self, parent, name, size=size)
self.section = section
def parseSub(self, directory, name, depth):
indexes = []
for index in directory.array("index"):
if index["is_subdir"].value:
indexes.append(index)
#indexes.sort(key=lambda index: index["offset"].value)
for index in indexes:
self.seekByte(index["offset"].value)
if depth == 1:
res_type = index["type"].value
else:
res_type = directory.res_type
yield Directory(self, name, res_type)
def createFields(self):
# Parse directories
depth = 0
subdir = Directory(self, "root")
yield subdir
subdirs = [subdir]
alldirs = [subdir]
while subdirs:
depth += 1
if MAX_DEPTH < depth:
self.error("EXE resource: depth too high (%s), stop parsing directories" % depth)
break
newsubdirs = []
for index, subdir in enumerate(subdirs):
name = "directory[%u][%u][]" % (depth, index)
try:
for field in self.parseSub(subdir, name, depth):
if field.__class__ == Directory:
newsubdirs.append(field)
yield field
except HACHOIR_ERRORS, err:
self.error("Unable to create directory %s: %s" % (name, err))
subdirs = newsubdirs
alldirs.extend(subdirs)
# Create resource list
resources = []
for directory in alldirs:
for index in directory.array("index"):
if not index["is_subdir"].value:
resources.append(index)
# Parse entries
entries = []
for resource in resources:
offset = resource["offset"].value
if offset is None:
continue
self.seekByte(offset)
entry = Entry(self, "entry[]", inode=resource)
yield entry
entries.append(entry)
entries.sort(key=lambda entry: entry["rva"].value)
# Parse resource content
for entry in entries:
try:
offset = self.section.rva2file(entry["rva"].value)
padding = self.seekByte(offset, relative=False)
if padding:
yield padding
yield ResourceContent(self, "content[]", entry)
except HACHOIR_ERRORS, err:
self.warning("Error when parsing entry %s: %s" % (entry.path, err))
size = (self.size - self.current_size) // 8
if size:
yield PaddingBytes(self, "padding_end", size)
class NE_VersionInfoNode(FieldSet):
TYPE_STRING = 1
TYPE_NAME = {
0: "binary",
1: "string",
}
def __init__(self, parent, name):
FieldSet.__init__(self, parent, name)
self._size = alignValue(self["size"].value, 4) * 8
def createFields(self):
yield UInt16(self, "size", "Node size (in bytes)")
yield UInt16(self, "data_size")
yield CString(self, "name", charset="ISO-8859-1")
size = paddingSize(self.current_size//8, 4)
if size:
yield NullBytes(self, "padding[]", size)
size = self["data_size"].value
if size:
if self["name"].value == "VS_VERSION_INFO":
yield VersionInfoBinary(self, "value", size=size*8)
else:
yield String(self, "value", size, charset="ISO-8859-1")
while 12 <= (self.size - self.current_size) // 8:
yield NE_VersionInfoNode(self, "node[]")
size = (self.size - self.current_size) // 8
if size:
yield NullBytes(self, "padding[]", size)
def createDescription(self):
text = "Version info node: %s" % self["name"].value
# if self["type"].value == self.TYPE_STRING and "value" in self:
# text += "=%s" % self["value"].value
return text
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
"""
PRC (Palm resource) parser.
Author: Sebastien Ponce
Creation date: 29 october 2008
"""
from hachoir_parser import Parser
from hachoir_core.field import (FieldSet,
UInt16, UInt32, TimestampMac32,
String, RawBytes)
from hachoir_core.endian import BIG_ENDIAN
class PRCHeader(FieldSet):
static_size = 78*8
def createFields(self):
yield String(self, "name", 32, "Name")
yield UInt16(self, "flags", "Flags")
yield UInt16(self, "version", "Version")
yield TimestampMac32(self, "create_time", "Creation time")
yield TimestampMac32(self, "mod_time", "Modification time")
yield TimestampMac32(self, "backup_time", "Backup time")
yield UInt32(self, "mod_num", "mod num")
yield UInt32(self, "app_info", "app info")
yield UInt32(self, "sort_info", "sort info")
yield UInt32(self, "type", "type")
yield UInt32(self, "id", "id")
yield UInt32(self, "unique_id_seed", "unique_id_seed")
yield UInt32(self, "next_record_list", "next_record_list")
yield UInt16(self, "num_records", "num_records")
class ResourceHeader(FieldSet):
static_size = 10*8
def createFields(self):
yield String(self, "name", 4, "Name of the resource")
yield UInt16(self, "flags", "ID number of the resource")
yield UInt32(self, "offset", "Pointer to the resource data")
def createDescription(self):
return "Resource Header (%s)" % self["name"]
class PRCFile(Parser):
PARSER_TAGS = {
"id": "prc",
"category": "program",
"file_ext": ("prc", ""),
"min_size": ResourceHeader.static_size, # At least one program header
"mime": (
u"application/x-pilot-prc",
u"application/x-palmpilot"),
"description": "Palm Resource File"
}
endian = BIG_ENDIAN
def validate(self):
# FIXME: Implement the validation function!
return False
def createFields(self):
# Parse header and program headers
yield PRCHeader(self, "header", "Header")
lens = []
firstOne = True
poff = 0
for index in xrange(self["header/num_records"].value):
r = ResourceHeader(self, "res_header[]")
if firstOne:
firstOne = False
else:
lens.append(r["offset"].value - poff)
poff = r["offset"].value
yield r
lens.append(self.size/8 - poff)
yield UInt16(self, "placeholder", "Place holder bytes")
for i in range(len(lens)):
yield RawBytes(self, "res[]", lens[i], '"'+self["res_header["+str(i)+"]/name"].value+"\" Resource")
def createDescription(self):
return "Palm Resource file"
+334
View File
@@ -0,0 +1,334 @@
"""
Python compiled source code parser.
Informations:
- Python 2.4.2 source code:
files Python/marshal.c and Python/import.c
Author: Victor Stinner
Creation: 25 march 2005
"""
DISASSEMBLE = False
from hachoir_parser import Parser
from hachoir_core.field import (FieldSet, UInt8,
UInt16, Int32, UInt32, Int64, ParserError, Float64, Enum,
Character, Bytes, RawBytes, PascalString8, TimestampUnix32)
from hachoir_core.endian import LITTLE_ENDIAN
from hachoir_core.bits import long2raw
from hachoir_core.text_handler import textHandler, hexadecimal
from hachoir_core.i18n import ngettext
if DISASSEMBLE:
from dis import dis
def disassembleBytecode(field):
bytecode = field.value
dis(bytecode)
# --- String and string reference ---
def parseString(parent):
yield UInt32(parent, "length", "Length")
length = parent["length"].value
if parent.name == "lnotab":
bytecode_offset=0
line_number=parent['../firstlineno'].value
for i in range(0,length,2):
bc_off_delta=UInt8(parent, 'bytecode_offset_delta[]')
yield bc_off_delta
bytecode_offset+=bc_off_delta.value
bc_off_delta._description='Bytecode Offset %i'%bytecode_offset
line_number_delta=UInt8(parent, 'line_number_delta[]')
yield line_number_delta
line_number+=line_number_delta.value
line_number_delta._description='Line Number %i'%line_number
elif 0 < length:
yield RawBytes(parent, "text", length, "Content")
if DISASSEMBLE and parent.name == "compiled_code":
disassembleBytecode(parent["text"])
def parseStringRef(parent):
yield textHandler(UInt32(parent, "ref"), hexadecimal)
def createStringRefDesc(parent):
return "String ref: %s" % parent["ref"].display
# --- Integers ---
def parseInt32(parent):
yield Int32(parent, "value")
def parseInt64(parent):
yield Int64(parent, "value")
def parseLong(parent):
yield Int32(parent, "digit_count")
for index in xrange( abs(parent["digit_count"].value) ):
yield UInt16(parent, "digit[]")
# --- Float and complex ---
def parseFloat(parent):
yield PascalString8(parent, "value")
def parseBinaryFloat(parent):
yield Float64(parent, "value")
def parseComplex(parent):
yield PascalString8(parent, "real")
yield PascalString8(parent, "complex")
def parseBinaryComplex(parent):
yield Float64(parent, "real")
yield Float64(parent, "complex")
# --- Tuple and list ---
def parseTuple(parent):
yield Int32(parent, "count", "Item count")
count = parent["count"].value
if count < 0:
raise ParserError("Invalid tuple/list count")
for index in xrange(count):
yield Object(parent, "item[]")
def createTupleDesc(parent):
count = parent["count"].value
items = ngettext("%s item", "%s items", count) % count
return "%s: %s" % (parent.code_info[2], items)
# --- Dict ---
def parseDict(parent):
"""
Format is: (key1, value1, key2, value2, ..., keyn, valuen, NULL)
where each keyi and valuei is an object.
"""
parent.count = 0
while True:
key = Object(parent, "key[]")
yield key
if key["bytecode"].value == "0":
break
yield Object(parent, "value[]")
parent.count += 1
def createDictDesc(parent):
return "Dict: %s" % (ngettext("%s key", "%s keys", parent.count) % parent.count)
# --- Code ---
def parseCode(parent):
if 0x3000000 <= parent.root.getVersion():
yield UInt32(parent, "arg_count", "Argument count")
yield UInt32(parent, "kwonlyargcount", "Keyword only argument count")
yield UInt32(parent, "nb_locals", "Number of local variables")
yield UInt32(parent, "stack_size", "Stack size")
yield UInt32(parent, "flags")
elif 0x2030000 <= parent.root.getVersion():
yield UInt32(parent, "arg_count", "Argument count")
yield UInt32(parent, "nb_locals", "Number of local variables")
yield UInt32(parent, "stack_size", "Stack size")
yield UInt32(parent, "flags")
else:
yield UInt16(parent, "arg_count", "Argument count")
yield UInt16(parent, "nb_locals", "Number of local variables")
yield UInt16(parent, "stack_size", "Stack size")
yield UInt16(parent, "flags")
yield Object(parent, "compiled_code")
yield Object(parent, "consts")
yield Object(parent, "names")
yield Object(parent, "varnames")
if 0x2000000 <= parent.root.getVersion():
yield Object(parent, "freevars")
yield Object(parent, "cellvars")
yield Object(parent, "filename")
yield Object(parent, "name")
if 0x2030000 <= parent.root.getVersion():
yield UInt32(parent, "firstlineno", "First line number")
else:
yield UInt16(parent, "firstlineno", "First line number")
yield Object(parent, "lnotab")
class Object(FieldSet):
bytecode_info = {
# Don't contains any data
'0': ("null", None, "NULL", None),
'N': ("none", None, "None", None),
'F': ("false", None, "False", None),
'T': ("true", None, "True", None),
'S': ("stop_iter", None, "StopIter", None),
'.': ("ellipsis", None, "ELLIPSIS", None),
'?': ("unknown", None, "Unknown", None),
'i': ("int32", parseInt32, "Int32", None),
'I': ("int64", parseInt64, "Int64", None),
'f': ("float", parseFloat, "Float", None),
'g': ("bin_float", parseBinaryFloat, "Binary float", None),
'x': ("complex", parseComplex, "Complex", None),
'y': ("bin_complex", parseBinaryComplex, "Binary complex", None),
'l': ("long", parseLong, "Long", None),
's': ("string", parseString, "String", None),
't': ("interned", parseString, "Interned", None),
'u': ("unicode", parseString, "Unicode", None),
'R': ("string_ref", parseStringRef, "String ref", createStringRefDesc),
'(': ("tuple", parseTuple, "Tuple", createTupleDesc),
'[': ("list", parseTuple, "List", createTupleDesc),
'<': ("set", parseTuple, "Set", createTupleDesc),
'>': ("frozenset", parseTuple, "Frozen set", createTupleDesc),
'{': ("dict", parseDict, "Dict", createDictDesc),
'c': ("code", parseCode, "Code", None),
}
def __init__(self, parent, name, **kw):
FieldSet.__init__(self, parent, name, **kw)
code = self["bytecode"].value
if code not in self.bytecode_info:
raise ParserError('Unknown bytecode: "%s"' % code)
self.code_info = self.bytecode_info[code]
if not name:
self._name = self.code_info[0]
if code == "l":
self.createValue = self.createValueLong
elif code in ("i", "I", "f", "g"):
self.createValue = lambda: self["value"].value
elif code == "T":
self.createValue = lambda: True
elif code == "F":
self.createValue = lambda: False
elif code in ("x", "y"):
self.createValue = self.createValueComplex
elif code in ("s", "t", "u"):
self.createValue = self.createValueString
self.createDisplay = self.createDisplayString
if code == 't':
if not hasattr(self.root,'string_table'):
self.root.string_table=[]
self.root.string_table.append(self)
elif code == 'R':
if hasattr(self.root,'string_table'):
self.createValue = self.createValueStringRef
def createValueString(self):
if "text" in self:
return self["text"].value
else:
return ""
def createDisplayString(self):
if "text" in self:
return self["text"].display
else:
return "(empty)"
def createValueLong(self):
is_negative = self["digit_count"].value < 0
count = abs(self["digit_count"].value)
total = 0
for index in xrange(count-1, -1, -1):
total <<= 15
total += self["digit[%u]" % index].value
if is_negative:
total = -total
return total
def createValueStringRef(self):
return self.root.string_table[self['ref'].value].value
def createDisplayStringRef(self):
return self.root.string_table[self['ref'].value].display
def createValueComplex(self):
return complex(
float(self["real"].value),
float(self["complex"].value))
def createFields(self):
yield Character(self, "bytecode", "Bytecode")
parser = self.code_info[1]
if parser:
for field in parser(self):
yield field
def createDescription(self):
create = self.code_info[3]
if create:
return create(self)
else:
return self.code_info[2]
class PythonCompiledFile(Parser):
PARSER_TAGS = {
"id": "python",
"category": "program",
"file_ext": ("pyc", "pyo"),
"min_size": 9*8,
"description": "Compiled Python script (.pyc/.pyo files)"
}
endian = LITTLE_ENDIAN
# Dictionnary which associate the pyc signature (32-bit integer)
# to a Python version string (eg. "m\xf2\r\n" => "Python 2.4b1").
# This list comes from CPython source code, see "MAGIC"
# and "pyc_magic" in file Python/import.c
MAGIC = {
# Python 1.x
20121: ("1.5", 0x1050000),
# Python 2.x
50823: ("2.0", 0x2000000),
60202: ("2.1", 0x2010000),
60717: ("2.2", 0x2020000),
62011: ("2.3a0", 0x2030000),
62021: ("2.3a0", 0x2030000),
62041: ("2.4a0", 0x2040000),
62051: ("2.4a3", 0x2040000),
62061: ("2.4b1", 0x2040000),
62071: ("2.5a0", 0x2050000),
62081: ("2.5a0 (ast-branch)", 0x2050000),
62091: ("2.5a0 (with)", 0x2050000),
62092: ("2.5a0 (WITH_CLEANUP opcode)", 0x2050000),
62101: ("2.5b3", 0x2050000),
62111: ("2.5b3", 0x2050000),
62121: ("2.5c1", 0x2050000),
62131: ("2.5c2", 0x2050000),
# Python 3.x
3000: ("3.0 (3000)", 0x3000000),
3010: ("3.0 (3010)", 0x3000000),
3020: ("3.0 (3020)", 0x3000000),
3030: ("3.0 (3030)", 0x3000000),
3040: ("3.0 (3040)", 0x3000000),
3050: ("3.0 (3050)", 0x3000000),
3060: ("3.0 (3060)", 0x3000000),
3070: ("3.0 (3070)", 0x3000000),
3080: ("3.0 (3080)", 0x3000000),
3090: ("3.0 (3090)", 0x3000000),
3100: ("3.0 (3100)", 0x3000000),
3102: ("3.0 (3102)", 0x3000000),
3110: ("3.0a4", 0x3000000),
3130: ("3.0a5", 0x3000000),
3131: ("3.0a5 unicode", 0x3000000),
}
# Dictionnary which associate the pyc signature (4-byte long string)
# to a Python version string (eg. "m\xf2\r\n" => "2.4b1")
STR_MAGIC = dict( \
(long2raw(magic | (ord('\r')<<16) | (ord('\n')<<24), LITTLE_ENDIAN), value[0]) \
for magic, value in MAGIC.iteritems())
def validate(self):
signature = self.stream.readBits(0, 16, self.endian)
if signature not in self.MAGIC:
return "Unknown version (%s)" % signature
if self.stream.readBytes(2*8, 2) != "\r\n":
return r"Wrong signature (\r\n)"
if self.stream.readBytes(8*8, 1) != 'c':
return "First object bytecode is not code"
return True
def getVersion(self):
if not hasattr(self, "version"):
signature = self.stream.readBits(0, 16, self.endian)
self.version = self.MAGIC[signature][1]
return self.version
def createFields(self):
yield Enum(Bytes(self, "signature", 4, "Python file signature and version"), self.STR_MAGIC)
yield TimestampUnix32(self, "timestamp", "Timestamp")
yield Object(self, "content")