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 void FindMessagesReferences() { int classRank = 1; ABCFile abc = ABCFiles.Last(); foreach (ASClass @class in abc.Classes) { ASInstance instance = @class.Instance; if (_messages.ContainsKey(@class)) { continue; } if (instance.Flags.HasFlag(ClassFlags.Interface)) { continue; } IEnumerable <ASMethod> methods = (new[] { @class.Constructor, instance.Constructor }) .Concat(instance.GetMethods()) .Concat(@class.GetMethods()); int methodRank = 0; foreach (ASMethod fromMethod in methods) { bool isStatic = (fromMethod.Trait?.IsStatic ?? @class.Constructor == fromMethod); ASContainer fromContainer = (isStatic ? (ASContainer)@class : instance); List <HReference> refernces = FindMessageReferences(@class, fromContainer, fromMethod); if (refernces.Count > 0) { methodRank++; } foreach (HReference reference in refernces) { reference.IsStatic = isStatic; reference.ClassRank = classRank; reference.MethodRank = methodRank; reference.GroupCount = refernces.Count; } } if (methodRank > 0) { classRank++; } } Dictionary <ASContainer, List <HReference> > froms = new Dictionary <ASContainer, List <HReference> >(); foreach (HMessage incomingMsg in InMessages.Values) { foreach (HReference reference in incomingMsg.References) { if (!froms.TryGetValue(reference.FromMethod.Container, out List <HReference> references)) { references = new List <HReference>(); froms.Add(reference.FromMethod.Container, references); } if (!references.Contains(reference)) { references.Add(reference); } } } classRank = 1; foreach (ASClass @class in abc.Classes) { ASContainer container = null; if (froms.TryGetValue(@class, out List <HReference> references)) { container = @class; } else if (froms.TryGetValue(@class.Instance, out references)) { container = @class.Instance; } if (container != null) { Dictionary <ASMethod, List <HReference> > methodReferenceGroups = new Dictionary <ASMethod, List <HReference> >(); foreach (HReference reference in references) { reference.FromClass = @class; reference.InstructionRank = -1; reference.ClassRank = classRank; reference.IsStatic = container.IsStatic; reference.GroupCount = references.Count; if (!methodReferenceGroups.TryGetValue(reference.FromMethod, out List <HReference> methodReferences)) { methodReferences = new List <HReference>(); methodReferenceGroups.Add(reference.FromMethod, methodReferences); } methodReferences.Add(reference); } int methodRank = 1; foreach (ASMethod method in container.GetMethods()) { if (methodReferenceGroups.TryGetValue(method, out List <HReference> methodReferences)) { foreach (HReference reference in methodReferences) { reference.MethodRank = methodRank; } methodRank++; } } classRank++; } } }
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); } }