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 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) ?? 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; if (instruction.OP == OPCode.FindPropStrict) { FindPropStrictIns findPropStrictIns = (FindPropStrictIns)instruction; multiname = findPropStrictIns.PropertyName; } else if (instruction.OP == OPCode.GetLex) { GetLexIns 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); }
private static void DumpIncoming(SortedDictionary <ushort, MessageItem> messages) { var packets = new List <PacketInfo>(); // Find info. foreach (var(id, message) in messages) { var packet = new PacketInfo { Id = id, Category = "Unknown", Name = $"Unknown_{id}" }; // First category attempt. var package = message.Clazz.QName.Namespace.Name; if (package.StartsWith("com.sulake.habbo.communication.messages.incoming")) { packet.Category = string.Join('.', package .Replace("com.sulake.habbo.communication.messages.incoming.", string.Empty) .Split('.') .Select(x => x[0].ToString().ToUpper() + x.Substring(1)) ); } // Parse constructor. GetLexIns parserIns = null; if (message.Clazz.Instance.Constructor.Parameters.Count == 1) { // Find parser inside constructor. var code = message.Clazz.Instance.Constructor.Body.ParseCode(); var parser = (GetLexIns)code.First(x => x.OP == OPCode.GetLex); parserIns = parser; } else if (message.Clazz.Instance.Constructor.Parameters.Count == 2) { // Attempt to find parser somewhere else. var abc = message.Clazz.GetABC(); foreach (var instance in abc.Instances) { if (instance.Constructor?.Body == null) { continue; } var instCode = instance.Constructor.Body.ParseCode(); var instConstruct = instCode.FirstOrDefault(x => x.OP == OPCode.ConstructProp && ((ConstructPropIns)x).PropertyName == message.Clazz.QName && ((ConstructPropIns)x).ArgCount == 2); if (instConstruct != null) { parserIns = (GetLexIns)instCode[instCode.IndexOf(instConstruct) - 1]; break; } } } else { throw new Exception($"Unknown parameters count {message.Clazz.Instance.Constructor.Parameters.Count}."); } if (parserIns != null) { var parserName = parserIns.TypeName.Name; if (parserName.EndsWith("MessageParser")) { packet.Name = parserName.Substring(0, parserName.Length - 13); } else if (parserName.EndsWith("Parser")) { packet.Name = parserName.Substring(0, parserName.Length - 6); } // Might give a better result than previous category. var parserPackage = parserIns.TypeName.Namespace.Name; if (parserPackage.StartsWith("com.sulake.habbo.communication.messages.parser")) { packet.Category = string.Join('.', parserPackage .Replace("com.sulake.habbo.communication.messages.parser.", string.Empty) .Split('.') .Select(x => x[0].ToString().ToUpper() + x.Substring(1)) ); } } packets.Add(packet); } // Print out. Console.WriteLine("# INCOMING"); foreach (var packet in packets.OrderBy(x => x.Category).ThenBy(x => x.Name)) { Console.WriteLine($"[{packet.Id,4}] {packet.Category} - {packet.Name}"); } }
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 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()); }