Example #1
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
            }
        }
Example #2
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;
                    }
                }
            }
        }
Example #3
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
            }
        }
Example #4
0
        protected void FormatBody(MethodBodyInfo body)
        {
            byte[] code = body.Code;

            AVM2Command command;
            uint i = 0;
            int n = code.Length;
            uint k;

            _output.Add("\r\n#maxStack " + body.MaxStack.Value + "\r\n");
            _output.Add("#localCount " + body.LocalCount.Value + "\r\n");
            _output.Add("#maxScopeDepth " + body.MaxScopeDepth.Value + "\r\n");
            _output.Add("#initScopeDepth " + body.InitScopeDepth.Value + "\r\n\r\n");

            while (i < n)
            {
                k = i;

                try
                {
                    command = Translator.ToCommand(code[i++]);
                }
                catch (Exception)
                {
                    throw new Exception(String.Format("Command {0} is not understood.", code[i - 1]));
                }

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

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

                FormatCommand(k, command);
            }

            _output.Add("\r\n\r\n");
        }
Example #5
0
File: Abc46.cs Project: wl3780/as3c
        public void ReadExternal(BinaryReader input)
        {
            #region frame

            char chr;
            _name = "";

            while ((chr = (char)input.ReadByte()) != 0)
            {
                _name += chr;
            }

            #endregion

            #region version

            _minor = input.ReadUInt16();
            _major = input.ReadUInt16();

            if (_major > VERSION_MAJOR)
            {
                throw new Exception(String.Format("Unsupported .abc format {0}.{1}.", MajorVersion, MinorVersion));
            }

            #endregion

            #region cpool_info

            _cpool = new ConstantPool();
            _cpool.ReadExternal(input);

            #endregion

            #region method_info

            uint n = Primitives.ReadU30(input).Value;

            _methods = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MethodInfo method = new MethodInfo();
                method.ReadExternal(input);

                _methods.Add(method);
            }

            #endregion

            #region metadata_info

            n = Primitives.ReadU30(input).Value;

            _metadata = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MetadataInfo metadata = new MetadataInfo();
                metadata.ReadExternal(input);

                _metadata.Add(metadata);
            }

            #endregion

            #region instance_info

            n = Primitives.ReadU30(input).Value;

            _instanceInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                InstanceInfo instanceInfo = new InstanceInfo();
                instanceInfo.ReadExternal(input);

                _instanceInfo.Add(instanceInfo);
            }

            #endregion

            #region class_info

            //n is same as for instance_info

            _classInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                ClassInfo classInfo = new ClassInfo();
                classInfo.ReadExternal(input);

                _classInfo.Add(classInfo);
            }

            #endregion

            #region script_info

            n = Primitives.ReadU30(input).Value;

            _scriptInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                ScriptInfo scriptInfo = new ScriptInfo();
                scriptInfo.ReadExternal(input);

                _scriptInfo.Add(scriptInfo);
            }

            #endregion

            #region method_body_info

            n = Primitives.ReadU30(input).Value;

            _methodBodyInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MethodBodyInfo methodBodyInfo = new MethodBodyInfo();
                methodBodyInfo.ReadExternal(input);

                _methodBodyInfo.Add(methodBodyInfo);
            }

            #endregion
        }
Example #6
0
        public void ReadExternal(BinaryReader input)
        {
            #region frame

            char chr;
            _name = "";

            while ((chr = (char)input.ReadByte()) != 0)
            {
                _name += chr;
            }

            #endregion

            #region version

            _minor = input.ReadUInt16();
            _major = input.ReadUInt16();

            if (_major > VERSION_MAJOR)
            {
                throw new Exception(String.Format("Unsupported .abc format {0}.{1}.", MajorVersion, MinorVersion));
            }

            #endregion

            #region cpool_info

            _cpool = new ConstantPool();
            _cpool.ReadExternal(input);

            #endregion

            #region method_info

            uint n = Primitives.ReadU30(input).Value;

            _methods = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MethodInfo method = new MethodInfo();
                method.ReadExternal(input);

                _methods.Add(method);
            }

            #endregion

            #region metadata_info

            n = Primitives.ReadU30(input).Value;

            _metadata = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MetadataInfo metadata = new MetadataInfo();
                metadata.ReadExternal(input);

                _metadata.Add(metadata);
            }

            #endregion

            #region instance_info

            n = Primitives.ReadU30(input).Value;

            _instanceInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                InstanceInfo instanceInfo = new InstanceInfo();
                instanceInfo.ReadExternal(input);

                _instanceInfo.Add(instanceInfo);
            }

            #endregion

            #region class_info

            //n is same as for instance_info

            _classInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                ClassInfo classInfo = new ClassInfo();
                classInfo.ReadExternal(input);

                _classInfo.Add(classInfo);
            }

            #endregion

            #region script_info

            n = Primitives.ReadU30(input).Value;

            _scriptInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                ScriptInfo scriptInfo = new ScriptInfo();
                scriptInfo.ReadExternal(input);

                _scriptInfo.Add(scriptInfo);
            }

            #endregion

            #region method_body_info

            n = Primitives.ReadU30(input).Value;

            _methodBodyInfo = new ArrayList(Capacity.Max(n));

            for (uint i = 0; i < n; ++i)
            {
                MethodBodyInfo methodBodyInfo = new MethodBodyInfo();
                methodBodyInfo.ReadExternal(input);

                _methodBodyInfo.Add(methodBodyInfo);
            }

            #endregion
        }
Example #7
0
 protected void FormatBody(SwfLibrary.Abc.MethodBodyInfo methodBody)
 {
     _output.Add("\r\n");
 }