Esempio n. 1
0
        private byte[] GenerateMethodInfo()
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            Method[] methods = this.methodMarshal.ToArray();
            writer.WriteU30Packed((uint)methods.Length);
            foreach (Method method in methods)
            {
                writer.WriteU30Packed((uint)method.ParamCount);

                if (method.ReturnType != null)
                {
                    writer.WriteU30Packed((uint)this.MultinameID(method.ReturnType));
                }
                else
                {
                    writer.WriteU30Packed(0);
                }

                using (IEnumerator <Multiname> i = method.ParamTypes)
                {
                    while (i.MoveNext())
                    {
                        writer.WriteU30Packed((uint)this.MultinameID(i.Current));
                    }
                }

                writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(method.Name));
                writer.WriteUI8((uint)method.Flags);

                if (method.HasOptionalArgs)
                {
                    /* ISSUE 9 */
                    throw new SWFModellerException(
                              SWFModellerError.UnimplementedFeature,
                              "Optional arguments in methods.");
                }

                if (method.HasParamNames)
                {
                    /* ISSUE 12 */
                    throw new SWFModellerException(
                              SWFModellerError.UnimplementedFeature,
                              "Named method parameters");
                }
            }

            writer.Close(); /* Closes the buffer */
            return(buf.ToArray());
        }
Esempio n. 2
0
        private byte[] GenerateMetadata(AbcCode code)
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.MetadataCount);

            foreach (string key in code.MetadataKeys)
            {
                writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(key));
                Dictionary <string, string> itemInfo = code.GetMetadata(key);
                writer.WriteU30Packed((uint)itemInfo.Count);
                foreach (string itemKey in itemInfo.Keys)
                {
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemKey));
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemInfo[itemKey]));
                }
            }

            writer.Close(); /* Closes the buffer */
            return(buf.ToArray());
        }
Esempio n. 3
0
        private byte[] GenerateScriptInfo(AbcCode code)
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.ScriptCount);

            foreach (Script s in code.Scripts)
            {
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(s.Method));

                writer.WriteU30Packed((uint)s.TraitCount);
                using (IEnumerator <Trait> i = s.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            writer.Close(); /* Closes the buffer */
            return(buf.ToArray());
        }
Esempio n. 4
0
        private byte[] GenerateClassInfo()
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            AS3ClassDef[] classes = this.classMarshal.ToArray();

            writer.WriteU30Packed((uint)classes.Length);
#if DEBUG
            int _cid = 1;
            this.writeLog.AppendLine("Classes count " + classes.Length);
