Example #1
0
        static private 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);
        }
Example #2
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 #3
0
        static void Main(string[] args)
        {
#if DEBUG
            DateTime start = DateTime.Now;
#endif
            try
            {
                #region Initialization

                try
                {
                    bool hasMethod = false;

                    if (args.Length < 1)
                    {
                        WriteInfo();
                        Console.WriteLine("[?] Use -help for some instructions.");
                        return;
                    }

                    for (int i = 0, n = args.Length; i < n; ++i)
                    {
                        switch (args[i])
                        {
                        case "-h":
                        case "-help":
                        case "-?":
                        case "/?":
                        case "/help":
                            WriteInfo();
                            Usage();
                            return;

                        // OPTIONS /////////////////////////////////////////////////////////////////////

                        case "-o":
                        case "-output":
                            _pathOutput = args[++i];
                            break;

                        case "-q":
                        case "-quiet":
                            _isQuiet = true;
                            break;

                        // REPLACE ////////////////////////////////////////////////////////////////////

                        case "-r":
                        case "-replace":
                            _action = Action.Replace;
                            break;

                        // REPLACE PROPERTIES ////////////////////////////////////////////////////////

                        case "-sm":
                        case "-static-method":
                            if (hasMethod)
                            {
                                throw new Exception("Two methods defined.");
                            }
                            _isMethodStatic = true;
                            _methodName     = args[++i];
                            break;

                        case "-m":
                        case "-method":
                            if (hasMethod)
                            {
                                throw new Exception("Two methods defined.");
                            }
                            _isMethodStatic = false;
                            _methodName     = args[++i];
                            break;

                        case "-co":
                        case "-constructor":
                            if (hasMethod)
                            {
                                throw new Exception("Two methods defined.");
                            }
                            _isConstructor  = true;
                            _isMethodStatic = false;
                            break;

                        case "-sc":
                        case "-static-constructor":
                            if (hasMethod)
                            {
                                throw new Exception("Two methods defined.");
                            }
                            _isConstructor  = true;
                            _isMethodStatic = true;
                            break;

                        case "-c":
                        case "-class":
                            _className = args[++i];
                            break;

                        case "-n":
                        case "-namespace":
                            _namespace = args[++i];
                            break;

                        // INLINE ///////////////////////////////////////////////////////////////////

                        case "-i":
                        case "-inline":
                            _action  = Action.Inline;
                            _pathSwf = args[++i];
                            break;

                        // PATCH ///////////////////////////////////////////////////////////////////
                        case "-optimize":
                            _action  = Action.Optimize;
                            _pathSwf = args[++i];
                            break;

                        // DASM ////////////////////////////////////////////////////////////////////

                        case "-d":
                        case "-dasm":
                            _action = Action.Dasm;
                            break;

                        // DASM PROPERTIES ////////////////////////////////////////////////////////

                        case "-a":
                        case "-as3c":
                            _dasmType = Dasm.As3c;
                            break;

                        case "-p":
                        case "-plain":
                            _dasmType = Dasm.Plain;
                            break;

                        default:
                            if (File.Exists(args[i]))
                            {
                                try
                                {
                                    BinaryReader fileHead = new BinaryReader(File.Open(args[i], FileMode.Open, FileAccess.Read));

                                    if (fileHead.BaseStream.Length < 3)
                                    {
                                        throw new Exception("Invalid file given.");
                                    }

                                    byte[] head = fileHead.ReadBytes(3);

                                    fileHead.Close();

                                    //TODO fix this ugly part...
                                    if ((head[0] == (byte)'C' || head[0] == (byte)'F') && head[1] == (byte)'W' && head[2] == (byte)'S')
                                    {
                                        if (_pathSwf != "")
                                        {
                                            throw new Exception("Two SWF files given.");
                                        }

                                        _pathSwf = args[i];
                                    }
                                    else
                                    {
                                        if ("" != _pathAsm)
                                        {
                                            throw new Exception("Two ASM files given.");
                                        }

                                        _pathAsm = args[i];
                                    }
                                }
                                catch (IOException io)
                                {
                                    WriteInfo();
                                    Console.Error.WriteLine("[-] Error: Can not open file {0}", args[i]);
#if DEBUG
                                    Console.Error.WriteLine("[-] {0}", io.Message);
#endif
                                    return;
                                }
                                catch (Exception e)
                                {
                                    WriteInfo();
                                    Console.Error.WriteLine("[-] Error: {0}", e.Message);
#if DEBUG
                                    Console.Error.WriteLine("[-] {0}", e.StackTrace);
#endif
                                    return;
                                }
                            }
                            else
                            {
                                if (args[i].IndexOf(".") != -1)
                                {
                                    WriteInfo();
                                    Console.Error.WriteLine("[-] File {0} does not exist.", args[i]);
                                    return;
                                }
                                else
                                {
                                    throw new Exception("Invalid argument given.");
                                }
                            }
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    WriteInfo();
                    Console.Error.WriteLine("[-] Error: Invalid arguments. Use -help for help ...");
#if DEBUG
                    Console.Error.WriteLine("[-] {0}", e.Message);
                    Console.Error.WriteLine("[-] {0}", e.StackTrace);
#endif
                    return;
                }

                if (!_isQuiet)
                {
                    Console.WriteLine("[i] As3c - ActionScript3 ASM compiler");
                }

                Translator.InitTable();

                #endregion

                #region Integrity scan for the Translator class (DEBUG only)

#if DEBUG
                if (Translator.CheckIntegrity())
                {
                    if (!_isQuiet)
                    {
                        Console.WriteLine("[+] Integrity scan passed!");
                    }
                }
                else
                {
                    Console.WriteLine("[-] Integrity scan failed...!");
                }
#endif

                #endregion

                FileStream fileInput;
                FileStream fileOutput;
                SwfFormat  swf;

                switch (_action)
                {
                case Action.Dasm:

                    #region Disassemble file

                    swf       = new SwfFormat();
                    fileInput = File.Open(_pathSwf, FileMode.Open, FileAccess.Read);

                    swf.Read(fileInput);

                    fileInput.Close();
                    fileInput.Dispose();

                    DisassemblerBase dasm;

                    switch (_dasmType)
                    {
                    case Dasm.As3c:
                        dasm = new DisassemblerAs3c();
                        break;

                    case Dasm.Plain:
                        dasm = new DisassemblerPlain();
                        break;

                    default:
                        throw new Exception();
                    }

                    dasm.Parse(swf);

                    if ("" == _pathOutput)
                    {
                        dasm.EmitToConsole();
                    }
                    else
                    {
                        fileOutput = File.Open(_pathOutput, FileMode.OpenOrCreate, FileAccess.Write);
                        dasm.EmitToStream(fileOutput);

                        fileOutput.Close();
                        fileOutput.Dispose();
                    }

                    #endregion

                    break;

                case Action.Optimize:

                    #region Optimize SWF

                    swf       = new SwfFormat();
                    fileInput = File.Open(_pathSwf, FileMode.Open, FileAccess.Read);

                    swf.Read(fileInput);

                    fileInput.Close();
                    fileInput.Dispose();

                    CompilerOptimize compOptimize = new CompilerOptimize(swf);

                    compOptimize.Compile();

                    fileOutput = File.Open((_pathOutput != "") ? _pathOutput : _pathSwf, FileMode.OpenOrCreate, FileAccess.Write);

                    swf.Write(fileOutput);

                    fileOutput.Close();
                    fileOutput.Dispose();

                    #endregion

                    break;

                case Action.Inline:

                    #region Compile inline instructions

                    swf       = new SwfFormat();
                    fileInput = File.Open(_pathSwf, FileMode.Open, FileAccess.Read);

                    swf.Read(fileInput);

                    fileInput.Close();
                    fileInput.Dispose();

                    CompilerInline compInline = new CompilerInline(swf);
                    compInline.Compile();

                    fileOutput = File.Open((_pathOutput != "") ? _pathOutput : _pathSwf, FileMode.OpenOrCreate, FileAccess.Write);

                    swf.Write(fileOutput);

                    fileOutput.Close();
                    fileOutput.Dispose();

                    #endregion

                    break;

                case Action.Replace:

                    #region Replace method body

                    #region Simple pre-check

                    if ("" == _pathAsm || !File.Exists(_pathAsm))
                    {
                        Console.Error.WriteLine("[-] No valid ASM input given.");
                        return;
                    }

                    if ("" == _pathSwf || !File.Exists(_pathSwf))
                    {
                        Console.Error.WriteLine("[-] No valid SWF target given.");
                        return;
                    }

                    if ("" == _className)
                    {
                        Console.Error.WriteLine("[-] No class given.");
                        return;
                    }

                    if (!_isConstructor)
                    {
                        if ("" == _methodName)
                        {
                            Console.Error.WriteLine("[-] Need method name or constructor to replace");
                            return;
                        }
                    }

                    #endregion

                    swf       = new SwfFormat();
                    fileInput = File.Open(_pathSwf, FileMode.Open, FileAccess.Read);

                    swf.Read(fileInput);

                    fileInput.Close();
                    fileInput.Dispose();

                    #region Body lookup

                    Abc46 abc = null;
                    SwfLibrary.Abc.MethodInfo method = null;
                    MethodBodyInfo            body   = null;
                    bool  instanceFound = false;
                    Abc46 currentAbc    = null;

                    string classFormat;

                    if (_className.IndexOf(".") != -1)
                    {
                        classFormat = "public::" + _className.Substring(0, _className.LastIndexOf(".")) + "::" + _className.Substring(_className.LastIndexOf(".") + 1, _className.Length - _className.LastIndexOf(".") - 1);
                    }
                    else
                    {
                        classFormat = "public::" + _className;
                    }

                    string methodFormat = _namespace + "::" + _methodName;

                    // Parse for all possibilities
                    for (int i = 0, n = swf.AbcCount; i < n; ++i)
                    {
                        currentAbc = swf.GetAbcAt(i);

                        for (int j = 0, m = currentAbc.Scripts.Count; j < m; ++j)
                        {
                            ScriptInfo script = (ScriptInfo)currentAbc.Scripts[j];

                            for (int k = 0, o = script.Traits.Count; k < o; ++k)
                            {
                                TraitInfo scriptTrait = (TraitInfo)script.Traits[k];

                                if (!(scriptTrait.Body is TraitClass))
                                {
                                    continue;
                                }

                                TraitClass   classBody    = (TraitClass)scriptTrait.Body;
                                ClassInfo    classInfo    = (ClassInfo)currentAbc.Classes[(int)classBody.ClassI];
                                InstanceInfo instanceInfo = (InstanceInfo)currentAbc.Instances[(int)classBody.ClassI];

                                string instanceName = NameUtil.ResolveMultiname(currentAbc, instanceInfo.Name);

                                if (classFormat == instanceName)
                                {
                                    instanceFound = true;

                                    if (!_isQuiet)
                                    {
                                        Console.WriteLine("[+] Found class {0}", instanceName);
                                    }

                                    if (_isMethodStatic)
                                    {
                                        if (_isConstructor)
                                        {
                                            if (null != body)
                                            {
                                                Console.Error.WriteLine("[-] Can not explicitly determine method body.");
                                                return;
                                            }

                                            method = (SwfLibrary.Abc.MethodInfo)currentAbc.Methods[(int)classInfo.CInit];

                                            body = FindBody(currentAbc, classInfo.CInit);

                                            abc = currentAbc;

                                            if (null != body)
                                            {
                                                if (!_isQuiet)
                                                {
                                                    Console.WriteLine("[+] Found static class initializer.");
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Console.Error.WriteLine("[-] Sorry, static methods do not work yet ...");
                                            return;
                                            //TODO support static methods...
                                        }
                                    }
                                    else
                                    {
                                        if (_isConstructor)
                                        {
                                            if (null != body)
                                            {
                                                Console.Error.WriteLine("[-] Can not explicitly determine method body.");
                                                return;
                                            }

                                            method = (SwfLibrary.Abc.MethodInfo)currentAbc.Methods[(int)instanceInfo.IInit];

                                            body = FindBody(currentAbc, instanceInfo.IInit);

                                            abc = currentAbc;

                                            if (null != body)
                                            {
                                                if (!_isQuiet)
                                                {
                                                    Console.WriteLine("[+] Found class initializer.");
                                                }
                                            }
                                        }
                                        else
                                        {
                                            // here begins the ugly part ...
                                            for (int l = 0, p = instanceInfo.Traits.Count; l < p; ++l)
                                            {
                                                TraitInfo instanceTrait = (TraitInfo)instanceInfo.Traits[l];

                                                if (!(instanceTrait.Body is TraitMethod))
                                                {
                                                    continue;
                                                }

                                                string methodName = NameUtil.ResolveMultiname(currentAbc, instanceTrait.Name);

                                                if ("" == _namespace)
                                                {
                                                    if ("public::" + _methodName != methodName &&
                                                        "private::" + _methodName != methodName &&
                                                        "protected::" + _methodName != methodName &&
                                                        "protected$::" + _methodName != methodName &&
                                                        "internal::" + _methodName != methodName)
                                                    {
                                                        continue;
                                                    }
                                                }
                                                else
                                                {
                                                    if (methodName != methodFormat)
                                                    {
                                                        continue;
                                                    }
                                                }

                                                if (null != body)
                                                {
                                                    Console.Error.WriteLine("[-] Can not explicitly determine method body.");
                                                    return;
                                                }

                                                TraitMethod methodBody = (TraitMethod)instanceTrait.Body;

                                                method = (SwfLibrary.Abc.MethodInfo)currentAbc.Methods[(int)methodBody.Method];

                                                body = FindBody(currentAbc, methodBody.Method);

                                                abc = currentAbc;

                                                if (null != body)
                                                {
                                                    if (!_isQuiet)
                                                    {
                                                        Console.WriteLine("[+] Found method {0}", methodName);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (null == body)
                    {
                        Console.Error.WriteLine("[-] Could not find {0}.", (instanceFound) ? "method" : "class");
                        return;
                    }

                    #endregion

                    //
                    // We have valid body to replace. Start the parser.
                    //

                    ParserAs3c parser = new ParserAs3c();
                    parser.Parse(_pathAsm);

                    //
                    // Convert the parser instructions to actual bytecode for the AVM2.
                    //

                    CompilerAs3c compAs3c = new CompilerAs3c();
                    compAs3c.Compile(currentAbc, parser.Instructions, parser.Labels, false);

                    //
                    // Get body information (maxstack, localcount, maxscopedepth, initscopedepth)
                    // We keep compiler directives in respect here ...
                    //

                    #region MethodBody information

                    U30 maxStack;
                    U30 maxScopeDepth;
                    U30 localCount;
                    U30 initScopeDepth = new U30();

                    if (parser.HasMaxStack)
                    {
                        maxStack       = new U30();
                        maxStack.Value = parser.MaxStack;
                    }
                    else
                    {
                        maxStack = ByteCodeAnalyzer.CalcMaxStack(compAs3c.Code);

                        if (maxStack.Value < method.ParameterCount.Value)
                        {
                            maxStack.Value = method.ParameterCount.Value;
                        }
                    }

                    if (parser.HasLocalCount)
                    {
                        localCount       = new U30();
                        localCount.Value = parser.LocalCount;
                    }
                    else
                    {
                        localCount = ByteCodeAnalyzer.CalcLocalCount(compAs3c.Code);
                    }

                    if (parser.HasInitScopeDepth)
                    {
                        initScopeDepth.Value = parser.InitScopeDepth;
                    }
                    else
                    {
                        initScopeDepth.Value = 1;
                    }

                    if (parser.HasMaxScopeDepth)
                    {
                        maxScopeDepth       = new U30();
                        maxScopeDepth.Value = parser.MaxScopeDepth;
                    }
                    else
                    {
                        maxScopeDepth        = ByteCodeAnalyzer.CalcScopeDepth(compAs3c.Code);
                        maxScopeDepth.Value += initScopeDepth.Value;
                    }

                    if (!_isQuiet)
                    {
                        Console.WriteLine("[i] InitScopeDepth: {0}", (int)initScopeDepth);
                        Console.WriteLine("[i] MaxScopeDepth: {0}", (int)maxScopeDepth);
                        Console.WriteLine("[i] MaxStack: {0}", (int)maxStack);
                        Console.WriteLine("[i] LocalCount: {0}", (int)localCount);
                    }

                    #endregion

                    //
                    // Replace the code of the body.
                    //

                    body.Code = compAs3c.Code;

                    //
                    // Update body information
                    //

                    body.MaxStack       = maxStack;
                    body.MaxScopeDepth  = maxScopeDepth;
                    body.InitScopeDepth = initScopeDepth;
                    body.LocalCount     = localCount;

                    #region Write output

                    if ("" == _pathOutput)
                    {
                        fileOutput = File.Open(_pathSwf, FileMode.OpenOrCreate, FileAccess.Write);
                    }
                    else
                    {
                        fileOutput = File.Open(_pathOutput, FileMode.OpenOrCreate, FileAccess.Write);
                    }

                    swf.Write(fileOutput);

                    fileOutput.Close();
                    fileOutput.Dispose();

                    #endregion

                    #endregion

                    break;

                case Action.Usage:
                    Usage();
                    break;
                }

                #region Program end

                if (!_isQuiet)
                {
                    Console.WriteLine("[i] Done.");
                }
                #endregion
            }
            catch (IOException ioex)
            {
                Console.Error.WriteLine("[-] Error: {0}", ioex.Message);
            }
            catch (InstructionException iex)
            {
                #region Parser errors

                string message;

                switch (iex.ErrorType)
                {
                case InstructionException.Type.InvalidSyntax:
                    message = "Error while parsing";
                    break;

                case InstructionException.Type.NotEnoughArguments:
                    message = "Not enough arguments";
                    break;

                case InstructionException.Type.TooManyArguments:
                    message = "Too many arguments";
                    break;

                case InstructionException.Type.UnknownType:
                    message = "Unknown type";
                    break;

                case InstructionException.Type.LabelRedefined:
                    message = "Label has already been defined";
                    break;

                case InstructionException.Type.LabelMissing:
                    message = "Label has never been defined";
                    break;

                default:
                    message = "Unknown error at";
                    break;
                }

                Console.Error.WriteLine("[-] " + message + ":");

                if (null != iex.ParserInfo)
                {
                    Console.Error.WriteLine("{0}({1}): {2}", iex.ParserInfo.FilePath, iex.ParserInfo.LineNumber, iex.ParserInfo.Line);
                }

                #endregion
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("[-] Unexpected error: {0}", ex.Message);
#if DEBUG
                Console.Error.WriteLine("[-] Stacktrace: {0}", ex.StackTrace);
#endif
            }

#if DEBUG
            DateTime end   = DateTime.Now;
            TimeSpan delta = end - start;

            Console.WriteLine("[i] Total: {0}sec {1}ms", delta.Seconds, delta.Milliseconds);
#endif
        }