//------------------------------------------------ //--- 010 Editor v3.0 Binary Template // // File: SWF.bt // Authors: Josh Zelonis, JPEXS // E-mail: zelonis@gmail.com // Version: 2.0 // Purpose: Defines a template for parsing Adobe Flash SWF files // based on the file format specification for Flash 9. // Category: Internet // File Mask: *.swf // ID Bytes: 43 57 53, 46 57 53, 5A 57 53 //CWS, FWS, ZWS // History: // 2.0 2023-03-10 JPEXS: AS3 bytecode (ABC) support, DefineSprite inner tags, MorphShape fix, Text tags, LZMA compressed SWF, various new added tags and fixes // 1.4 2023-03-07 JPEXS: GradientMatrix for FOCALGRADIENT fill style, FILTER.FilterId is ubyte, not ushort // 1.3 2016-01-30 SweetScape: Updated header for repository submission. // 1.2 TQN: Add code to check CWS file. // 1.1 J Zelonis: Updated email address. // 1.0 J Zelonis: Initial release. // //------------------------------------------------ /*************** * Action Tags * ***************/ local quad ActionTagEnd = 0; local byte isCompressed = 0; typedef struct { ubyte Register; string ParamName; } REGISTERPARAM; typedef struct { string value; } CONSTANTPOOL; typedef struct { string value; } PARAMS; typedef struct { ubyte Type; switch (Type) { case 0: string String; break; case 1: float Float; break; case 4: ubyte RegisterNumber; break; case 5: ubyte Boolean; break; case 6: double Double; break; case 7: int Integer; break; case 8: ubyte Constant8; break; case 9: ushort Constant16; break; default: Warning("Unexpected Value detected."); } } TYPECONST; typedef struct { local int i; ubyte ActionCode; if (ActionCode >=0x80) { ushort Length; ActionTagEnd = FTell() + Length; } switch (ActionCode) { /************************ * SWF 3 Action Model * ************************/ case 0x81: /* ActionGotoFrame */ if (Length != 2) { Warning("ActionGotoFrame: Length must be 2."); } ushort Frame; break; case 0x83: /* ActionGetURL */ string UrlString; string TargetString; break; case 0x04: /* ActionNextFrame */ case 0x05: /* ActionPreviousFrame */ case 0x06: /* ActionPlay */ case 0x07: /* ActionStop */ case 0x08: /* ActionToggleQuality */ case 0x09: /* ActionStopSounds */ break; case 0x8a: /* ActionWaitForFrame */ if (Length != 3) { Warning("ActionWaitForFrame: Length must be 3."); } ushort Frame; ubyte SkipCount; break; case 0x8b: /* ActionSetTarget */ string TargetName; break; case 0x8c: /* ActionGoToLabel */ string Label; break; /************************ * SWF 4 Action Model * ************************/ case 0x96: /* ActionPush */ do { TYPECONST TypeConst; } while (FTell() < ActionTagEnd); break; case 0x17: /* ActionPop */ case 0x0a: /* ActionAdd */ case 0x0b: /* ActionSubtract */ case 0x0c: /* ActionMultiply */ case 0x0d: /* ActionDivide */ case 0x0e: /* ActionEquals */ case 0x0f: /* ActionLess */ case 0x10: /* ActionAnd */ case 0x11: /* ActionOr */ case 0x12: /* ActionNot */ case 0x13: /* ActionStringEquals */ case 0x14: /* ActionStringLength */ case 0x21: /* ActionStringAdd */ case 0x15: /* ActionStringExtract */ case 0x29: /* ActionStringLess */ case 0x31: /* ActionMBStringLength */ case 0x35: /* ActionMBStringExtract */ case 0x18: /* ActionToInteger */ case 0x32: /* ActionCharToAscii */ case 0x33: /* ActionAsciiToChar */ case 0x36: /* ActionMBCharToAscii */ case 0x37: /* ActionMBAsciiToChar */ break; case 0x99: /* ActionJump */ short BranchOffset; break; case 0x9d: /* ActionIf */ short BranchOffset; break; case 0x9e: /* ActionCall */ case 0x1c: /* ActionGetVariable */ case 0x1d: /* ActionSetVariable */ break; case 0x9a: /* ActionGetURL2 */ ubyte SendVarsMethod : 2; ubyte Reserved : 4; ubyte LoadTargetFlag : 1; ubyte LoadVariablesFlag : 1; break; case 0x9f: /* ActionGotoFrame2 */ ubyte Reserved : 6; ubyte SceneBiasFlag : 1; ubyte PlayFlag : 1; if (SceneBiasFlag == 1) { ushort SceneBias; } break; case 0x20: /* ActionSetTarget2 */ case 0x22: /* ActionGetProperty */ case 0x23: /* ActionSetProperty */ case 0x24: /* ActionCloneSprite */ case 0x25: /* ActionRemoveSprite */ case 0x27: /* ActionStartDrag */ case 0x28: /* ActionEndDrag */ break; case 0x8d: /* ActionWaitForFrame2 */ ubyte SkipCount; break; case 0x26: /* ActionTrace */ case 0x34: /* ActionGetTime */ case 0x30: /* ActionRandomNumber */ break; /************************ * SWF 5 Action Model * ************************/ case 0x3d: /* ActionCallFunction */ case 0x52: /* ActionCallMethod */ break; case 0x88: /* ActionConstantPool */ ushort Count; for (i=0; i=0x80) { ubyte Padding[ActionTagEnd - FTell()]; } break; } /***************************************** * This is a fixup for files that aren't * parsing correctly. This may be due to * my code, obfuscation techniques or * other unknown circumstances. *****************************************/ if (ActionCode>=0x80) { if (ActionTagEnd>FTell()) { ubyte Padding[ActionTagEnd-FTell()]; Printf("WARNING: ActionTag padded to 0x%LXh\n", FTell()); } else if (ActionTagEnd; string GetActionType(ACTIONRECORD &ActionTag) { string action; ubyte ActionType = ActionTag.ActionCode; switch (ActionType) { case 0x81: return "ActionGotoFrame"; case 0x83: return "ActionGetURL"; case 0x04: return "ActionNextFrame"; case 0x05: return "ActionPreviousFrame"; case 0x06: return "ActionPlay"; case 0x07: return "ActionStop"; case 0x08: return "ActionToggleQuality"; case 0x09: return "ActionStopSounds"; case 0x8a: return "ActionWaitForFrame"; case 0x8b: return "ActionSetTarget"; case 0x8c: return "ActionGoToLabel"; case 0x96: return "ActionPush"; case 0x17: return "ActionPop"; case 0x0a: return "ActionAdd"; case 0x0b: return "ActionSubtract"; case 0x0c: return "ActionMultiply"; case 0x0d: return "ActionDivide"; case 0x0e: return "ActionEquals"; case 0x0f: return "ActionLess"; case 0x10: return "ActionAnd"; case 0x11: return "ActionOr"; case 0x12: return "ActionNot"; case 0x13: return "ActionStringEquals"; case 0x14: return "ActionStringLength"; case 0x21: return "ActionStringAdd"; case 0x15: return "ActionStringExtract"; case 0x29: return "ActionStringLess"; case 0x31: return "ActionMBStringLength"; case 0x35: return "ActionMBStringExtract"; case 0x18: return "ActionToInteger"; case 0x32: return "ActionCharToAscii"; case 0x33: return "ActionAsciiToChar"; case 0x36: return "ActionMBCharToAscii"; case 0x37: return "ActionMBAsciiToChar"; case 0x99: return "ActionJump"; case 0x9d: return "ActionIf"; case 0x9e: return "ActionCall"; case 0x1c: return "ActionGetVariable"; case 0x1d: return "ActionSetVariable"; case 0x9a: return "ActionGetURL2"; case 0x9f: return "ActionGotoFrame2"; case 0x20: return "ActionSetTarget2"; case 0x22: return "ActionGetProperty"; case 0x23: return "ActionSetProperty"; case 0x24: return "ActionCloneSprite"; case 0x25: return "ActionRemoveSprite"; case 0x27: return "ActionStartDrag"; case 0x28: return "ActionEndDrag"; case 0x8d: return "ActionWaitForFrame2"; case 0x26: return "ActionTrace"; case 0x34: return "ActionGetTime"; case 0x30: return "ActionRandomNumber"; case 0x3d: return "ActionCallFunction"; case 0x52: return "ActionCallMethod"; case 0x88: return "ActionConstantPool"; case 0x9b: return "ActionDefineFunction"; case 0x3c: return "ActionDefineLocal"; case 0x41: return "ActionDefineLocal2"; case 0x3a: return "ActionDelete"; case 0x3b: return "ActionDelete2"; case 0x46: return "ActionEnumerate"; case 0x49: return "ActionEquals2"; case 0x4e: return "ActionGetMember"; case 0x42: return "ActionInitArray"; case 0x43: return "ActionInitObject"; case 0x53: return "ActionNewMethod"; case 0x40: return "ActionNewObject"; case 0x4f: return "ActionSetMember"; case 0x45: return "ActionTargetPath"; case 0x94: return "ActionWith"; case 0x4a: return "ActionToNumber"; case 0x4b: return "ActionToString"; case 0x44: return "ActionTypeOf"; case 0x47: return "ActionAdd2"; case 0x48: return "ActionLess2"; case 0x3f: return "ActionModulo"; case 0x60: return "ActionBitAnd"; case 0x63: return "ActionBitLShift"; case 0x61: return "ActionBitOr"; case 0x64: return "ActionBitRShift"; case 0x65: return "ActionBitURShift"; case 0x62: return "ActionBitXor"; case 0x51: return "ActionDecrement"; case 0x50: return "ActionIncrement"; case 0x4c: return "ActionPushDuplicate"; case 0x3e: return "ActionReturn"; case 0x4d: return "ActionStackSwap"; case 0x87: return "ActionStoreRegister"; case 0x55: return "ActionEnumerate2"; case 0x66: return "ActionStrictEquals"; case 0x67: return "ActionGreater"; case 0x68: return "ActionStringGreater"; case 0x8e: return "ActionDefineFunction2"; case 0x69: return "ActionExtends"; case 0x2b: return "ActionCastOp"; case 0x2c: return "ActionImplementsOp"; case 0x8f: return "ActionTry"; case 0x2a: return "ActionThrow"; case 0x00: return "END"; default: SPrintf(action, "%02Xh", ActionType); } return action; } /************** * Data Types * **************/ local quad SWFTagEnd; local ushort CurrentTag; typedef struct { byte value; } SI8; typedef struct { short value; } SI16; typedef struct { int value; } SI32; typedef struct { ubyte value; } UI8; typedef struct { ushort value; } UI16; typedef struct { uint value; } UI32; typedef struct { quad value; } UI64; typedef struct { int whole : 16; int decimal : 16; } FIXED; typedef struct { short whole : 8; short decimal : 8; } FIXED8; typedef struct { ushort sign : 1; ushort exponent : 5; ushort mantissa : 10; } FLOAT16; typedef struct { BigEndian(); local uint value = 0; local uint i=0; do { ubyte next : 1; ubyte valuePart : 7; value = value | ((uint)valuePart << (i * 7)); i++; } while (i<5 & next); } EncodedU32 ; typedef struct { do { char character; } while (character != 0x00); } STRING; typedef struct { ubyte LanguageCode; } LANGCODE; typedef struct { ubyte Red; ubyte Green; ubyte Blue; } RGB; typedef struct { ubyte Red; ubyte Green; ubyte Blue; ubyte Alpha; } RGBA; typedef struct { ubyte Alpha; ubyte Red; ubyte Green; ubyte Blue; } ARGB; /*********************************************** * The min values in this are going to look * wrong because there isn't any pretty way * for 010 to print an Nbits-bit signed number. * The key is that the max values match expected * values and because there isn't any variation * on how the numbers are being calculated and * no bit padding, we can assume these are * correct. ***********************************************/ typedef struct { ubyte Nbits : 5; BitfieldDisablePadding(); int Xmin : Nbits; int Xmax : Nbits; int Ymin : Nbits; int Ymax : Nbits; BitfieldEnablePadding(); } RECT; typedef struct { BitfieldEnablePadding(); BitfieldLeftToRight(); ubyte HasScale : 1; if (HasScale) { ubyte NScaleBits : 5; BitfieldDisablePadding(); int ScaleX : NScaleBits; int ScaleY : NScaleBits; } ubyte HasRotate : 1; if (HasRotate) { ubyte NRotateBits : 5; BitfieldDisablePadding(); int RotateSkew0 : NRotateBits; int RotateSkew1 : NRotateBits; } ubyte NTranslateBits : 5; BitfieldDisablePadding(); int TranslateX : NTranslateBits; int TranslateY : NTranslateBits; BitfieldEnablePadding(); } MATRIX; typedef struct { ushort Tag; string Name; } ASSETS; typedef struct { EncodedU32 Offset; string Name; } OFFSETANDNAME; typedef struct { BitfieldEnablePadding(); ubyte HasAddTerms : 1; ubyte HasMultTerms : 1; ubyte Nbits : 4; BitfieldDisablePadding(); if (HasMultTerms) { short RedMultTerm : Nbits; short GreenMultTerm : Nbits; short BlueMultTerm : Nbits; } if (HasAddTerms) { short RedAddTerm : Nbits; short GreenAddTerm : Nbits; short BlueAddTerm : Nbits; } BitfieldEnablePadding(); } CXFORM; typedef struct { BitfieldEnablePadding(); ubyte HasAddTerms : 1; ubyte HasMultTerms : 1; ubyte Nbits : 4; BitfieldDisablePadding(); if (HasMultTerms) { short RedMultTerm : Nbits; short GreenMultTerm : Nbits; short BlueMultTerm : Nbits; short AlphaMultTerm : Nbits; } if (HasAddTerms) { short RedAddTerm : Nbits; short GreenAddTerm : Nbits; short BlueAddTerm : Nbits; short AlphaAddTerm : Nbits; } BitfieldEnablePadding(); } CXFORMWITHALPHA; typedef struct { ushort ClipEventKeyUp : 1; ushort ClipEventKeyDown : 1; ushort ClipEventMouseUp : 1; ushort ClipEventMouseDown : 1; ushort ClipEventMouseMove : 1; ushort ClipEventUnload : 1; ushort ClipEventEnterFrame : 1; ushort ClipEventLoad : 1; ushort ClipEventDragOver : 1; ushort ClipEventRollOut : 1; ushort ClipEventRollOver : 1; ushort ClipEventReleaseOutside : 1; ushort ClipEventRelease : 1; ushort ClipEventPress : 1; ushort ClipEventInitialize : 1; ushort ClipEventData : 1; if (File.Header.Version >= 6) { ushort Reserved : 5; ushort ClipEventConstruct : 1; ushort ClipEventKeyPress : 1; ushort ClipEventDragout : 1; ushort Reserved : 8; } } CLIPEVENTFLAGS; typedef struct { CLIPEVENTFLAGS EventFlags; uint ActionRecordSize; if ((File.Header.Version>5) && EventFlags.ClipEventKeyPress) { ubyte KeyCode; } do { ACTIONRECORD Action; } while (Action.ActionCode!=0x00); } CLIPACTIONRECORD; typedef struct { local uint clips; ushort Reserved; CLIPEVENTFLAGS AllEventFlags; do { CLIPACTIONRECORD ClipActionRecord; } while ((SWFTagEnd-FTell())>9); /* min bytes in CLIPACTIONRECORD */ if (File.Header.Version>5) { uint ClipActionEndFlag; } else { ushort ClipActionEndFlag; } } CLIPACTIONS; typedef struct { float Matrix[20]; } COLORMATRIXFILTER; typedef struct { ubyte MatrixX; ubyte MatrixY; float Divisor; float Bias; float Matrix[MatrixX * MatrixY]; RGBA DefaultColor; ubyte Reserved : 6; ubyte Clamp : 1; ubyte PreserveAlpha : 1; } CONVOLUTIONFILTER; typedef struct { FIXED BlurX; FIXED BlurY; ubyte Passes : 5; ubyte Reserved : 3; } BLURFILTER; typedef struct { RGBA DropShadowColor; FIXED BlurX; FIXED BlurY; FIXED Angle; FIXED Distance; FIXED8 Strength; ubyte InnerShadow : 1; ubyte Knockout : 1; ubyte CompositeSource : 1; ubyte Passes : 5; } DROPSHADOWFILTER; typedef struct { RGBA GlowColor; FIXED BlurX; FIXED BlurY; FIXED8 Strength; ubyte InnerShadow : 1; ubyte Knockout : 1; ubyte CompositeSource : 1; ubyte Passes : 5; } GLOWFILTER; typedef struct { RGBA ShadowColor; RGBA HighlightColor; FIXED BlurX; FIXED BlurY; FIXED Angle; FIXED Distance; FIXED8 Strength; ubyte InnerShadow : 1; ubyte Knockout : 1; ubyte CompositeSource : 1; ubyte OnTop : 1; ubyte Passes : 4; } BEVELFILTER; typedef struct { ubyte Ratio; if ((CurrentTag == 2) /* DefineShape */ || (CurrentTag == 22)) { /* DefineShape2 */ RGB Color; } else { /* DefineShape3 or DefineShape4 */ RGBA Color; } } GRADRECORD; typedef struct { local short i; ubyte SpreadMode : 2; ubyte InterpolationMode : 2; ubyte NumGradients : 4; for (i=0; i; string GetFillStyleType(ubyte fillStyleType) { switch (fillStyleType) { case 0x00: return "solid fill"; case 0x10: return "linear gradient fill"; case 0x12: return "radial gradient fill"; case 0x13: return "focal radial gradient fill"; case 0x40: return "repeating bitmap fill"; case 0x41: return "clipped bitmap fill"; case 0x42: return "non-smoothed repeating bitmap fill"; case 0x43: return "non-smoothed clipped bitmap fill"; default: return Str("unknown0x%02X", fillStyleType); } } typedef struct { local ushort i; ubyte FillStyleCount; if (FillStyleCount == 0xff) { UI16 FillStyleCountExtended; for (i=0; i; string GetShapeRecordType(SHAPERECORD &ShapeRecord) { if (ShapeRecord.TypeFlag) { if (ShapeRecord.StraightFlag) { return "StraightEdgeRecord"; } else { return "CurvedEdgeRecord"; } } else if (ShapeRecord.TypeFlag || ShapeRecord.StateNewStyles || ShapeRecord.StateLineStyle || ShapeRecord.StateFillStyle1 || ShapeRecord.StateFillStyle0 || ShapeRecord.StateMoveTo) { return "StyleChangeRecord"; } else { return "EndShapeRecord"; } } typedef struct { BitfieldEnablePadding(); ubyte NumFillBits : 4; ubyte NumLineBits : 4; local ubyte FillBits = NumFillBits; local ubyte LineBits = NumLineBits; BitfieldDisablePadding(); do { SHAPERECORD ShapeRecord; } while (ShapeRecord.TypeFlag || ShapeRecord.StateNewStyles || ShapeRecord.StateLineStyle || ShapeRecord.StateFillStyle1 || ShapeRecord.StateFillStyle0 || ShapeRecord.StateMoveTo); BitfieldEnablePadding(); } SHAPE; typedef struct { BitfieldEnablePadding(); FILLSTYLEARRAY FillStyles; LINESTYLEARRAY LineStyles; ubyte NumFillBits : 4; ubyte NumLineBits : 4; local ubyte FillBits = NumFillBits; local ubyte LineBits = NumLineBits; BitfieldDisablePadding(); do { SHAPERECORD ShapeRecord; } while (ShapeRecord.TypeFlag || ShapeRecord.StateNewStyles || ShapeRecord.StateLineStyle || ShapeRecord.StateFillStyle1 || ShapeRecord.StateFillStyle0 || ShapeRecord.StateMoveTo); BitfieldEnablePadding(); } SHAPEWITHSTYLE; typedef struct { ubyte StartRatio; RGBA StartColor; ubyte EndRatio; RGBA EndColor; } MORPHGRADRECORD; typedef struct { // Despite of documentation (UI8 1-8), there are two fields // spreadMode and interPolationMode which are same as in GRADIENT local short i; ubyte SpreadMode : 2; ubyte InterpolationMode : 2; ubyte NumGradients : 4; for (i=0; i; typedef struct { ushort StartWidth; ushort EndWidth; ubyte StartCapStyle : 2; ubyte JoinStyle : 2; ubyte HasFillFlag : 1; ubyte NoHScaleFlag : 1; ubyte NoVScaleFlag : 1; ubyte PixelHintingFlag : 1; ubyte NoClose : 1; ubyte EndCapStyle : 2; if (JoinStyle == 2) { ushort MiterLimitFactor; } if (HasFillFlag == 0) { RGBA StartColor; RGBA EndColor; } else { MORPHFILLSTYLE FillType; } } MORPHLINESTYLE2; typedef struct { ushort StartWidth; ushort EndWidth; RGBA StartColor; RGBA EndColor; } MORPHLINESTYLE; typedef struct { ubyte LineStyleCount; if (LineStyleCount == 0xff) { ushort LineStyleCountExtended; for (i=0; i; BitfieldEnablePadding(); } } TEXTRECORD; string GetTextRecordName(TEXTRECORD &textRecord) { if (0 == textRecord.TextRecordType && 0 == textRecord.StyleFlagsReserved && 0 == textRecord.StyleFlagsHasFont && 0 == textRecord.StyleFlagsHasColor && 0 == textRecord.StyleFlagsHasYOffset && 0 == textRecord.StyleFlagsHasXOffset ) { return "struct EndOfRecordsFlag"; } return "struct TEXTRECORD TextRecords"; } /**************** * AS3 ByteCode * ****************/ typedef struct { BigEndian(); local int i=0; local uint value = 0; BitfieldDisablePadding(); do { ubyte next : 1; uint valuePart : 7; value += valuePart << (i * 7); i++; } while (i<5 & next); BitfieldEnablePadding(); } u32 ; typedef struct { BigEndian(); local int i=0; local uint value = 0; BitfieldDisablePadding(); do { ubyte next : 1; uint valuePart : 7; value += valuePart << (i * 7); i++; } while (i<5 & next); BitfieldEnablePadding(); value = value & 0x3FFFFFFF; } u30 ; typedef struct { BigEndian(); local int i=0; local uint value = 0; BitfieldDisablePadding(); do { ubyte next : 1; uint valuePart : 7; value += valuePart << (i * 7); i++; } while (i<5 & next); if ((value >> 31) == 1) { value = -(value & 0x7fffffff); } BitfieldEnablePadding(); } s32 ; typedef unsigned short u16; typedef double d64; typedef unsigned byte u8; typedef signed byte s8; typedef unsigned byte decimal[16]; typedef hfloat float4[4]; typedef struct { local int value; ubyte val1; ubyte val2; ubyte val3; value = val1 + ((uint)val2 << 8) + ((uint)val3 << 16); if ((value >> 23) == 1) { value |= 0xff000000; } } s24; local u16 abc_minor_version; local u16 abc_major_version; typedef struct { u30 size; if (size.value > 0) { char utf8[size.value]; } } string_info ; string StringInfoFunc(string_info &s) { if (s.size.value == 0) { return ""; } return s.utf8; } typedef struct { u8 kind ; u30 name; } namespace_info ; string GetNamespaceType(namespace_info &namespace) { switch (namespace.kind) { case 0x08: return "Namespace"; case 0x16: return "PackageNamespace"; case 0x17: return "PackageInternalNs"; case 0x18: return "ProtectedNamespace"; case 0x19: return "ExplicitNamespace"; case 0x1A: return "StaticProtectedNs"; case 0x05: return "PrivateNs"; default: return Str("Unknown0x%02X", namespace.kind); } } typedef struct { u30 count; u30 ns[count.value] ; } ns_set_info; typedef struct { u8 kind ; switch (kind) { case 0x07: /* QName */ case 0x0D: /* QNameA */ u30 ns; u30 name; break; case 0x0F: /* RTQName */ case 0x10: /* RTQNameA */ u30 name; break; case 0x11: /* RTQNameL */ case 0x12: /* RTQNameLA */ //no data break; case 0x09: /* Multiname */ case 0x0E: /* MultinameA */ u30 name; u30 ns_set; break; case 0x1B: /* MultinameL */ case 0x1C: /* MultinameLA */ u30 ns_set; break; case 0x1D: /* TypeName */ u30 qname; u30 params_length; u30 param[params_length.value] ; break; } } multiname_info ; string GetMultinameType(multiname_info &multiname) { switch (multiname.kind) { case 0x07: return "QName"; case 0x0D: return "QNameA"; case 0x0F: return "RTQName"; case 0x10: return "RTQNameA"; case 0x11: return "RTQNameL"; case 0x12: return "RTQNameLA"; case 0x09: return "Multiname"; case 0x0E: return "MultinameA"; case 0x1B: return "MultinameL"; case 0x1C: return "MultinameLA"; case 0x1D: return "TypeName"; default: return Str("Unknown0x%02X", multiname.kind); } } typedef struct { u30 int_count; if (int_count.value > 1) { s32 integer[int_count.value - 1] ; } u30 uint_count; if (uint_count.value > 1) { u32 uinteger[uint_count.value - 1] ; } u30 double_count; if (double_count.value > 1) { d64 double_[double_count.value - 1]; } if (abc_minor_version >= 17) { u30 decimal_count; if (decimal_count.value > 1) { decimal decimal_[decimal_count.value - 1]; } } if (abc_major_version > 47 || (abc_major_version == 47 && abc_minor_version > 16)) { u30 float_count; if (float_count.value > 1) { hfloat float_[float_count.value - 1]; } u30 float4_count; if (float4_count.value > 1) { float4 float4_[float4_count.value - 1]; } } u30 string_count; if (string_count.value > 1) { string_info string_ [string_count.value - 1] ; } u30 namespace_count; if (namespace_count.value > 1) { namespace_info namespace[namespace_count.value - 1] ; } u30 ns_set_count; if (ns_set_count.value > 1) { ns_set_info ns_set[ns_set_count.value - 1] ; } u30 multiname_count; if (multiname_count.value > 1) { multiname_info multiname[multiname_count.value - 1] ; } } cpool_info; typedef struct { u30 val; u8 kind ; } option_detail ; string GetConstantType(u8 kind) { switch (kind) { case 0x03: return "CONSTANT_Int"; case 0x04: return "CONSTANT_UInt"; case 0x06: return "CONSTANT_Double"; case 0x01: return "CONSTANT_Utf8"; case 0x0B: return "CONSTANT_True"; case 0x0A: return "CONSTANT_False"; case 0x0C: return "CONSTANT_Null"; case 0x00: return "CONSTANT_Undefined"; case 0x08: return "CONSTANT_Namespace"; case 0x16: return "CONSTANT_PackageNamespace"; case 0x17: return "CONSTANT_PackageInternalNs"; case 0x18: return "CONSTANT_ProtectedNamespace"; case 0x19: return "CONSTANT_ExplicitNamespace"; case 0x1A: return "CONSTANT_StaticProtectedNs"; case 0x05: return "CONSTANT_PrivateNs"; default: return Str("Unknown0x%02X", kind); } } typedef struct { u30 option_count; option_detail option[option_count.value] ; } option_info; typedef struct { u30 param_count; u30 return_type; if (param_count.value > 0) { u30 param_type[param_count.value] ; } u30 name; BitfieldDisablePadding(); ubyte HAS_PARAM_NAMES : 1; ubyte SET_DXNS : 1; ubyte reserved : 2; ubyte HAS_OPTIONAL : 1; ubyte NEED_REST : 1; ubyte NEED_ACTIVATION : 1; ubyte NEED_ARGUMENTS : 1; BitfieldEnablePadding(); if (HAS_OPTIONAL) { option_info options; } if (HAS_PARAM_NAMES) { struct param_info { u30 param_name[param_count.value] ; } param_names; } } method_info; typedef struct { u30 key; u30 value; } item_info; typedef struct { u30 name; u30 item_count; if (item_count.value > 0) { item_info items[item_count.value] ; } } metadata_info; typedef struct { u30 name; BitfieldDisablePadding(); ubyte reserved : 1; ubyte ATTR_Metadata : 1; ubyte ATTR_Override : 1; ubyte ATTR_Final : 1; ubyte kind_type : 4 ; BitfieldEnablePadding(); switch(kind_type) { case 0x00: /* Trait_Slot */ case 0x06: /* Trait_Const */ u30 slot_id; u30 type_name; u30 vindex; if (vindex.value != 0) { u8 vkind; } break; case 0x04: /* Trait_Class*/ u30 slot_id; u30 classi; break; case 0x05: /* Trait_Function */ u30 slot_id; u30 function; break; case 0x01: /* Trait_Method */ case 0x02: /* Trait_Getter */ case 0x03: /* Trait_Setter */ u30 disp_id; u30 method; break; } if (ATTR_Metadata) { u30 metadata_count; u30 metadata[metadata_count.value] ; } } traits_info ; string GetTraitType(traits_info &trait) { switch (trait.kind_type) { case 0x00: return "Trait_Slot"; case 0x06: return "Trait_Const"; case 0x04: return "Trait_Class"; case 0x05: return "Trait_Function"; case 0x01: return "Trait_Method"; case 0x02: return "Trait_Getter"; case 0x03: return "Trait_Setter"; default: return Str("Unknown0x%02X", trait.kind_type); } } typedef struct { u30 name; u30 super_name; BigEndian(); BitfieldDisablePadding(); ubyte reserved : 3; ubyte ClassNonNullable : 1; ubyte ClassProtectedNs : 1; ubyte ClassInterface : 1; ubyte ClassFinal : 1; ubyte ClassSealed : 1; BitfieldEnablePadding(); if (ClassProtectedNs) { u30 protectedNs; } u30 intrf_count; if (intrf_count.value > 0) { u30 interface[intrf_count.value] ; } u30 iinit; u30 trait_count; if (trait_count.value > 0) { traits_info trait[trait_count.value] ; } } instance_info; typedef struct { u30 cinit; u30 trait_count; if (trait_count.value > 0) { traits_info traits[trait_count.value] ; } } class_info; typedef struct { u30 init; u30 trait_count; if (trait_count.value > 0) { traits_info trait[trait_count.value] ; } } script_info; typedef struct { u30 from; u30 to; u30 target; u30 exc_type; u30 var_name; } exception_info; typedef struct { u8 instruction ; switch(instruction) { case 0x01: /* bkpt */ break; case 0x02: /* nop */ break; case 0x03: /* throw */ break; case 0x04: /* getsuper */ u30 index; break; case 0x05: /* setsuper */ u30 index; break; case 0x06: /* dxns */ u30 index; break; case 0x07: /* dxnslate */ break; case 0x08: /* kill */ u30 index; break; case 0x09: /* label */ break; case 0x0A: /* lf32x4 */ break; case 0x0B: /* sf32x4 */ break; case 0x0C: /* ifnlt */ s24 offset; break; case 0x0D: /* ifnle */ s24 offset; break; case 0x0E: /* ifngt */ s24 offset; break; case 0x0F: /* ifnge */ s24 offset; break; case 0x10: /* jump */ s24 offset; break; case 0x11: /* iftrue */ s24 offset; break; case 0x12: /* iffalse */ s24 offset; break; case 0x13: /* ifeq */ s24 offset; break; case 0x14: /* ifne */ s24 offset; break; case 0x15: /* iflt */ s24 offset; break; case 0x16: /* ifle */ s24 offset; break; case 0x17: /* ifgt */ s24 offset; break; case 0x18: /* ifge */ s24 offset; break; case 0x19: /* ifstricteq */ s24 offset; break; case 0x1A: /* ifstrictne */ s24 offset; break; case 0x1B: /* lookupswitch */ s24 default_offset; u30 case_count; s24 case_offset[case_count.value + 1] ; break; case 0x1C: /* pushwith */ break; case 0x1D: /* popscope */ break; case 0x1E: /* nextname */ break; case 0x1F: /* hasnext */ break; case 0x20: /* pushnull */ break; case 0x21: /* pushundefined */ break; case 0x22: /* pushconstant */ u30 value; break; case 0x23: /* nextvalue */ break; case 0x24: /* pushbyte */ s8 value; break; case 0x25: /* pushshort */ u30 value; break; case 0x26: /* pushtrue */ break; case 0x27: /* pushfalse */ break; case 0x28: /* pushnan */ break; case 0x29: /* pop */ break; case 0x2A: /* dup */ break; case 0x2B: /* swap */ break; case 0x2C: /* pushstring */ u30 value; break; case 0x2D: /* pushint */ u30 value; break; case 0x2E: /* pushuint */ u30 value; break; case 0x2F: /* pushdouble */ u30 value; break; case 0x30: /* pushscope */ break; case 0x31: /* pushnamespace */ u30 value; break; case 0x32: /* hasnext2 */ u30 object_reg; u30 index_reg; break; case 0x33: /* pushdecimal */ u30 value; break; case 0x34: /* pushdnan */ break; case 0x35: /* li8 */ break; case 0x36: /* li16 */ break; case 0x37: /* li32 */ break; case 0x38: /* lf32 */ break; case 0x39: /* lf64 */ break; case 0x3A: /* si8 */ break; case 0x3B: /* si16 */ break; case 0x3C: /* si32 */ break; case 0x3D: /* sf32 */ break; case 0x3E: /* sf64 */ break; case 0x40: /* newfunction */ u30 index; break; case 0x41: /* call */ u30 arg_count; break; case 0x42: /* construct */ u30 arg_count; break; case 0x43: /* callmethod */ u30 index; u30 arg_count; break; case 0x44: /* callstatic */ u30 index; u30 arg_count; break; case 0x45: /* callsuper */ u30 index; u30 arg_count; break; case 0x46: /* callproperty */ u30 index; u30 arg_count; break; case 0x47: /* returnvoid */ break; case 0x48: /* returnvalue */ break; case 0x49: /* constructsuper */ u30 arg_count; break; case 0x4A: /* constructprop */ u30 index; u30 arg_count; break; case 0x4C: /* callproplex */ u30 index; u30 arg_count; break; case 0x4D: /* callinterface */ u30 index; break; case 0x4E: /* callsupervoid */ u30 index; u30 arg_count; break; case 0x4F: /* callpropvoid */ u30 index; u30 arg_count; break; case 0x50: /* sxi1 */ break; case 0x51: /* sxi8 */ break; case 0x52: /* sxi16 */ break; case 0x53: /* applytype */ u30 arg_count; break; case 0x54: /* pushfloat4 */ u30 value; break; case 0x55: /* newobject */ u30 arg_count; break; case 0x56: /* newarray */ u30 arg_count; break; case 0x57: /* newactivation */ break; case 0x58: /* newclass */ u30 index; break; case 0x59: /* getdescendants */ u30 index; break; case 0x5A: /* newcatch */ u30 index; break; case 0x5B: /* deldescendants */ u30 index; break; case 0x5C: /* findpropglobal */ u30 index; break; case 0x5D: /* findpropstrict */ u30 index; break; case 0x5E: /* findproperty */ u30 index; break; case 0x5F: /* finddef */ u30 index; break; case 0x60: /* getlex */ u30 index; break; case 0x61: /* setproperty */ u30 index; break; case 0x62: /* getlocal */ u30 index; break; case 0x63: /* setlocal */ u30 index; break; case 0x64: /* getglobalscope */ break; case 0x65: /* getscopeobject */ u30 index; break; case 0x66: /* getproperty */ u30 index; break; case 0x67: /* getouterscope */ u30 index; break; case 0x68: /* initproperty */ u30 index; break; case 0x6A: /* deleteproperty */ u30 index; break; case 0x6B: /* deletepropertylate */ break; case 0x6C: /* getslot */ u30 slotindex; break; case 0x6D: /* setslot */ u30 slotindex; break; case 0x6E: /* getglobalslot */ u30 slotindex; break; case 0x6F: /* setglobalslot */ u30 slotindex; break; case 0x70: /* convert_s */ break; case 0x71: /* esc_xelem */ break; case 0x72: /* esc_xattr */ break; case 0x73: /* convert_i */ break; case 0x74: /* convert_u */ break; case 0x75: /* convert_d */ break; case 0x76: /* convert_b */ break; case 0x77: /* convert_o */ break; case 0x78: /* checkfilter */ break; case 0x79: /* convert_f */ break; case 0x7A: /* unplus */ break; case 0x7B: /* convert_f4 */ break; case 0x80: /* coerce */ u30 index; break; case 0x81: /* coerce_b */ break; case 0x82: /* coerce_a */ break; case 0x83: /* coerce_i */ break; case 0x84: /* coerce_d */ break; case 0x85: /* coerce_s */ break; case 0x86: /* astype */ u30 index; break; case 0x87: /* astypelate */ break; case 0x88: /* coerce_u */ break; case 0x89: /* coerce_o */ break; case 0x8F: /* negate_p */ u30 number_context; break; case 0x90: /* negate */ break; case 0x91: /* increment */ break; case 0x92: /* inclocal */ u30 index; break; case 0x93: /* decrement */ break; case 0x94: /* declocal */ u30 index; break; case 0x95: /* typeof */ break; case 0x96: /* not */ break; case 0x97: /* bitnot */ break; case 0x9C: /* increment_p */ u30 number_context; break; case 0x9D: /* inclocal_p */ u30 number_context; u30 index; break; case 0x9E: /* decrement_p */ u30 number_context; break; case 0x9F: /* declocal_p */ u30 number_context; u30 index; break; case 0xA0: /* add */ break; case 0xA1: /* subtract */ break; case 0xA2: /* multiply */ break; case 0xA3: /* divide */ break; case 0xA4: /* modulo */ break; case 0xA5: /* lshift */ break; case 0xA6: /* rshift */ break; case 0xA7: /* urshift */ break; case 0xA8: /* bitand */ break; case 0xA9: /* bitor */ break; case 0xAA: /* bitxor */ break; case 0xAB: /* equals */ break; case 0xAC: /* strictequals */ break; case 0xAD: /* lessthan */ break; case 0xAE: /* lessequals */ break; case 0xAF: /* greaterthan */ break; case 0xB0: /* greaterequals */ break; case 0xB1: /* instanceof */ break; case 0xB2: /* istype */ u30 index; break; case 0xB3: /* istypelate */ break; case 0xB4: /* in */ break; case 0xB5: /* add_p */ u30 number_context; break; case 0xB6: /* subtract_p */ u30 number_context; break; case 0xB7: /* multiply_p */ u30 number_context; break; case 0xB8: /* divide_p */ u30 number_context; break; case 0xB9: /* modulo_p */ u30 number_context; break; case 0xC0: /* increment_i */ break; case 0xC1: /* decrement_i */ break; case 0xC2: /* inclocal_i */ u30 index; break; case 0xC3: /* declocal_i */ u30 index; break; case 0xC4: /* negate_i */ break; case 0xC5: /* add_i */ break; case 0xC6: /* subtract_i */ break; case 0xC7: /* multiply_i */ break; case 0xD0: /* getlocal0 */ break; case 0xD1: /* getlocal1 */ break; case 0xD2: /* getlocal2 */ break; case 0xD3: /* getlocal3 */ break; case 0xD4: /* setlocal0 */ break; case 0xD5: /* setlocal1 */ break; case 0xD6: /* setlocal2 */ break; case 0xD7: /* setlocal3 */ break; case 0xEF: /* debug */ u8 debug_type; u30 index; u8 reg; u30 extra; break; case 0xF0: /* debugline */ u30 linenum; break; case 0xF1: /* debugfile */ u30 index; break; case 0xF2: /* bkptline */ u30 linenum; break; case 0xF3: /* timestamp */ break; case 0x00: case 0x3F: case 0x4B: /* callsuperid */ case 0x69: /* setpropertylate */ case 0x7C: case 0x7D: case 0x7E: case 0x7F: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x98: case 0x99: case 0x9A: /* concat */ case 0x9B: /* add_d */ case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: /* invalid */ case 0xEE: /* abs_jump */ case 0xF4: case 0xF5: /* verifypass */ case 0xF6: /* alloc */ case 0xF7: /* mark */ case 0xF8: /* wb */ case 0xF9: /* prologue */ case 0xFA: /* sendenter */ case 0xFB: /* doubletoatom */ case 0xFC: /* sweep */ case 0xFD: /* codegenop */ case 0xFE: /* verifyop */ case 0xFF: /* decode */ Printf("UNKNOWN avm2 instruction: 0x%02X\n", instruction); break; } } avm2_instruction ; string GetInstructionName(avm2_instruction &instruction) { switch (instruction.instruction) { case 0x01: return "bkpt"; case 0x02: return "nop"; case 0x03: return "throw"; case 0x04: return "getsuper"; case 0x05: return "setsuper"; case 0x06: return "dxns"; case 0x07: return "dxnslate"; case 0x08: return "kill"; case 0x09: return "label"; case 0x0A: return "lf32x4"; case 0x0B: return "sf32x4"; case 0x0C: return "ifnlt"; case 0x0D: return "ifnle"; case 0x0E: return "ifngt"; case 0x0F: return "ifnge"; case 0x10: return "jump"; case 0x11: return "iftrue"; case 0x12: return "iffalse"; case 0x13: return "ifeq"; case 0x14: return "ifne"; case 0x15: return "iflt"; case 0x16: return "ifle"; case 0x17: return "ifgt"; case 0x18: return "ifge"; case 0x19: return "ifstricteq"; case 0x1A: return "ifstrictne"; case 0x1B: return "lookupswitch"; case 0x1C: return "pushwith"; case 0x1D: return "popscope"; case 0x1E: return "nextname"; case 0x1F: return "hasnext"; case 0x20: return "pushnull"; case 0x21: return "pushundefined"; case 0x22: return "pushconstant"; case 0x23: return "nextvalue"; case 0x24: return "pushbyte"; case 0x25: return "pushshort"; case 0x26: return "pushtrue"; case 0x27: return "pushfalse"; case 0x28: return "pushnan"; case 0x29: return "pop"; case 0x2A: return "dup"; case 0x2B: return "swap"; case 0x2C: return "pushstring"; case 0x2D: return "pushint"; case 0x2E: return "pushuint"; case 0x2F: return "pushdouble"; case 0x30: return "pushscope"; case 0x31: return "pushnamespace"; case 0x32: return "hasnext2"; case 0x33: return "pushdecimal"; case 0x34: return "pushdnan"; case 0x35: return "li8"; case 0x36: return "li16"; case 0x37: return "li32"; case 0x38: return "lf32"; case 0x39: return "lf64"; case 0x3A: return "si8"; case 0x3B: return "si16"; case 0x3C: return "si32"; case 0x3D: return "sf32"; case 0x3E: return "sf64"; case 0x40: return "newfunction"; case 0x41: return "call"; case 0x42: return "construct"; case 0x43: return "callmethod"; case 0x44: return "callstatic"; case 0x45: return "callsuper"; case 0x46: return "callproperty"; case 0x47: return "returnvoid"; case 0x48: return "returnvalue"; case 0x49: return "constructsuper"; case 0x4A: return "constructprop"; case 0x4B: return "callsuperid"; case 0x4C: return "callproplex"; case 0x4D: return "callinterface"; case 0x4E: return "callsupervoid"; case 0x4F: return "callpropvoid"; case 0x50: return "sxi1"; case 0x51: return "sxi8"; case 0x52: return "sxi16"; case 0x53: return "applytype"; case 0x54: return "pushfloat4"; case 0x55: return "newobject"; case 0x56: return "newarray"; case 0x57: return "newactivation"; case 0x58: return "newclass"; case 0x59: return "getdescendants"; case 0x5A: return "newcatch"; case 0x5B: return "deldescendants"; case 0x5C: return "findpropglobal"; case 0x5D: return "findpropstrict"; case 0x5E: return "findproperty"; case 0x5F: return "finddef"; case 0x60: return "getlex"; case 0x61: return "setproperty"; case 0x62: return "getlocal"; case 0x63: return "setlocal"; case 0x64: return "getglobalscope"; case 0x65: return "getscopeobject"; case 0x66: return "getproperty"; case 0x67: return "getouterscope"; case 0x68: return "initproperty"; case 0x69: return "setpropertylate"; case 0x6A: return "deleteproperty"; case 0x6B: return "deletepropertylate"; case 0x6C: return "getslot"; case 0x6D: return "setslot"; case 0x6E: return "getglobalslot"; case 0x6F: return "setglobalslot"; case 0x70: return "convert_s"; case 0x71: return "esc_xelem"; case 0x72: return "esc_xattr"; case 0x73: return "convert_i"; case 0x74: return "convert_u"; case 0x75: return "convert_d"; case 0x76: return "convert_b"; case 0x77: return "convert_o"; case 0x78: return "checkfilter"; case 0x79: return "convert_f"; case 0x7A: return "unplus"; case 0x7B: return "convert_f4"; case 0x80: return "coerce"; case 0x81: return "coerce_b"; case 0x82: return "coerce_a"; case 0x83: return "coerce_i"; case 0x84: return "coerce_d"; case 0x85: return "coerce_s"; case 0x86: return "astype"; case 0x87: return "astypelate"; case 0x88: return "coerce_u"; case 0x89: return "coerce_o"; case 0x8F: return "negate_p"; case 0x90: return "negate"; case 0x91: return "increment"; case 0x92: return "inclocal"; case 0x93: return "decrement"; case 0x94: return "declocal"; case 0x95: return "typeof"; case 0x96: return "not"; case 0x97: return "bitnot"; case 0x9A: return "concat"; case 0x9B: return "add_d"; case 0x9C: return "increment_p"; case 0x9D: return "inclocal_p"; case 0x9E: return "decrement_p"; case 0x9F: return "declocal_p"; case 0xA0: return "add"; case 0xA1: return "subtract"; case 0xA2: return "multiply"; case 0xA3: return "divide"; case 0xA4: return "modulo"; case 0xA5: return "lshift"; case 0xA6: return "rshift"; case 0xA7: return "urshift"; case 0xA8: return "bitand"; case 0xA9: return "bitor"; case 0xAA: return "bitxor"; case 0xAB: return "equals"; case 0xAC: return "strictequals"; case 0xAD: return "lessthan"; case 0xAE: return "lessequals"; case 0xAF: return "greaterthan"; case 0xB0: return "greaterequals"; case 0xB1: return "instanceof"; case 0xB2: return "istype"; case 0xB3: return "istypelate"; case 0xB4: return "in"; case 0xB5: return "add_p"; case 0xB6: return "subtract_p"; case 0xB7: return "multiply_p"; case 0xB8: return "divide_p"; case 0xB9: return "modulo_p"; case 0xC0: return "increment_i"; case 0xC1: return "decrement_i"; case 0xC2: return "inclocal_i"; case 0xC3: return "declocal_i"; case 0xC4: return "negate_i"; case 0xC5: return "add_i"; case 0xC6: return "subtract_i"; case 0xC7: return "multiply_i"; case 0xD0: return "getlocal0"; case 0xD1: return "getlocal1"; case 0xD2: return "getlocal2"; case 0xD3: return "getlocal3"; case 0xD4: return "setlocal0"; case 0xD5: return "setlocal1"; case 0xD6: return "setlocal2"; case 0xD7: return "setlocal3"; case 0xED: return "invalid"; case 0xEE: return "abs_jump"; case 0xEF: return "debug"; case 0xF0: return "debugline"; case 0xF1: return "debugfile"; case 0xF2: return "bkptline"; case 0xF3: return "timestamp"; case 0xF5: return "verifypass"; case 0xF6: return "alloc"; case 0xF7: return "mark"; case 0xF8: return "wb"; case 0xF9: return "prologue"; case 0xFA: return "sendenter"; case 0xFB: return "doubletoatom"; case 0xFC: return "sweep"; case 0xFD: return "codegenop"; case 0xFE: return "verifyop"; case 0xFF: return "decode"; default: return Str("unknown0x%02X", instruction.instruction); } } typedef struct { u30 code_length; local quad code_start=FTell(); while (FTell() < code_start + code_length.value) { avm2_instruction instruction; } } avm2_code; typedef struct { u30 method; u30 max_stack; u30 local_count; u30 init_scope_depth; u30 max_scope_depth; //u8 code[code_length.value]; avm2_code code; u30 exception_count; if (exception_count.value > 0) { exception_info exception[exception_count.value] ; } u30 trait_count; if (trait_count.value > 0) { traits_info trait[trait_count.value] ; } } method_body_info; typedef struct { u16 minor_version; u16 major_version; abc_minor_version = minor_version; abc_major_version = major_version; cpool_info constant_pool; u30 method_count; if (method_count.value > 0) { method_info method[method_count.value] ; } u30 metadata_count; if (metadata_count.value > 0) { metadata_info metadata[metadata_count.value] ; } u30 class_count; if (class_count.value > 0) { instance_info instance[class_count.value] ; class_info class[class_count.value] ; } u30 script_count; if (script_count.value > 0) { script_info script[script_count.value] ; } u30 method_body_count; if (method_body_count.value > 0) { method_body_info method_body[method_body_count.value] ; } } abcFile; /************ * SWF Tags * ************/ typedef struct { BitfieldEnablePadding(); LittleEndian(); ushort TagType : 10; ushort TagLength : 6; if (TagLength==0x3F) { int Length; } } RECORDHEADER; struct SWFTAG; typedef struct { local int i; BitfieldLeftToRight(); RECORDHEADER Header; CurrentTag = Header.TagType; if (Header.TagLength < 0x3f) { SWFTagEnd = FTell() + Header.TagLength; } else { SWFTagEnd = FTell() + Header.Length; } switch (Header.TagType) { /************************ * DoAction Tags * ************************/ case 59: /* DoInitAction */ ushort SpriteID; case 12: /* DoAction */ do { ACTIONRECORD ActionTag; } while (ActionTag.ActionCode!=0x00); break; case 72: /* DoABC */ abcFile ABCData; break; case 82: /* DoABC2 */ uint Flags; string Name; abcFile ABCData; break; /************************ * Display List Tags * ************************/ case 4: /* PlaceObject */ ushort CharacterId; ushort Depth; MATRIX Matrix; if (Header.TagLength == 0x3f) { if (Header.Length < (sizeof(Matrix)+4)) { CXFORM ColorTransform; } } else if (Header.TagLength < (sizeof(Matrix)+4)) { CXFORM ColorTransform; } break; case 26: /* PlaceObject2 */ ubyte PlaceFlagHasClipActions : 1; ubyte PlaceFlagHasClipDepth : 1; ubyte PlaceFlagHasName : 1; ubyte PlaceFlagHasRatio : 1; ubyte PlaceFlagHasColorTransform : 1; ubyte PlaceFlagHasMatrix : 1; ubyte PlaceFlagHasCharacter : 1; ubyte PlaceFlagMove : 1; ushort Depth; if (PlaceFlagHasCharacter) ushort CharacterId; if (PlaceFlagHasMatrix) MATRIX Matrix; if (PlaceFlagHasColorTransform) CXFORMWITHALPHA ColorTransform; if (PlaceFlagHasRatio) ushort Ratio; if (PlaceFlagHasName) string Name; if (PlaceFlagHasClipDepth) ushort ClipDepth; if (PlaceFlagHasClipActions) CLIPACTIONS ClipActions; break; case 70: /* PlaceObject3 */ ubyte PlaceFlagHasClipActions : 1; ubyte PlaceFlagHasClipDepth : 1; ubyte PlaceFlagHasName : 1; ubyte PlaceFlagHasRatio : 1; ubyte PlaceFlagHasColorTransform : 1; ubyte PlaceFlagHasMatrix : 1; ubyte PlaceFlagHasCharacter : 1; ubyte PlaceFlagMove : 1; ubyte Reserved : 1; ubyte PlaceFlagOpaqueBackground : 1; ubyte PlaceFlagHasVisible : 1; ubyte PlaceFlagHasImage : 1; ubyte PlaceFlagHasClassName : 1; ubyte PlaceFlagHasCacheAsBitmap : 1; ubyte PlaceFlagHasBlendMode : 1; ubyte PlaceFlagHasFilterList : 1; ushort Depth; if (PlaceFlagHasClassName || (PlaceFlagHasImage && PlaceFlagHasCharacter)) { string ClassName; } if (PlaceFlagHasCharacter) { ushort CharacterId; } if (PlaceFlagHasMatrix) { MATRIX Matrix; } if (PlaceFlagHasColorTransform) { CXFORMWITHALPHA ColorTransform; } if (PlaceFlagHasRatio) { ushort Ratio; } if (PlaceFlagHasName) { string Name; } if (PlaceFlagHasFilterList) { FILTERLIST SurfaceFilterList; } if (PlaceFlagHasBlendMode) { ubyte BlendMode; } if (PlaceFlagHasCacheAsBitmap) { ubyte BitmapCache; } if (PlaceFlagHasVisible) { ubyte Visible; } if (PlaceFlagOpaqueBackground) { RGBA BackgroundColor; } if (PlaceFlagHasClipActions) { CLIPACTIONS ClipActions; } break; case 94: /* PlaceObject4 */ ubyte PlaceFlagHasClipActions : 1; ubyte PlaceFlagHasClipDepth : 1; ubyte PlaceFlagHasName : 1; ubyte PlaceFlagHasRatio : 1; ubyte PlaceFlagHasColorTransform : 1; ubyte PlaceFlagHasMatrix : 1; ubyte PlaceFlagHasCharacter : 1; ubyte PlaceFlagMove : 1; ubyte Reserved : 1; ubyte PlaceFlagOpaqueBackground : 1; ubyte PlaceFlagHasVisible : 1; ubyte PlaceFlagHasImage : 1; ubyte PlaceFlagHasClassName : 1; ubyte PlaceFlagHasCacheAsBitmap : 1; ubyte PlaceFlagHasBlendMode : 1; ubyte PlaceFlagHasFilterList : 1; ushort Depth; if (PlaceFlagHasClassName || (PlaceFlagHasImage && PlaceFlagHasCharacter)) { string ClassName; } if (PlaceFlagHasCharacter) { ushort CharacterId; } if (PlaceFlagHasMatrix) { MATRIX Matrix; } if (PlaceFlagHasColorTransform) { CXFORMWITHALPHA ColorTransform; } if (PlaceFlagHasRatio) { ushort Ratio; } if (PlaceFlagHasName) { string Name; } if (PlaceFlagHasFilterList) { FILTERLIST SurfaceFilterList; } if (PlaceFlagHasBlendMode) { ubyte BlendMode; } if (PlaceFlagHasCacheAsBitmap) { ubyte BitmapCache; } if (PlaceFlagHasVisible) { ubyte Visible; } if (PlaceFlagOpaqueBackground) { RGBA BackgroundColor; } if (PlaceFlagHasClipActions) { CLIPACTIONS ClipActions; } if ((SWFTagEnd-FTell())>0) { ubyte AmfData[SWFTagEnd-FTell()]; //TODO: parse AMF metadata } break; case 5: /* RemoveObject */ ushort CharacterId; ushort Depth; break; case 28: /* RemoveObject2 */ ushort Depth; break; case 1: /* ShowFrame */ break; /************************ * Control Tags * ************************/ case 9: /* SetBackgroundColor */ RGB BackgroundColor; break; case 43: /* FrameLabel */ string Name; if ((File.Header.Version>=6) && (SWFTagEnd>FTell())) { ubyte NamedAnchor; } break; case 24: /* Protect */ if ((SWFTagEnd-FTell())>0) { ubyte Password[SWFTagEnd-FTell()]; } break; case 0: /* End */ break; case 56: /* ExportAssets */ ushort Count; for (i=0; i; EncodedU32 FrameLabelCount; struct FRAMENUMLABEL { EncodedU32 FrameNum; string FrameLabel; } FrameNumLabel[FrameLabelCount.value] ;; break; /************************ * Shape Tags * ************************/ case 2: /* DefineShape */ ushort ShapeId; RECT ShapeBounds; SHAPEWITHSTYLE Shapes; break; case 22: /* DefineShape2 */ ushort ShapeId; RECT ShapeBounds; SHAPEWITHSTYLE Shapes; break; case 32: /* DefineShape3 */ ushort ShapeId; RECT ShapeBounds; SHAPEWITHSTYLE Shapes; break; case 83: /* DefineShape4 */ ushort ShapeId; RECT ShapeBounds; RECT EdgeBounds; ubyte Reserved : 6; ubyte UsesNonScalingStrokes : 1; ubyte UsesScalingStrokes : 1; SHAPEWITHSTYLE Shapes; break; /************************ * Bitmap Tags * ************************/ case 6: /* DefineBits */ ushort CharacterId; if ((SWFTagEnd-FTell())>0) { ubyte JPEGData[SWFTagEnd-FTell()]; } break; case 8: /* JPEGTables */ if ((SWFTagEnd-FTell())>0) { ubyte JPEGData[SWFTagEnd-FTell()]; } break; case 21: /* DefineBitsJPEG2 */ ushort CharacterId; if ((SWFTagEnd-FTell())>0) { ubyte JPEGData[SWFTagEnd-FTell()]; } break; case 35: /* DefineBitsJPEG3 */ ushort CharacterID; uint AlphaDataOffset; if (AlphaDataOffset) { ubyte JPEGData[AlphaDataOffset]; } if ((SWFTagEnd-FTell())>0) { ubyte BitmapAlphaData[SWFTagEnd-FTell()]; } break; case 90: /* DefineBitsJPEG4 */ ushort CharacterID; uint AlphaDataOffset; if (AlphaDataOffset) { ubyte JPEGData[AlphaDataOffset]; } ushort DeblockParam; if ((SWFTagEnd-FTell())>0) { ubyte BitmapAlphaData[SWFTagEnd-FTell()]; } break; case 20: /* DefineBitsLossless */ ushort CharacterID; ubyte BitmapFormat; ushort BitmapWidth; ushort BitmapHeight; if (BitmapFormat == 3) { ubyte BitmapColorTableSize; ubyte ZlibBitmapData[SWFTagEnd-FTell()]; } else if (BitmapFormat == 4 || BitmapFormat == 5) { ubyte ZlibBitmapData[SWFTagEnd-FTell()]; } break; case 36: /* DefineBitsLossless2 */ ushort CharacterID; ubyte BitmapFormat; ushort BitmapWidth; ushort BitmapHeight; if (BitmapFormat == 3) { ubyte BitmapColorTableSize; ubyte ZlibBitmapData[SWFTagEnd-FTell()]; } else if (BitmapFormat == 4 || BitmapFormat == 5) { ubyte ZlibBitmapData[SWFTagEnd-FTell()]; } break; /************************ * Shape Morphing Tags * ************************/ case 46: /* DefineMorphShape */ ushort CharacterId; RECT StartBounds; RECT EndBounds; uint Offset; MORPHFILLSTYLEARRAY MorphFillStyles; MORPHLINESTYLES MorphLineStyles; SHAPE StartEdges; SHAPE EndEdges; break; case 84: /* DefineMorphShape2 */ ushort CharacterId; RECT StartBounds; RECT EndBounds; RECT StartEdgeBounds; RECT EndEdgeBounds; ubyte Reserved : 6; ubyte UsesNonScalingStrokes : 1; ubyte UsesScalingStrokes : 1; uint Offset; MORPHFILLSTYLEARRAY MorphFillStyles; MORPHLINESTYLES MorphLineStyles; SHAPE StartEdges; SHAPE EndEdges; break; /************************ * Font Tags * ************************/ case 10: /* DefineFont */ ushort FontID; if (SWFTagEnd-FTell()>0) { ushort OffsetTable; local ushort nGlyphs = OffsetTable / 2; ushort OffsetTable[nGlyphs - 1]; SHAPE GlyphShapeTable[nGlyphs]; } break; case 13: /* DefineFontInfo */ ushort FontID; ubyte FontNameLen; BitfieldDisablePadding(); ubyte FontName[FontNameLen]; BitfieldEnablePadding(); ubyte FontFlagsReserved : 2; ubyte FontFlagsSmallText : 1; ubyte FontFlagsShiftJIS : 1; ubyte FontFlagsANSI : 1; ubyte FontFlagsBold : 1; ubyte FontFlagsWideCodes : 1; ubyte CodeTable[SWFTagEnd-FTell()]; break; case 62: /* DefineFontInfo2 */ ushort FontID; ubyte FontNameLen; BitfieldDisablePadding(); ubyte FontName[FontNameLen]; BitfieldEnablePadding(); ubyte FontFlagsReserved : 2; ubyte FontFlagsSmallText : 1; ubyte FontFlagsShiftJIS : 1; ubyte FontFlagsANSI : 1; ubyte FontFlagsBold : 1; ubyte FontFlagsWideCodes : 1; LANGCODE LanguageCode; ubyte CodeTable[SWFTagEnd-FTell()]; break; case 48: /* DefineFont2 */ case 75: /* DefineFont3 */ ushort FontID; ubyte FontFlagsHasLayout : 1; ubyte FontFlagsShiftJIS : 1; ubyte FontFlagsSmallText : 1; ubyte FontFlagsANSI : 1; ubyte FontFlagsWideOffsets : 1; ubyte FontFlagsWideCodes : 1; ubyte FontFlagsItalic : 1; ubyte FontFlagsBold : 1; LANGCODE LanguageCode; ubyte FontNameLen; ubyte FontName[FontNameLen]; ushort NumGlyphs; if (FontFlagsWideOffsets) { if (NumGlyphs) { uint OffsetTable[NumGlyphs]; } uint CodeTableOffset; } else { if (NumGlyphs) { ushort OffsetTable[NumGlyphs]; } ushort CodeTableOffset; } for (i=0; i0) { ubyte FontData[SWFTagEnd-FTell()]; } break; case 73: /* DefineFontAlignZones */ ushort FontID; ubyte CSMTableHint : 2; ubyte Reserved : 6; while ((SWFTagEnd-FTell())>0) { ZONERECORD ZoneTable; } break; case 88: /* DefineFontName */ ushort FontID; string FontName; string FontCopyright; break; case 11: /* DefineText */ case 33: /* DefineText2 */ ushort CharacterID; RECT TextBounds; MATRIX TextMatrix; ubyte GlyphBits; ubyte AdvanceBits; CurrentGlyphBits = GlyphBits; CurrentAdvanceBits = AdvanceBits; do { TEXTRECORD TextRecords ; } while (TextRecords.TextRecordType || TextRecords.StyleFlagsReserved || TextRecords.StyleFlagsHasFont || TextRecords.StyleFlagsHasColor || TextRecords.StyleFlagsHasYOffset || TextRecords.StyleFlagsHasXOffset); break; case 37: /* DefineEditText */ ushort CharacterID; RECT Bounds; ubyte HasText : 1; ubyte WordWrap : 1; ubyte Multiline : 1; ubyte Password : 1; ubyte ReadOnly : 1; ubyte HasTextColor : 1; ubyte HasMaxLength : 1; ubyte HasFont : 1; ubyte HasFontClass : 1; ubyte AutoSize : 1; ubyte HasLayout : 1; ubyte NoSelect : 1; ubyte Border : 1; ubyte WasStatic : 1; ubyte HTML : 1; ubyte UseOutlines : 1; if (HasFont) { ushort FontID; } if (HasFontClass) { string FontClass; } if (HasFont) { ushort FontHeight; } if (HasTextColor) { RGBA TextColor; } if (HasMaxLength) { ushort MaxLength; } if (HasLayout) { ubyte Align; ushort LeftMargin; ushort RightMargin; ushort Indent; ushort Leading; } string VariableName; if (HasText) { string InitialText; } break; case 74: /* CSMTextSettings */ ushort TextID; ubyte UseFlashType : 2; ubyte GridFit : 3; ubyte Reserved : 3; float Thickness; float Sharpness; ubyte Reserved2; break; /************************ * Sound Tags * ************************/ case 14: /* DefineSound */ ushort SoundId; ubyte SoundFormat : 4; ubyte SoundRate : 2; ubyte SoundSize : 1; ubyte SoundType : 1; uint SoundSampleCount; ubyte SoundData[SWFTagEnd-FTell()]; break; case 15: /* StartSound */ ushort SoundId; SOUNDINFO SoundInfo; break; case 89: /* StartSound2 */ string SoundClassName; SOUNDINFO SoundInfo; break; case 18: /* SoundStreamHead */ ubyte Reserved : 4; ubyte PlaybackSoundRate : 2; ubyte PlaybackSoundSize : 1; ubyte PlaybackSoundType : 1; ubyte StreamSoundCompression : 4; ubyte StreamSoundRate : 2; ubyte StreamSoundSize : 1; ubyte StreamSoundType : 1; ushort StreamSoundSampleCount; if (StreamSoundCompression==2) { short LatencySeek; } break; case 45: /* SoundStreamHead2 */ ubyte Reserved : 4; ubyte PlaybackSoundRate : 2; ubyte PlaybackSoundSize : 1; ubyte PlaybackSoundType : 1; ubyte StreamSoundCompression : 4; ubyte StreamSoundRate : 2; ubyte StreamSoundSize : 1; ubyte StreamSoundType : 1; ushort StreamSoundSampleCount; if (StreamSoundCompression==2) { short LatencySeek; } break; case 19: /* SoundStreamBlock */ ubyte StreamSoundData[SWFTagEnd-FTell()]; break; /************************ * Button Tags * ************************/ case 7: /* DefineButton */ ushort ButtonId; do { BUTTONRECORD Character; } while (Character.ButtonReserved || Character.ButtonHasBlendMode || Character.ButtonHasFilterList || Character.ButtonStateHitTest || Character.ButtonStateDown || Character.ButtonStateOver || Character.ButtonStateUp); do { ACTIONRECORD Action; } while (Action.ActionCode!=0x00); break; case 34: /* DefineButton2 */ ushort ButtonId; ubyte ReservedFlags : 7; ubyte TrackAsMenu : 1; ushort ActionOffset; do { BUTTONRECORD Character; } while (Character.ButtonReserved || Character.ButtonHasBlendMode || Character.ButtonHasFilterList || Character.ButtonStateHitTest || Character.ButtonStateDown || Character.ButtonStateOver || Character.ButtonStateUp); while ((SWFTagEnd-FTell())>0) { BUTTONCONDACTION Action; } break; case 23: /* DefineButtonCxform */ ushort ButtonId; CXFORM ButtonColorTransform; break; case 17: /* DefineButtonSound */ ushort ButtonId; ushort ButtonSoundChar0; if (ButtonSoundChar0) { SOUNDINFO ButtonSoundInfo0; } ushort ButtonSoundChar1; if (ButtonSoundChar1) { SOUNDINFO ButtonSoundInfo1; } ushort ButtonSoundChar2; if (ButtonSoundChar2) { SOUNDINFO ButtonSoundInfo2; } ushort ButtonSoundChar3; if (ButtonSoundChar3) { SOUNDINFO ButtonSoundInfo3; } break; /************************ * Sprite Tags * ************************/ case 39: /* DefineSprite */ ushort SpriteID; ushort FrameCount; local quad SpriteSWFTagEnd; SpriteSWFTagEnd = SWFTagEnd; struct SWFTAGS { if (SpriteSWFTagEnd-FTell() > 0) { do { SWFTAG Tag; } while ((SpriteSWFTagEnd-FTell() > 0) && Tag.Header.TagType != 0); } } ControlTags; if (SpriteSWFTagEnd-FTell() > 0) { ubyte RemainingData[SpriteSWFTagEnd-FTell()]; } SWFTagEnd = SpriteSWFTagEnd; CurrentTag = 39; break; /************************ * Video Tags * ************************/ case 60: /* DefineVideoSteam */ ushort CharacterID; ushort NumFrames; ushort Width; ushort Height; ubyte VideoFlagsReserved : 4; ubyte VideoFlagsDeblocking : 3; ubyte VideoFlagsSmoothing : 1; ubyte CodecID; break; case 61: /* VideoFrame */ ushort StreamID; ushort FrameNum; ubyte VideoData[SWFTagEnd-FTell()]; break; /************************ * Binary Data Tags * ************************/ case 87: /* DefineBinaryData */ ushort Tag; uint Reserved; ubyte Data[SWFTagEnd-FTell()]; break; /************************ * Undocumented Tags * ************************/ case 41: /* ProductInfo */ uint ProductId; uint Edition; ubyte MajorVersion; ubyte MinorVersion; uint BuildLow; uint BuildHigh; uint CompilationDateLow; uint CompilationDateHigh; break; case 63: /* DebugID */ ubyte DebugID[16]; break; case 93: /* EnableTelemetry */ uint Reserved : 16; if ((SWFTagEnd-FTell())>0) { ubyte PasswordHash[32]; } break; case 253: /* Amayeta Encryption */ if ((SWFTagEnd-FTell())>0) { ubyte Data[SWFTagEnd-FTell()]; } break; default: if ((SWFTagEnd-FTell())>0) { ubyte Data[SWFTagEnd-FTell()]; } break; } if ((SWFTagEnd-FTell())>0) { ubyte Padding[SWFTagEnd-FTell()]; if (Header.TagType != 83) { Printf("PADDING: Tag padded to 0x%LXh\n", FTell()); } } else if ((SWFTagEnd-FTell())<0) { if (Header.TagType != 48) { Printf("TAG OVERRUN: Expected next tag at 0x%LXh\n", SWFTagEnd); } } } SWFTAG ; string GetTagType(SWFTAG &Tag) { string result; ubyte TagType = Tag.Header.TagType; switch (TagType) { /************************ * DoAction Tags * ************************/ case 59: return "DoInitAction"; case 12: return "DoAction"; case 72: return "DoABC"; case 82: return "DoABC2"; /************************ * Display List Tags * ************************/ case 4: return "PlaceObject"; case 26: return "PlaceObject2"; case 70: return "PlaceObject3"; case 94: return "PlaceObject4"; case 5: return "RemoveObject"; case 28: return "RemoveObject2"; case 1: return "ShowFrame"; /************************ * Control Tags * ************************/ case 9: return "SetBackgroundColor"; case 43: return "FrameLabel"; case 24: return "Protect"; case 0: return "End"; case 56: return "ExportAssets"; case 57: return "ImportAssets"; case 58: return "EnableDebugger"; case 64: return "EnableDebugger2"; case 65: return "ScriptLimits"; case 66: return "SetTabIndex"; case 69: return "FileAttributes"; case 71: return "ImportAsset2"; case 76: return "SymbolClass"; case 77: return "Metadata"; case 78: return "DefineScalingGrid"; case 86: return "DefineSceneAndFrameLabelData"; /************************ * Shape Tags * ************************/ case 2: return "DefineShape"; case 22: return "DefineShape2"; case 32: return "DefineShape3"; case 83: return "DefineShape4"; /************************ * Bitmap Tags * ************************/ case 6: return "DefineBits"; case 8: return "JPEGTables"; case 21: return "DefineBitsJPEG2"; case 35: return "DefineBitsJPEG3"; case 90: return "DefineBitsJPEG4"; case 20: return "DefineBitsLossless"; case 36: return "DefineBitsLossless2"; /************************ * Shape Morphing Tags * ************************/ case 46: return "DefineMorphShape"; case 84: return "DefineMorphShape2"; /************************ * Font Tags * ************************/ case 10: return "DefineFont"; case 13: return "DefineFontInfo"; case 62: return "DefineFontInfo2"; case 48: return "DefineFont2"; case 75: return "DefineFont3"; case 91: return "DefineFont4"; case 73: return "DefineFontAlignZones"; case 88: return "DefineFontName"; case 11: return "DefineText"; case 33: return "DefineText2"; case 37: return "DefineEditText"; case 74: return "CSMTextSettings"; /************************ * Sound Tags * ************************/ case 14: return "DefineSound"; case 15: return "StartSound"; case 89: return "StartSound2"; case 18: return "SoundStreamHead"; case 45: return "SoundStreamHead2"; case 19: return "SoundStreamBlock"; /************************ * Button Tags * ************************/ case 7: return "DefineButton"; case 34: return "DefineButton2"; case 23: return "DefineButtonCxform"; case 17: return "DefineButtonSound"; /************************ * Sprite Tags * ************************/ case 39: return "DefineSprite"; /************************ * Video Tags * ************************/ case 60: return "DefineVideoSteam"; case 61: return "VideoFrame"; /************************ * Binary Data Tags * ************************/ case 87: return "DefineBinaryData"; /************************ * Undocumented Tags * ************************/ case 41: return "ProductInfo"; case 63: return "DebugID"; case 93: return "EnableTelemetry"; case 253: return "Amayeta Encrypt"; default: return "\0"; } return "\0"; } /************************************************************* * SWF File * * This section of the template contains the header structure * as well as the structure that defines the overall loop that * will be executed. *************************************************************/ BitfieldLeftToRight(); typedef struct { SetBackColor(cLtGray); uchar Signature[3]; uchar Version; if (Signature[0] == 'F' && Signature[1] == 'W' && Signature[2] == 'S') { uint FileLength; RECT Rect; BigEndian(); ushort FrameRate; LittleEndian(); ushort FrameCount; } else if (Signature[0] == 'C' && Signature[1] == 'W' && Signature[2] == 'S') { Printf("This is a Zlib compressed SWF file\n"); isCompressed = 1; uint UncompressedSize; byte ZlibData[FileSize() - FTell()]; } else if (Signature[0] == 'Z' && Signature[1] == 'W' && Signature[2] == 'S') { Printf("This is a LZMA compressed SWF file\n"); isCompressed = 1; uint UncompressedSize; uint LzmaSize; ubyte LzmaProperties[5]; byte LzmaData[LzmaSize]; } } SWFHEADER; typedef struct { SWFHEADER Header; if (0 == isCompressed) { do { SWFTAG Tag; } while (!FEof() && Tag.Header.TagType != 0); } } SWF; /************************ * Start File Parsing * ************************/ SWF File;