Пример #1
0
        /// <summary>
        /// Injects the specified public RSA keys into the bytecode that handles the verification of the received primes.
        /// </summary>
        /// <param name="exponent">The public exponent.</param>
        /// <param name="modulus">The public modulus.</param>
        public void ReplaceRSAKeys(int exponent, string modulus)
        {
            ABCFile    abc = ABCFiles[2];
            ASInstance habboCommDemoInstance = abc.FindFirstInstanceByName("HabboCommunicationDemo");

            IEnumerable <MethodGetterSetterTrait> mgsTraits =
                habboCommDemoInstance.FindMethodGetterSetterTraits();

            ASMethod method          = null;
            int      rsaKeyTypeIndex = abc.Constants.IndexOfMultiname("RSAKey");

            foreach (MethodGetterSetterTrait mgsTrait in mgsTraits)
            {
                if (mgsTrait.Method.ReturnType.Name != "void")
                {
                    continue;
                }
                if (mgsTrait.Method.Parameters.Count != 1)
                {
                    continue;
                }

                if (ContainsOperation(mgsTrait.Method, OPCode.GetLex, rsaKeyTypeIndex))
                {
                    method = mgsTrait.Method;
                    WriteLog($"Found reference to 'RSAKey' in method '{method}'.");
                    break;
                }
            }

            using (var outCode = new FlashWriter())
                using (var inCode = new FlashReader(method.Body.Bytecode))
                {
                    int modulusStringIndex     = abc.Constants.AddString(modulus);
                    int exponentStringIndex    = abc.Constants.AddString(exponent.ToString("x")); // Turn the number to hex, remeber guys, (65537= 10001(hex))
                    int keyObfuscatorTypeIndex = abc.Constants.IndexOfMultiname("KeyObfuscator");

                    // Replace the first 'GetLex[KeyObfuscator]' operation with 'PushString[modulus]'.
                    ReplaceNextOperation(inCode, outCode, method,
                                         OPCode.GetLex, new object[] { keyObfuscatorTypeIndex },
                                         OPCode.PushString, new object[] { modulusStringIndex });

                    // Ignore these operations, do not write.
                    inCode.ReadValuesUntil(OPCode.CallProperty);

                    // Replace the second 'GetLex[KeyObfuscator]' operation with 'PushString[exponent]'.
                    ReplaceNextOperation(inCode, outCode, method,
                                         OPCode.GetLex, new object[] { keyObfuscatorTypeIndex },
                                         OPCode.PushString, new object[] { exponentStringIndex });

                    // Ignore these operations, do not write.
                    inCode.ReadValuesUntil(OPCode.CallProperty);

                    CopyBytecode(inCode, outCode);
                    method.Body.Bytecode = outCode.ToArray();
                }
        }
Пример #2
0
        /// <summary>
        /// Returns the hardcoded client revision string from the Outgoing[4000] message class.
        /// </summary>
        /// <returns></returns>
        public string GetClientRevision()
        {
            if (!string.IsNullOrWhiteSpace(_clientRevision))
            {
                return(_clientRevision);
            }

            if (!(OutgoingMessages?.ContainsKey(4000) ?? false))
            {
                return(string.Empty);
            }

            ASInstance outgoingInstance = OutgoingMessages[4000].Instance;
            ASMethod   method           = outgoingInstance.FindFirstMethod(null, "Array");

            if (method == null)
            {
                return(string.Empty);
            }

            using (var inCode = new FlashReader(method.Body.Bytecode))
            {
                object[] values          = inCode.ReadValuesUntil(OPCode.PushString);
                var      pushStringIndex = (int)values[0];

                _clientRevision = method.ABC.Constants.Strings[pushStringIndex];
            }
            return(_clientRevision);
        }
Пример #3
0
 protected bool ContainsOperation(ASMethod method, OPCode operation, params object[] expectedValues)
 {
     using (var inCode = new FlashReader(method.Body.Bytecode))
     {
         while (inCode.IsDataAvailable)
         {
             return(inCode.ReadValuesUntil(
                        operation, expectedValues) != null);
         }
     }
     return(false);
 }
Пример #4
0
        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
        }
