""" SWF (Macromedia/Adobe Flash) file parser. Documentation: - Alexis' SWF Reference: http://www.m2osw.com/swf_alexref.html - Tamarin ABC format: http://www.m2osw.com/abc_format.html Authors: Sebastien Ponce, Robert Xiao Creation date: 26 April 2008 """ from hachoir_parser import Parser from hachoir_core.field import (FieldSet, ParserError, Bit, Bits, UInt8, UInt32, Int16, UInt16, Float32, Float64, CString, Enum, Bytes, RawBytes, NullBits, String, SubFile, Field) from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN from hachoir_core.field.float import FloatExponent from struct import unpack class FlashPackedInteger(Bits): def __init__(self, parent, name, signed=False, nbits=30, description=None): Bits.__init__(self, parent, name, 8, description) stream = self._parent.stream addr = self.absolute_address size = 0 value = 0 mult = 1 while True: byte = stream.readBits(addr+size, 8, LITTLE_ENDIAN) value += mult * (byte & 0x7f) size += 8 mult <<= 7 if byte < 128: break self._size = size if signed and (1 << (nbits-1)) <= value: value -= (1 << nbits) self.createValue = lambda: value class FlashU30(FlashPackedInteger): def __init__(self, parent, name, description=None): FlashPackedInteger.__init__(self, parent, name, signed=False, nbits=30, description=description) class FlashS32(FlashPackedInteger): def __init__(self, parent, name, description=None): FlashPackedInteger.__init__(self, parent, name, signed=True, nbits=32, description=description) class FlashU32(FlashPackedInteger): def __init__(self, parent, name, description=None): FlashPackedInteger.__init__(self, parent, name, signed=False, nbits=32, description=description) class FlashFloat64(FieldSet): def createFields(self): yield Bits(self, "mantissa_high", 20) yield FloatExponent(self, "exponent", 11) yield Bit(self, "negative") yield Bits(self, "mantissa_low", 32) def createValue(self): # Manual computation: # mantissa = mantissa_high * 2^32 + mantissa_low # float = 2^exponent + (1 + mantissa / 2^52) # (and float is negative if negative=True) bytes = self.parent.stream.readBytes( self.absolute_address, self.size//8) # Mix bytes: xxxxyyyy <=> yyyyxxxx bytes = bytes[4:8] + bytes[0:4] return unpack('" def createValue(self): if "data" in self: return self["data"].value else: return "" class ABCConstantNamespace(FieldSet): NAMESPACE_KIND = {8: "Namespace", 5: "PrivateNamespace", 22: "PackageNamespace", 23: "PacakgeInternalNamespace", 24: "ProtectedNamespace", 25: "ExplicitNamespace", 26: "MultinameL"} def createFields(self): yield Enum(UInt8(self, "kind"), self.NAMESPACE_KIND) yield ABCStringIndex(self, "name_index") def createDisplay(self): return "%s %s"%(self["kind"].display, self["name_index"].display) def createValue(self): return self["name_index"].value class ABCConstantNamespaceSet(FieldSet): def createFields(self): ctr = FlashU30(self, "namespace_count") yield ctr for i in xrange(ctr.value): yield ABCNSIndex(self, "namespace_index[]") def createDescription(self): ret = [fld.display for fld in self.array("namespace_index")] return ', '.join(ret) class ABCConstantMultiname(FieldSet): MULTINAME_KIND = {7: "Qname", 13: "QnameA", 9: "Multiname", 14: "MultinameA", 15: "RTQname", 16: "RTQnameA", 27: "MultinameL", 17: "RTQnameL", 18: "RTQnameLA"} def createFields(self): yield Enum(UInt8(self, "kind"), self.MULTINAME_KIND) kind = self["kind"].value if kind in (7,13): # Qname yield FlashU30(self, "namespace_index") yield ABCStringIndex(self, "name_index") elif kind in (9,14): # Multiname yield ABCStringIndex(self, "name_index") yield FlashU30(self, "namespace_set_index") elif kind in (15,16): # RTQname yield ABCStringIndex(self, "name_index") elif kind == 27: # MultinameL yield FlashU30(self, "namespace_set_index") elif kind in (17,18): # RTQnameL pass def createDisplay(self): kind = self["kind"].display if "name_index" in self: return kind + " " + self["name_index"].display return kind def createValue(self): return self["kind"].value class ABCTrait(FieldSet): TRAIT_KIND = {0: "slot", 1: "method", 2: "getter", 3: "setter", 4: "class", 5: "function", 6: "const",} def createFields(self): yield ABCMultinameIndex(self, "name_index") yield Enum(Bits(self, "kind", 4), self.TRAIT_KIND) yield Enum(Bit(self, "is_final"), {True:'final',False:'virtual'}) yield Enum(Bit(self, "is_override"), {True:'override',False:'new'}) yield Bit(self, "has_metadata") yield Bits(self, "unused", 1) kind = self["kind"].value if kind in (0,6): # slot, const yield FlashU30(self, "slot_id") yield ABCMultinameIndex(self, "type_index") ### TODO reference appropriate constant pool using value_kind yield FlashU30(self, "value_index") if self['value_index'].value != 0: yield UInt8(self, "value_kind") elif kind in (1,2,3): # method, getter, setter yield FlashU30(self, "disp_id") yield ABCMethodIndex(self, "method_info") elif kind == 4: # class yield FlashU30(self, "disp_id") yield FlashU30(self, "class_info") elif kind == 5: # function yield FlashU30(self, "disp_id") yield ABCMethodIndex(self, "method_info") if self['has_metadata'].value: yield ABCObjectArray(self, "metadata", FlashU30) class ABCValueKind(FieldSet): def createFields(self): yield FlashU30(self, "value_index") yield UInt8(self, "value_kind") class ABCMethodInfo(FieldSet): def createFields(self): yield FlashU30(self, "param_count") yield ABCMultinameIndex(self, "ret_type") for i in xrange(self["param_count"].value): yield ABCMultinameIndex(self, "param_type[]") yield ABCStringIndex(self, "name_index") yield Bit(self, "need_arguments") yield Bit(self, "need_activation") yield Bit(self, "need_rest") yield Bit(self, "has_optional") yield Bit(self, "ignore_rest") yield Bit(self, "explicit") yield Bit(self, "setsdxns") yield Bit(self, "has_paramnames") if self["has_optional"].value: yield ABCObjectArray(self, "optional", ABCValueKind) if self["has_paramnames"].value: for i in xrange(self["param_count"].value): yield FlashU30(self, "param_name[]") def createDescription(self): ret = GetMultiname(self, self["ret_type"].value) ret += " " + self["name_index"].display ret += "(" + ", ".join(GetMultiname(self, fld.value) for fld in self.array("param_type")) + ")" return ret class ABCMetadataInfo(FieldSet): def createFields(self): yield ABCStringIndex(self, "name_index") yield FlashU30(self, "values_count") count = self["values_count"].value for i in xrange(count): yield FlashU30(self, "key[]") for i in xrange(count): yield FlashU30(self, "value[]") class ABCInstanceInfo(FieldSet): def createFields(self): yield ABCMultinameIndex(self, "name_index") yield ABCMultinameIndex(self, "super_index") yield Bit(self, "is_sealed") yield Bit(self, "is_final") yield Bit(self, "is_interface") yield Bit(self, "is_protected") yield Bits(self, "unused", 4) if self['is_protected'].value: yield ABCNSIndex(self, "protectedNS") yield FlashU30(self, "interfaces_count") for i in xrange(self["interfaces_count"].value): yield ABCMultinameIndex(self, "interface[]") yield ABCMethodIndex(self, "iinit_index") yield ABCObjectArray(self, "trait", ABCTrait) class ABCClassInfo(FieldSet): def createFields(self): yield ABCMethodIndex(self, "cinit_index") yield ABCObjectArray(self, "trait", ABCTrait) class ABCScriptInfo(FieldSet): def createFields(self): yield ABCMethodIndex(self, "init_index") yield ABCObjectArray(self, "trait", ABCTrait) class ABCException(FieldSet): def createFields(self): yield FlashU30(self, "start") yield FlashU30(self, "end") yield FlashU30(self, "target") yield FlashU30(self, "type_index") yield FlashU30(self, "name_index") class ABCMethodBody(FieldSet): def createFields(self): yield ABCMethodIndex(self, "method_info") yield FlashU30(self, "max_stack") yield FlashU30(self, "max_regs") yield FlashU30(self, "scope_depth") yield FlashU30(self, "max_scope") yield FlashU30(self, "code_length") yield RawBytes(self, "code", self['code_length'].value) yield ABCObjectArray(self, "exception", ABCException) yield ABCObjectArray(self, "trait", ABCTrait) def parseABC(parent, size): code = parent["code"].value if code == parent.TAG_DO_ABC_DEFINE: yield UInt32(parent, "action_flags") yield CString(parent, "action_name") yield UInt16(parent, "minor_version") yield UInt16(parent, "major_version") parent.isABC = True yield ABCConstantPool(parent, "int", FlashS32) yield ABCConstantPool(parent, "uint", FlashU32) yield ABCConstantPool(parent, "double", Float64) yield ABCConstantPool(parent, "string", ABCConstantString) yield ABCConstantPool(parent, "namespace", ABCConstantNamespace) yield ABCConstantPool(parent, "namespace_set", ABCConstantNamespaceSet) yield ABCConstantPool(parent, "multiname", ABCConstantMultiname) yield ABCObjectArray(parent, "method", ABCMethodInfo) yield ABCObjectArray(parent, "metadata", ABCMetadataInfo) yield ABCClassArray(parent, "class") yield ABCObjectArray(parent, "script", ABCScriptInfo) yield ABCObjectArray(parent, "body", ABCMethodBody)