#endif
            /* First, instance info... */
            foreach (AS3ClassDef clazz in classes)
            {
#if DEBUG
                this.writeLog.AppendLine((_cid++) + " Class " + clazz.Name + " (mn ID " + (uint)this.MultinameID(clazz.Name) + ")");
#endif
                writer.WriteU30Packed((uint)this.MultinameID(clazz.Name));
                writer.WriteU30Packed((uint)this.MultinameID(clazz.Supername));
                writer.WriteUI8((uint)clazz.Flags);

                if (clazz.IsProtectedNS)
                {
                    writer.WriteU30Packed((uint)this.NamespaceID(clazz.ProtectedNS));
                }

                writer.WriteU30Packed((uint)clazz.InterfaceCount);

                using (IEnumerator <Multiname> i = clazz.Interfaces)
                {
                    while (i.MoveNext())
                    {
#if DEBUG
                        this.writeLog.AppendLine("    implements " + i.Current + " (mn ID " + (uint)this.MultinameID(i.Current) + ")");
#endif
                        writer.WriteU30Packed((uint)this.MultinameID(i.Current));
                    }
                }
#if DEBUG
                this.writeLog.AppendLine("    Iinit ID " + (uint)this.methodMarshal.GetIDFor(clazz.Iinit));
#endif
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(clazz.Iinit));

                writer.WriteU30Packed((uint)clazz.InstanceTraitCount);
                using (IEnumerator <Trait> i = clazz.InstanceTraits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            /* Second, class info... */
            foreach (AS3ClassDef clazz in classes)
            {
#if DEBUG
                this.writeLog.AppendLine("Class cinit ID for '" + clazz.Name + "' " + (uint)this.methodMarshal.GetIDFor(clazz.Cinit));
#endif
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(clazz.Cinit));

                writer.WriteU30Packed((uint)clazz.ClassTraitCount);
                using (IEnumerator <Trait> i = clazz.ClassTraits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            writer.Close(); /* Closes the buffer */
            return(buf.ToArray());
        }
Esempio n. 5
0
        public void AssembleIfNecessary(DoABC codeTag, bool insertDebugCodes, string mainClassName, StringBuilder writeLog)
        {
            this.InsertDebugCodes = insertDebugCodes;

#if DEBUG
            this.writeLog = writeLog;
            if (this.writeLog == null)
            {
                /* Bit of a kludge. If we passed null for this, we don't want a log. We'd rather not
                 * put null tests everywhere though, so we create this string builder and log stuff
                 * to it knowing full well it will be discarded and is a waste of time. It's convenient,
                 * and it's only the debug build, so we don't really care about the waste. */
                this.writeLog = new StringBuilder();
            }
#endif

            /* Firstly, if any methods are altered, we need to decompile all of them since the
             * table references will all be wrong. Check all the methods for tampering... */

            AbcCode code = codeTag.Code;

            if (!code.IsTampered)
            {
                return;
            }

            /* At this point, all we know is that at least one piece of code
             * needs re-assembly. IsTampered doesn't meant everything is necessarily
             * tampered, although it probably is. */

            /* We've established that we actually do need to do some work */

            MemoryStream      buffer = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buffer);

            /* Ok, someone tampered with a method. Now we need to decompile them all and
             * re-build them... */
            foreach (Method m in code.Methods)
            {
                if (!m.Tampered)
                {
                    m.Tampered = true; /* Dissassembles the code and forces re-assembly. */
                }
            }

            /* Another side-effect of such meddling is the need to re-build the tables... */
            this.ReBuildTables(code, mainClassName);

            /* At this point, we will have a set of clean-built or untampered tables, and
             * calls to Method.Bytes will either return pre-built bytecode, or assemble it
             * on-demand for us. In other words, everything can just be dumped into a file. */

            writer.WriteUI16(AbcFileValues.MinorVersion);
            writer.WriteUI16(AbcFileValues.MajorVersion);

            byte[] methodInfoBytes = this.GenerateMethodInfo();
            byte[] metadataBytes   = this.GenerateMetadata(code);
            byte[] classInfo       = this.GenerateClassInfo();
            byte[] scriptInfo      = this.GenerateScriptInfo(code);

            /* When we write out the constant pool, the constants are fixed in the code object with
             * those values. In other words at this point we'd better be damn sure we've added all the
             * constants to the pools. */
            this.WriteConstantPool(writer, code);

            writer.Write(methodInfoBytes, 0, methodInfoBytes.Length);
            writer.Write(metadataBytes, 0, metadataBytes.Length);
            writer.Write(classInfo, 0, classInfo.Length);
            writer.Write(scriptInfo, 0, scriptInfo.Length);

            this.WriteMethodBodies(writer);

            writer.Close(); /* Also closes buffer. */
            codeTag.Bytecode = buffer.ToArray();
        }
Esempio n. 6
0
        private byte[] GenerateScriptInfo(AbcCode code)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.ScriptCount);

            foreach (Script s in code.Scripts)
            {
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(s.Method));

                writer.WriteU30Packed((uint)s.TraitCount);
                using (IEnumerator<Trait> i = s.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }
