Esempio n. 1
0
File: DoABC.cs Progetto: wl3780/as3c
        public override void ReadExternal(BinaryReader input)
        {
            _flags = input.ReadUInt32();

            _abc = new Abc46();
            _abc.Length = (uint)(_parent.Header.Length - 4);
            _abc.ReadExternal(input);
        }
Esempio n. 2
0
        protected override void FormatAbc(SwfLibrary.Abc.Abc46 abc)
        {
            base.FormatAbc(abc);

            MethodBodyInfo methodBody;
            AVM2Command    command;

            int n = abc.MethodBodies.Count;

            for (int i = 0; i < n; ++i)
            {
                methodBody = (MethodBodyInfo)abc.MethodBodies[i];

                FormatBody(methodBody);

                byte[] code = methodBody.Code;

                uint j = 0;
                int  m = code.Length;
                uint k;

                while (j < m)
                {
                    k       = j;
                    command = Translator.ToCommand(code[j++]);

                    if (null == command)
                    {
                        throw new Exception("Unknown opcode detected.");
                    }

                    j += command.ReadParameters(code, j);

                    FormatCommand(k, command);
                }
            }
        }
Esempio n. 3
0
        private static MethodBodyInfo FindBody(Abc46 abc, U30 methodIndex)
        {
            SwfLibrary.Abc.MethodInfo methodInfo = (SwfLibrary.Abc.MethodInfo)abc.Methods[(int)methodIndex];
            MethodBodyInfo methodBody = null;

            for (int i = 0, n = abc.MethodBodies.Count; i < n; ++i)
            {
                methodBody = (MethodBodyInfo)abc.MethodBodies[i];

                if (methodBody.Method.Value == methodIndex.Value)
                {
                    break;
                }
            }

            return methodBody;
        }
Esempio n. 4
0
        public static void CheckInlineFlag(Abc46 abc, MethodBodyInfo body)
        {
            byte[] code = body.Code;

            uint i = 0;
            uint n = (uint)code.Length;

            while (i < n)
            {
                AVM2Command command = Translator.ToCommand(code[i++]);
                i += command.ReadParameters(code, i);

                if (command.OpCode == (byte)Op.FindPropertyStrict)
                {
                    string name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value]));

                    if (CompilerInline.inlineMarker == name)
                    {
                        body.IsInline = true;
                        return;
                    }
                }
            }
        }
