Пример #1
0
        private void WriteMethodBodies(ABCDataTypeWriter writer)
        {
            Method[] methods = this.methodMarshal.ToArray();
            writer.WriteU30Packed((uint)methods.Length);

            foreach (Method m in methods)
            {
                writer.WriteU30Packed((uint)this.methodMarshal.GetExistingIDFor(m));

                writer.WriteU30Packed(m.MaxStack);
                writer.WriteU30Packed(m.LocalCount);
                writer.WriteU30Packed(m.InitScopeDepth);
                writer.WriteU30Packed(m.MaxScopeDepth);

                byte[] bytecode = m.Bytes;

                writer.WriteU30Packed((uint)bytecode.Length);
                writer.Write(bytecode, 0, bytecode.Length);

                /* Exception handlers... */

                /* ISSUE 11: This is a fixed list from the moment the method is loaded. You can't add and
                 * remove from exception handlers since they are referenced from newexception opcodes
                 * by index into this list. Fix this by removing the list and marshalling the references
                 * when required. */
                writer.WriteU30Packed((uint)m.ExceptionHandlerCount);
                using (IEnumerator <ExceptionHandler> i = m.ExceptionHandlers)
                {
                    while (i.MoveNext())
                    {
                        ExceptionHandler eh = i.Current;

                        writer.WriteU30Packed((uint)((int)eh.From));
                        writer.WriteU30Packed((uint)((int)eh.To));
                        writer.WriteU30Packed((uint)((int)eh.Target));

                        if (eh.IsCatchAll)
                        {
                            writer.WriteU30Packed(0);
                        }
                        else
                        {
                            writer.WriteU30Packed((uint)this.multinameMarshal.GetIDFor(eh.CatchType));
                        }

                        writer.WriteU30Packed((uint)this.multinameMarshal.GetIDFor(eh.VarName));
                    }
                }

                /* Method traits... */
                writer.WriteU30Packed((uint)m.TraitCount);
                using (IEnumerator <Trait> i = m.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }
        }
Пример #2
0
        private void WriteMethodBodies(ABCDataTypeWriter writer)
        {
            Method[] methods = this.methodMarshal.ToArray();
            writer.WriteU30Packed((uint)methods.Length);

            foreach (Method m in methods)
            {
                writer.WriteU30Packed((uint)this.methodMarshal.GetExistingIDFor(m));

                writer.WriteU30Packed(m.MaxStack);
                writer.WriteU30Packed(m.LocalCount);
                writer.WriteU30Packed(m.InitScopeDepth);
                writer.WriteU30Packed(m.MaxScopeDepth);

                byte[] bytecode = m.Bytes;

                writer.WriteU30Packed((uint)bytecode.Length);
                writer.Write(bytecode, 0, bytecode.Length);

                /* Exception handlers... */
                /* ISSUE 11: This is a fixed list from the moment the method is loaded. You can't add and
                 * remove from exception handlers since they are referenced from newexception opcodes
                 * by index into this list. Fix this by removing the list and marshalling the references
                 * when required. */
                writer.WriteU30Packed((uint)m.ExceptionHandlerCount);
                using (IEnumerator<ExceptionHandler> i = m.ExceptionHandlers)
                {
                    while (i.MoveNext())
                    {
                        ExceptionHandler eh = i.Current;

                        writer.WriteU30Packed((uint)((int)eh.From));
                        writer.WriteU30Packed((uint)((int)eh.To));
                        writer.WriteU30Packed((uint)((int)eh.Target));

                        if (eh.IsCatchAll)
                        {
                            writer.WriteU30Packed(0);
                        }
                        else
                        {
                            writer.WriteU30Packed((uint)this.multinameMarshal.GetIDFor(eh.CatchType));
                        }

                        writer.WriteU30Packed((uint)this.multinameMarshal.GetIDFor(eh.VarName));
                    }
                }

                /* Method traits... */
                writer.WriteU30Packed((uint)m.TraitCount);
                using (IEnumerator<Trait> i = m.Traits)
                {
                    while (i.MoveNext())
                    {
                        this.WriteTraitInfo(writer, i.Current);
                    }
                }
            }
        }
Пример #3
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();
        }
Пример #4
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();
        }