Represents a block of binary bytecode in a simple DoABC tag.
Beispiel #1
0
        /// <summary>
        /// Generates a main timeline script for a new SWF
        /// </summary>
        /// <param name="qClassName">Qualified class name for the MainTimeline class,
        /// e.g. mygeneratedswf_fla.MainTimeline</param>
        /// <returns>A DoABC tag that can be inserted into a new SWF, which may be the one
        /// from the timeline (And so may already be in the SWF).</returns>
        public static DoABC GenerateDefaultScript(string qClassName, Timeline timeline)
        {
            DoABC abc = timeline.Root.FirstScript;

            if (abc == null)
            {
                abc      = new DoABC(true, string.Empty, null, null);
                abc.code = new AbcCode();
            }

            AS3ClassDef classDef = GenerateTimelineClass(abc.code, qClassName, timeline.Root.Context);

            timeline.Class = classDef;

            Script s = new Script()
            {
                Method = GenerateTimelineScript(abc.code, classDef)
            };

            abc.code.AddScript(s);

            s.AddTrait(new ClassTrait()
            {
                As3class = classDef, Kind = TraitKind.Class, Name = timeline.Class.Name
            });

            return(abc);
        }
Beispiel #2
0
        /// <summary>
        /// Merges some code into this code.
        /// </summary>
        /// <param name="abc">The code to merge into this object. Once merged, you should
        /// discard 'abc'.</param>
        internal void Merge(DoABC abc, SWFContext ctx)
        {
            /* Because we want everything to be object references... */

            AbcCode abcCode  = abc.Code; /* This is a kludge to force initial parsing of the abc data, if not done already */
            AbcCode thisCode = this.Code;

            abc.Disassemble(); /* This ensures that the code is disassembled into mergable form */
            this.Disassemble();

            foreach (AS3ClassDef clazz in abc.Code.Classes)
            {
                AS3ClassDef classCollision = thisCode.GetClassByQName(clazz.Name.QualifiedName);
                if (classCollision != null)
                {
                    throw new SWFModellerException(
                              SWFModellerError.CodeMerge,
                              "Class name collision on " + clazz.Name,
                              ctx.Sentinel("ClassNameCollision"));
                }

                thisCode.AddClass(clazz);
            }
        }
Beispiel #3
0
        /// <summary>
        /// This takes an existing script and merges it into our script by merging
        /// constants and classes together in a terrifying clash of opcodes. Where we have
        /// multiple scripts, we will merge into the first one, because we need to pick one
        /// and have no way to decide what would be best.
        /// </summary>
        /// <param name="abc">The script to merge into our one.</param>
        public void MergeScript(DoABC abc)
        {
            if (this.scripts.Count == 0)
            {
                this.AddScript(abc);
                /* Well, that was easy */
                return;
            }

            this.scripts[0].Merge(abc, this.Context);
        }
Beispiel #4
0
 /// <summary>
 /// Adds a script.
 /// </summary>
 /// <param name="abc">The abc code.</param>
 public void AddScript(DoABC abc)
 {
     this.scripts.Add(abc);
 }
Beispiel #5
0
        /// <summary>
        /// Merges some code into this code.
        /// </summary>
        /// <param name="abc">The code to merge into this object. Once merged, you should
        /// discard 'abc'.</param>
        internal void Merge(DoABC abc, SWFContext ctx)
        {
            /* Because we want everything to be object references... */

            AbcCode abcCode = abc.Code; /* This is a kludge to force initial parsing of the abc data, if not done already */
            AbcCode thisCode = this.Code;

            abc.Disassemble(); /* This ensures that the code is disassembled into mergable form */
            this.Disassemble();

            foreach (AS3ClassDef clazz in abc.Code.Classes)
            {
                AS3ClassDef classCollision = thisCode.GetClassByQName(clazz.Name.QualifiedName);
                if (classCollision != null)
                {
                    throw new SWFModellerException(
                            SWFModellerError.CodeMerge,
                            "Class name collision on " + clazz.Name,
                            ctx.Sentinel("ClassNameCollision"));
                }

                thisCode.AddClass(clazz);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Generates a main timeline script for a new SWF
        /// </summary>
        /// <param name="qClassName">Qualified class name for the MainTimeline class,
        /// e.g. mygeneratedswf_fla.MainTimeline</param>
        /// <returns>A DoABC tag that can be inserted into a new SWF, which may be the one
        /// from the timeline (And so may already be in the SWF).</returns>
        public static DoABC GenerateDefaultScript(string qClassName, Timeline timeline)
        {
            DoABC abc = timeline.Root.FirstScript;
            if (abc == null)
            {
                abc = new DoABC(true, string.Empty, null, null);
                abc.code = new AbcCode();
            }

            AS3ClassDef classDef = GenerateTimelineClass(abc.code, qClassName, timeline.Root.Context);
            timeline.Class = classDef;

            Script s = new Script() { Method = GenerateTimelineScript(abc.code, classDef) };

            abc.code.AddScript(s);

            s.AddTrait(new ClassTrait() { As3class = classDef, Kind = TraitKind.Class, Name = timeline.Class.Name });

            return abc;
        }
Beispiel #7
0
        public void AssembleIfNecessary(DoABC codeTag, bool insertDebugCodes, string mainClassName, StringBuilder writeLog)
        {
            this.InsertDebugCodes = insertDebugCodes;

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

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

            AbcCode code = codeTag.Code;

            if (!code.IsTampered)
            {
                return;
            }

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

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

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

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

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

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

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

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

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

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

            this.WriteMethodBodies(writer);

            writer.Close(); /* Also closes buffer. */
            codeTag.Bytecode = buffer.ToArray();
        }