/// <summary> /// Turns bytecode into an AbcCode object. /// </summary> /// <param name="bytecode">The bytecode, as chopped out of a SWF.</param> /// <param name="readLog">Ignored in release builds. This logs /// on every constant value read for unit test inspection.</param> /// <returns>A string rendition of the bytecode.</returns> public AbcCode Read(byte[] bytecode, StringBuilder readLog) { #if DEBUG this.ReadLog = readLog; if (this.ReadLog != null) { this.ReadLog.AppendLine("\nNew ABC file\n-----------\n"); } #endif this.code = new AbcCode(); this.abcdtr = new ABCDataTypeReader(new MemoryStream(bytecode)); this.LateResolutions = new Dictionary <object, int>(); int minor = this.abcdtr.ReadUI16(); int major = this.abcdtr.ReadUI16(); if (minor != AbcFileValues.MinorVersion || major != AbcFileValues.MajorVersion) { throw new SWFModellerException( SWFModellerError.ABCParsing, "Unsupported version, or not an ABC file."); } this.ReadConstantPool(); this.ReadMethods(); this.ReadMetadata(); this.ReadClasses(); this.ReadScriptDefs(); this.ReadMethodBodies(); this.ResolveReferences(); return(this.code); }
/// <summary> /// Turns bytecode into an AbcCode object. /// </summary> /// <param name="bytecode">The bytecode, as chopped out of a SWF.</param> /// <param name="readLog">Ignored in release builds. This logs /// on every constant value read for unit test inspection.</param> /// <returns>A string rendition of the bytecode.</returns> public AbcCode Read(byte[] bytecode, StringBuilder readLog) { #if DEBUG this.ReadLog = readLog; if (this.ReadLog != null) { this.ReadLog.AppendLine("\nNew ABC file\n-----------\n"); } #endif this.code = new AbcCode(); this.abcdtr = new ABCDataTypeReader(new MemoryStream(bytecode)); this.LateResolutions = new Dictionary<object, int>(); int minor = this.abcdtr.ReadUI16(); int major = this.abcdtr.ReadUI16(); if (minor != AbcFileValues.MinorVersion || major != AbcFileValues.MajorVersion) { throw new SWFModellerException( SWFModellerError.ABCParsing, "Unsupported version, or not an ABC file."); } this.ReadConstantPool(); this.ReadMethods(); this.ReadMetadata(); this.ReadClasses(); this.ReadScriptDefs(); this.ReadMethodBodies(); this.ResolveReferences(); return this.code; }
/// <summary> /// Convenience method for creating an opcode from a position in a byte array. /// Returns an opcode object with references resolved and advances the position /// to the next place in the byte array. /// </summary> /// <param name="reader">Where to read the next opcode from</param> /// <param name="abc">The code within which we're reading</param> /// <returns>A new Opcode object, or null if there was no more data to be read</returns> public static Opcode BuildOpcode(ABCDataTypeReader reader, AbcCode abc) { Opcode op = new Opcode(abc); int code; code = reader.ReadUI8(); if (code == -1) { return(null); } op.Instruction = (uint)code; if (OpcodeTable[code] == null) { throw new SWFModellerException( SWFModellerError.Internal, "Bad opcode 0x" + code.ToString("X") + " at @" + (reader.Offset - 1)); } OpcodeDef info = (OpcodeDef)OpcodeTable[code]; List <object> args = new List <object>(); if (info.Mnemonic == Mnemonics.LookupSwitch) { /* Special case: Has a variable arg */ args.Add(reader.ReadSI24()); /* default offset */ uint caseCount = reader.ReadU30(); args.Add(caseCount); for (int i = 0; i < caseCount + 1; i++) { args.Add(reader.ReadSI24()); } } else { if (info.Args != null) { foreach (ArgType type in info.Args) { switch (type) { case ArgType.MultinameU30: args.Add(abc.GetMultiname((int)reader.ReadU30())); break; case ArgType.OffsetS24: args.Add(reader.ReadSI24()); break; case ArgType.StringU30: args.Add(abc.StringConsts[reader.ReadU30()]); break; case ArgType.RegisterU30: case ArgType.ObjectRegisterU30: case ArgType.PropertyRegisterU30: args.Add(reader.ReadU30()); break; case ArgType.ByteU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.ShortU30: case ArgType.IntU30: case ArgType.UintU30: case ArgType.DoubleU30: args.Add(reader.ReadU30()); break; case ArgType.ShortS30: args.Add((int)reader.ReadU30()); break; case ArgType.ByteS8: args.Add(reader.ReadSI8()); break; case ArgType.NamespaceU30: args.Add(abc.GetNamespace((int)reader.ReadU30())); break; case ArgType.MethodU30: args.Add(abc.GetMethod((int)reader.ReadU30())); break; case ArgType.CountU30: args.Add(reader.ReadU30()); break; case ArgType.ClassU30: args.Add(abc.GetClass((int)reader.ReadU30())); break; case ArgType.ExceptionU30: args.Add(reader.ReadU30()); break; case ArgType.StackU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.SlotU30: args.Add(reader.ReadU30()); break; case ArgType.DebugU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.DebugTypeU30: args.Add(reader.ReadU30()); break; case ArgType.StringU8: args.Add(abc.StringConsts[reader.ReadUI8()]); break; case ArgType.LineNumberU30: args.Add(reader.ReadU30()); break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Oops. Not done " + type.ToString()); } } } } op.Args = args.ToArray(); return(op); }
/// <summary> /// Convenience method for creating an opcode from a position in a byte array. /// Returns an opcode object with references resolved and advances the position /// to the next place in the byte array. /// </summary> /// <param name="reader">Where to read the next opcode from</param> /// <param name="abc">The code within which we're reading</param> /// <returns>A new Opcode object, or null if there was no more data to be read</returns> public static Opcode BuildOpcode(ABCDataTypeReader reader, AbcCode abc) { Opcode op = new Opcode(abc); int code; code = reader.ReadUI8(); if (code == -1) { return null; } op.Instruction = (uint)code; if (OpcodeTable[code] == null) { throw new SWFModellerException( SWFModellerError.Internal, "Bad opcode 0x" + code.ToString("X") + " at @" + (reader.Offset - 1)); } OpcodeDef info = (OpcodeDef)OpcodeTable[code]; List<object> args = new List<object>(); if (info.Mnemonic == Mnemonics.LookupSwitch) { /* Special case: Has a variable arg */ args.Add(reader.ReadSI24()); /* default offset */ uint caseCount = reader.ReadU30(); args.Add(caseCount); for (int i = 0; i < caseCount + 1; i++) { args.Add(reader.ReadSI24()); } } else { if (info.Args != null) { foreach (ArgType type in info.Args) { switch (type) { case ArgType.MultinameU30: args.Add(abc.GetMultiname((int)reader.ReadU30())); break; case ArgType.OffsetS24: args.Add(reader.ReadSI24()); break; case ArgType.StringU30: args.Add(abc.StringConsts[reader.ReadU30()]); break; case ArgType.RegisterU30: case ArgType.ObjectRegisterU30: case ArgType.PropertyRegisterU30: args.Add(reader.ReadU30()); break; case ArgType.ByteU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.ShortU30: case ArgType.IntU30: case ArgType.UintU30: case ArgType.DoubleU30: args.Add(reader.ReadU30()); break; case ArgType.ShortS30: args.Add((int)reader.ReadU30()); break; case ArgType.ByteS8: args.Add(reader.ReadSI8()); break; case ArgType.NamespaceU30: args.Add(abc.GetNamespace((int)reader.ReadU30())); break; case ArgType.MethodU30: args.Add(abc.GetMethod((int)reader.ReadU30())); break; case ArgType.CountU30: args.Add(reader.ReadU30()); break; case ArgType.ClassU30: args.Add(abc.GetClass((int)reader.ReadU30())); break; case ArgType.ExceptionU30: args.Add(reader.ReadU30()); break; case ArgType.StackU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.SlotU30: args.Add(reader.ReadU30()); break; case ArgType.DebugU8: args.Add((byte)reader.ReadUI8()); break; case ArgType.DebugTypeU30: args.Add(reader.ReadU30()); break; case ArgType.StringU8: args.Add(abc.StringConsts[reader.ReadUI8()]); break; case ArgType.LineNumberU30: args.Add(reader.ReadU30()); break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Oops. Not done " + type.ToString()); } } } } op.Args = args.ToArray(); return op; }
/// <summary> /// Converts the method's bytecode into parsed opcodes, if it hasn't been /// disassembled already. /// </summary> /// <returns>Returns this method, for call chaining.</returns> public Method Disassemble() { if (this.opcodes != null) { // Already disassembled return(this); } ABCDataTypeReader reader = new ABCDataTypeReader(new MemoryStream(this.Bytes)); List <Opcode> ops = new List <Opcode>(); Dictionary <int, Opcode> offsetToOpcode = new Dictionary <int, Opcode>(); Dictionary <Opcode, int> opcodeToOffset = new Dictionary <Opcode, int>(); Dictionary <Opcode, int> opcodeLen = new Dictionary <Opcode, int>(); Opcode op = null; do { int offset = (int)reader.Offset; op = Opcode.BuildOpcode(reader, this.Code); if (op != null) { #if (DEBUG) op.NumberLabel = ++this.opcodeIndex; #endif int len = op.Mnemonic == Opcode.Mnemonics.LookupSwitch ? 0 : (int)reader.Offset - offset; offsetToOpcode.Add(offset, op); opcodeToOffset.Add(op, offset); opcodeLen.Add(op, len); ops.Add(op); } }while (op != null); foreach (ExceptionHandler eh in this.exceptionHandlers) { eh.From = offsetToOpcode[eh.From]; eh.To = offsetToOpcode[eh.To]; eh.Target = offsetToOpcode[eh.Target]; } this.opcodes = ops.ToArray(); foreach (Opcode hasOffsets in this.opcodes.Where(o => o.HasOffsets)) { hasOffsets.OffsetProc(delegate(object arg) { int offset = (int)arg; int current = opcodeToOffset[hasOffsets]; int len = opcodeLen[hasOffsets]; int jumpTo = current + offset + len; return(offsetToOpcode[jumpTo]); }); } return(this); }