public void ReadExternal(BinaryReader input) { _paramCount = Primitives.ReadU30(input); _returnType = Primitives.ReadU30(input); _paramType = new ArrayList(Capacity.Max(_paramCount)); for (uint i = 0; i < _paramCount._value; ++i) { _paramType.Add(Primitives.ReadU30(input)); } _name = Primitives.ReadU30(input); _flags = input.ReadByte(); if (HasFlag(HasOptional)) { _optionInfo = new OptionInfo(); _optionInfo.ReadExternal(input); } if (HasFlag(HasParamNames)) { //param_info { u30 param_name[param_count] } _paramName = new ArrayList(Capacity.Max(_paramCount)); for (uint i = 0; i < _paramCount._value; ++i) { _paramName.Add(Primitives.ReadU30(input)); } } }
public void ReadExternal(BinaryReader input) { _from = Primitives.ReadU30(input); _to = Primitives.ReadU30(input); _target = Primitives.ReadU30(input); _execType = Primitives.ReadU30(input); _varName = Primitives.ReadU30(input); }
public static U30 CalcScopeDepth(byte[] code) { ClearFlags(); uint i = 0; uint n = (uint)code.Length; int scopeDepth = 0; int maxScopeDepth = 0; while (i < n) { AVM2Command cmd = null; try { cmd = Translator.ToCommand(code[i++]); } catch (Exception) { DebugUtil.DumpOpUntilError(code); throw new Exception(String.Format("Can not translate {0} correct at {1}.", code[i - 1], i - 1)); } if (null == cmd) { throw new Exception(); } i += cmd.ReadParameters(code, i); switch (cmd.OpCode) { case (byte)Op.PushScope: case (byte)Op.PushWith: scopeDepth++; break; case (byte)Op.PopScope: scopeDepth--; break; } if (scopeDepth > maxScopeDepth) { maxScopeDepth = scopeDepth; } } U30 result = new U30(); result.Value = (uint)maxScopeDepth; return(result); }
public override void ReadExternal(BinaryReader input) { _slotId = Primitives.ReadU30(input); _typeName = Primitives.ReadU30(input); _vIndex = Primitives.ReadU30(input); if (0 != _vIndex.Value) { _vKind = input.ReadByte(); _hasKind = true; } }
public void ReadExternal(BinaryReader input) { _cinit = Primitives.ReadU30(input); uint n = Primitives.ReadU30(input).Value; _traits = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { TraitInfo ti = new TraitInfo(); ti.ReadExternal(input); _traits.Add(ti); } }
public void ReadExternal(BinaryReader input) { uint count = Primitives.ReadU30(input).Value; _ns = new ArrayList(Capacity.Max(count)); for (uint i = 0; i < count; ++i) { U30 ns = Primitives.ReadU30(input); _ns.Add(ns); if (0 == ns.Value) { throw new VerifyException("Namespace must not be 0."); } } }
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 static U30 GetClass(Abc46 abc, string argument) { U30 multinameIndex = GetMultiname(abc, argument); U30 result = new U30(); for (int i = 0, n = abc.Instances.Count; i < n; ++i) { InstanceInfo ii = (InstanceInfo)abc.Instances[i]; if (ii.Name.Value == multinameIndex.Value) { result.Value = (uint)i; break; } } return(result); }
public static U30 GetClass(Abc46 abc, string argument) { U30 multinameIndex = GetMultiname(abc, argument); U30 result = new U30(); for (int i = 0, n = abc.Instances.Count; i < n; ++i) { InstanceInfo ii = (InstanceInfo)abc.Instances[i]; if (ii.Name.Value == multinameIndex.Value) { result.Value = (uint)i; break; } } return result; }
public void ReadExternal(BinaryReader input) { _name = Primitives.ReadU30(input); _superName = Primitives.ReadU30(input); _flags = input.ReadByte(); if (ClassProtectedNs == (_flags & ClassProtectedNs)) { _protectedNs = Primitives.ReadU30(input); } uint n = Primitives.ReadU30(input).Value; _interface = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { U30 iid = Primitives.ReadU30(input); if (0 == iid.Value) { throw new VerifyException("Interface must not be 0."); } _interface.Add(iid); } _iinit = Primitives.ReadU30(input); n = Primitives.ReadU30(input).Value; _traits = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { TraitInfo ti = new TraitInfo(); ti.ReadExternal(input); _traits.Add(ti); } }
//public uint WriteParameters(byte[] code, uint index) public void WriteParameters(BinaryWriter output) { for (int i = 0; i < _parameterCount; ++i) { switch (_types[i]) { case ParameterType.U30: U30 _u30 = (U30)_parameters[i]; Primitives.WriteU30(output, _u30); break; case ParameterType.U8: output.Write((byte)_parameters[i]); break; case ParameterType.S24: S24 _s24 = (S24)_parameters[i]; Primitives.WriteS24(output, _s24); break; case ParameterType.UInt: U32 _u32 = (U32)_parameters[i]; Primitives.WriteU32(output, _u32); break; case ParameterType.Dynamic: S24 d_s24 = (S24)_parameters[0]; Primitives.WriteS24(output, d_s24); U30 c_u30 = (U30)_parameters[1]; Primitives.WriteU30(output, c_u30); for (int j = 0; j <= c_u30.Value; ++j) { S24 j_s24 = (S24)_parameters[2 + j]; Primitives.WriteS24(output, j_s24); } break; } } }
public void ReadExternal(BinaryReader input) { _name = Primitives.ReadU30(input); if (0 == _name.Value) throw new VerifyException("Name must not be 0."); uint n = Primitives.ReadU30(input).Value; _items = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { ItemInfo itemInfo = new ItemInfo(); itemInfo.key = Primitives.ReadU30(input); itemInfo.value = Primitives.ReadU30(input); _items.Add(itemInfo); } }
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); }
public void ReadExternal(BinaryReader input) { uint n; _method = Primitives.ReadU30(input); _maxStack = Primitives.ReadU30(input); _localCount = Primitives.ReadU30(input); _initScopeDepth = Primitives.ReadU30(input); _maxScopeDepth = Primitives.ReadU30(input); n = Primitives.ReadU30(input).Value; _code = new byte[n];//the holy grail...finally... for (uint i = 0; i < n; ++i) { _code[i] = input.ReadByte(); } n = Primitives.ReadU30(input).Value; _exceptionInfo = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { ExceptionInfo ei = new ExceptionInfo(); ei.ReadExternal(input); _exceptionInfo.Add(ei); } n = Primitives.ReadU30(input).Value; _traits = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { TraitInfo ti = new TraitInfo(); ti.ReadExternal(input); _traits.Add(ti); } }
public void ReadExternal(BinaryReader input) { _name = Primitives.ReadU30(input); if (0 == _name.Value) { throw new VerifyException("Name must not be 0."); } uint n = Primitives.ReadU30(input).Value; _items = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { ItemInfo itemInfo = new ItemInfo(); itemInfo.key = Primitives.ReadU30(input); itemInfo.value = Primitives.ReadU30(input); _items.Add(itemInfo); } }
public static U30 CalcMaxStack(byte[] code) { ClearFlags(); uint i = 0; uint n = (uint)code.Length; int stack = 0; int maxStack = 0; bool corrupt = false; uint j = 0; List <ConditionalJump> jumps = new List <ConditionalJump>(); List <uint> unconditionalJumps = new List <uint>(); ConditionalJump cj; int jumpIndex = 0; do { while (i < n) { AVM2Command cmd = null; try { cmd = Translator.ToCommand(code[i++]); } catch (Exception) { DebugUtil.DumpOpUntilError(code); throw new Exception(String.Format("Can not translate {0} correct at {1}.", code[i - 1], i - 1)); } if (null == cmd) { throw new Exception(); } i += cmd.ReadParameters(code, i); // There are a couple of opcodes marked "incorrect" with a comment. // The explanation is: If the index in the multiname array is a RTQName // there could be a namspace and/or namespace set on the stack as well // that would be popped. // // We do not take that in account here - in the worst case that a namespace // and namespace set is present it could add +2 to the max sack if the // stack is greater than the one we already have. // // In the calculation of the possible max stack we will therefore only remove // the number of arguments from the current value. If there are no arguments // the opcode will be listed here as incorrect without any following calculation. // // Although this is not a problem for the Flash Player. It is just not very // nice... switch (cmd.OpCode) { case (byte)Op.Jump: if (!unconditionalJumps.Contains(i)) { unconditionalJumps.Add(i); i = (uint)((int)i + (int)((S24)cmd.Parameters[0]).Value); } else { //LOOP BAAM! } break; case (byte)Op.PushByte: case (byte)Op.PushDouble: case (byte)Op.PushFalse: case (byte)Op.PushInt: case (byte)Op.PushNamespace: case (byte)Op.PushNaN: case (byte)Op.PushNull: case (byte)Op.PushShort: case (byte)Op.PushString: case (byte)Op.PushTrue: case (byte)Op.PushUInt: case (byte)Op.PushUndefined: case (byte)Op.Dup: case (byte)Op.FindProperty: //incorrect case (byte)Op.FindPropertyStrict: //incorrect case (byte)Op.GetGlobalScope: case (byte)Op.GetGlobalSlot: case (byte)Op.GetLex: case (byte)Op.GetLocal: case (byte)Op.GetLocal0: case (byte)Op.GetLocal1: case (byte)Op.GetLocal2: case (byte)Op.GetLocal3: case (byte)Op.GetScopeObject: case (byte)Op.HasNext2: case (byte)Op.NewActivation: case (byte)Op.NewCatch: case (byte)Op.NewFunction: ++stack; break; case (byte)Op.IfFalse: case (byte)Op.IfTrue: --stack; cj = new ConditionalJump(); cj.offset = (S24)cmd.Parameters[0]; cj.pos = i; cj.stack = stack; if (!ContainsJumpFrom(jumps, cj)) { jumps.Add(cj); } break; case (byte)Op.Add: case (byte)Op.AddInt: case (byte)Op.AsTypeLate: case (byte)Op.BitAnd: case (byte)Op.BitOr: case (byte)Op.BitXor: case (byte)Op.Divide: case (byte)Op.DefaultXmlNamespaceLate: case (byte)Op.Equals: case (byte)Op.GreaterEquals: case (byte)Op.GreaterThan: case (byte)Op.HasNext: case (byte)Op.In: case (byte)Op.InstanceOf: case (byte)Op.IsTypeLate: case (byte)Op.LessEquals: case (byte)Op.LessThan: case (byte)Op.LeftShift: case (byte)Op.Modulo: case (byte)Op.Multiply: case (byte)Op.MultiplyInt: case (byte)Op.NextName: case (byte)Op.NextValue: case (byte)Op.Pop: case (byte)Op.PushScope: //pop from stack, push to scope stack case (byte)Op.PushWith: //pop from stack, push to scope stack case (byte)Op.ReturnValue: case (byte)Op.RightShift: case (byte)Op.SetLocal: case (byte)Op.SetLocal0: case (byte)Op.SetLocal1: case (byte)Op.SetLocal2: case (byte)Op.SetLocal3: case (byte)Op.SetGlobalSlot: case (byte)Op.StrictEquals: case (byte)Op.Subtract: case (byte)Op.SubtractInt: case (byte)Op.Throw: case (byte)Op.UnsignedRightShift: --stack; break; case (byte)Op.LookupSwitch: --stack; for (int k = 2; k < cmd.ParameterCount; ++k) { cj.offset = (S24)cmd.Parameters[k]; cj.pos = i; cj.stack = stack; if (!ContainsJumpFrom(jumps, cj)) { jumps.Add(cj); } } break; case (byte)Op.IfEqual: 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: stack -= 2; cj = new ConditionalJump(); cj.offset = (S24)cmd.Parameters[0]; cj.pos = i; cj.stack = stack; if (!ContainsJumpFrom(jumps, cj)) { jumps.Add(cj); } break; case (byte)Op.InitProperty: case (byte)Op.SetProperty: //incorrect case (byte)Op.SetSlot: case (byte)Op.SetSuper: //incorrect stack -= 2; break; case (byte)Op.Call: case (byte)Op.ConstructSuper: stack -= 1 + (int)((U30)cmd.Parameters[0]); break; case (byte)Op.Construct: stack -= (int)((U30)cmd.Parameters[0]);; break; case (byte)Op.NewArray: stack -= (int)((U30)cmd.Parameters[0]) - 1; break; case (byte)Op.CallMethod: case (byte)Op.CallProperty: //incorrect case (byte)Op.CallPropertyLex: //incorrect case (byte)Op.CallPropertyVoid: //incorrect case (byte)Op.CallStatic: case (byte)Op.CallSuper: //incorrect case (byte)Op.CallSuperVoid: //incorrect case (byte)Op.ConstructProperty: stack -= (int)((U30)cmd.Parameters[1]); break; case (byte)Op.NewObject: stack -= ((int)((U30)cmd.Parameters[0])) << 1; break; //case (byte)Op.DeleteProperty://incorrect //case (byte)Op.GetDescendants://incorrect //case (byte)Op.GetProperty://incorrect //case (byte)Op.GetSuper://incorrect // break; } if (stack < 0) { RaiseFlag(InvalidStack); corrupt = true; Console.WriteLine("[-] Warning: Stack underflow error at operation {0} (#{1})...", cmd.StringRepresentation, j); } if (stack > maxStack) { maxStack = stack; } ++j; } if (jumpIndex < jumps.Count) { ConditionalJump nextScan = jumps[jumpIndex++]; i = (uint)((int)nextScan.pos + (int)nextScan.offset); stack = nextScan.stack; } else { break; } } while (true); U30 result = new U30(); result.Value = (uint)maxStack; if (corrupt) { DebugUtil.DumpOpUntilError(code); } return(result); }
public static U30 CalcLocalCount(ArrayList instructions) { ClearFlags(); int i = 0; int n = instructions.Count; uint local = 0; uint maxLocal = 0; while (i < n) { AVM2Command avm2Command = null; if (instructions[i] is Instruction) { avm2Command = ((Instruction)instructions[i]).Command; } else if (instructions[i] is AVM2Command) { avm2Command = (AVM2Command)instructions[i]; } else if (instructions[i] is Label) { ++i; continue; } else { throw new Exception("Unknown instruction type."); } switch (avm2Command.OpCode) { case (byte)Op.Debug: byte type = (byte)avm2Command.Parameters[0]; if (1 == type) { local = (byte)avm2Command.Parameters[2] + 1U; } break; case (byte)Op.SetLocal: case (byte)Op.GetLocal: U30 register = (U30)avm2Command.Parameters[0]; local = register.Value + 1U; break; case (byte)Op.SetLocal0: case (byte)Op.GetLocal0: local = 1; break; case (byte)Op.SetLocal1: case (byte)Op.GetLocal1: local = 2; break; case (byte)Op.SetLocal2: case (byte)Op.GetLocal2: local = 3; break; case (byte)Op.SetLocal3: case (byte)Op.GetLocal3: local = 4; break; } if (local > maxLocal) { maxLocal = local; } ++i; } U30 result = new U30(); result.Value = maxLocal; return(result); }
public static U30 GetNamespace(Abc46 abc, string argument) { NamespaceInfo ns; for (int i = 0, n = abc.ConstantPool.NamespaceTable.Count; i < n; ++i) { ns = (NamespaceInfo)abc.ConstantPool.NamespaceTable[i]; string namespaceString = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: namespaceString = "private"; break; case NamespaceInfo.ProtectedNamespace: namespaceString = "protected"; break; case NamespaceInfo.StaticProtectedNs: namespaceString = "protected$"; break; case NamespaceInfo.PackageInternalNs: namespaceString = "internal"; break; case NamespaceInfo.PackageNamespace: namespaceString = "public"; break; default: namespaceString = "*"; break; } namespaceString += "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (argument.IndexOf(namespaceString) != -1) { U30 nsIndex = new U30(); nsIndex.Value = (uint)i; return(nsIndex); } } NamespaceInfo newNs = new NamespaceInfo(); string name = ""; byte kind = 0; if (0 == argument.IndexOf("private::")) { kind = NamespaceInfo.PrivateNs; name = argument.Substring(8); } else if (0 == argument.IndexOf("public::")) { kind = NamespaceInfo.PackageNamespace; name = argument.Substring(7); } newNs.Kind = kind; if ("" == name) { newNs.Name = (U30)0; } else { newNs.Name = (U30)abc.ConstantPool.ResolveString(name); } U30 result = new U30(); result.Value = (uint)abc.ConstantPool.NamespaceTable.Count; abc.ConstantPool.NamespaceTable.Add(newNs); return(result); }
public static U30 GetMultiname(Abc46 abc, string argument) { if (argument.StartsWith("#")) { int index = int.Parse(argument.Substring(1, argument.Length - 1)); if (index < abc.ConstantPool.MultinameTable.Count && index > 0) { return((U30)index); } throw new Exception(String.Format("Invalid multiname {0}", index)); } NamespaceInfo ns; NamespaceSetInfo nss; StringInfo name; bool skipQname = argument.IndexOf("[") == 0; if (skipQname) { //BAD quick dirty hack argument = argument.Replace(" ", ""); } string tempName; U30 result = new U30(); for (int i = 1, n = abc.ConstantPool.MultinameTable.Count; i < n; ++i) { MultinameInfo multiName = (MultinameInfo)abc.ConstantPool.MultinameTable[i]; switch (multiName.Kind) { #region QName, QNameA case MultinameInfo.QName: case MultinameInfo.QNameA: if (skipQname) { continue; } ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)multiName.Data[0].Value]); name = ((StringInfo)abc.ConstantPool.StringTable[(int)multiName.Data[1].Value]); tempName = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: tempName = "private"; break; case NamespaceInfo.ProtectedNamespace: tempName = "protected"; break; case NamespaceInfo.StaticProtectedNs: tempName = "protected$"; break; case NamespaceInfo.PackageInternalNs: tempName = "internal"; break; case NamespaceInfo.PackageNamespace: tempName = "public"; break; default: tempName = "*"; break; } if (0 != ns.Name.Value) { string namespaceName = ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if ("" != namespaceName && tempName != "") { tempName += "::"; } tempName += namespaceName; } tempName += "::" + name.ToString(); if (tempName == argument) { result.Value = (uint)i; return(result); } break; #endregion #region MultinameL, MultinameLA case MultinameInfo.MultinameL: case MultinameInfo.MultinameLA: if (!skipQname) { continue; } tempName = "["; nss = (NamespaceSetInfo)abc.ConstantPool.NamespaceSetTable[(int)multiName.Data[0].Value]; for (int j = 0, m = nss.NamespaceSet.Count; j < m; ++j) { U30 nssNs = (U30)nss.NamespaceSet[j]; ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)nssNs.Value]); string r2 = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: r2 = "private"; break; case NamespaceInfo.ProtectedNamespace: r2 = "protected"; break; case NamespaceInfo.StaticProtectedNs: r2 = "protected$"; break; case NamespaceInfo.PackageInternalNs: r2 = "internal"; break; case NamespaceInfo.PackageNamespace: r2 = "public"; break; default: r2 = "*"; break; } tempName += r2 + "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (j != (m - 1)) { tempName += ","; } } tempName += "]"; if (argument == tempName) { result.Value = (uint)i; return(result); } break; #endregion default: continue; } } if (skipQname) { #region Create MultinameL // // Create a MultinameL // // Remove [] from argument argument = argument.Substring(1, argument.Length - 2); // Get new NamespaceSet index U30 setIndex = new U30(); setIndex.Value = (uint)abc.ConstantPool.NamespaceSetTable.Count; // Create MultinameInfo MultinameInfo newName = new MultinameInfo(); newName.Data = new U30[1] { setIndex }; newName.Kind = MultinameInfo.MultinameL; // Create NamespaceSet NamespaceSetInfo newSet = new NamespaceSetInfo(); newSet.NamespaceSet = new ArrayList(); abc.ConstantPool.NamespaceSetTable.Add(newSet); for (int i = 0, n = abc.ConstantPool.NamespaceTable.Count; i < n; ++i) { ns = (NamespaceInfo)abc.ConstantPool.NamespaceTable[i]; string r2 = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: r2 = "private"; break; case NamespaceInfo.ProtectedNamespace: r2 = "protected"; break; case NamespaceInfo.StaticProtectedNs: r2 = "protected$"; break; case NamespaceInfo.PackageInternalNs: r2 = "internal"; break; case NamespaceInfo.PackageNamespace: r2 = "public"; break; default: r2 = "*"; break; } r2 += "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (argument.IndexOf(r2) != -1) { U30 nsIndex = new U30(); nsIndex.Value = (uint)i; newSet.NamespaceSet.Add(nsIndex); } } result.Value = (uint)abc.ConstantPool.MultinameTable.Count; abc.ConstantPool.MultinameTable.Add(newName); #endregion } else { #region Create QName // Create a QName U30 nsIndex = new U30(); if (argument.IndexOf("::") == argument.LastIndexOf("::")) { nsIndex.Value = GetNamespace(abc, argument.Substring(0, argument.LastIndexOf("::") + 2)).Value; } else { nsIndex.Value = GetNamespace(abc, argument.Substring(0, argument.LastIndexOf("::"))).Value; } MultinameInfo newQName = new MultinameInfo(); newQName.Data = new U30[2] { nsIndex, (U30)abc.ConstantPool.ResolveString(argument.Substring(argument.LastIndexOf("::") + 2)) }; newQName.Kind = MultinameInfo.QName; result.Value = (uint)abc.ConstantPool.MultinameTable.Count; abc.ConstantPool.MultinameTable.Add(newQName); #endregion } return(result); }
public void ReadExternal(BinaryReader input) { uint n; _method = Primitives.ReadU30(input); _maxStack = Primitives.ReadU30(input); _localCount = Primitives.ReadU30(input); _initScopeDepth = Primitives.ReadU30(input); _maxScopeDepth = Primitives.ReadU30(input); n = Primitives.ReadU30(input).Value; _code = new byte[n];//the holy grail...finally... for (uint i = 0; i < n; ++i) _code[i] = input.ReadByte(); n = Primitives.ReadU30(input).Value; _exceptionInfo = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { ExceptionInfo ei = new ExceptionInfo(); ei.ReadExternal(input); _exceptionInfo.Add(ei); } n = Primitives.ReadU30(input).Value; _traits = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { TraitInfo ti = new TraitInfo(); ti.ReadExternal(input); _traits.Add(ti); } }
public void ReadExternal(BinaryReader input) { _val = Primitives.ReadU30(input); _kind = input.ReadByte(); }
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 }
public static U30 GetMultiname(Abc46 abc, string argument) { if (argument.StartsWith("#")) { int index = int.Parse(argument.Substring(1,argument.Length-1)); if (index < abc.ConstantPool.MultinameTable.Count && index > 0) { return (U30)index; } throw new Exception(String.Format("Invalid multiname {0}", index)); } NamespaceInfo ns; NamespaceSetInfo nss; StringInfo name; bool skipQname = argument.IndexOf("[") == 0; if (skipQname) { //BAD quick dirty hack argument = argument.Replace(" ", ""); } string tempName; U30 result = new U30(); for (int i = 1, n = abc.ConstantPool.MultinameTable.Count; i < n; ++i) { MultinameInfo multiName = (MultinameInfo)abc.ConstantPool.MultinameTable[i]; switch (multiName.Kind) { #region QName, QNameA case MultinameInfo.QName: case MultinameInfo.QNameA: if (skipQname) continue; ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)multiName.Data[0].Value]); name = ((StringInfo)abc.ConstantPool.StringTable[(int)multiName.Data[1].Value]); tempName = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: tempName = "private"; break; case NamespaceInfo.ProtectedNamespace: tempName = "protected"; break; case NamespaceInfo.StaticProtectedNs: tempName = "protected$"; break; case NamespaceInfo.PackageInternalNs: tempName = "internal"; break; case NamespaceInfo.PackageNamespace: tempName = "public"; break; default: tempName = "*"; break; } if (0 != ns.Name.Value) { string namespaceName = ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if ("" != namespaceName && tempName != "") tempName += "::"; tempName += namespaceName; } tempName += "::" + name.ToString(); if (tempName == argument) { result.Value = (uint)i; return result; } break; #endregion #region MultinameL, MultinameLA case MultinameInfo.MultinameL: case MultinameInfo.MultinameLA: if (!skipQname) continue; tempName = "["; nss = (NamespaceSetInfo)abc.ConstantPool.NamespaceSetTable[(int)multiName.Data[0].Value]; for (int j = 0, m = nss.NamespaceSet.Count; j < m; ++j) { U30 nssNs = (U30)nss.NamespaceSet[j]; ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)nssNs.Value]); string r2 = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: r2 = "private"; break; case NamespaceInfo.ProtectedNamespace: r2 = "protected"; break; case NamespaceInfo.StaticProtectedNs: r2 = "protected$"; break; case NamespaceInfo.PackageInternalNs: r2 = "internal"; break; case NamespaceInfo.PackageNamespace: r2 = "public"; break; default: r2 = "*"; break; } tempName += r2 + "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (j != (m-1)) tempName += ","; } tempName += "]"; if (argument == tempName) { result.Value = (uint)i; return result; } break; #endregion default: continue; } } if (skipQname) { #region Create MultinameL // // Create a MultinameL // // Remove [] from argument argument = argument.Substring(1, argument.Length - 2); // Get new NamespaceSet index U30 setIndex = new U30(); setIndex.Value = (uint)abc.ConstantPool.NamespaceSetTable.Count; // Create MultinameInfo MultinameInfo newName = new MultinameInfo(); newName.Data = new U30[1] { setIndex }; newName.Kind = MultinameInfo.MultinameL; // Create NamespaceSet NamespaceSetInfo newSet = new NamespaceSetInfo(); newSet.NamespaceSet = new ArrayList(); abc.ConstantPool.NamespaceSetTable.Add(newSet); for (int i = 0, n = abc.ConstantPool.NamespaceTable.Count; i < n; ++i) { ns = (NamespaceInfo)abc.ConstantPool.NamespaceTable[i]; string r2 = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: r2 = "private"; break; case NamespaceInfo.ProtectedNamespace: r2 = "protected"; break; case NamespaceInfo.StaticProtectedNs: r2 = "protected$"; break; case NamespaceInfo.PackageInternalNs: r2 = "internal"; break; case NamespaceInfo.PackageNamespace: r2 = "public"; break; default: r2 = "*"; break; } r2 += "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (argument.IndexOf(r2) != -1) { U30 nsIndex = new U30(); nsIndex.Value = (uint)i; newSet.NamespaceSet.Add(nsIndex); } } result.Value = (uint)abc.ConstantPool.MultinameTable.Count; abc.ConstantPool.MultinameTable.Add(newName); #endregion } else { #region Create QName // Create a QName U30 nsIndex = new U30(); if (argument.IndexOf("::") == argument.LastIndexOf("::")) { nsIndex.Value = GetNamespace(abc, argument.Substring(0, argument.LastIndexOf("::") + 2)).Value; } else nsIndex.Value = GetNamespace(abc, argument.Substring(0, argument.LastIndexOf("::"))).Value; MultinameInfo newQName = new MultinameInfo(); newQName.Data = new U30[2] { nsIndex, (U30)abc.ConstantPool.ResolveString(argument.Substring(argument.LastIndexOf("::") + 2)) }; newQName.Kind = MultinameInfo.QName; result.Value = (uint)abc.ConstantPool.MultinameTable.Count; abc.ConstantPool.MultinameTable.Add(newQName); #endregion } return result; }
public void ReadExternal(BinaryReader input) { _paramCount = Primitives.ReadU30(input); _returnType = Primitives.ReadU30(input); _paramType = new ArrayList(Capacity.Max(_paramCount)); for (uint i = 0; i < _paramCount._value; ++i) _paramType.Add(Primitives.ReadU30(input)); _name = Primitives.ReadU30(input); _flags = input.ReadByte(); if (HasFlag(HasOptional)) { _optionInfo = new OptionInfo(); _optionInfo.ReadExternal(input); } if (HasFlag(HasParamNames)) { //param_info { u30 param_name[param_count] } _paramName = new ArrayList(Capacity.Max(_paramCount)); for (uint i = 0; i < _paramCount._value; ++i) _paramName.Add(Primitives.ReadU30(input)); } }
public static string ResolveMultiname(Abc46 abc, U30 index) { return ResolveMultiname(abc, (MultinameInfo)abc.ConstantPool.MultinameTable[(int)index.Value]); }
public static U30 GetNamespace(Abc46 abc, string argument) { NamespaceInfo ns; for (int i = 0, n = abc.ConstantPool.NamespaceTable.Count; i < n; ++i) { ns = (NamespaceInfo)abc.ConstantPool.NamespaceTable[i]; string namespaceString = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: namespaceString = "private"; break; case NamespaceInfo.ProtectedNamespace: namespaceString = "protected"; break; case NamespaceInfo.StaticProtectedNs: namespaceString = "protected$"; break; case NamespaceInfo.PackageInternalNs: namespaceString = "internal"; break; case NamespaceInfo.PackageNamespace: namespaceString = "public"; break; default: namespaceString = "*"; break; } namespaceString += "::" + ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if (argument.IndexOf(namespaceString) != -1) { U30 nsIndex = new U30(); nsIndex.Value = (uint)i; return nsIndex; } } NamespaceInfo newNs = new NamespaceInfo(); string name = ""; byte kind = 0; if(0 == argument.IndexOf("private::")) { kind = NamespaceInfo.PrivateNs; name = argument.Substring(8); } else if (0 == argument.IndexOf("public::")) { kind = NamespaceInfo.PackageNamespace; name = argument.Substring(7); } newNs.Kind = kind; if ("" == name) newNs.Name = (U30)0; else newNs.Name = (U30)abc.ConstantPool.ResolveString(name); U30 result = new U30(); result.Value = (uint)abc.ConstantPool.NamespaceTable.Count; abc.ConstantPool.NamespaceTable.Add(newNs); return result; }
public static U30 CalcMaxStack(byte[] code) { ClearFlags(); uint i = 0; uint n = (uint)code.Length; int stack = 0; int maxStack = 0; bool corrupt = false; uint j = 0; List<ConditionalJump> jumps = new List<ConditionalJump>(); List<uint> unconditionalJumps = new List<uint>(); ConditionalJump cj; int jumpIndex = 0; do { while (i < n) { AVM2Command cmd = null; try { cmd = Translator.ToCommand(code[i++]); } catch (Exception) { DebugUtil.DumpOpUntilError(code); throw new Exception(String.Format("Can not translate {0} correct at {1}.", code[i - 1], i-1)); } if (null == cmd) throw new Exception(); i += cmd.ReadParameters(code, i); // There are a couple of opcodes marked "incorrect" with a comment. // The explanation is: If the index in the multiname array is a RTQName // there could be a namspace and/or namespace set on the stack as well // that would be popped. // // We do not take that in account here - in the worst case that a namespace // and namespace set is present it could add +2 to the max sack if the // stack is greater than the one we already have. // // In the calculation of the possible max stack we will therefore only remove // the number of arguments from the current value. If there are no arguments // the opcode will be listed here as incorrect without any following calculation. // // Although this is not a problem for the Flash Player. It is just not very // nice... switch (cmd.OpCode) { case (byte)Op.Jump: if (!unconditionalJumps.Contains(i)) { unconditionalJumps.Add(i); i = (uint)((int)i + (int)((S24)cmd.Parameters[0]).Value); } else { //LOOP BAAM! } break; case (byte)Op.PushByte: case (byte)Op.PushDouble: case (byte)Op.PushFalse: case (byte)Op.PushInt: case (byte)Op.PushNamespace: case (byte)Op.PushNaN: case (byte)Op.PushNull: case (byte)Op.PushShort: case (byte)Op.PushString: case (byte)Op.PushTrue: case (byte)Op.PushUInt: case (byte)Op.PushUndefined: case (byte)Op.Dup: case (byte)Op.FindProperty://incorrect case (byte)Op.FindPropertyStrict://incorrect case (byte)Op.GetGlobalScope: case (byte)Op.GetGlobalSlot: case (byte)Op.GetLex: case (byte)Op.GetLocal: case (byte)Op.GetLocal0: case (byte)Op.GetLocal1: case (byte)Op.GetLocal2: case (byte)Op.GetLocal3: case (byte)Op.GetScopeObject: case (byte)Op.HasNext2: case (byte)Op.NewActivation: case (byte)Op.NewCatch: case (byte)Op.NewFunction: ++stack; break; case (byte)Op.IfFalse: case (byte)Op.IfTrue: --stack; cj = new ConditionalJump(); cj.offset = (S24)cmd.Parameters[0]; cj.pos = i; cj.stack = stack; if(!ContainsJumpFrom(jumps, cj)) jumps.Add(cj); break; case (byte)Op.Add: case (byte)Op.AddInt: case (byte)Op.AsTypeLate: case (byte)Op.BitAnd: case (byte)Op.BitOr: case (byte)Op.BitXor: case (byte)Op.Divide: case (byte)Op.DefaultXmlNamespaceLate: case (byte)Op.Equals: case (byte)Op.GreaterEquals: case (byte)Op.GreaterThan: case (byte)Op.HasNext: case (byte)Op.In: case (byte)Op.InstanceOf: case (byte)Op.IsTypeLate: case (byte)Op.LessEquals: case (byte)Op.LessThan: case (byte)Op.LeftShift: case (byte)Op.Modulo: case (byte)Op.Multiply: case (byte)Op.MultiplyInt: case (byte)Op.NextName: case (byte)Op.NextValue: case (byte)Op.Pop: case (byte)Op.PushScope://pop from stack, push to scope stack case (byte)Op.PushWith://pop from stack, push to scope stack case (byte)Op.ReturnValue: case (byte)Op.RightShift: case (byte)Op.SetLocal: case (byte)Op.SetLocal0: case (byte)Op.SetLocal1: case (byte)Op.SetLocal2: case (byte)Op.SetLocal3: case (byte)Op.SetGlobalSlot: case (byte)Op.StrictEquals: case (byte)Op.Subtract: case (byte)Op.SubtractInt: case (byte)Op.Throw: case (byte)Op.UnsignedRightShift: --stack; break; case (byte)Op.LookupSwitch: --stack; for (int k = 2; k < cmd.ParameterCount; ++k) { cj.offset = (S24)cmd.Parameters[k]; cj.pos = i; cj.stack = stack; if (!ContainsJumpFrom(jumps, cj)) jumps.Add(cj); } break; case (byte)Op.IfEqual: 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: stack -= 2; cj = new ConditionalJump(); cj.offset = (S24)cmd.Parameters[0]; cj.pos = i; cj.stack = stack; if (!ContainsJumpFrom(jumps, cj)) jumps.Add(cj); break; case (byte)Op.InitProperty: case (byte)Op.SetProperty://incorrect case (byte)Op.SetSlot: case (byte)Op.SetSuper://incorrect stack -= 2; break; case (byte)Op.Call: case (byte)Op.ConstructSuper: stack -= 1 + (int)((U30)cmd.Parameters[0]); break; case (byte)Op.Construct: stack -= (int)((U30)cmd.Parameters[0]); ; break; case (byte)Op.NewArray: stack -= (int)((U30)cmd.Parameters[0]) - 1; break; case (byte)Op.CallMethod: case (byte)Op.CallProperty://incorrect case (byte)Op.CallPropertyLex://incorrect case (byte)Op.CallPropertyVoid://incorrect case (byte)Op.CallStatic: case (byte)Op.CallSuper://incorrect case (byte)Op.CallSuperVoid://incorrect case (byte)Op.ConstructProperty: stack -= (int)((U30)cmd.Parameters[1]); break; case (byte)Op.NewObject: stack -= ((int)((U30)cmd.Parameters[0])) << 1; break; //case (byte)Op.DeleteProperty://incorrect //case (byte)Op.GetDescendants://incorrect //case (byte)Op.GetProperty://incorrect //case (byte)Op.GetSuper://incorrect // break; } if (stack < 0) { RaiseFlag(InvalidStack); corrupt = true; Console.WriteLine("[-] Warning: Stack underflow error at operation {0} (#{1})...", cmd.StringRepresentation, j); } if (stack > maxStack) maxStack = stack; ++j; } if(jumpIndex < jumps.Count) { ConditionalJump nextScan = jumps[jumpIndex++]; i = (uint)((int)nextScan.pos + (int)nextScan.offset); stack = nextScan.stack; } else { break; } } while (true); U30 result = new U30(); result.Value = (uint)maxStack; if (corrupt) DebugUtil.DumpOpUntilError(code); return result; }
public override void ReadExternal(BinaryReader input) { _slotId = Primitives.ReadU30(input); _classI = Primitives.ReadU30(input); }
public static U30 CalcLocalCount(ArrayList instructions) { ClearFlags(); int i = 0; int n = instructions.Count; uint local = 0; uint maxLocal = 0; while (i < n) { AVM2Command avm2Command = null; if (instructions[i] is Instruction) { avm2Command = ((Instruction)instructions[i]).Command; } else if (instructions[i] is AVM2Command) { avm2Command = (AVM2Command)instructions[i]; } else if (instructions[i] is Label) { ++i; continue; } else { throw new Exception("Unknown instruction type."); } switch (avm2Command.OpCode) { case (byte)Op.Debug: byte type = (byte)avm2Command.Parameters[0]; if (1 == type) { local = (byte)avm2Command.Parameters[2] + 1U; } break; case (byte)Op.SetLocal: case (byte)Op.GetLocal: U30 register = (U30)avm2Command.Parameters[0]; local = register.Value + 1U; break; case (byte)Op.SetLocal0: case (byte)Op.GetLocal0: local = 1; break; case (byte)Op.SetLocal1: case (byte)Op.GetLocal1: local = 2; break; case (byte)Op.SetLocal2: case (byte)Op.GetLocal2: local = 3; break; case (byte)Op.SetLocal3: case (byte)Op.GetLocal3: local = 4; break; } if (local > maxLocal) maxLocal = local; ++i; } U30 result = new U30(); result.Value = maxLocal; return result; }
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 }
public static int Max(U30 count) { return(Max((uint)count)); }
public void ReadExternal(BinaryReader input) { _name = Primitives.ReadU30(input); if (0 == (uint)_name) { throw new VerifyException("Name must not be 0."); } _kind = input.ReadByte(); _type = (byte)(_kind & 0xf); _attr = (byte)((_kind >> 4) & 0xf); switch (_type) { case TraitSlot: _body = new TraitSlot(this); break; case TraitConst: _body = new TraitConst(this); break; case TraitClass: _body = new TraitClass(this); break; case TraitFunction: _body = new TraitFunction(this); break; case TraitMethod: _body = new TraitMethod(this); break; case TraitGetter: _body = new TraitGetter(this); break; case TraitSetter: _body = new TraitSetter(this); break; default: throw new VerifyException("Unexpected trait body."); } _body.ReadExternal(input); if (AttributeMetadata == (_attr & AttributeMetadata)) { uint n = Primitives.ReadU30(input).Value; _metadata = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) { _metadata.Add(Primitives.ReadU30(input)); } } }
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); }
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 } }
public static string ResolveMultiname(Abc46 abc, U30 index) { return(ResolveMultiname(abc, (MultinameInfo)abc.ConstantPool.MultinameTable[(int)index.Value])); }
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 } }
/** * HERE STARTS THE SPAGHETTI CODE */ public static string ResolveMultiname(Abc46 abc, MultinameInfo multiName) { NamespaceInfo ns; NamespaceSetInfo nss; StringInfo name; string result; switch (multiName.Kind) { case MultinameInfo.RTQName: case MultinameInfo.RTQNameA: //Console.WriteLine("[-] RTQName/RTQNameA is currently not supported."); return(((StringInfo)abc.ConstantPool.StringTable[(int)multiName.Data[0].Value]).ToString()); case MultinameInfo.QName: case MultinameInfo.QNameA: ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)multiName.Data[0].Value]); name = ((StringInfo)abc.ConstantPool.StringTable[(int)multiName.Data[1].Value]); 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."); } if (0 != ns.Name.Value) { string namespaceName = ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString(); if ("" != namespaceName && result != "") { result += "::"; } result += namespaceName; } result += "::" + name.ToString(); return(result); case MultinameInfo.RTQNameL: case MultinameInfo.RTQNameLA: Console.WriteLine("[-] RTQNameL/RTQameLA is currently not supported."); return(""); case MultinameInfo.Multiname_: case MultinameInfo.MultinameA: //TODO fix this -- what about the namespace set here? //Console.WriteLine("[-] Multiname/MultinameA is currently not supported."); name = ((StringInfo)abc.ConstantPool.StringTable[(int)multiName.Data[0].Value]); nss = ((NamespaceSetInfo)abc.ConstantPool.NamespaceSetTable[(int)multiName.Data[1].Value]); return(name.ToString());; case MultinameInfo.MultinameL: case MultinameInfo.MultinameLA: //Console.WriteLine("[-] MultinameL/MultinameLA is currently not supported.") nss = ((NamespaceSetInfo)abc.ConstantPool.NamespaceSetTable[(int)multiName.Data[0].Value]); string set = "["; for (int i = 0, n = nss.NamespaceSet.Count; i < n; ++i) { U30 nssNs = (U30)nss.NamespaceSet[i]; ns = ((NamespaceInfo)abc.ConstantPool.NamespaceTable[(int)nssNs.Value]); string r2 = ""; switch (ns.Kind) { case NamespaceInfo.Namespace: case NamespaceInfo.ExplicitNamespace: //TODO implement this //user defined break; case NamespaceInfo.PrivateNs: r2 = "private"; break; case NamespaceInfo.ProtectedNamespace: r2 = "protected"; break; case NamespaceInfo.StaticProtectedNs: r2 = "protected$"; break; case NamespaceInfo.PackageInternalNs: r2 = "internal"; break; case NamespaceInfo.PackageNamespace: r2 = "public"; break; default: r2 = "*"; break; } set += String.Format("{0}::{1}", r2, ((StringInfo)abc.ConstantPool.StringTable[(int)ns.Name.Value]).ToString()); if (i != n - 1) { set += ", "; } } set += "]"; return(set); default: return("*"); //throw new VerifyException("Unknown multiname kind."); } }
public override void ReadExternal(BinaryReader input) { _dispId = Primitives.ReadU30(input); _method = Primitives.ReadU30(input); }
protected void FormatCommand(uint address, AVM2Command cmd) { string output = ""; //output += String.Format("{0:X4}\t", address); //output += String.Format("{0}\t", address); if (((byte)Op.Label == cmd.OpCode) || _labels.IsMarked(address)) { output += String.Format("\r\n.label{0}:\r\n", _labels.GetLabelAt(address).id); } output += "\t" + cmd.StringRepresentation + "\t\t"; if (cmd.StringRepresentation.Length < 8) { output += "\t"; } int n = cmd.Parameters.Count; int m = n - 1; switch (cmd.OpCode) { // Param 1: U30 -> Multiname 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.GetSuper: case (byte)Op.InitProperty: case (byte)Op.IsType: case (byte)Op.SetProperty: output += NameUtil.ResolveMultiname(_abc, GetMultiname(cmd, 0)); break; case (byte)Op.GetProperty: output += NameUtil.ResolveMultiname(_abc, GetMultiname(cmd, 0)); break; // Param 1: U30 -> Multiname // Param 2: Param count case (byte)Op.CallProperty: case (byte)Op.CallPropertyLex: case (byte)Op.CallPropertyVoid: case (byte)Op.CallSuper: case (byte)Op.CallSuperVoid: case (byte)Op.ConstructProperty: output += NameUtil.ResolveMultiname(_abc, GetMultiname(cmd, 0)); output += ", " + ((U30)cmd.Parameters[1]).Value.ToString(); break; // Param 1: U30 -> MethodInfo // Param 2: Param count case (byte)Op.CallStatic: output += ((StringInfo)(_abc.ConstantPool.StringTable[(int)GetMethod(cmd, 0).Name.Value])).ToString(); output += ", " + ((U30)cmd.Parameters[1]).Value.ToString(); break; // Param 1: U30 -> InstanceInfo case (byte)Op.NewClass: InstanceInfo ii = (InstanceInfo)_abc.Instances[(int)((U30)cmd.Parameters[0]).Value]; output += NameUtil.ResolveClass(_abc, ii); break; // Param 1: ? case (byte)Op.PushNamespace: output += GetNamespace(cmd, 0); break; // Param 1: U30 -> DoubleTable case (byte)Op.PushDouble: //TODO fix this and do not use replace... output += GetDouble(cmd, 0).ToString().Replace(',', '.'); break; // Param 1: U30 -> IntTable case (byte)Op.PushInt: output += GetInt(cmd, 0); break; // Param 1: U30 -> UIntTable case (byte)Op.PushUInt: output += GetUInt(cmd, 0); break; // Param 1: U30 -> StringTable case (byte)Op.DebugFile: case (byte)Op.PushString: output += '"' + GetString(cmd, 0).ToString() + '"'; break; // Param 1: ? case (byte)Op.NewFunction: output += ((U30)cmd.Parameters[0]).Value + " ;call to anonymous method " + ((U30)cmd.Parameters[0]).Value; break; // Param 1: S24 -> Jump Offset 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)cmd.Parameters[0]; // addr + (1byte opcode) + (offset byte length) + (offset value) output += String.Format(".label{0}", _labels.GetLabelAt((uint)(address + 1 + offset.Length + offset.Value)).id) + "\r\n"; break; case (byte)Op.LookupSwitch: S24 defaultLabel = (S24)cmd.Parameters[0]; U30 count = (U30)cmd.Parameters[1]; output += String.Format(".label{0}", _labels.GetLabelAt((uint)(address + defaultLabel.Value)).id) + ", "; for (int i = 0, o = (int)count.Value + 1; i < o; ++i) { S24 offsetLabel = (S24)cmd.Parameters[2 + i]; output += String.Format(".label{0}", _labels.GetLabelAt((uint)(address + offsetLabel.Value)).id); if (i != o - 1) { output += ", "; } } output += "\r\n"; break; default: for (int i = 0; i < n; ++i) { object t = cmd.Parameters[i]; if (t is byte) { output += String.Format("{0}", (byte)t); } else if (t is S24) { output += String.Format("{0}", ((S24)t).Value); } else if (t is U30) { output += String.Format("{0}", ((U30)t).Value); } else if (t is U32) { output += String.Format("{0}", ((U32)t).Value); } if (i != m) { output += ", "; } } break; } output += "\r\n"; _output.Add(output); }
public uint ReadParameters(byte[] code, uint index) { _parameters.Clear(); uint p = index; for (int i = 0; i < _parameterCount; ++i) { switch (_types[i]) { case ParameterType.U30: U30 _u30 = Primitives.ReadU30(code, p); p += _u30.Length; _parameters.Add(_u30); break; case ParameterType.U8: _parameters.Add(code[p++]); break; case ParameterType.S24: S24 _s24 = Primitives.ReadS24(code, p); p += _s24.Length; _parameters.Add(_s24); break; case ParameterType.UInt: U32 _u32 = Primitives.ReadU32(code, p); p += _u32.Length; _parameters.Add(_u32); break; case ParameterType.Dynamic: S24 d_s24 = Primitives.ReadS24(code, p); p += d_s24.Length; _parameters.Add(d_s24); U30 c_u30 = Primitives.ReadU30(code, p); p += c_u30.Length; _parameters.Add(c_u30); for (int j = 0; j <= c_u30.Value; ++j) { S24 j_s24 = Primitives.ReadS24(code, p); p += j_s24.Length; _parameters.Add(j_s24); } break; } } return(p - index); }
public void ReadExternal(BinaryReader input) { _name = Primitives.ReadU30(input); if (0 == (uint)_name) { throw new VerifyException("Name must not be 0."); } _kind = input.ReadByte(); _type = (byte)(_kind & 0xf); _attr = (byte)((_kind >> 4) & 0xf); switch (_type) { case TraitSlot: _body = new TraitSlot(this); break; case TraitConst: _body = new TraitConst(this); break; case TraitClass: _body = new TraitClass(this); break; case TraitFunction: _body = new TraitFunction(this); break; case TraitMethod: _body = new TraitMethod(this); break; case TraitGetter: _body = new TraitGetter(this); break; case TraitSetter: _body = new TraitSetter(this); break; default: throw new VerifyException("Unexpected trait body."); } _body.ReadExternal(input); if (AttributeMetadata == (_attr & AttributeMetadata)) { uint n = Primitives.ReadU30(input).Value; _metadata = new ArrayList(Capacity.Max(n)); for (uint i = 0; i < n; ++i) _metadata.Add(Primitives.ReadU30(input)); } }
public static U30 CalcLocalCount(byte[] code) { ClearFlags(); uint i = 0; uint n = (uint)code.Length; uint local = 0; uint maxLocal = 0; while (i < n) { AVM2Command cmd = null; try { cmd = Translator.ToCommand(code[i++]); } catch (Exception) { DebugUtil.DumpOpUntilError(code); throw new Exception(String.Format("Can not translate {0} correct at {1}.", code[i - 1], i - 1)); } if (null == cmd) throw new Exception(); i += cmd.ReadParameters(code, i); switch (cmd.OpCode) { case (byte)Op.Debug: byte type = (byte)cmd.Parameters[0]; if (1 == type) { local = (byte)cmd.Parameters[2] + 1U; } break; case (byte)Op.SetLocal: case (byte)Op.GetLocal: U30 register = (U30)cmd.Parameters[0]; local = register.Value + 1U; break; case (byte)Op.SetLocal0: case (byte)Op.GetLocal0: local = 1; break; case (byte)Op.SetLocal1: case (byte)Op.GetLocal1: local = 2; break; case (byte)Op.SetLocal2: case (byte)Op.GetLocal2: local = 3; break; case (byte)Op.SetLocal3: case (byte)Op.GetLocal3: local = 4; break; } if (local > maxLocal) maxLocal = local; } U30 result = new U30(); result.Value = maxLocal; return result; }
public static U30 CalcScopeDepth(byte[] code) { ClearFlags(); uint i = 0; uint n = (uint)code.Length; int scopeDepth = 0; int maxScopeDepth = 0; while (i < n) { AVM2Command cmd = null; try { cmd = Translator.ToCommand(code[i++]); } catch (Exception) { DebugUtil.DumpOpUntilError(code); throw new Exception(String.Format("Can not translate {0} correct at {1}.", code[i - 1], i - 1)); } if (null == cmd) throw new Exception(); i += cmd.ReadParameters(code, i); switch (cmd.OpCode) { case (byte)Op.PushScope: case (byte)Op.PushWith: scopeDepth++; break; case (byte)Op.PopScope: scopeDepth--; break; } if (scopeDepth > maxScopeDepth) maxScopeDepth = scopeDepth; } U30 result = new U30(); result.Value = (uint)maxScopeDepth; return result; }
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 }
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 }
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 int Max(U30 count) { return Max((uint)count); }