public void Write(ASTrait trait) { Write(trait.Id); Write(trait.QName); Write(trait.IsStatic); Write((byte)trait.Kind); Write((byte)trait.Attributes); switch (trait.Kind) { case TraitKind.Slot: case TraitKind.Constant: { Write(trait.Type); if (trait.Value != null) { Write(trait.ValueKind, trait.Value); } break; } case TraitKind.Method: case TraitKind.Getter: case TraitKind.Setter: { Write(trait.Method); break; } } }
protected void ScanForMessageReferences(ABCFile abc) { if (!FindMessageInstances()) { return; } if (_messageReferencesCache.Count > 0) { return; } var messageClasses = new Dictionary <string, ASClass>( OutgoingTypes.Count + IncomingTypes.Count); foreach (ASClass outClass in OutgoingTypes.Values) { messageClasses.Add( outClass.Instance.Type.ObjName, outClass); } foreach (ASClass inClass in IncomingTypes.Values) { messageClasses.Add( inClass.Instance.Type.ObjName, inClass); } foreach (ASClass asClass in abc.Classes) { ASInstance asInstance = asClass.Instance; if (asInstance.ClassInfo.HasFlag(ClassFlags.Interface)) { continue; } ScanForMessageReference(messageClasses, asClass, asClass.Constructor, 0); ScanForMessageReference(messageClasses, asClass, asClass.Instance.Constructor, 0); if (asInstance.Traits.Count < 1) { continue; } for (int i = 0; i < asInstance.Traits.Count; i++) { ASTrait trait = asInstance.Traits[i]; if (trait.TraitType != TraitType.Method) { continue; } var mgsTrait = (MethodGetterSetterTrait)trait.Data; ScanForMessageReference(messageClasses, asClass, mgsTrait.Method, i); } } }
/// <summary> /// Modifies the "ClientHelloMessageComposer" (Packet 4000) class /// to send the current environment instead of the protocol revision. /// </summary> public void PatchClientHelloMessageComposer() { var abc = _flash.AbcGame; // Grab ClientHelloMessageComposer. var composerClass = MessagesOutgoing[4000].Clazz; // Find CommunicationUtils. var communicationUtilsClass = _lookup.Get(HabboClass.CommunicationUtils); var communicationUtilsMethod = communicationUtilsClass.Traits .AsParallel() .FirstOrDefault(x => x.IsStatic && x.Kind == TraitKind.Method && x.Method.Parameters.Count == 2 && x.Method.Parameters[1].IsOptional && x.Method.ReturnType.Name.Equals("String")); if (communicationUtilsMethod == null) { throw new ApplicationException("Unable to find communicationUtilsMethod."); } // Find com.sulake.habbo.communication.demo:IncomingMessages. var incomingMessagesClass = _lookup.Get(HabboClass.IncomingMessages); var incomingMessagesMethod = incomingMessagesClass.Instance.Traits .AsParallel() .Where(x => x.Kind == TraitKind.Method && x.Method.Parameters.Count == 1 && x.Method.Parameters[0].Type.Name.Equals("Event") && x.Method.Parameters[0].IsOptional && x.Method.ReturnType.Name.Equals("void")) .Select(x => x.Method) .FirstOrDefault(); if (incomingMessagesMethod == null) { throw new ApplicationException("Unable to find incomingMessagesMethod."); } var incomingMessagesCode = incomingMessagesMethod.Body.ParseCode(); // Modify the method of IncomingMessages. var constructComposer = incomingMessagesCode .Where(x => x.OP == OPCode.ConstructProp && ((ConstructPropIns)x).PropertyName.NameIndex == composerClass.QName.NameIndex) .Cast <ConstructPropIns>() .First(); // IncomingMessages: Add an argument when constructing the message. constructComposer.ArgCount = 1; // IncomingMessages: Add the argument value. incomingMessagesCode.InsertRange(incomingMessagesCode.IndexOf(constructComposer), new ASInstruction[] { new GetLexIns(abc, abc.Pool.Multinames.IndexOf(communicationUtilsClass.QName)), new PushStringIns(abc, "environment"), new CallPropertyIns(abc, communicationUtilsMethod.QNameIndex, 1), new CoerceSIns() }); // IncomingMessages: Increase stack. incomingMessagesMethod.Body.MaxStack += 4; incomingMessagesMethod.Body.Code = incomingMessagesCode.ToArray(); // Modify the constructor of ClientHelloMessageComposer. var composerConstructor = composerClass.Instance.Constructor; var composerCode = composerConstructor.Body.ParseCode(); // ClientHelloMessageComposer: Add "String" parameter. composerConstructor.Parameters.Add(new ASParameter(abc.Pool, composerConstructor) { TypeIndex = abc.Pool.GetMultinameIndex("String") }); // ClientHelloMessageComposer: Add "environmentId" variable. var composerSlotQName = new ASMultiname(abc.Pool) { NameIndex = abc.Pool.AddConstant("environmentId"), Kind = MultinameKind.QName, NamespaceIndex = 1 }; var composerSlot = new ASTrait(abc) { Kind = TraitKind.Slot, QNameIndex = abc.Pool.AddConstant(composerSlotQName), TypeIndex = abc.Pool.GetMultinameIndex("String") }; composerClass.Instance.Traits.Add(composerSlot); // ClientHelloMessageComposer: Set parameter of constructor to "environmentId". composerCode.InsertRange(composerCode.Count - 1, new ASInstruction[] { new GetLocal1Ins(), new FindPropertyIns(abc, composerSlot.QNameIndex), new SwapIns(), new SetPropertyIns(abc, composerSlot.QNameIndex), }); composerConstructor.Body.LocalCount = 2; composerConstructor.Body.MaxStack = 2; composerConstructor.Body.Code = composerCode.ToArray(); // Modify the method that returns packet as array. var getArrayMethod = composerClass.Instance.Traits .AsParallel() .First(x => x.Kind == TraitKind.Method && x.Method.Parameters.Count == 0 && x.Method.ReturnType.Name.Equals("Array")); var getArrayCode = getArrayMethod.Method.Body.ParseCode(); // getArray: Remove everything until constructing array. getArrayCode.Clear(); getArrayCode.AddRange(new ASInstruction[] { new GetLocal0Ins(), new PushScopeIns(), new PushStringIns(abc, Revision), new PushStringIns(abc, RevisionProtocol), new PushIntIns(abc, 3), // Android. new PushIntIns(abc, 1), new GetLexIns(abc, composerSlot.QNameIndex), new NewArrayIns(5), new ReturnValueIns(), }); // getArray: Apply patch. getArrayMethod.Method.Body.MaxStack = 5; getArrayMethod.Method.Body.LocalCount = 1; getArrayMethod.Method.Body.Code = getArrayCode.ToArray(); // ClientHelloMessageComposer: Clean class. composerClass.Instance.Traits.Remove(composerClass.Instance.Traits.First(x => x.Kind == TraitKind.Slot && x.QNameIndex != composerSlot.QNameIndex)); }
public bool FindMessageInstances() { if (OutgoingTypes.Count > 0 && IncomingTypes.Count > 0) { return(true); } ABCFile abc = ABCFiles[2]; ASClass habboMessages = abc.FindClassByName("HabboMessages"); if (habboMessages == null || habboMessages.Traits.Count < 2) { return(false); } ASTrait incomingMap = habboMessages.Traits[0]; ASTrait outgoingMap = habboMessages.Traits[1]; using (var mapReader = new FlashReader( habboMessages.Constructor.Body.Bytecode.ToArray())) { while (mapReader.Position != mapReader.Length) { OPCode op = mapReader.ReadOP(); if (op != OPCode.GetLex) { continue; } int mapTypeIndex = mapReader.Read7BitEncodedInt(); bool isOutgoing = (mapTypeIndex == outgoingMap.TypeIndex); bool isIncoming = (mapTypeIndex == incomingMap.TypeIndex); if (!isOutgoing && !isIncoming) { continue; } op = mapReader.ReadOP(); if (op != OPCode.PushShort && op != OPCode.PushByte) { continue; } ushort header = 0; if (op == OPCode.PushByte) { header = mapReader.ReadByte(); } else { header = (ushort)mapReader.Read7BitEncodedInt(); } op = mapReader.ReadOP(); if (op != OPCode.GetLex) { continue; } int messageTypeIndex = mapReader.Read7BitEncodedInt(); ASMultiname messageType = abc.Constants.Multinames[messageTypeIndex]; ASClass messageInstance = abc.FindClassByName(messageType.ObjName); if (isOutgoing) { OutgoingTypes[header] = messageInstance; } else if (isIncoming) { IncomingTypes[header] = messageInstance; } } } return(OutgoingTypes.Count > 0 && IncomingTypes.Count > 0); }
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); }