/// <summary> /// Dissassembles the Habbo Hotel flash client. /// </summary> public override void Disassemble() { WriteLog("Disassembling..."); base.Disassemble(); ABCFile abc = ABCFiles[2]; ASClass habboMessagesClass = abc.FindFirstClassByName("HabboMessages"); if (habboMessagesClass != null) { FindHabboMessageClasses(habboMessagesClass); WriteLog(string.Format("Outgoing({0})/Incoming({1}) messages extracted.", OutgoingMessages.Count, IncomingMessages.Count)); } }
/// <summary> /// Dissassembles the Habbo Hotel flash client. /// </summary> public override void Disassemble() { WriteLog("Disassembling..."); base.Disassemble(); for (int i = 0; i < ABCFiles.Count; i++) { ABCFile abc = ABCFiles[i]; //WriteLog($"Fixing local registers in {abc.Methods.Count:n0} methods."); //FixLocalRegisters(abc); if (i == 2) { ASClass habboMessagesClass = abc.FindFirstClassByName("HabboMessages"); if (habboMessagesClass != null) { FindHabboMessageClasses(habboMessagesClass); WriteLog(string.Format("Outgoing({0})/Incoming({1}) messages extracted.", OutgoingMessages.Count, IncomingMessages.Count)); } } } }
protected int FindMessageReferences(ASClass fromClass, TraitContainer container, ASMethod fromMethod, int rank, int msgReferencesFound) { ABCFile abc = fromClass.ABC; using (var inCode = new FlashReader(fromMethod.Body.Bytecode)) { var multinameStack = new Stack <ASMultiname>(); while (inCode.IsDataAvailable) { OPCode op = inCode.ReadOP(); object[] values = inCode.ReadValues(op); switch (op) { #region Case: GetProperty case OPCode.GetProperty: { multinameStack.Push(abc.Constants.Multinames[(int)values[0]]); break; } #endregion #region Case: NewFunction case OPCode.NewFunction: { ASMethod newFuncMethod = abc.Methods[(int)values[0]]; msgReferencesFound = FindMessageReferences(fromClass, container, newFuncMethod, rank, msgReferencesFound); break; } #endregion #region Case: ConstructProp case OPCode.ConstructProp: { ASMultiname constructPropType = abc.Constants.Multinames[(int)values[0]]; ASClass messageClass = abc.FindFirstClassByName(constructPropType.Name); if (messageClass == null || !IsMessageClass(messageClass)) { continue; } if (!_messageReferences.ContainsKey(messageClass)) { _messageReferences[messageClass] = new List <ASReference>(); } var msgReference = new ASReference(messageClass, fromClass, fromMethod); if (!IsMessageOutgoing(messageClass)) { ASMultiname topName = multinameStack.Pop(); msgReference.FromMethod = null; IEnumerable <MethodGetterSetterTrait> mgsTraits = container.FindMethodGetterSetterTraits(); rank = 0; // TODO: Move this into a method or something, I'm re-writing it below as well. foreach (MethodGetterSetterTrait mgsTrait in mgsTraits) { rank++; if (mgsTrait.Method.TraitName == topName.Name) { msgReference.FromMethod = mgsTrait.Method; break; } } if (msgReference.FromMethod == null && multinameStack.Count > 0) { ASMultiname bottomName = multinameStack.Pop(); foreach (ASTrait trait in container.Traits) { switch (trait.TraitType) { #region Case: Slot, Constant case TraitType.Slot: case TraitType.Constant: { if (trait.Name.Name != bottomName.Name) { continue; } var scTrait = (SlotConstantTrait)trait.Data; if (scTrait.TypeName.MultinameType != ConstantType.QName) { continue; } ASClass slotValueClass = abc.FindFirstClassByName(scTrait.TypeName.Name); rank = 0; mgsTraits = slotValueClass.Instance.FindMethodGetterSetterTraits(); foreach (MethodGetterSetterTrait mgsTrait in mgsTraits) { rank++; if (mgsTrait.Method.TraitName == topName.Name) { msgReference.FromMethod = mgsTrait.Method; break; } } if (msgReference.FromMethod != null) { msgReference.FromClass = slotValueClass; } break; } #endregion } if (msgReference.FromMethod != null) { break; } } } } msgReference.Id = ((++msgReferencesFound) + rank); // We can't rely on the amount of references found, since the hooking of incoming messages are randomized each revision. if (!IsMessageOutgoing(messageClass)) { msgReference.Id = rank; } _messageReferences[messageClass].Add(msgReference); break; } #endregion } } } return(msgReferencesFound); }
protected void FindHabboMessageClasses(ASClass habboMessageClass) { if (habboMessageClass == null) { throw new NullReferenceException(nameof(habboMessageClass)); } if (OutgoingMessages != null && IncomingMessages != null) { return; } ABCFile abc = habboMessageClass.ABC; if (habboMessageClass.Traits.Count < 2) { return; } int incomingMapTypeIndex = habboMessageClass.Traits[0].NameIndex; int outgoingMapTypeIndex = habboMessageClass.Traits[1].NameIndex; var outgoingClasses = new Dictionary <ushort, ASClass>(); var incomingClasses = new Dictionary <ushort, ASClass>(); ASMethod constructor = habboMessageClass.Constructor; using (var inCode = new FlashReader(constructor.Body.Bytecode)) { while (inCode.IsDataAvailable) { object[] values = inCode.ReadValuesUntil(OPCode.GetLex); if (values == null) { break; } // Check if the instruction is referencing one of the in/out map types. int getLexTypeIndex = (int)values[0]; bool isOutgoing = (getLexTypeIndex == outgoingMapTypeIndex); if (!isOutgoing && getLexTypeIndex != incomingMapTypeIndex) { continue; } OPCode op = 0; values = inCode.ReadValuesUntilEither(out op, OPCode.PushByte, OPCode.PushShort); if (values == null) { return; } var header = Convert.ToUInt16(values[0]); values = inCode.ReadValuesUntil(OPCode.GetLex); if (values == null) { return; } getLexTypeIndex = (int)values[0]; ASMultiname messageType = abc.Constants.Multinames[getLexTypeIndex]; ASClass messageClass = abc.FindFirstClassByName(messageType.Name); Dictionary <ushort, ASClass> messageClasses = (isOutgoing ? outgoingClasses : incomingClasses); messageClasses[header] = messageClass; _isMessageOutgoing[messageClass] = isOutgoing; } } #region Organize Outgoing Message Dictionaries IOrderedEnumerable <KeyValuePair <ushort, ASClass> > orderedOutgoing = outgoingClasses.OrderBy(kvp => kvp.Key); _outgoingHeaders = orderedOutgoing .ToDictionary(kvp => kvp.Value, kvp => kvp.Key); OutgoingMessages = new ReadOnlyDictionary <ushort, ASClass>( orderedOutgoing.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); #endregion #region Organize Incoming Message Dictionaries IOrderedEnumerable <KeyValuePair <ushort, ASClass> > orderedIncoming = incomingClasses.OrderBy(kvp => kvp.Key); _incomingHeaders = orderedIncoming .ToDictionary(kvp => kvp.Value, kvp => kvp.Key); IncomingMessages = new ReadOnlyDictionary <ushort, ASClass>( orderedIncoming.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); #endregion }