Esempio n. 5
0
        protected void PatchBody(Abc46 abc, MethodBodyInfo body, int bodyId)
        {
            AVM2Command command;
            AVM2Command inlineCommand;
            Dictionary<string, Label> labels = new Dictionary<string, Label>();
            ArrayList instructions = new ArrayList();
            Label label;
            string labelId;

            byte[] il = body.Code;

            uint i = 0;
            uint n = (uint)il.Length;

            uint addr;

            string name;

            bool hasManualMaxStack = false;
            uint manualMaxStackValue = 0;

            bool patchBody = false;
            //bool parseInline = false;

            _labelUtil.Clear();

            //
            // We will convert the bytecode into a format that the As3c compiler can understand.
            // When converting labels we will use a ':' in front of them instead of a '.' char for
            // the ones "defined" by the ASC so that we have unique names (label syntax is .label)
            //

            while (i < n)
            {
                addr = i;

                if (_labelUtil.IsMarked(addr))
                {
                    labelId = String.Format(":{0}:", _labelUtil.GetLabelAt(addr).id);
                    label = new Label(labelId);

                    labels.Add(labelId, label);
                    instructions.Add(label);
                }

                command = Translator.ToCommand(il[i++]);

                if (null == command)
                {
                    throw new Exception("Unknown opcode detected.");
                }

                i += command.ReadParameters(il, i);

                switch (command.OpCode)
                {
                    case (byte)Op.Label:

                        labelId = String.Format(":{0}:", _labelUtil.GetLabelAt(addr).id);
                        label = new Label(labelId);

                        labels.Add(labelId, label);
                        instructions.Add(label);

                        break;

                    case (byte)Op.IfEqual:
                    case (byte)Op.IfFalse:
                    case (byte)Op.IfGreaterEqual:
                    case (byte)Op.IfGreaterThan:
                    case (byte)Op.IfLessEqual:
                    case (byte)Op.IfLowerThan:
                    case (byte)Op.IfNotEqual:
                    case (byte)Op.IfNotGreaterEqual:
                    case (byte)Op.IfNotGreaterThan:
                    case (byte)Op.IfNotLowerEqual:
                    case (byte)Op.IfNotLowerThan:
                    case (byte)Op.IfStrictEqual:
                    case (byte)Op.IfStrictNotEqual:
                    case (byte)Op.IfTrue:
                    case (byte)Op.Jump:
                        // Convert label offset to label reference ...
                        S24 offset = (S24)command.Parameters[0];
                        command.Parameters[0] = String.Format(":{0}:",_labelUtil.GetLabelAt((uint)(addr + 1 + offset.Length + offset.Value)).id);
                        instructions.Add(command);
                        break;

                    case (byte)Op.GetLex:
                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value]));
                        //Console.WriteLine("Called GetLex {0}", name);
                        instructions.Add(command);
                        break;

                    case (byte)Op.FindPropertyStrict:
                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value]));
                        #region INLINE Block
                        if (inlineWrapper == name)
                        {
                            bool parse = true;
                            patchBody = true;

            #if DEBUG
                            Console.WriteLine("[i] Parsing inline block in method {0}", body.Method.Value);
            #endif
                            while (parse && i < n)
                            {
                                inlineCommand = Translator.ToCommand(il[i++]);

                                if (null == inlineCommand)
                                {
                                    throw new Exception("Unknown opcode detected.");
                                }

                                i += inlineCommand.ReadParameters(il, i);

                                switch (inlineCommand.OpCode)
                                {
                                    //
                                    // Debug instructions are kept even if they are in an inline block
                                    //

                                    case (byte)Op.Debug:
                                    case (byte)Op.DebugFile:
                                    case (byte)Op.DebugLine:
                                        instructions.Add(inlineCommand);
                                        break;

                                    //
                                    // Strings are treated as labels -- but make sure it is actually one!
                                    //

                                    case (byte)Op.PushString:

                                        labelId = ((StringInfo)abc.ConstantPool.StringTable[(int)((U30)inlineCommand.Parameters[0])]).ToString();

                                        if (labelId.IndexOf('.') != 0 || labelId.IndexOf(':') != (labelId.Length - 1))
                                        {
                                            throw new Exception(String.Format("Invalid string \"{0}\" in an inline block. Labels have the format \".labelName:\"", labelId));
                                        }

                                        labelId = labelId.Substring(0, labelId.Length - 1);
                                        label = new Label(labelId);

                                        labels.Add(labelId, label);
                                        instructions.Add(label);
                                        break;

                                    //
                                    // GetLex is the one that will bring public::de.popforge.asm::Op on the stack
                                    //

                                    case (byte)Op.GetLex:
                                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)inlineCommand.Parameters[0]).Value]));

                                        if (inlineKeyword != name)
                                        {
                                            throw new Exception("Malformed inline block. GetLex call with invalid parameters");
                                        }

                                        List<AVM2Command> args = new List<AVM2Command>();
                                        AVM2Command userCommand = null;
                                        uint argc;

                                        while (i < n)
                                        {
                                            AVM2Command arg = Translator.ToCommand(il[i++]);

                                            if (null == arg)
                                            {
                                                throw new Exception("Unknown opcode detected.");
                                            }

                                            i += arg.ReadParameters(il, i);

                                            if ((byte)Op.CallProperty == arg.OpCode)
                                            {
                                                name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)arg.Parameters[0]).Value]));
                                                userCommand = Translator.ToCommand(name, true);
                                                argc = ((U30)arg.Parameters[1]).Value;

                                                if (null == userCommand)
                                                {
                                                    throw new Exception(String.Format("Unknown command {0}.", name));
                                                }

                                                break;
                                            }

                                            args.Add(arg);
                                        }

                                        if (null == userCommand)
                                        {
                                            throw new Exception("Malformed inline block.");
                                        }

                                        instructions.Add(new Instruction(abc, userCommand, args));

                                        break;

                                    case (byte)Op.CallPropertyVoid:
                                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)inlineCommand.Parameters[0]).Value]));
                                        if (inlineWrapper == name)
                                        {
                                            parse = false;
                                        }
                                        else
                                        {
                                            throw new Exception("Malformed inline block. Method calls are not accepted ...");
                                        }
                                        break;
                                }
                            }

            #if DEBUG
                            Console.WriteLine("[+] Inline block parsed");
            #endif
                        }
            #endregion
                        #region INLINE Marker
                        else if (inlineMarker == name)
                        {
            #if DEBUG
                            Console.WriteLine("[i] Body {0} has been marked as inline", body.Method.Value);
            #endif

                            bool parse = true;

                            while (parse && i < n)
                            {
                                inlineCommand = Translator.ToCommand(il[i++]);

                                if (null == inlineCommand)
                                {
                                    throw new Exception("Unknown opcode detected.");
                                }

                                i += inlineCommand.ReadParameters(il, i);

                                switch (inlineCommand.OpCode)
                                {

                                    case (byte)Op.CallPropertyVoid:
                                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)inlineCommand.Parameters[0]).Value]));
                                        if (inlineMarker == name)
                                        {
                                            parse = false;
                                        }
                                        else
                                        {
                                            throw new Exception("Malformed inline block. Method calls are not accepted ...");
                                        }
                                        break;
                                }
                            }

            #if DEBUG
                            Console.WriteLine("[+] Inline marker parsed.");
            #endif
                            patchBody = true;
                        }
            #endregion
                        #region MAX_STACK Marker
                        else if (inlineMaxStack == name)
                        {
            #if DEBUG
                            Console.WriteLine("[i] Body {0} has a manual maximum stack set.", body.Method.Value);
            #endif

                            bool parse = true;

                            uint maxStackValue = 0;
                            bool hasMaxValue = false;

                            while (parse && i < n)
                            {
                                inlineCommand = Translator.ToCommand(il[i++]);

                                if (null == inlineCommand)
                                {
                                    throw new Exception("Unknown opcode detected.");
                                }

                                i += inlineCommand.ReadParameters(il, i);

                                switch (inlineCommand.OpCode)
                                {
                                    case (byte)Op.PushByte:
                                        maxStackValue = (uint)((byte)inlineCommand.Parameters[0]);
                                        hasMaxValue = true;
                                        break;

                                    case (byte)Op.PushShort:
                                        maxStackValue = (uint)((U30)inlineCommand.Parameters[0]);
                                        hasMaxValue = true;
                                        break;

                                    case (byte)Op.PushInt:
                                        maxStackValue = (uint)((S32)abc.ConstantPool.IntTable[(int)((U30)inlineCommand.Parameters[0]).Value]).Value;
                                        hasMaxValue = true;
                                        break;

                                    case (byte)Op.PushDouble:
                                        throw new Exception("Max stack has to be an integer constant.");

                                    case (byte)Op.CallPropertyVoid:

                                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)inlineCommand.Parameters[0]).Value]));

                                        if (inlineMaxStack == name)
                                        {
                                            parse = false;
                                        }
                                        else
                                        {
                                            throw new Exception("Malformed inline block. Method calls are not accepted ...");
                                        }
                                        break;
                                }
                            }

            #if DEBUG
                            Console.WriteLine("[+] MaxStack marker parsed.");
            #endif
                            if (hasMaxValue)
                            {
                                hasManualMaxStack = true;
                                manualMaxStackValue = maxStackValue;
                            }

                            patchBody = true;
                        }
                        #endregion
                        else
                        {
                            instructions.Add(command);
                        }
                        break;

                    default:
                        instructions.Add(command);
                        break;
                }
            }

            if (patchBody)
            {
                //
                // We have to patch this function ...
                // Note: We do not change the initScopeDepth
                //

            #if DEBUG
                Console.WriteLine("[i] Patching body (id: {0})", bodyId);
            #endif
                CompilerAs3c compAs3c = new CompilerAs3c();

                compAs3c.Compile(abc, instructions, labels, false);

                // Now .. only patch if we find a correct stack!

                U30 maxStack;

                if (!hasManualMaxStack)
                {
                    maxStack = ByteCodeAnalyzer.CalcMaxStack(compAs3c.Code);
                }
                else
                {
                    maxStack = (U30)manualMaxStackValue;
                }

                if (hasManualMaxStack || 0 == (ByteCodeAnalyzer.Flags & ByteCodeAnalyzer.InvalidStack))
                {
                    MethodInfo method = (MethodInfo)abc.Methods[(int)body.Method.Value];

                    body.MaxStack = maxStack;
                    body.MaxScopeDepth = body.InitScopeDepth + ByteCodeAnalyzer.CalcScopeDepth(compAs3c.Code);

                    U30 minLocalCount = method.ParameterCount;
                    U30 maxLocalCount = ByteCodeAnalyzer.CalcLocalCount(compAs3c.Code);

                    if (maxLocalCount.Value > minLocalCount.Value)
                    {
                        body.LocalCount = ByteCodeAnalyzer.CalcLocalCount(compAs3c.Code);
                    }
                    //else <- we would have unused parameters in a function...

                    body.Code = compAs3c.Code;
                }
                else
                {
                    //
                    // What else? We will display warnings automatically but what about
                    // telling the guy in which function he has an invalid stack?
                    //
                }

            #if DEBUG
                Console.WriteLine("[+] Body patched");
            #endif
            }
        }
