private PacketValue[] GetOutgoingStructure(ASCode code, Local getLocal) { List <PacketValue> structure = new List <PacketValue>(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction == getLocal) { break; } if (!Local.IsGetLocal(instruction.OP)) { continue; } Local local = (Local)instruction; if (local.Register != getLocal.Register) { continue; } for (i += 1; i < code.Count; i++) { ASInstruction next = code[i]; if (next.OP != OPCode.CallPropVoid) { continue; } CallPropVoidIns callPropVoid = (CallPropVoidIns)next; if (callPropVoid.PropertyName.Name != "push") { continue; } ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetProperty) { ASClass classToCheck = Class; GetPropertyIns getProperty = (GetPropertyIns)previous; ASMultiname propertyName = getProperty.PropertyName; ASInstruction beforeGetProp = code[i - 2]; if (beforeGetProp.OP == OPCode.GetLex) { GetLexIns getLex = (GetLexIns)beforeGetProp; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetPacketValue(propertyName, classToCheck, out PacketValue piece)) { return(null); } structure.Add(piece); } } } return(structure.Count == 0 ? null : structure.ToArray()); }
private string GetOutgoingStructure(ASCode code, Local getLocal) { string structure = null; for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction == getLocal) { break; } if (!Local.IsGetLocal(instruction.OP)) { continue; } var local = (Local)instruction; if (local.Register != getLocal.Register) { continue; } for (i += 1; i < code.Count; i++) { ASInstruction next = code[i]; if (next.OP != OPCode.CallPropVoid) { continue; } var callPropVoid = (CallPropVoidIns)next; if (callPropVoid.PropertyName.Name != "push") { continue; } ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetProperty) { ASClass classToCheck = Class; var getProperty = (GetPropertyIns)previous; ASMultiname propertyName = getProperty.PropertyName; ASInstruction beforeGetProp = code[i - 2]; if (beforeGetProp.OP == OPCode.GetLex) { var getLex = (GetLexIns)beforeGetProp; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetStructurePiece(propertyName, classToCheck, out char piece)) { return(null); } structure += piece; } } } return(structure); }
public ASCode ParseCode(bool ignoreCache = false) { if (_cachedCode != null && !ignoreCache) { return(_cachedCode); } return(_cachedCode = new ASCode(ABC, this)); }
private void LoadMessages() { ABCFile abc = ABCFiles.Last(); ASClass habboMessagesClass = abc.GetClass("HabboMessages"); if (habboMessagesClass == null) { IsPostShuffle = false; foreach (ASClass @class in abc.Classes) { if (@class.Traits.Count != 2 || @class.Traits[0].Type?.Name != "Map" || @class.Traits[1].Type?.Name != "Map") { continue; } if (@class.Instance.Traits.Count != 2) { continue; } habboMessagesClass = @class; break; } if (habboMessagesClass == null) { return; } } ASCode code = habboMessagesClass.Constructor.Body.ParseCode(); int outMapTypeIndex = habboMessagesClass.Traits[1].QNameIndex; ASInstruction[] instructions = code .Where(i => i.OP == OPCode.GetLex || i.OP == OPCode.PushShort || i.OP == OPCode.PushByte).ToArray(); for (int i = 0; i < instructions.Length; i += 3) { GetLexIns getLexInst = instructions[i + 0] as GetLexIns; bool isOutgoing = getLexInst?.TypeNameIndex == outMapTypeIndex; Primitive primitive = instructions[i + 1] as Primitive; ushort id = Convert.ToUInt16(primitive?.Value); getLexInst = instructions[i + 2] as GetLexIns; ASClass messageClass = abc.GetClass(getLexInst?.TypeName.Name); HMessage message = new HMessage(id, isOutgoing, messageClass); (isOutgoing ? OutMessages : InMessages).Add(id, message); if (!_messages.ContainsKey(messageClass)) { _messages.Add(messageClass, message); } } }
private ASClass GetMessageParser() { ABCFile abc = Class.GetABC(); ASInstance instance = Class.Instance; ASInstance superInstance = abc.GetInstance(instance.Super); if (superInstance == null) { superInstance = instance; } ASMethod parserGetterMethod = superInstance.GetGetter("parser")?.Method; if (parserGetterMethod == null) { return(null); } IEnumerable <ASMethod> methods = instance.GetMethods(); foreach (ASMethod method in methods.Concat(new[] { instance.Constructor })) { ASCode code = method.Body.ParseCode(); foreach (ASInstruction instruction in code) { ASMultiname multiname = null; if (instruction.OP == OPCode.FindPropStrict) { var findPropStrictIns = (FindPropStrictIns)instruction; multiname = findPropStrictIns.PropertyName; } else if (instruction.OP == OPCode.GetLex) { var getLexIns = (GetLexIns)instruction; multiname = getLexIns.TypeName; } else { continue; } foreach (ASClass refClass in abc.GetClasses(multiname)) { ASInstance refInstance = refClass.Instance; if (refInstance.ContainsInterface(parserGetterMethod.ReturnType.Name)) { return(refClass); } } } } return(null); }
public static int IndexOf(this ASCode code, int startIndex, OPCode op) { for (var i = startIndex; i < code.Count; i++) { if (code[i].OP == op) { return(i); } } return(-1); }
public static int LastIndexOf(this ASCode code, int startIndex, OPCode op) { for (var i = startIndex; i >= 0; i--) { if (code[i].OP == op) { return(i); } } return(-1); }
public static int LastIndexOf(this ASCode code, OPCode op) { for (var i = code.Count - 1; i >= 0; i--) { if (code[i].OP == op) { return(i); } } return(-1); }
public void Write(ASMethod method) { Write(method.IsConstructor); if (!method.IsConstructor) { Write(method.ReturnType); } Write(method.Parameters.Count); foreach (ASParameter parameter in method.Parameters) { Write(parameter.Type); if (!string.IsNullOrWhiteSpace(parameter.Name) && HGame.IsValidIdentifier(parameter.Name, true)) { Write(parameter.Name); } Write(parameter.IsOptional); if (parameter.IsOptional) { Write((byte)parameter.ValueKind); Write(parameter.ValueKind, parameter.Value); } } ASCode code = method.Body.ParseCode(); foreach (OPCode op in code.GetOPGroups().Keys) { if (op != OPCode.GetLex && op != OPCode.GetProperty && op != OPCode.CallProperty) { continue; } Write((byte)op); } }
public ASMethodBody(ABCFile abc, FlashReader reader) { _abc = abc; MethodIndex = reader.Read7BitEncodedInt(); MaxStack = reader.Read7BitEncodedInt(); LocalCount = reader.Read7BitEncodedInt(); InitialScopeDepth = reader.Read7BitEncodedInt(); MaxScopeDepth = reader.Read7BitEncodedInt(); Code = new ASCode(abc, this, reader.ReadBytes(reader.Read7BitEncodedInt())); Exceptions = new List<ASException>(reader.Read7BitEncodedInt()); for (int i = 0; i < Exceptions.Capacity; i++) Exceptions.Add(new ASException(abc, reader)); Traits = new List<ASTrait>(reader.Read7BitEncodedInt()); for (int i = 0; i < Traits.Capacity; i++) Traits.Add(new ASTrait(abc, reader)); Method.Body = this; }
private List <HReference> FindMessageReferences(ASClass fromClass, ASContainer fromContainer, ASMethod fromMethod) { int instructionRank = 0; ABCFile abc = fromMethod.GetABC(); Stack <ASMultiname> nameStack = new Stack <ASMultiname>(); List <HReference> references = new List <HReference>(); ASContainer container = null; ASCode code = fromMethod.Body.ParseCode(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; switch (instruction.OP) { default: continue; case OPCode.NewFunction: { NewFunctionIns newFunction = (NewFunctionIns)instruction; references.AddRange(FindMessageReferences(fromClass, fromContainer, newFunction.Method)); continue; } case OPCode.GetProperty: { GetPropertyIns getProperty = (GetPropertyIns)instruction; nameStack.Push(getProperty.PropertyName); continue; } case OPCode.GetLex: { GetLexIns getLex = (GetLexIns)instruction; container = abc.GetClass(getLex.TypeName.Name); continue; } case OPCode.GetLocal_0: { container = fromContainer; continue; } case OPCode.ConstructProp: { ConstructPropIns constructProp = (ConstructPropIns)instruction; nameStack.Push(constructProp.PropertyName); break; } } ASMultiname messageQName = nameStack.Pop(); if (string.IsNullOrWhiteSpace(messageQName.Name)) { continue; } ASClass messageClass = abc.GetClass(messageQName.Name); if (messageClass == null) { continue; } if (!_messages.TryGetValue(messageClass, out HMessage message)) { continue; } if (message.References.Any(r => r.FromMethod == fromMethod)) { continue; } HReference reference = new HReference(); message.References.Add(reference); if (message.IsOutgoing) { reference.FromClass = fromClass; reference.FromMethod = fromMethod; reference.InstructionRank = ++instructionRank; reference.IsAnonymous = (!fromMethod.IsConstructor && fromMethod.Trait == null); references.Add(reference); } else { ASMultiname methodName = nameStack.Pop(); ASMethod callbackMethod = fromContainer.GetMethod(methodName.Name); if (callbackMethod == null) { callbackMethod = container.GetMethod(methodName.Name); if (callbackMethod == null) { ASMultiname slotName = nameStack.Pop(); ASTrait hostTrait = container.GetTraits(TraitKind.Slot) .FirstOrDefault(st => st.QName == slotName); container = abc.GetInstance(hostTrait.Type.Name); callbackMethod = container.GetMethod(methodName.Name); } } reference.FromMethod = callbackMethod; } } return(references); }
private PacketValue[] GetOutgoingStructure(ASCode code, ASInstruction beforeReturn, int length) { int getLocalEndIndex = -1; int pushingEndIndex = code.IndexOf(beforeReturn); PacketValue[] structure = new PacketValue[length]; Dictionary <int, int> pushedLocals = new Dictionary <int, int>(); for (int i = pushingEndIndex - 1; i >= 0; i--) { ASInstruction instruction = code[i]; if (instruction.OP == OPCode.GetProperty) { ASClass classToCheck = Class; GetPropertyIns getProperty = (GetPropertyIns)instruction; ASMultiname propertyName = getProperty.PropertyName; ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetLex) { GetLexIns getLex = (GetLexIns)previous; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetPacketValue(propertyName, classToCheck, out PacketValue piece)) { return(null); } structure[--length] = piece; } else if (Local.IsGetLocal(instruction.OP) && instruction.OP != OPCode.GetLocal_0) { Local local = (Local)instruction; pushedLocals.Add(local.Register, --length); if (getLocalEndIndex == -1) { getLocalEndIndex = i; } } if (length == 0) { break; } } for (int i = getLocalEndIndex - 1; i >= 0; i--) { ASInstruction instruction = code[i]; if (!Local.IsSetLocal(instruction.OP)) { continue; } Local local = (Local)instruction; if (pushedLocals.TryGetValue(local.Register, out int structIndex)) { ASInstruction beforeSet = code[i - 1]; pushedLocals.Remove(local.Register); switch (beforeSet.OP) { case OPCode.PushInt: case OPCode.PushByte: case OPCode.Convert_i: structure[structIndex] = PacketValue.Integer; break; case OPCode.Coerce_s: case OPCode.PushString: structure[structIndex] = PacketValue.String; break; case OPCode.PushTrue: case OPCode.PushFalse: structure[structIndex] = PacketValue.Boolean; break; default: throw new Exception($"Don't know what this value type is, tell someone about this please.\r\nOP: {beforeSet.OP}"); } } if (pushedLocals.Count == 0) { break; } } return(structure); }
private PacketValue[] GetOutgoingStructure(ASClass @class, ASMultiname propertyName) { ASMethod constructor = @class.Instance.Constructor; if (constructor.Body.Exceptions.Count > 0) { return(null); } ASCode code = constructor.Body.ParseCode(); if (code.JumpExits.Count > 0 || code.SwitchExits.Count > 0) { return(null); } List <PacketValue> structure = new List <PacketValue>(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction.OP == OPCode.NewArray) { NewArrayIns newArray = (NewArrayIns)instruction; if (newArray.ArgCount > 0) { PacketValue[] structurePieces = new PacketValue[newArray.ArgCount]; for (int j = i - 1, length = newArray.ArgCount; j >= 0; j--) { ASInstruction previous = code[j]; if (Local.IsGetLocal(previous.OP) && previous.OP != OPCode.GetLocal_0) { Local local = (Local)previous; ASParameter parameter = constructor.Parameters[local.Register - 1]; if (!TryGetPacketValue(parameter.Type, null, out PacketValue piece)) { return(null); } structurePieces[--length] = piece; } if (length == 0) { structure.AddRange(structurePieces); break; } } } } else if (instruction.OP == OPCode.ConstructSuper) { ConstructSuperIns constructSuper = (ConstructSuperIns)instruction; if (constructSuper.ArgCount > 0) { ASClass superClass = @class.GetABC().GetClass(@class.Instance.Super); structure.AddRange(GetOutgoingStructure(superClass, propertyName)); } } if (instruction.OP != OPCode.GetProperty) { continue; } GetPropertyIns getProperty = (GetPropertyIns)instruction; if (getProperty.PropertyName != propertyName) { continue; } ASInstruction next = code[++i]; ASClass classToCheck = @class; if (Local.IsGetLocal(next.OP)) { if (next.OP == OPCode.GetLocal_0) { continue; } Local local = (Local)next; ASParameter parameter = constructor.Parameters[local.Register - 1]; if (!TryGetPacketValue(parameter.Type, null, out PacketValue piece)) { return(null); } structure.Add(piece); } else { if (next.OP == OPCode.FindPropStrict) { classToCheck = null; } else if (next.OP == OPCode.GetLex) { GetLexIns getLex = (GetLexIns)next; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } do { next = code[++i]; propertyName = null; if (next.OP == OPCode.GetProperty) { getProperty = (GetPropertyIns)next; propertyName = getProperty.PropertyName; } else if (next.OP == OPCode.CallProperty) { CallPropertyIns callProperty = (CallPropertyIns)next; propertyName = callProperty.PropertyName; } }while (next.OP != OPCode.GetProperty && next.OP != OPCode.CallProperty); if (!TryGetPacketValue(propertyName, classToCheck, out PacketValue piece)) { return(null); } structure.Add(piece); } } return(structure.Count == 0 ? null : structure.ToArray()); }
protected void RemoveDeadFalseConditions(ASCode code) { using (var inCode = new FlashReader(code.ToArray())) using (var outCode = new FlashWriter(inCode.Length)) { while (inCode.Position != inCode.Length) { OPCode op = inCode.ReadOP(); if (op != OPCode.PushFalse) { outCode.WriteOP(op); continue; } op = inCode.ReadOP(); if (op != OPCode.PushFalse) { outCode.WriteOP(OPCode.PushFalse); outCode.WriteOP(op); continue; } op = inCode.ReadOP(); if (op != OPCode.IfNe) { outCode.WriteOP(OPCode.PushFalse); outCode.WriteOP(OPCode.PushFalse); outCode.WriteOP(op); continue; } else inCode.ReadS24(); } code.Clear(); code.AddRange(outCode.ToArray()); } }
private PacketValue[] GetOutgoingStructure(ASClass @class) { ASMethod getArrayMethod = @class.Instance.GetMethod(null, "Array", 0); if (getArrayMethod == null) { ASClass superClass = @class.GetABC().GetClass(@class.Instance.Super); return(GetOutgoingStructure(superClass)); } if (getArrayMethod.Body.Exceptions.Count > 0) { return(null); } ASCode getArrayCode = getArrayMethod.Body.ParseCode(); if (getArrayCode.JumpExits.Count > 0 || getArrayCode.SwitchExits.Count > 0) { // Unable to parse data structure that relies on user input that is not present, // since the structure may change based on the provided input. return(null); } ASInstruction resultPusher = null; for (int i = getArrayCode.Count - 1; i >= 0; i--) { ASInstruction instruction = getArrayCode[i]; if (instruction.OP == OPCode.ReturnValue) { resultPusher = getArrayCode[i - 1]; break; } } int argCount = -1; if (resultPusher.OP == OPCode.ConstructProp) { argCount = ((ConstructPropIns)resultPusher).ArgCount; } else if (resultPusher.OP == OPCode.NewArray) { argCount = ((NewArrayIns)resultPusher).ArgCount; } if (argCount > 0) { return(GetOutgoingStructure(getArrayCode, resultPusher, argCount)); } if (argCount == 0 || resultPusher.OP == OPCode.PushNull) { return(null); } if (resultPusher.OP == OPCode.GetProperty) { GetPropertyIns getProperty = (GetPropertyIns)resultPusher; return(GetOutgoingStructure(Class, getProperty.PropertyName)); } return(Local.IsGetLocal(resultPusher.OP) ? GetOutgoingStructure(getArrayCode, (Local)resultPusher) : null); }
public ASMethodBody(ABCFile abc) { _abc = abc; Code = new ASCode(abc, this); }
private PacketValue[] GetIncomingStructure(ASInstance instance, ASMethod method) { if (method.Body.Exceptions.Count > 0) { return(null); } ASCode code = method.Body.ParseCode(); if (code.JumpExits.Count > 0 || code.SwitchExits.Count > 0) { return(null); } List <PacketValue> structure = new List <PacketValue>(); ABCFile abc = method.GetABC(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction.OP != OPCode.GetLocal_1) { continue; } ASInstruction next = code[++i]; switch (next.OP) { case OPCode.CallProperty: { CallPropertyIns callProperty = (CallPropertyIns)next; if (callProperty.ArgCount > 0) { ASMultiname propertyName = null; ASInstruction previous = code[i - 2]; switch (previous.OP) { case OPCode.GetLex: { GetLexIns getLex = (GetLexIns)previous; propertyName = getLex.TypeName; break; } case OPCode.ConstructProp: { ConstructPropIns constructProp = (ConstructPropIns)previous; propertyName = constructProp.PropertyName; break; } case OPCode.GetLocal_0: { propertyName = instance.QName; break; } } ASInstance innerInstance = abc.GetInstance(propertyName); ASMethod innerMethod = innerInstance.GetMethod(callProperty.PropertyName.Name, null, callProperty.ArgCount); if (innerMethod == null) { ASClass innerClass = abc.GetClass(propertyName); innerMethod = innerClass.GetMethod(callProperty.PropertyName.Name, null, callProperty.ArgCount); } PacketValue[] innerStructure = GetIncomingStructure(innerInstance, innerMethod); if (innerStructure == null) { return(null); } structure.AddRange(innerStructure); } else { if (!TryGetPacketValue(callProperty.PropertyName, null, out PacketValue piece)) { return(null); } structure.Add(piece); } break; } case OPCode.ConstructProp: { ConstructPropIns constructProp = (ConstructPropIns)next; ASInstance innerInstance = abc.GetInstance(constructProp.PropertyName); PacketValue[] innerStructure = GetIncomingStructure(innerInstance, innerInstance.Constructor); if (innerStructure == null) { return(null); } structure.AddRange(innerStructure); break; } case OPCode.ConstructSuper: { ASInstance superInstance = abc.GetInstance(instance.Super); PacketValue[] innerStructure = GetIncomingStructure(superInstance, superInstance.Constructor); if (innerStructure == null) { return(null); } structure.AddRange(innerStructure); break; } case OPCode.CallSuper: { CallSuperIns callSuper = (CallSuperIns)next; ASInstance superInstance = abc.GetInstance(instance.Super); ASMethod superMethod = superInstance.GetMethod(callSuper.MethodName.Name, null, callSuper.ArgCount); PacketValue[] innerStructure = GetIncomingStructure(superInstance, superMethod); if (innerStructure == null) { return(null); } structure.AddRange(innerStructure); break; } case OPCode.CallPropVoid: { CallPropVoidIns callPropVoid = (CallPropVoidIns)next; if (callPropVoid.ArgCount != 0) { return(null); } if (!TryGetPacketValue(callPropVoid.PropertyName, null, out PacketValue piece)) { return(null); } structure.Add(piece); break; } default: return(null); } } return(structure.Count == 0 ? null : structure.ToArray()); }
private string GetIncomingStructure(ASInstance instance, ASMethod method) { if (method.Body.Exceptions.Count > 0) { return(null); } ASCode code = method.Body.ParseCode(); if (code.JumpExits.Count > 0 || code.SwitchExits.Count > 0) { return(null); } string structure = null; ABCFile abc = method.GetABC(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction.OP != OPCode.GetLocal_1) { continue; } ASInstruction next = code[++i]; switch (next.OP) { case OPCode.CallProperty: { var callProperty = (CallPropertyIns)next; if (callProperty.ArgCount > 0) { ASMultiname propertyName = null; ASInstruction previous = code[i - 2]; switch (previous.OP) { case OPCode.GetLex: { var getLex = (GetLexIns)previous; propertyName = getLex.TypeName; break; } case OPCode.ConstructProp: { var constructProp = (ConstructPropIns)previous; propertyName = constructProp.PropertyName; break; } case OPCode.GetLocal_0: { propertyName = instance.QName; break; } } ASInstance innerInstance = abc.GetInstance(propertyName); ASMethod innerMethod = innerInstance.GetMethod(callProperty.PropertyName.Name, null, callProperty.ArgCount); if (innerMethod == null) { ASClass innerClass = abc.GetClass(propertyName); innerMethod = innerClass.GetMethod(callProperty.PropertyName.Name, null, callProperty.ArgCount); } string innerStructure = GetIncomingStructure(innerInstance, innerMethod); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; } else { if (!TryGetStructurePiece(callProperty.PropertyName, null, out char piece)) { return(null); } structure += piece; } break; } case OPCode.ConstructProp: { var constructProp = (ConstructPropIns)next; ASInstance innerInstance = abc.GetInstance(constructProp.PropertyName); string innerStructure = GetIncomingStructure(innerInstance, innerInstance.Constructor); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.ConstructSuper: { ASInstance superInstance = abc.GetInstance(instance.Super); string innerStructure = GetIncomingStructure(superInstance, superInstance.Constructor); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.CallSuper: { var callSuper = (CallSuperIns)next; ASInstance superInstance = abc.GetInstance(instance.Super); ASMethod superMethod = superInstance.GetMethod(callSuper.MethodName.Name, null, callSuper.ArgCount); string innerStructure = GetIncomingStructure(superInstance, superMethod); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.CallPropVoid: { var callPropVoid = (CallPropVoidIns)next; if (callPropVoid.ArgCount != 0) { return(null); } if (!TryGetStructurePiece(callPropVoid.PropertyName, null, out char piece)) { return(null); } structure += piece; break; } default: return(null); } } return(structure); }
public void ReplaceLocalizationDefaults(RetroLocalizationConfig[] localizationConfigs) { var abc = _flash.AbcGame; var symbols = (SymbolClassTag)_flash.Tags.Last(x => x.Kind == TagKind.SymbolClass); var localizationClass = abc.GetClass("HabboLocalizationCom"); // Save all old localizations. var localizations = localizationConfigs .Select(x => x.HotelCodeBase).Distinct() .ToDictionary(x => x, y => { var binaryDataId = symbols.Entries.First(x => x.Item2.Contains(y)); var binaryData = (DefineBinaryDataTag)_flash.Tags.First(x => x.Kind == TagKind.DefineBinaryData && ((DefineBinaryDataTag)x).Id == binaryDataId.Item1); return(binaryData.Data); }); // Find all old localizations. var localizationSymbols = symbols.Entries.Where(x => x.Item2.Contains("default_localizations_")).ToArray(); var localizationTraits = localizationClass.Traits.Where(x => x.IsStatic && x.QName.Name.StartsWith("default_localizations_")).ToArray(); var localizationClasses = abc.Classes.Where(x => x.QName.Name.StartsWith("default_localizations_")).ToArray(); if (localizationSymbols.Length != localizationTraits.Length || localizationTraits.Length != localizationClasses.Length) { throw new ApplicationException("Localization result amount mismatch."); } // Remove all old localization references. // - Remove symbols foreach (var symbol in localizationSymbols) { _flash.Tags.RemoveAll(x => x.Kind == TagKind.DefineBinaryData && ((DefineBinaryDataTag)x).Id == symbol.Item1); symbols.Entries.RemoveAll(x => x.Item1 == symbol.Item1); } // - Remove "public static var default_localizations_*" localizationClass.Traits.RemoveAll(trait => trait.QName.Name.StartsWith("default_localizations_")); var body = localizationClass.Constructor.Body.ParseCode(); var getLex = body.First(x => x.OP == OPCode.GetLex && ((GetLexIns)x).TypeName.Name.StartsWith("default_localizations_")); var getLexIndex = body.IndexOf(getLex); var setProp = body.LastIndexOf(body.Count - 1, OPCode.SetProperty); body.RemoveRange(getLexIndex, setProp - getLexIndex + 1); localizationClass.Constructor.Body.Code = body.ToArray(); // - Remove "default_localizations_" classes / instances / scripts // TODO: Figure out how to fix all index based stuff, because this messes it up. DO NOT USE YET. // _flash.AbcGame.Classes.RemoveAll(x => x.QName.Name.StartsWith("default_localizations_")); // _flash.AbcGame.Instances.RemoveAll(x => x.QName.Name.StartsWith("default_localizations_")); // _flash.AbcGame.Scripts.RemoveAll(x => x.QName.Name.Contains("default_localizations_")); // Add localizations. foreach (var config in localizationConfigs) { var localizationName = $"custom_localizations_{config.HotelCode}"; var defLocalizationName = $"own_default_localizations_{config.HotelCode}"; var localizationMultiNameIndex = abc.Pool.AddConstant(new ASMultiname(abc.Pool) { NameIndex = abc.Pool.AddConstant(localizationName), Kind = MultinameKind.QName, NamespaceIndex = 1 }); #region Create localization class // Create instance. var instanceConstructor = new ASMethod(abc) { ReturnTypeIndex = 0 }; var instanceConstructorIndex = abc.AddMethod(instanceConstructor); var instanceConstructorBody = new ASMethodBody(abc) { MethodIndex = instanceConstructorIndex, MaxStack = 1, LocalCount = 1, InitialScopeDepth = 0, MaxScopeDepth = 1, Code = new byte[] { 0xD0, 0x30, 0xD0, 0x49, 0x00, 0x47 } }; abc.AddMethodBody(instanceConstructorBody); // Create class. var classConstructor = new ASMethod(abc) { ReturnTypeIndex = 0 }; var classConstructorIndex = abc.AddMethod(classConstructor); var classConstructorBody = new ASMethodBody(abc) { MethodIndex = classConstructorIndex, MaxStack = 0, LocalCount = 1, InitialScopeDepth = 0, MaxScopeDepth = 0, Code = new byte[] { 0x47 } }; abc.AddMethodBody(classConstructorBody); // Add class to SWF. var classIndex = abc.AddClass( new ASClass(abc) { ConstructorIndex = classConstructorIndex }, new ASInstance(abc) { ConstructorIndex = instanceConstructorIndex, QNameIndex = localizationMultiNameIndex, SuperIndex = abc.Pool.GetMultinameIndex("ByteArray"), Flags = ClassFlags.Sealed } ); // Create script. var initializerMethod = new ASMethod(abc) { ReturnTypeIndex = 0 }; var initializerMethodIndex = abc.AddMethod(initializerMethod); var initializerMethodBody = new ASMethodBody(abc) { MethodIndex = initializerMethodIndex, MaxStack = 3, LocalCount = 1, InitialScopeDepth = 0, MaxScopeDepth = 3, Code = new byte[0] }; abc.AddMethodBody(initializerMethodBody); var initializerMethodBodyCode = new ASCode(abc, initializerMethodBody); initializerMethodBodyCode.AddRange(new ASInstruction[] { new GetLocal0Ins(), new PushScopeIns(), new GetScopeObjectIns(0), new GetLexIns(abc, abc.Pool.GetMultinameIndex("Object")), new PushScopeIns(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ByteArray")), new DupIns(), new PushScopeIns(), new NewClassIns(abc, classIndex), new PopScopeIns(), new PopScopeIns(), new InitPropertyIns(abc, localizationMultiNameIndex), new ReturnVoidIns() }); initializerMethodBody.Code = initializerMethodBodyCode.ToArray(); var initScript = new ASScript(abc) { InitializerIndex = initializerMethodIndex }; initScript.Traits.Add(new ASTrait(abc) { ClassIndex = classIndex, QNameIndex = localizationMultiNameIndex, Kind = TraitKind.Class }); _flash.AbcGame.AddScript(initScript); #endregion #region Create binary data symbol var symbolId = symbols.AddSymbol(localizationName); var data = localizations[config.HotelCodeBase]; _flash.Tags.Insert(_flash.Tags.IndexOf(symbols), new DefineBinaryDataTag(symbolId, data)); #endregion #region Add to HabboLocalizationCom var defLocalizationMultiNameIndex = abc.Pool.AddConstant(new ASMultiname(abc.Pool) { NameIndex = abc.Pool.AddConstant(defLocalizationName), Kind = MultinameKind.QName, NamespaceIndex = 1 }); localizationClass.Traits.Add(new ASTrait(abc) { QNameIndex = defLocalizationMultiNameIndex, TypeIndex = abc.Pool.GetMultinameIndex("Class") }); var constructorBody = localizationClass.Constructor.Body.ParseCode(); constructorBody.InsertRange(constructorBody.Count - 1, new ASInstruction[] { new GetLexIns(abc, localizationMultiNameIndex), new FindPropertyIns(abc, defLocalizationMultiNameIndex), new SwapIns(), new SetPropertyIns(abc, defLocalizationMultiNameIndex) }); localizationClass.Constructor.Body.Code = constructorBody.ToArray(); #endregion } // Swap localization to load. var stringId = abc.Pool.Strings.IndexOf("default_localizations_"); abc.Pool.Strings[stringId] = "own_default_localizations_"; // Replace localization_configuration_txt. var locConfigBuilder = new StringBuilder(); for (var i = 0; i < localizationConfigs.Length; i++) { var config = localizationConfigs[i]; var currentId = i + 1; locConfigBuilder.AppendLine($"localization.{currentId}={config.HotelCode}"); locConfigBuilder.AppendLine($"localization.{currentId}.code={config.Code}"); locConfigBuilder.AppendLine($"localization.{currentId}.name={config.Name}"); locConfigBuilder.AppendLine($"localization.{currentId}.url={config.Url}"); } var locConfigId = symbols.Entries.First(x => x.Item2.Contains("localization_configuration_txt")); var locConfig = (DefineBinaryDataTag)_flash.Tags.First(x => x.Kind == TagKind.DefineBinaryData && ((DefineBinaryDataTag)x).Id == locConfigId.Item1); locConfig.Data = Encoding.UTF8.GetBytes(locConfigBuilder.ToString()); // Replace localizations manifest. string localizationManifestStr = null; DefineBinaryDataTag localizationManifest = null; foreach (var(entryId, _) in symbols.Entries) { var binaryData = (DefineBinaryDataTag)_flash.Tags.FirstOrDefault(x => x.Kind == TagKind.DefineBinaryData && ((DefineBinaryDataTag)x).Id == entryId); if (binaryData != null) { var dataString = Encoding.UTF8.GetString(binaryData.Data); if (dataString.Contains("<asset mimeType=\"text/plain\" name=\"default_localizations_en\" />")) { localizationManifestStr = dataString; localizationManifest = binaryData; break; } } } if (localizationManifest == null || localizationManifestStr == null) { throw new ApplicationException("Could not find localizationManifest or localizationManifestStr."); } var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(localizationManifestStr); var defaultLoc = new string[] { "development_localizations" }; var manifestAssets = xmlDocument.GetElementsByTagName("assets")[0]; manifestAssets.RemoveAll(); foreach (var name in defaultLoc.Union(localizationConfigs.Select(x => "own_default_localizations_" + x.HotelCode))) { var child = xmlDocument.CreateElement("asset"); child.SetAttribute("mimeType", "text/plain"); child.SetAttribute("name", name); manifestAssets.AppendChild(child); } using (var stringWriter = new StringWriter()) using (var xmlTextWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true })) { xmlDocument.WriteTo(xmlTextWriter); xmlTextWriter.Flush(); localizationManifest.Data = Encoding.UTF8.GetBytes(stringWriter.GetStringBuilder().ToString()); } }
public void InjectMessageLogger() { ABCFile abc = ABCFiles.Last(); ASInstance decoderInstance = null; foreach (ASInstance instance in abc.Instances) { if (instance.IsInterface) { continue; } if (instance.Traits.Count != 12) { continue; } if (instance.Constructor.Parameters.Count != 2) { continue; } if (instance.Constructor.Parameters[0].Type.Name != "int") { continue; } if (instance.Constructor.Parameters[1].Type.Name != "ByteArray") { continue; } decoderInstance = instance; break; } var methods = decoderInstance.GetMethods(); var i = 0; foreach (var method in methods) { ASCode methodCode = method.Body.ParseCode(); switch (i) { case 0: // set header methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertIIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncomingHeader"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 2), new GetLocal1Ins() }); break; case 1: // readString methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertSIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "string"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; case 2: // readInteger methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertIIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "integer"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; case 3: // readBoolean methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertBIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "boolean"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; case 4: // readShort methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertIIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "short"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; case 5: // readByte methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertIIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "byte"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; case 6: // readFloat methodCode.InsertRange(methodCode.Count - 1, new ASInstruction[] { new ConvertDIns(), new SetLocal1Ins(), new GetLexIns(abc, abc.Pool.GetMultinameIndex("ExternalInterface")), new PushStringIns(abc, "FlashExternalInterface.logIncoming"), new PushStringIns(abc, "float"), new GetLocal1Ins(), new CallPropVoidIns(abc, abc.Pool.GetMultinameIndex("call"), 3), new GetLocal1Ins() }); break; } i++; method.Body.Code = methodCode.ToArray(); method.Body.LocalCount += 2; method.Body.MaxStack += 3; Console.WriteLine("Patched function " + i); } }