public override void ReadExternal(BinaryReader input) { _flags = input.ReadUInt32(); _abc = new Abc46(); _abc.Length = (uint)(_parent.Header.Length - 4); _abc.ReadExternal(input); }
protected override void FormatAbc(SwfLibrary.Abc.Abc46 abc) { base.FormatAbc(abc); MethodBodyInfo methodBody; AVM2Command command; int n = abc.MethodBodies.Count; for (int i = 0; i < n; ++i) { methodBody = (MethodBodyInfo)abc.MethodBodies[i]; FormatBody(methodBody); byte[] code = methodBody.Code; uint j = 0; int m = code.Length; uint k; while (j < m) { k = j; command = Translator.ToCommand(code[j++]); if (null == command) { throw new Exception("Unknown opcode detected."); } j += command.ReadParameters(code, j); FormatCommand(k, command); } } }
private static 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; }
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; } } } }
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 } }
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 } }
protected override void FormatAbc(Abc46 abc46) { base.FormatAbc(abc46); _abc = abc46; _output.Add(";namespaces:\r\n"); for (int i = 0, n = _abc.ConstantPool.NamespaceTable.Count; i < n; ++i) { NamespaceInfo ns = (NamespaceInfo)_abc.ConstantPool.NamespaceTable[i]; string result = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: result = "private"; break; case NamespaceInfo.ProtectedNamespace: result = "protected"; break; case NamespaceInfo.StaticProtectedNs: result = "protected$"; break; case NamespaceInfo.PackageInternalNs: result = "internal"; break; case NamespaceInfo.PackageNamespace: result = "public"; break; default: result = "*"; break; //throw new VerifyException("Unexpected namespace kind."); } result += "::"; result += ((StringInfo)_abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, result)); } _output.Add(";multinames:\r\n"); for (int i = 0, n = abc46.ConstantPool.MultinameTable.Count; i < n; ++i) { _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, NameUtil.ResolveMultiname(abc46, i))); } _output.Add(";strings\r\n"); for (int i = 0, n = abc46.ConstantPool.StringTable.Count; i < n; ++i) { _output.Add(String.Format(";id{0}\t\t{1}\r\n", i, ((StringInfo)abc46.ConstantPool.StringTable[i]).ToString())); } for (int i = 0, n = _abc.Scripts.Count; i < n; ++i) { FormatScript(i); } }
protected virtual void FormatAbc(Abc46 abc46) { }
public void Compile(Abc46 abc, ArrayList instructions, Dictionary<string, Label> labels, bool patchMath) { #if DEBUG //Console.WriteLine("[i] Starting to compile method body ..."); #endif // // Create buffer // MemoryStream buffer = new MemoryStream(); BinaryWriter output = new BinaryWriter(buffer); // // Convert compiler instructions to IL. // Instruction instruction; Label label; List<ReplaceInformation> replaceList = new List<ReplaceInformation>(); bool hasLocalMath = false; uint mathRegister = 0; U30 mathMultiName = new U30(); AVM2Command mathCommand = null; AVM2Command lastCommand = null; for (int i = 0, n = instructions.Count; i < n; ++i) { if (instructions[i] is Label) { label = (Label)instructions[i]; label.Address = (uint)buffer.Position; if (!label.Referenced) { output.Write((byte)Op.Label); } } else if (instructions[i] is AVM2Command) { AVM2Command command = (AVM2Command)instructions[i]; output.Write((byte)command.OpCode); switch (command.OpCode) { 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: string labelId = (string)command.Parameters[0]; try { label = labels[labelId]; } catch(Exception) { Console.WriteLine("[-] WARNING: Jumping to an unknown label"); continue; } if (label.HasAddress) { int offset = (int)(label.Address - ((uint)buffer.Position + 3)); Primitives.WriteS24(output, offset); } else { replaceList.Add(new ReplaceInformation((uint)buffer.Position, label, false)); Primitives.WriteS24(output, 0); } label.Referenced = true; break; case (byte)Op.GetLex: if (patchMath) { string lexName = NameUtil.ResolveMultiname(abc, (MultinameInfo)(abc.ConstantPool.MultinameTable[(int)((U30)command.Parameters[0]).Value])); // // If getlex public::Math is called we will repalce it with // a get_local N where Math will be stored. // if (("public::Math" == lexName || "Math" == lexName) && (null != lastCommand) && (lastCommand.OpCode != (byte)Op.SetLocal)) { #if DEBUG Console.WriteLine("[i] Found call to Math class ..."); #endif if (!hasLocalMath) { mathMultiName = (U30)command.Parameters[0]; U30 currentMaxLocal = ByteCodeAnalyzer.CalcLocalCount(instructions); #if DEBUG Console.WriteLine(String.Format("[i] Math register will be {0}", currentMaxLocal.Value)); #endif if (currentMaxLocal.Value < 4) { int val = (int)currentMaxLocal.Value; mathCommand = Translator.ToCommand((byte)(0xd0 + val)); } else { mathCommand = Translator.ToCommand((byte)Op.GetLocal); mathCommand.Parameters.Add(currentMaxLocal); } mathRegister = currentMaxLocal.Value; hasLocalMath = true; } output.Seek(-1, SeekOrigin.Current); output.Write((byte)mathCommand.OpCode); if (mathCommand.OpCode == (byte)Op.GetLocal) mathCommand.WriteParameters(output); } else { command.WriteParameters(output); } } else { command.WriteParameters(output); } break; default: command.WriteParameters(output); break; } lastCommand = command; } else if (instructions[i] is Instruction) { instruction = (Instruction)instructions[i]; output.Write(instruction.Command.OpCode); switch (instruction.Command.OpCode) { case (byte)Op.PushShort: Primitives.WriteU30(output, (U30)Convert.ToInt32(instruction.Arguments[0])); break; case (byte)Op.AsType: case (byte)Op.Coerce: case (byte)Op.DeleteProperty: case (byte)Op.FindProperty: case (byte)Op.FindPropertyStrict: case (byte)Op.GetDescendants: case (byte)Op.GetLex: case (byte)Op.GetProperty: case (byte)Op.GetSuper: case (byte)Op.InitProperty: case (byte)Op.IsType: case (byte)Op.SetProperty: case (byte)Op.PushNamespace: Primitives.WriteU30(output, NameUtil.GetMultiname(abc, instruction.Arguments[0])); break; case (byte)Op.CallProperty: case (byte)Op.CallPropertyLex: case (byte)Op.CallPropertyVoid: case (byte)Op.CallSuper: case (byte)Op.CallSuperVoid: case (byte)Op.ConstructProperty: Primitives.WriteU30(output, NameUtil.GetMultiname(abc, instruction.Arguments[0])); Primitives.WriteU30(output, Convert.ToUInt32(instruction.Arguments[1])); break; case (byte)Op.NewClass: Primitives.WriteU30(output, NameUtil.GetClass(abc, instruction.Arguments[0])); break; case (byte)Op.PushDouble: Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveDouble(Convert.ToDouble(instruction.Arguments[0].Replace('.', ',')))); break; case (byte)Op.PushInt: Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveInt((S32)Convert.ToInt32(instruction.Arguments[0]))); break; case (byte)Op.PushUInt: Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveUInt((U32)Convert.ToUInt32(instruction.Arguments[0]))); break; case (byte)Op.DebugFile: case (byte)Op.PushString: if (instruction.Arguments[0].StartsWith("\"") && instruction.Arguments[0].EndsWith("\""))//TODO fix ugly hack { Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveString(instruction.Arguments[0].Substring(1, instruction.Arguments[0].Length - 2))); } else { Primitives.WriteU30(output, (U30)abc.ConstantPool.ResolveString(instruction.Arguments[0])); } 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: // // Solve label offset // string labelId = null; try { labelId = instruction.Arguments[0]; } catch (Exception) { Console.WriteLine("[-] WARNING: Jumping to an unknown label"); continue; } // // Make sure the label exsists. // if (!labels.ContainsKey(labelId)) { #if DEBUG Console.WriteLine("[-] Label \"{0}\" is missing ...", labelId); #endif throw new InstructionException(InstructionException.Type.LabelMissing, instruction.DebugInfo); } label = labels[labelId]; if (label.HasAddress) { // // We already have the label address. This is a negative jump offset. // int offset = (int)(label.Address - ((uint)buffer.Position + 3)); Primitives.WriteS24(output, offset); } else { // // We do not know the label address. This is a positive jump offset. // Mark label to be solved afterwards and write a placeholder ... // replaceList.Add(new ReplaceInformation((uint)buffer.Position, label, false)); Primitives.WriteS24(output, 0); } label.Referenced = true; break; default: if (0 < instruction.Command.ParameterCount) { try { foreach (string argument in instruction.Arguments) { output.Write((byte)Convert.ToByte(argument)); } } catch (Exception) { throw new InstructionException(InstructionException.Type.UnknownType, instruction.DebugInfo); } } break; } lastCommand = instruction.Command; } } int labelOffset = 0; #region Add automatically generated code // // Add local variable containing Math // if (patchMath && hasLocalMath) { #if DEBUG Console.WriteLine("[i] Body has local Math"); #endif int mathAddress = 2; int lastOpCode = -1; int opCode = -1; long lastPosition = output.BaseStream.Position; output.BaseStream.Seek(0, SeekOrigin.Begin); while(((opCode = output.BaseStream.ReadByte()) != -1)) { if (lastOpCode == (byte)Op.GetLocal0 && opCode == (byte)Op.PushScope) { break; } lastOpCode = opCode; } mathAddress = (int)output.BaseStream.Position; output.BaseStream.Seek(lastPosition, SeekOrigin.Begin); #if DEBUG //Console.WriteLine("[i] Dump Before:"); //DebugUtil.Dump((MemoryStream)output.BaseStream); #endif InsertByte(output, mathAddress); InsertByte(output, mathAddress); labelOffset += 2; int byteCoundMulti = 0; while (byteCoundMulti < mathMultiName.Length) { byteCoundMulti++; labelOffset++; InsertByte(output, mathAddress); } if (mathRegister > 3) { #if DEBUG Console.WriteLine("[i] Adding extra register"); #endif int byteCount = 0; while (byteCount < ((U30)mathRegister).Length+1) { ++byteCount; ++labelOffset; InsertByte(output, mathAddress); } } output.Seek(mathAddress, SeekOrigin.Begin); AVM2Command getLexCommand = Translator.ToCommand((byte)Op.GetLex); getLexCommand.Parameters.Add(mathMultiName); output.Write((byte)getLexCommand.OpCode); getLexCommand.WriteParameters(output); if (mathRegister > 3) { AVM2Command setLocalCommand = Translator.ToCommand((byte)Op.SetLocal); setLocalCommand.Parameters.Add((U30)mathRegister); output.Write((byte)setLocalCommand.OpCode); setLocalCommand.WriteParameters(output); } else { output.Write((byte)(0xd4 + mathRegister)); } #if DEBUG //Console.WriteLine("[i] Dump After:"); //DebugUtil.Dump((MemoryStream)output.BaseStream); #endif output.Seek(0, SeekOrigin.End); output.Flush(); } #endregion // // Solve remainig labels // for (int i = 0, n = replaceList.Count; i < n; ++i) { ReplaceInformation replaceInfo = replaceList[i]; label = replaceInfo.label; if (!label.Referenced || !label.HasAddress) { Console.WriteLine("[-] Warning: Label {0} has never been defined or used ...", label.Identifier); continue; } if (replaceInfo.lookUpSwitch) { // // LookUpSwitch with special offset calculation // throw new Exception("IMPLEMENT ME!"); } else { // // Simple jump // int offset = (int)(label.Address - ((uint)replaceInfo.address + 3)); buffer.Seek(replaceInfo.address + labelOffset, SeekOrigin.Begin); Primitives.WriteS24(output, offset); } } // // Convert stream to byte[] // buffer.Seek(0, SeekOrigin.Begin); BinaryReader reader = new BinaryReader(buffer); _code = reader.ReadBytes((int)buffer.Length); // // Clean up // reader.Close(); buffer.Dispose(); #if DEBUG //Console.WriteLine("[i] Done compiling method body ..."); #endif }