Esempio n. 6
0
        private void PatchBody(Abc46 abc, MethodBodyInfo body, int bodyId)
        {
            AVM2Command command;
            AVM2Command inlineCommand;
            Dictionary<string, Label> labels = new Dictionary<string, Label>();
            ArrayList instructions = new ArrayList();
            Label label;
            string labelId;

            byte[] il = body.Code;

            uint i = 0;
            uint n = (uint)il.Length;

            uint addr;

            string name;

            bool patchBody = false;
            bool ignoreBody = false;

            _labelUtil.Clear();

            while (i < n)
            {
                addr = i;

                if (_labelUtil.IsMarked(addr))
                {
                    labelId = String.Format(":{0}:", _labelUtil.GetLabelAt(addr).id);
                    label = new Label(labelId);

                    labels.Add(labelId, label);
                    instructions.Add(label);
                }

                command = Translator.ToCommand(il[i++]);

                if (null == command)
                {
                    throw new Exception("Unknown opcode detected.");
                }

                i += command.ReadParameters(il, i);

                switch (command.OpCode)
                {
                    case (byte)Op.Label:
                        labelId = String.Format(":{0}:", _labelUtil.GetLabelAt(addr).id);
                        label = new Label(labelId);
                        labels.Add(labelId, label);
                        instructions.Add(label);
                        break;

                    case (byte)Op.IfEqual:
                    case (byte)Op.IfFalse:
                    case (byte)Op.IfGreaterEqual:
                    case (byte)Op.IfGreaterThan:
                    case (byte)Op.IfLessEqual:
                    case (byte)Op.IfLowerThan:
                    case (byte)Op.IfNotEqual:
                    case (byte)Op.IfNotGreaterEqual:
                    case (byte)Op.IfNotGreaterThan:
                    case (byte)Op.IfNotLowerEqual:
                    case (byte)Op.IfNotLowerThan:
                    case (byte)Op.IfStrictEqual:
                    case (byte)Op.IfStrictNotEqual:
                    case (byte)Op.IfTrue:
                    case (byte)Op.Jump:
                        S24 offset = (S24)command.Parameters[0];
                        command.Parameters[0] = String.Format(":{0}:", _labelUtil.GetLabelAt((uint)(addr + 1 + offset.Length + offset.Value)).id);
                        instructions.Add(command);
                        break;

                    case (byte)Op.GetLex:
                        name = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value]));
                        if ("public::Math" == name || "Math" == name)
                            patchBody = true;
                        instructions.Add(command);
                        break;

                    case (byte)Op.LookupSwitch:
                        ignoreBody = true;
                        instructions.Add(command);
                        break;

                    default:
                        instructions.Add(command);
                        break;
                }
            }

            if (ignoreBody)
            {
            #if DEBUG
                Console.WriteLine("[-] Have to ignore body because of lookupswitch ...");
            #endif
            }

            if (patchBody && !ignoreBody)
            {
                //
                // We have to patch this function ...
                // Note: We do not change the initScopeDepth
                //

            #if DEBUG
                Console.WriteLine("[i] Patching body (id: {0})", bodyId);
            #endif
                CompilerAs3c compAs3c = new CompilerAs3c();

                compAs3c.Compile(abc, instructions, labels, true);

                // Now .. only patch if we find a correct stack!

                U30 maxStack = maxStack = ByteCodeAnalyzer.CalcMaxStack(compAs3c.Code);

                if (0 == (ByteCodeAnalyzer.Flags & ByteCodeAnalyzer.InvalidStack))
                {
                    MethodInfo method = (MethodInfo)abc.Methods[(int)body.Method.Value];

                    body.MaxStack = maxStack;
                    body.MaxScopeDepth = body.InitScopeDepth + ByteCodeAnalyzer.CalcScopeDepth(compAs3c.Code);

                    U30 minLocalCount = method.ParameterCount;
                    U30 maxLocalCount = ByteCodeAnalyzer.CalcLocalCount(compAs3c.Code);

                    if (maxLocalCount.Value > minLocalCount.Value)
                    {
                        body.LocalCount = ByteCodeAnalyzer.CalcLocalCount(compAs3c.Code);
                    }
                    //else <- we would have unused parameters in a function...

                    body.Code = compAs3c.Code;
                }
                else
                {
                    //
                    // What else? We will display warnings automatically but what about
                    // telling the guy in which function he has an invalid stack?
                    //
                }

            #if DEBUG
                Console.WriteLine("[+] Body patched");
            #endif
            }
        }
