/// <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(); } }
/// <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); }
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); }
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 }
/// <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; } } } } }