Пример #5
0
        /// <summary>
        /// Modifies the bytecode to allow the client to connect to anywhere.
        /// </summary>
        public void BypassRemoteHostCheck()
        {
            ABCFile    abc           = ABCFiles[2];
            ASInstance habboCommMngr = abc.FindFirstInstanceByName("HabboCommunicationManager");

            if (habboCommMngr == null)
            {
                return;
            }

            int    hostValueSlotObjTypeIndex = -1;
            string hostValueSlotObjName      = string.Empty;

            foreach (ASTrait trait in habboCommMngr.Traits)
            {
                if (trait.TraitType != TraitType.Slot)
                {
                    continue;
                }
                if (((SlotConstantTrait)trait.Data).TypeName.Name != "String")
                {
                    continue;
                }

                hostValueSlotObjName      = trait.Name.Name;
                hostValueSlotObjTypeIndex = trait.NameIndex;
                break;
            }

            ASMethod initCompMethod = habboCommMngr
                                      .FindFirstMethod("initComponent", "void");

            int getPropertyObjTypeIndex = abc.Constants
                                          .IndexOfMultiname("getProperty");

            ASMethod initConnectionMethod = null;

            using (var outCode = new FlashWriter())
                using (var inCode = new FlashReader(initCompMethod.Body.Bytecode))
                {
                    object[] values = inCode.ReadValuesUntil(OPCode.CallPropVoid, null, 0);

                    if (values == null)
                    {
                        return;
                    }
                    CopyBytecode(inCode, outCode, 0, inCode.Position);

                    outCode.WriteOP(OPCode.GetLocal_0);
                    outCode.WriteOP(OPCode.FindPropStrict, getPropertyObjTypeIndex);
                    outCode.WriteOP(OPCode.PushString, abc.Constants.AddString("connection.info.host"));
                    outCode.WriteOP(OPCode.CallProperty, getPropertyObjTypeIndex, 1);
                    outCode.WriteOP(OPCode.InitProperty, hostValueSlotObjTypeIndex);
                    WriteLog($"Method '{initCompMethod}' modified to include '{hostValueSlotObjName} = getProperty(\"connection.info.host\");'.");

                    CopyBytecode(inCode, outCode);
                    initCompMethod.Body.Bytecode = outCode.ToArray();

                    values = inCode.ReadValuesUntil(OPCode.CallPropVoid);
                    ASMultiname callPropVoidType = abc.Constants.Multinames[(int)values[0]];
                    initConnectionMethod = habboCommMngr.FindFirstMethod(callPropVoidType.Name, "void");
                }

            using (var outCode = new FlashWriter())
                using (var inCode = new FlashReader(initConnectionMethod.Body.Bytecode))
                {
                    int  ifNeCount          = 0;
                    int  byteJumpCountPos   = 0;
                    int  differenceOffset   = 0;
                    uint byteJumpCountValue = 0;
                    int  magicNumberIndex   = abc.Constants.AddInteger(65290);
                    while (inCode.IsDataAvailable)
                    {
                        OPCode   op     = inCode.ReadOP();
                        object[] values = null;

                        if (op != OPCode.PushInt)
                        {
                            values = inCode.ReadValues(op);
                            outCode.WriteOP(op, values);

                            if (op == OPCode.IfNe &&
                                (++ifNeCount == 2 || ifNeCount == 4))
                            {
                                byteJumpCountPos   = (outCode.Position - 3);
                                byteJumpCountValue = (uint)values[0];
                            }
                            continue;
                        }

                        bool isFinalPushInt = false;
                        int  pushIntIndex   = inCode.Read7BitEncodedInt();
                        int  pushIntValue   = abc.Constants.Integers[pushIntIndex];
                        #region Switch: pushIntValue
                        switch (pushIntValue)
                        {
                        case 65244: //97
                        case 65185: //32
                        case 65191: //175
                        case 65189: //123
                        case 65188: //164
                        case 65174: //45
                        case 65238: //297
                        case 65184: //127
                        case 65171: //20
                        case 65172: //58
                        {
                            pushIntIndex   = magicNumberIndex;
                            isFinalPushInt = (pushIntValue == 65172);
                            break;
                        }
                        }
                        #endregion
                        outCode.WriteOP(op, pushIntIndex);

                        int byteDifference = (((inCode.Position - outCode.Length) * -1) - differenceOffset);
                        if (isFinalPushInt)
                        {
                            int curPos = outCode.Position;
                            differenceOffset += byteDifference;

                            outCode.Position = byteJumpCountPos;
                            outCode.WriteS24(byteJumpCountValue + (uint)byteDifference);
                            outCode.Position = curPos;

                            if (ifNeCount == 4)
                            {
                                CopyBytecode(inCode, outCode);
                                initConnectionMethod.Body.Bytecode = outCode.ToArray();
                                WriteLog($"Method '{initConnectionMethod}' modified to not append suffix to the host value.");
                                return;
                            }
                        }
                    }
                }
        }