private static IEnumerable <MethodBase> MethodCalls(this MethodInfo methodInfo) { return (MethodBodyInfo .Create(methodInfo) .Calls()); }
public static IncrementalMethodBodyInfo Create(MethodBodyInfo mbi, IEnumerable <int> history = null) { var imbi = new IncrementalMethodBodyInfo { Identity = mbi.Identity, TypeName = mbi.TypeName, MethodToString = mbi.MethodToString, Instructions = mbi.Instructions.Select(i => new AgingInstruction { ILString = i }).ToArray(), LengthHistory = new List <int>(history ?? Enumerable.Empty <int>()) { mbi.Instructions.Count } }; for (var i = 0; i < imbi.LengthHistory.Count - 1; i++) { for (var a = imbi.LengthHistory[i]; a < imbi.LengthHistory[i + 1]; a++) { imbi.Instructions[a].Age = i + 1; } } return(imbi); }
private void GetObjectData() { using (Stream output = m_objectProvider.GetData()) { BinaryFormatter formatter = new BinaryFormatter(); m_mbi = (MethodBodyInfo)formatter.Deserialize(output, null); } }
private static IEnumerable <MethodBase> Calls(this MethodBodyInfo methodBody) { return(methodBody .Instructions .Select(instr => instr as InlineMethodInstruction) .Where(instr => instr != null) .Select(instr => instr.Method) .Where(call => !call.IsPrivate)); }
public uint IndexOfMethodBody(MethodBodyInfo value) { int index = Array.IndexOf(MethodBodyArray, value, 0); if (index == -1) { throw new Exception("Couldn't find element in array"); } return((uint)index); }
public MethodBodyMirror GetMethodBody() { if (body == null) { MethodBodyInfo info = vm.conn.Method_GetBody(id); body = new MethodBodyMirror(vm, this, info); } return(body); }
private static void AppendMethod(MethodBase method, StringBuilder sb) { var res = MethodBodyInfo.Create(method); sb.AppendLine($"{res.MethodToString} // 0X{res.Identity:X2}"); sb.AppendLine("{"); foreach (var instr in res.Instructions) { sb.AppendLine(" " + instr); } sb.AppendLine("}"); }
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); }
public void WriteMethodBodyInfo(MethodBodyInfo value) { WriteU30(value.Method.Index); WriteU30(value.MaxStack); WriteU30(value.LocalCount); WriteU30(value.MinScopeDepth); WriteU30(value.MaxScopeDepth); WriteU30((uint)value.Code.Length); WriteBytes(value.Code); WriteU30((uint)value.ExceptionArray.Length); foreach (ExceptionInfo exceptionInfo in value.ExceptionArray) { WriteExceptionInfo(exceptionInfo); } WriteU30((uint)value.TraitsArray.Count); foreach (TraitsInfo traitsInfo in value.TraitsArray) { WriteTraitsInfo(traitsInfo); } }
protected void FormatMethod(U30 method) { MethodInfo methodInfo = (MethodInfo)_abc.Methods[(int)method]; MethodBodyInfo methodBody = null; int bodyIndex = 0; for (int i = 0, n = _abc.MethodBodies.Count; i < n; ++i) { methodBody = (MethodBodyInfo)_abc.MethodBodies[i]; if (methodBody.Method.Value == method.Value) { bodyIndex = i; break; } } _output.Add(String.Format(";body{0}\r\n", bodyIndex)); FormatBody(methodBody); }
protected void FormatBody(MethodBodyInfo body) { byte[] code = body.Code; AVM2Command command; uint i = 0; int n = code.Length; uint k; _output.Add("\r\n#maxStack " + body.MaxStack.Value + "\r\n"); _output.Add("#localCount " + body.LocalCount.Value + "\r\n"); _output.Add("#maxScopeDepth " + body.MaxScopeDepth.Value + "\r\n"); _output.Add("#initScopeDepth " + body.InitScopeDepth.Value + "\r\n\r\n"); while (i < n) { k = i; try { command = Translator.ToCommand(code[i++]); } catch (Exception) { throw new Exception(String.Format("Command {0} is not understood.", code[i - 1])); } if (null == command) { throw new Exception("Unknown opcode detected."); } i += command.ReadParameters(code, i); FormatCommand(k, command); } _output.Add("\r\n\r\n"); }
public override void GetData(object method, Stream outgoingData) { if (method != null) { try { MethodBodyInfo info = new MethodBodyInfo(); info.TypeName = method.GetType().Name; info.MethodToString = method.ToString(); IILReader reader = ILReaderFactory.GetReader(method); foreach (ILInstruction instr in reader) info.Instructions.Add(instr.ToString()); info.FixupSuccess = true; BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(outgoingData, info); } catch (Exception) { } } }
private MiniBrowser FindOrCreateChildForm(MethodBodyInfo mbi) { foreach (var form in MdiChildren) { var miniBrowser = form as MiniBrowser; if (mbi.Identity == miniBrowser?.CurrentData?.Identity) { miniBrowser.Focus(); return(miniBrowser); } } var newChild = new MiniBrowser { Text = mbi.MethodToString, MdiParent = this }; newChild.Show(); return(newChild); }
public MethodBodyInfo ReadMethodBodyInfo(Abc abc, uint index) { MethodBodyInfo result = new MethodBodyInfo(index); result.Method = abc.MethodArray[ReadU30()]; result.MaxStack = ReadU30(); result.LocalCount = ReadU30(); result.MinScopeDepth = ReadU30(); result.MaxScopeDepth = ReadU30(); result.Code = ReadBytes((int)ReadU30()); result.ExceptionArray = new ExceptionInfo[ReadU30()]; for (int i = 0; i < result.ExceptionArray.Length; i++) { result.ExceptionArray[i] = ReadExceptionInfo(); } TraitsInfo[] traits = new TraitsInfo[ReadU30()]; for (int i = 0; i < traits.Length; i++) { traits[i] = ReadTraitsInfo(abc); } result.TraitsArray = new TraitsArray(traits); return(result); }
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; } } } }
private void ReconstructMethodBodies(Workspace workspace, TypeDefinition declaringType) { if (declaringType.HasMethods) { foreach (MethodDefinition methodDef in declaringType.Methods) { if (methodDef.HasBody) { MethodBody methodBody = methodDef.Body; byte[] serializedBody = SerializeMethodBody(workspace, methodBody); MethodBodyInfo info = new MethodBodyInfo() { Bytes = serializedBody, }; workspace.MethodBodyTable.AppendMethodBody(info); } } } }
public static IncrementalMethodBodyInfo Create(MethodBodyInfo mbi) { return(Create(mbi, null)); }
internal MethodBodyMirror(VirtualMachine vm, MethodMirror method, MethodBodyInfo info) : base(vm, 0) { this.method = method; this.info = info; }
internal MethodBodyInfo Method_GetBody(long id) { var res = SendReceive(CommandSet.METHOD, (int)CmdMethod.GET_BODY, new PacketWriter().WriteId(id)); MethodBodyInfo info = new MethodBodyInfo(); info.il = new byte[res.ReadInt()]; for (int i = 0; i < info.il.Length; ++i) info.il[i] = (byte)res.ReadByte(); return info; }
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 } }
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 }
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 } }