Esempio n. 7
0
        protected override void FormatAbc(Abc46 abc46)
        {
            base.FormatAbc(abc46);

            _abc = abc46;

            _output.Add(";namespaces:\r\n");

            for (int i = 0, n = _abc.ConstantPool.NamespaceTable.Count; i < n; ++i)
            {
                NamespaceInfo ns = (NamespaceInfo)_abc.ConstantPool.NamespaceTable[i];

                string result = "";

                switch (ns.Kind)
                {
                    case NamespaceInfo.Namespace:
                    case NamespaceInfo.ExplicitNamespace:
                        //TODO implement this
                        //user defined
                        break;
                    case NamespaceInfo.PrivateNs:
                        result = "private";
                        break;
                    case NamespaceInfo.ProtectedNamespace:
                        result = "protected";
                        break;
                    case NamespaceInfo.StaticProtectedNs:
                        result = "protected$";
                        break;
                    case NamespaceInfo.PackageInternalNs:
                        result = "internal";
                        break;
                    case NamespaceInfo.PackageNamespace:
                        result = "public";
                        break;
                    default:
                        result = "*";
                        break;
                    //throw new VerifyException("Unexpected namespace kind.");
                }

                result += "::";
                result += ((StringInfo)_abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString();

                _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, result));
            }

            _output.Add(";multinames:\r\n");

            for (int i = 0, n = abc46.ConstantPool.MultinameTable.Count; i < n; ++i)
            {
                _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, NameUtil.ResolveMultiname(abc46, i)));
            }

            _output.Add(";strings\r\n");

            for (int i = 0, n = abc46.ConstantPool.StringTable.Count; i < n; ++i)
            {
                _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, ((StringInfo)abc46.ConstantPool.StringTable[i]).ToString()));
            }

            for (int i = 0, n = _abc.Scripts.Count; i < n; ++i)
            {
                FormatScript(i);
            }
        }