Esempio n. 7
0
        private void AssembleMethod(Method method)
        {
            MemoryStream      buf    = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            this.methodMarshal.Register(method);

            using (IEnumerator <ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    this.RegisterMultiname(eh.CatchType);
                    this.RegisterMultiname(eh.VarName);
                }
            }

            bool insertDebugCodes = this.InsertDebugCodes;

            if (insertDebugCodes)
            {
                /* Quick check to see if the code already has them, in which case we
                 * won't bother. */
                foreach (Opcode op in method.Opcodes)
                {
                    if (op.Mnemonic == Opcode.Mnemonics.DebugFile || op.Mnemonic == Opcode.Mnemonics.DebugLine)
                    {
                        insertDebugCodes = false;
                        break;
                    }
                }
            }

            IEnumerable <Opcode> opcodes = method.Opcodes;

            if (insertDebugCodes)
            {
                List <Opcode> debugged = new List <Opcode>();

                debugged.Add(Opcode.CreateDebugFile(method.SourceFile));

                /* Let's just check this string won't break things... */
                uint srcPos = (uint)this.stringMarshal.GetIDFor(method.SourceFile);
                if (srcPos > 255)
                {
                    /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                    throw new SWFModellerException(
                              SWFModellerError.CodeMerge,
                              "Marshaller failed to keep debug string at low index");
                }

                uint lineNumber = 1; /* For our fake debug info. */
                foreach (Opcode op in opcodes)
                {
                    debugged.Add(Opcode.CreateDebugLine(lineNumber++));
                    debugged.Add(op);
                }

                opcodes = debugged;
            }

            Dictionary <Opcode, int> offsetMap = new Dictionary <Opcode, int>();
            Dictionary <Opcode, int> lenMap    = new Dictionary <Opcode, int>();
            List <KeyValuePair <Opcode, KeyValuePair <Opcode, int> > > unresolvedOffsets = new List <KeyValuePair <Opcode, KeyValuePair <Opcode, int> > >();

            foreach (Opcode op in opcodes)
            {
                int startOffset = (int)writer.Offset;
                offsetMap.Add(op, startOffset);

                writer.WriteUI8(op.Instruction);

                if (op.Mnemonic == Opcode.Mnemonics.LookupSwitch)
                {
                    for (int i = 0; i < op.Args.Length; i++)
                    {
                        int argOffset = (int)writer.Offset - startOffset;
                        KeyValuePair <Opcode, int> sourceInfo = new KeyValuePair <Opcode, int>(op, argOffset);
                        object argOb = op.Args[i];
                        if (i == 1)
                        {
                            writer.WriteU30Packed((uint)(op.Args.Length - 3));
                        }
                        else
                        {
                            unresolvedOffsets.Add(new KeyValuePair <Opcode, KeyValuePair <Opcode, int> >((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                        }
                    }

                    lenMap.Add(op, 0);
                    continue;
                }

                Opcode.ArgType[] types = op.ArgTypes;
                if (types == null)
                {
                    /* done. */
                    lenMap.Add(op, (int)writer.Offset - startOffset);
                    continue;
                }

                if (types.Length != op.Args.Length)
                {
                    throw new SWFModellerException(
                              SWFModellerError.Internal,
                              "Arg mismatch in op " + op + " (" + types.Length + " expected)");
                }

                for (int i = 0; i < op.Args.Length; i++)
                {
                    object         argOb   = op.Args[i];
                    Opcode.ArgType argType = types[i];

                    switch (argType)
                    {
                    case Opcode.ArgType.MultinameU30:
                        writer.WriteU30Packed((uint)this.MultinameID((Multiname)argOb));
                        break;

                    case Opcode.ArgType.CountU30:
                    case Opcode.ArgType.UintU30:
                    case Opcode.ArgType.IntU30:
                    case Opcode.ArgType.LineNumberU30:
                    case Opcode.ArgType.RegisterU30:
                    case Opcode.ArgType.ObjectRegisterU30:
                    case Opcode.ArgType.PropertyRegisterU30:
                    case Opcode.ArgType.ShortU30:
                    case Opcode.ArgType.DoubleU30:
                        writer.WriteU30Packed((uint)argOb);
                        break;

                    case Opcode.ArgType.ByteU8:
                    case Opcode.ArgType.DebugU8:
                    case Opcode.ArgType.StackU8:
                        writer.WriteUI8((byte)argOb);
                        break;

                    case Opcode.ArgType.StringU8:
                        uint spos = (uint)this.stringMarshal.GetIDFor((string)argOb);
                        if (spos > 255)
                        {
                            /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                            throw new SWFModellerException(
                                      SWFModellerError.Internal,
                                      "Marshaller failed to keep debug string at low index");
                        }

                        writer.WriteUI8(spos);
                        break;

                    case Opcode.ArgType.StringU30:
                        writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor((string)argOb));
                        break;

                    case Opcode.ArgType.ClassU30:
                        writer.WriteU30Packed((uint)this.classMarshal.GetIDFor((AS3ClassDef)argOb));
                        break;

                    case Opcode.ArgType.ByteS8:
                        writer.WriteSI8((int)argOb);
                        break;

                    case Opcode.ArgType.ShortS30:
                        writer.WriteSI32((int)argOb);     /* Spec says this signed value is a U30. Stupid spec. */
                        break;

                    case Opcode.ArgType.OffsetS24:
                        if (argOb is Opcode)
                        {
                            int argOffset = (int)writer.Offset - startOffset;
                            KeyValuePair <Opcode, int> sourceInfo = new KeyValuePair <Opcode, int>(op, argOffset);
                            unresolvedOffsets.Add(new KeyValuePair <Opcode, KeyValuePair <Opcode, int> >((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD);     /* Because dead beef won't fit in 3 bytes. */
                        }
                        else
                        {
                            /* ISSUE 73 */
                            throw new SWFModellerException(
                                      SWFModellerError.UnimplementedFeature,
                                      "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                        }

                        break;

                    case Opcode.ArgType.ExceptionU30:
                        writer.WriteU30Packed((uint)argOb);     /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                        break;

                    case Opcode.ArgType.SlotU30:
                        writer.WriteU30Packed((uint)argOb);     /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                        break;

                    case Opcode.ArgType.NamespaceU30:
                    case Opcode.ArgType.MethodU30:
                    case Opcode.ArgType.DebugTypeU30:
                    default:
                        /* ISSUE 73 */
                        throw new SWFModellerException(
                                  SWFModellerError.UnimplementedFeature,
                                  "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                    }
                }

                lenMap.Add(op, (int)writer.Offset - startOffset);
            }

            using (IEnumerator <ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    eh.From   = offsetMap[eh.From];
                    eh.To     = offsetMap[eh.To];
                    eh.Target = offsetMap[eh.Target];
                }
            }

            writer.Close(); /* Also closes the buffer. */

            byte[] byteBuffer = buf.ToArray();

            foreach (KeyValuePair <Opcode, KeyValuePair <Opcode, int> > link in unresolvedOffsets)
            {
                KeyValuePair <Opcode, int> sourceInfo = link.Value;
                int srcOffset = offsetMap[sourceInfo.Key];
                int argOffset = srcOffset + sourceInfo.Value;
                int val       = offsetMap[link.Key] - srcOffset - lenMap[sourceInfo.Key];
                new ABCDataTypeWriter(new MemoryStream(byteBuffer, argOffset, 3)).WriteSI24(val);
            }

            method.Bytes = byteBuffer;
        }
Esempio n. 8
0
        private byte[] GenerateMethodInfo()
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            Method[] methods = this.methodMarshal.ToArray();
            writer.WriteU30Packed((uint)methods.Length);
            foreach (Method method in methods)
            {
                writer.WriteU30Packed((uint)method.ParamCount);

                if (method.ReturnType != null)
                {
                    writer.WriteU30Packed((uint)this.MultinameID(method.ReturnType));
                }
                else
                {
                    writer.WriteU30Packed(0);
                }

                using (IEnumerator<Multiname> i = method.ParamTypes)
                {
                    while (i.MoveNext())
                    {
                        writer.WriteU30Packed((uint)this.MultinameID(i.Current));
                    }
                }

                writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(method.Name));
                writer.WriteUI8((uint)method.Flags);

                if (method.HasOptionalArgs)
                {
                    /* ISSUE 9 */
                    throw new SWFModellerException(
                            SWFModellerError.UnimplementedFeature,
                            "Optional arguments in methods.");
                }

                if (method.HasParamNames)
                {
                    /* ISSUE 12 */
                    throw new SWFModellerException(
                            SWFModellerError.UnimplementedFeature,
                            "Named method parameters");
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }
Esempio n. 9
0
        private byte[] GenerateMetadata(AbcCode code)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            writer.WriteU30Packed((uint)code.MetadataCount);

            foreach (string key in code.MetadataKeys)
            {
                writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(key));
                Dictionary<string, string> itemInfo = code.GetMetadata(key);
                writer.WriteU30Packed((uint)itemInfo.Count);
                foreach (string itemKey in itemInfo.Keys)
                {
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemKey));
                    writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor(itemInfo[itemKey]));
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }
Esempio n. 10
0
        public void AssembleIfNecessary(DoABC codeTag, bool insertDebugCodes, string mainClassName, StringBuilder writeLog)
        {
            this.InsertDebugCodes = insertDebugCodes;

            #if DEBUG
            this.writeLog = writeLog;
            if (this.writeLog == null)
            {
                /* Bit of a kludge. If we passed null for this, we don't want a log. We'd rather not
                 * put null tests everywhere though, so we create this string builder and log stuff
                 * to it knowing full well it will be discarded and is a waste of time. It's convenient,
                 * and it's only the debug build, so we don't really care about the waste. */
                this.writeLog = new StringBuilder();
            }
            #endif

            /* Firstly, if any methods are altered, we need to decompile all of them since the
             * table references will all be wrong. Check all the methods for tampering... */

            AbcCode code = codeTag.Code;

            if (!code.IsTampered)
            {
                return;
            }

            /* At this point, all we know is that at least one piece of code
             * needs re-assembly. IsTampered doesn't meant everything is necessarily
             * tampered, although it probably is. */

            /* We've established that we actually do need to do some work */

            MemoryStream buffer = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buffer);

            /* Ok, someone tampered with a method. Now we need to decompile them all and
             * re-build them... */
            foreach (Method m in code.Methods)
            {
                if (!m.Tampered)
                {
                    m.Tampered = true; /* Dissassembles the code and forces re-assembly. */
                }
            }

            /* Another side-effect of such meddling is the need to re-build the tables... */
            this.ReBuildTables(code, mainClassName);

            /* At this point, we will have a set of clean-built or untampered tables, and
             * calls to Method.Bytes will either return pre-built bytecode, or assemble it
             * on-demand for us. In other words, everything can just be dumped into a file. */

            writer.WriteUI16(AbcFileValues.MinorVersion);
            writer.WriteUI16(AbcFileValues.MajorVersion);

            byte[] methodInfoBytes = this.GenerateMethodInfo();
            byte[] metadataBytes = this.GenerateMetadata(code);
            byte[] classInfo = this.GenerateClassInfo();
            byte[] scriptInfo = this.GenerateScriptInfo(code);

            /* When we write out the constant pool, the constants are fixed in the code object with
             * those values. In other words at this point we'd better be damn sure we've added all the
             * constants to the pools. */
            this.WriteConstantPool(writer, code);

            writer.Write(methodInfoBytes, 0, methodInfoBytes.Length);
            writer.Write(metadataBytes, 0, metadataBytes.Length);
            writer.Write(classInfo, 0, classInfo.Length);
            writer.Write(scriptInfo, 0, scriptInfo.Length);

            this.WriteMethodBodies(writer);

            writer.Close(); /* Also closes buffer. */
            codeTag.Bytecode = buffer.ToArray();
        }
Esempio n. 11
0
        private byte[] GenerateClassInfo()
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            AS3ClassDef[] classes = this.classMarshal.ToArray();

            writer.WriteU30Packed((uint)classes.Length);
            #if DEBUG
            int _cid = 1;
            this.writeLog.AppendLine("Classes count " + classes.Length);
            #endif
            /* First, instance info... */
            foreach (AS3ClassDef clazz in classes)
            {
            #if DEBUG
                this.writeLog.AppendLine((_cid++) + " Class " + clazz.Name + " (mn ID " + (uint)this.MultinameID(clazz.Name) + ")");
            #endif
                writer.WriteU30Packed((uint)this.MultinameID(clazz.Name));
                writer.WriteU30Packed((uint)this.MultinameID(clazz.Supername));
                writer.WriteUI8((uint)clazz.Flags);

                if (clazz.IsProtectedNS)
                {
                    writer.WriteU30Packed((uint)this.NamespaceID(clazz.ProtectedNS));
                }

                writer.WriteU30Packed((uint)clazz.InterfaceCount);

                using (IEnumerator<Multiname> i = clazz.Interfaces)
                {
                    while (i.MoveNext())
                    {
            #if DEBUG
                        this.writeLog.AppendLine("    implements " + i.Current + " (mn ID " + (uint)this.MultinameID(i.Current) + ")");
            #endif
                        writer.WriteU30Packed((uint)this.MultinameID(i.Current));
                    }
                }
            #if DEBUG
                this.writeLog.AppendLine("    Iinit ID " + (uint)this.methodMarshal.GetIDFor(clazz.Iinit));
            #endif
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(clazz.Iinit));

                writer.WriteU30Packed((uint)clazz.InstanceTraitCount);
                using (IEnumerator<Trait> i = clazz.InstanceTraits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            /* Second, class info... */
            foreach (AS3ClassDef clazz in classes)
            {
            #if DEBUG
                this.writeLog.AppendLine("Class cinit ID for '" + clazz.Name + "' " + (uint)this.methodMarshal.GetIDFor(clazz.Cinit));
            #endif
                writer.WriteU30Packed((uint)this.methodMarshal.GetIDFor(clazz.Cinit));

                writer.WriteU30Packed((uint)clazz.ClassTraitCount);
                using (IEnumerator<Trait> i = clazz.ClassTraits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }

            writer.Close(); /* Closes the buffer */
            return buf.ToArray();
        }
Esempio n. 12
0
        private void AssembleMethod(Method method)
        {
            MemoryStream buf = new MemoryStream();
            ABCDataTypeWriter writer = new ABCDataTypeWriter(buf);

            this.methodMarshal.Register(method);

            using (IEnumerator<ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    this.RegisterMultiname(eh.CatchType);
                    this.RegisterMultiname(eh.VarName);
                }
            }

            bool insertDebugCodes = this.InsertDebugCodes;

            if (insertDebugCodes)
            {
                /* Quick check to see if the code already has them, in which case we
                 * won't bother. */
                foreach (Opcode op in method.Opcodes)
                {
                    if (op.Mnemonic == Opcode.Mnemonics.DebugFile || op.Mnemonic == Opcode.Mnemonics.DebugLine)
                    {
                        insertDebugCodes = false;
                        break;
                    }
                }
            }

            IEnumerable<Opcode> opcodes = method.Opcodes;

            if (insertDebugCodes)
            {
                List<Opcode> debugged = new List<Opcode>();

                debugged.Add(Opcode.CreateDebugFile(method.SourceFile));

                /* Let's just check this string won't break things... */
                uint srcPos = (uint)this.stringMarshal.GetIDFor(method.SourceFile);
                if (srcPos > 255)
                {
                    /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                    throw new SWFModellerException(
                            SWFModellerError.CodeMerge,
                            "Marshaller failed to keep debug string at low index");
                }

                uint lineNumber = 1; /* For our fake debug info. */
                foreach (Opcode op in opcodes)
                {
                    debugged.Add(Opcode.CreateDebugLine(lineNumber++));
                    debugged.Add(op);
                }

                opcodes = debugged;
            }

            Dictionary<Opcode, int> offsetMap = new Dictionary<Opcode, int>();
            Dictionary<Opcode, int> lenMap = new Dictionary<Opcode, int>();
            List<KeyValuePair<Opcode, KeyValuePair<Opcode, int>>> unresolvedOffsets = new List<KeyValuePair<Opcode, KeyValuePair<Opcode, int>>>();

            foreach (Opcode op in opcodes)
            {
                int startOffset = (int)writer.Offset;
                offsetMap.Add(op, startOffset);

                writer.WriteUI8(op.Instruction);

                if (op.Mnemonic == Opcode.Mnemonics.LookupSwitch)
                {
                    for (int i = 0; i < op.Args.Length; i++)
                    {
                        int argOffset = (int)writer.Offset - startOffset;
                        KeyValuePair<Opcode, int> sourceInfo = new KeyValuePair<Opcode, int>(op, argOffset);
                        object argOb = op.Args[i];
                        if (i == 1)
                        {
                            writer.WriteU30Packed((uint)(op.Args.Length - 3));
                        }
                        else
                        {
                            unresolvedOffsets.Add(new KeyValuePair<Opcode, KeyValuePair<Opcode, int>>((Opcode)argOb, sourceInfo));
                            writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                        }
                    }

                    lenMap.Add(op, 0);
                    continue;
                }

                Opcode.ArgType[] types = op.ArgTypes;
                if (types == null)
                {
                    /* done. */
                    lenMap.Add(op, (int)writer.Offset - startOffset);
                    continue;
                }

                if (types.Length != op.Args.Length)
                {
                    throw new SWFModellerException(
                            SWFModellerError.Internal,
                            "Arg mismatch in op " + op + " (" + types.Length + " expected)");
                }

                for (int i = 0; i < op.Args.Length; i++)
                {
                    object argOb = op.Args[i];
                    Opcode.ArgType argType = types[i];

                    switch (argType)
                    {
                        case Opcode.ArgType.MultinameU30:
                            writer.WriteU30Packed((uint)this.MultinameID((Multiname)argOb));
                            break;

                        case Opcode.ArgType.CountU30:
                        case Opcode.ArgType.UintU30:
                        case Opcode.ArgType.IntU30:
                        case Opcode.ArgType.LineNumberU30:
                        case Opcode.ArgType.RegisterU30:
                        case Opcode.ArgType.ObjectRegisterU30:
                        case Opcode.ArgType.PropertyRegisterU30:
                        case Opcode.ArgType.ShortU30:
                        case Opcode.ArgType.DoubleU30:
                            writer.WriteU30Packed((uint)argOb);
                            break;

                        case Opcode.ArgType.ByteU8:
                        case Opcode.ArgType.DebugU8:
                        case Opcode.ArgType.StackU8:
                            writer.WriteUI8((byte)argOb);
                            break;

                        case Opcode.ArgType.StringU8:
                            uint spos = (uint)this.stringMarshal.GetIDFor((string)argOb);
                            if (spos > 255)
                            {
                                /* ISSUE 10: Best fix may be to strip out debug opcodes. */
                                throw new SWFModellerException(
                                        SWFModellerError.Internal,
                                        "Marshaller failed to keep debug string at low index");
                            }

                            writer.WriteUI8(spos);
                            break;

                        case Opcode.ArgType.StringU30:
                            writer.WriteU30Packed((uint)this.stringMarshal.GetIDFor((string)argOb));
                            break;

                        case Opcode.ArgType.ClassU30:
                            writer.WriteU30Packed((uint)this.classMarshal.GetIDFor((AS3ClassDef)argOb));
                            break;

                        case Opcode.ArgType.ByteS8:
                            writer.WriteSI8((int)argOb);
                            break;

                        case Opcode.ArgType.ShortS30:
                            writer.WriteSI32((int)argOb); /* Spec says this signed value is a U30. Stupid spec. */
                            break;

                        case Opcode.ArgType.OffsetS24:
                            if (argOb is Opcode)
                            {
                                int argOffset = (int)writer.Offset - startOffset;
                                KeyValuePair<Opcode, int> sourceInfo = new KeyValuePair<Opcode, int>(op, argOffset);
                                unresolvedOffsets.Add(new KeyValuePair<Opcode, KeyValuePair<Opcode, int>>((Opcode)argOb, sourceInfo));
                                writer.WriteSI24(0x00FFDEAD); /* Because dead beef won't fit in 3 bytes. */
                            }
                            else
                            {
                                /* ISSUE 73 */
                                throw new SWFModellerException(
                                        SWFModellerError.UnimplementedFeature,
                                        "Unsupported op arg type in " + op.Mnemonic.ToString() + ": " + argType);
                            }

                            break;

                        case Opcode.ArgType.ExceptionU30:
                            writer.WriteU30Packed((uint)argOb); /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                            break;

                        case Opcode.ArgType.SlotU30:
                            writer.WriteU30Packed((uint)argOb); /* Reference into the fixed list of exception handlers. TODO: Make it not so fixed. */
                            break;

                        case Opcode.ArgType.NamespaceU30:
                        case Opcode.ArgType.MethodU30:
                        case Opcode.ArgType.DebugTypeU30:
                        default:
                            /* ISSUE 73 */
                            throw new SWFModellerException(
                                    SWFModellerError.UnimplementedFeature,
                                    "Unsupported op arg type in "+op.Mnemonic.ToString()+": " + argType);
                    }
                }

                lenMap.Add(op, (int)writer.Offset - startOffset);
            }

            using (IEnumerator<ExceptionHandler> i = method.ExceptionHandlers)
            {
                while (i.MoveNext())
                {
                    ExceptionHandler eh = i.Current;
                    eh.From = offsetMap[eh.From];
                    eh.To = offsetMap[eh.To];
                    eh.Target = offsetMap[eh.Target];
                }
            }

            writer.Close(); /* Also closes the buffer. */

            byte[] byteBuffer = buf.ToArray();

            foreach (KeyValuePair<Opcode, KeyValuePair<Opcode, int>> link in unresolvedOffsets)
            {
                KeyValuePair<Opcode, int> sourceInfo = link.Value;
                int srcOffset = offsetMap[sourceInfo.Key];
                int argOffset = srcOffset + sourceInfo.Value;
                int val = offsetMap[link.Key] - srcOffset - lenMap[sourceInfo.Key];
                new ABCDataTypeWriter(new MemoryStream(byteBuffer, argOffset, 3)).WriteSI24(val);
            }

            method.Bytes = byteBuffer;
        }