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); } } } }
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); } } } }
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(); }