Esempio n. 8
0
 protected virtual void FormatAbc(Abc46 abc46)
 {
 }
Esempio n. 9
0
        public void Compile(Abc46 abc, ArrayList instructions, Dictionary<string, Label> labels, bool patchMath)
        {
            #if DEBUG
            //Console.WriteLine("[i] Starting to compile method body ...");
            #endif
            //
            // Create buffer
            //

            MemoryStream buffer = new MemoryStream();
            BinaryWriter output = new BinaryWriter(buffer);

            //
            // Convert compiler instructions to IL.
            //
            Instruction instruction;
            Label label;
            List<ReplaceInformation> replaceList = new List<ReplaceInformation>();

            bool hasLocalMath = false;
            uint mathRegister = 0;
            U30 mathMultiName = new U30();
            AVM2Command mathCommand = null;
            AVM2Command lastCommand = null;

            for (int i = 0, n = instructions.Count; i < n; ++i)
            {
                if (instructions[i] is Label)
                {
                    label = (Label)instructions[i];

                    label.Address = (uint)buffer.Position;

                    if (!label.Referenced)
                    {
                        output.Write((byte)Op.Label);
                    }
                }
                else if (instructions[i] is AVM2Command)
                {
                    AVM2Command command = (AVM2Command)instructions[i];

                    output.Write((byte)command.OpCode);

                    switch (command.OpCode)
                    {
                        case (byte)Op.IfEqual:
                        case (byte)Op.IfFalse:
                        case (byte)Op.IfGreaterEqual:
                        case (byte)Op.IfGreaterThan:
                        case (byte)Op.IfLessEqual:
                        case (byte)Op.IfLowerThan:
                        case (byte)Op.IfNotEqual:
                        case (byte)Op.IfNotGreaterEqual:
                        case (byte)Op.IfNotGreaterThan:
                        case (byte)Op.IfNotLowerEqual:
                        case (byte)Op.IfNotLowerThan:
                        case (byte)Op.IfStrictEqual:
                        case (byte)Op.IfStrictNotEqual:
                        case (byte)Op.IfTrue:
                        case (byte)Op.Jump:
                            string labelId = (string)command.Parameters[0];

                            try
                            {
                                label = labels[labelId];
                            }
                            catch(Exception)
                            {
                                Console.WriteLine("[-] WARNING: Jumping to an unknown label");
                                continue;
                            }

                            if (label.HasAddress)
                            {
                                int offset = (int)(label.Address - ((uint)buffer.Position + 3));
                                Primitives.WriteS24(output, offset);
                            }
                            else
                            {
                                replaceList.Add(new ReplaceInformation((uint)buffer.Position, label, false));
                                Primitives.WriteS24(output, 0);
                            }

                            label.Referenced = true;
                            break;

                        case (byte)Op.GetLex:
                            if (patchMath)
                            {
                                string lexName = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value]));

                                //
                                // If getlex public::Math is called we will repalce it with
                                // a get_local N where Math will be stored.
                                //

                                if (("public::Math" == lexName || "Math" == lexName) && (null != lastCommand) && (lastCommand.OpCode != (byte)Op.SetLocal))
                                {
            #if DEBUG
                                    Console.WriteLine("[i] Found call to Math class ...");
            #endif

                                    if (!hasLocalMath)
                                    {
                                        mathMultiName = (U30)command.Parameters[0];

                                        U30 currentMaxLocal = ByteCodeAnalyzer.CalcLocalCount(instructions);

            #if DEBUG
                                        Console.WriteLine(String.Format("[i] Math register will be {0}", currentMaxLocal.Value));
            #endif

                                        if (currentMaxLocal.Value < 4)
                                        {
                                            int val = (int)currentMaxLocal.Value;
                                            mathCommand = Translator.ToCommand((byte)(0xd0 + val));
                                        }
                                        else
                                        {
                                            mathCommand = Translator.ToCommand((byte)Op.GetLocal);
                                            mathCommand.Parameters.Add(currentMaxLocal);
                                        }

                                        mathRegister = currentMaxLocal.Value;

                                        hasLocalMath = true;
                                    }

                                    output.Seek(-1, SeekOrigin.Current);
                                    output.Write((byte)mathCommand.OpCode);

                                    if (mathCommand.OpCode == (byte)Op.GetLocal)
                                        mathCommand.WriteParameters(output);
                                }
                                else
                                {
                                    command.WriteParameters(output);
                                }
                            }
                            else
                            {
                                command.WriteParameters(output);
                            }
                            break;

                        default:
                            command.WriteParameters(output);
                            break;
                    }

                    lastCommand = command;
                }
                else if (instructions[i] is Instruction)
                {
                    instruction = (Instruction)instructions[i];

                    output.Write(instruction.Command.OpCode);

                    switch (instruction.Command.OpCode)
                    {
                        case (byte)Op.PushShort:
                            Primitives.WriteU30(output, (U30)Convert.ToInt32(instruction.Arguments[0]));
                            break;

                        case (byte)Op.AsType:
                        case (byte)Op.Coerce:
                        case (byte)Op.DeleteProperty:
                        case (byte)Op.FindProperty:
                        case (byte)Op.FindPropertyStrict:
                        case (byte)Op.GetDescendants:
                        case (byte)Op.GetLex:
                        case (byte)Op.GetProperty:
                        case (byte)Op.GetSuper:
                        case (byte)Op.InitProperty:
                        case (byte)Op.IsType:
                        case (byte)Op.SetProperty:
                        case (byte)Op.PushNamespace:
                            Primitives.WriteU30(output, NameUtil.GetMultiname(abc, instruction.Arguments[0]));
                            break;

                        case (byte)Op.CallProperty:
                        case (byte)Op.CallPropertyLex:
                        case (byte)Op.CallPropertyVoid:
                        case (byte)Op.CallSuper:
                        case (byte)Op.CallSuperVoid:
                        case (byte)Op.ConstructProperty:
                            Primitives.WriteU30(output, NameUtil.GetMultiname(abc, instruction.Arguments[0]));
                            Primitives.WriteU30(output, Convert.ToUInt32(instruction.Arguments[1]));
                            break;

                        case (byte)Op.NewClass:
                            Primitives.WriteU30(output, NameUtil.GetClass(abc, instruction.Arguments[0]));
                            break;

                        case (byte)Op.PushDouble:
                            Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveDouble(Convert.ToDouble(instruction.Arguments[0].Replace('.', ','))));
                            break;

                        case (byte)Op.PushInt:
                            Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveInt((S32)Convert.ToInt32(instruction.Arguments[0])));
                            break;

                        case (byte)Op.PushUInt:
                            Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveUInt((U32)Convert.ToUInt32(instruction.Arguments[0])));
                            break;

                        case (byte)Op.DebugFile:
                        case (byte)Op.PushString:
                            if (instruction.Arguments[0].StartsWith("\"") && instruction.Arguments[0].EndsWith("\""))//TODO fix ugly hack
                            {
                                Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveString(instruction.Arguments[0].Substring(1, instruction.Arguments[0].Length - 2)));
                            }
                            else
                            {
                                Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveString(instruction.Arguments[0]));
                            }
                            break;

                        case (byte)Op.IfEqual:
                        case (byte)Op.IfFalse:
                        case (byte)Op.IfGreaterEqual:
                        case (byte)Op.IfGreaterThan:
                        case (byte)Op.IfLessEqual:
                        case (byte)Op.IfLowerThan:
                        case (byte)Op.IfNotEqual:
                        case (byte)Op.IfNotGreaterEqual:
                        case (byte)Op.IfNotGreaterThan:
                        case (byte)Op.IfNotLowerEqual:
                        case (byte)Op.IfNotLowerThan:
                        case (byte)Op.IfStrictEqual:
                        case (byte)Op.IfStrictNotEqual:
                        case (byte)Op.IfTrue:
                        case (byte)Op.Jump:
                            //
                            // Solve label offset
                            //

                            string labelId = null;

                            try
                            {
                                labelId = instruction.Arguments[0];
                            }
                            catch (Exception)
                            {
                                Console.WriteLine("[-] WARNING: Jumping to an unknown label");
                                continue;
                            }

                            //
                            // Make sure the label exsists.
                            //

                            if (!labels.ContainsKey(labelId))
                            {
            #if DEBUG
                                Console.WriteLine("[-] Label \"{0}\" is missing ...", labelId);
            #endif
                                throw new InstructionException(InstructionException.Type.LabelMissing, instruction.DebugInfo);
                            }

                            label = labels[labelId];

                            if (label.HasAddress)
                            {
                                //
                                // We already have the label address. This is a negative jump offset.
                                //

                                int offset = (int)(label.Address - ((uint)buffer.Position + 3));
                                Primitives.WriteS24(output, offset);
                            }
                            else
                            {
                                //
                                // We do not know the label address. This is a positive jump offset.
                                // Mark label to be solved afterwards and write a placeholder ...
                                //

                                replaceList.Add(new ReplaceInformation((uint)buffer.Position, label, false));
                                Primitives.WriteS24(output, 0);
                            }

                            label.Referenced = true;
                            break;

                        default:
                            if (0 < instruction.Command.ParameterCount)
                            {
                                try
                                {
                                    foreach (string argument in instruction.Arguments)
                                    {
                                        output.Write((byte)Convert.ToByte(argument));
                                    }
                                }
                                catch (Exception)
                                {
                                    throw new InstructionException(InstructionException.Type.UnknownType, instruction.DebugInfo);
                                }
                            }
                            break;
                    }

                    lastCommand = instruction.Command;
                }
            }

            int labelOffset = 0;

            #region Add automatically generated code

            //
            // Add local variable containing Math
            //

            if (patchMath && hasLocalMath)
            {
            #if DEBUG
                Console.WriteLine("[i] Body has local Math");
            #endif

                int mathAddress = 2;

                int lastOpCode = -1;
                int opCode = -1;

                long lastPosition = output.BaseStream.Position;

                output.BaseStream.Seek(0, SeekOrigin.Begin);

                while(((opCode = output.BaseStream.ReadByte()) != -1))
                {
                    if (lastOpCode == (byte)Op.GetLocal0 && opCode == (byte)Op.PushScope)
                    {
                        break;
                    }

                    lastOpCode = opCode;
                }

                mathAddress = (int)output.BaseStream.Position;

                output.BaseStream.Seek(lastPosition, SeekOrigin.Begin);

            #if DEBUG
                //Console.WriteLine("[i] Dump Before:");
                //DebugUtil.Dump((MemoryStream)output.BaseStream);
            #endif

                InsertByte(output, mathAddress);
                InsertByte(output, mathAddress);

                labelOffset += 2;

                int byteCoundMulti = 0;

                while (byteCoundMulti < mathMultiName.Length)
                {
                    byteCoundMulti++;
                    labelOffset++;
                    InsertByte(output, mathAddress);
                }

                if (mathRegister > 3)
                {
            #if DEBUG
                    Console.WriteLine("[i] Adding extra register");
            #endif
                    int byteCount = 0;

                    while (byteCount < ((U30)mathRegister).Length+1)
                    {
                        ++byteCount;
                        ++labelOffset;
                        InsertByte(output, mathAddress);
                    }
                }

                output.Seek(mathAddress, SeekOrigin.Begin);

                AVM2Command getLexCommand = Translator.ToCommand((byte)Op.GetLex);
                getLexCommand.Parameters.Add(mathMultiName);

                output.Write((byte)getLexCommand.OpCode);
                getLexCommand.WriteParameters(output);

                if (mathRegister > 3)
                {
                    AVM2Command setLocalCommand = Translator.ToCommand((byte)Op.SetLocal);
                    setLocalCommand.Parameters.Add((U30)mathRegister);

                    output.Write((byte)setLocalCommand.OpCode);
                    setLocalCommand.WriteParameters(output);
                }
                else
                {
                    output.Write((byte)(0xd4 + mathRegister));
                }

            #if DEBUG
                //Console.WriteLine("[i] Dump After:");
                //DebugUtil.Dump((MemoryStream)output.BaseStream);
            #endif

                output.Seek(0, SeekOrigin.End);
                output.Flush();
            }

            #endregion

            //
            // Solve remainig labels
            //

            for (int i = 0, n = replaceList.Count; i < n; ++i)
            {
                ReplaceInformation replaceInfo = replaceList[i];

                label = replaceInfo.label;

                if (!label.Referenced || !label.HasAddress)
                {
                    Console.WriteLine("[-] Warning: Label {0} has never been defined or used ...", label.Identifier);
                    continue;
                }

                if (replaceInfo.lookUpSwitch)
                {
                    //
                    // LookUpSwitch with special offset calculation
                    //

                    throw new Exception("IMPLEMENT ME!");
                }
                else
                {
                    //
                    // Simple jump
                    //

                    int offset = (int)(label.Address - ((uint)replaceInfo.address + 3));

                    buffer.Seek(replaceInfo.address + labelOffset, SeekOrigin.Begin);
                    Primitives.WriteS24(output, offset);
                }
            }

            //
            // Convert stream to byte[]
            //

            buffer.Seek(0, SeekOrigin.Begin);

            BinaryReader reader = new BinaryReader(buffer);

            _code = reader.ReadBytes((int)buffer.Length);

            //
            // Clean up
            //

            reader.Close();
            buffer.Dispose();

            #if DEBUG
            //Console.WriteLine("[i] Done compiling method body ...");
            #endif
        }