/// <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 void FindMessageReferences() { ABCFile abc = ABCFiles[2]; WriteLog($"Searching {abc.Methods.Count:n0} methods for references to Outgoing({OutgoingMessages.Count})/Incoming({IncomingMessages.Count}) messages..."); foreach (ASClass asClass in abc.Classes) { ASInstance asInstance = asClass.Instance; if (asInstance.Flags.HasFlag(ClassFlags.Interface)) { continue; } int referencesFound = 0; referencesFound += FindMessageReferences(asClass, asClass, asClass.Constructor, -1, 0); referencesFound += FindMessageReferences(asClass, asClass.Instance, asClass.Instance.Constructor, -2, 0); referencesFound += FindMessageReferences(asClass, asClass); referencesFound += FindMessageReferences(asClass, asClass.Instance); } // What to do with the total message reference count in a class? int usedOutMsgs = _messageReferences.Count(msgClass => _isMessageOutgoing[msgClass.Key]); int unusedOutMsgs = (OutgoingMessages.Count - usedOutMsgs); int usedInMsgs = (_messageReferences.Count - usedOutMsgs); int unusedInMsgs = (IncomingMessages.Count - usedInMsgs); WriteLog($@"Outgoing/Incoming message reference search complete. Unused Outgoing messages: {unusedOutMsgs}/{OutgoingMessages.Count} Unused Incoming messages: {unusedInMsgs}/{IncomingMessages.Count}"); }
static string DumpMessages(string type, IDictionary <ushort, ASClass> messages) { string headerDump = string.Empty; bool isOutgoing = (type == "Outgoing"); IList <Tuple <ushort, string, ASInstance> > organizedMessages = OrganizeByHash(messages, Client, isOutgoing); foreach (Tuple <ushort, string, ASInstance> organizedMessage in organizedMessages) { ushort header = organizedMessage.Item1; string hash = organizedMessage.Item2; ASInstance instance = organizedMessage.Item3; string ctorSignature = instance.Constructor.ToString(); if (!isOutgoing) { ASClass parserClass = Client.GetIncomingParser(instance); ctorSignature += (", Parser: " + parserClass.Instance.Type.ObjName); } headerDump += $"{type}[{header}]({hash}): {instance.Type.ObjName}{ctorSignature}\r\n"; CountDuplicates(isOutgoing, hash); } return(headerDump.Trim()); }
/// <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(); } }
public string ExtractPacketLog(HMessage packet, bool toServer) { ASInstance messageInstance = (toServer ? MainUI.ConnectionPg.Game.OutgoingTypes : MainUI.ConnectionPg.Game.IncomingTypes)[packet.Header].Instance; string arrow = (toServer ? "->" : "<-"); string type = (toServer ? "Outgoing" : "Incoming"); return($"{type}({packet.Header}, {packet.Length}, {messageInstance.Type.ObjName}) {arrow} {packet}"); }
private ASClass GetMessageParser() { ABCFile abc = Class.GetABC(); ASInstance instance = Class.Instance; ASInstance superInstance = abc.GetInstance(instance.Super); if (superInstance == null) { superInstance = 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 = null; if (instruction.OP == OPCode.FindPropStrict) { var findPropStrictIns = (FindPropStrictIns)instruction; multiname = findPropStrictIns.PropertyName; } else if (instruction.OP == OPCode.GetLex) { var 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); }
public string ExtractStructureLog(HMessage packet, bool toServer) { if (!toServer || _invalidStructures[packet.Destination] .Contains(packet.Header)) { return(string.Empty); } ASInstance messageInstance = (toServer ? MainUI.ConnectionPg.Game.OutgoingTypes : MainUI.ConnectionPg.Game.IncomingTypes)[packet.Header].Instance; string arguments = $"{{l}}{{u:{packet.Header}}}"; ASMethod messageCtor = messageInstance.Constructor; foreach (ASParameter param in messageCtor.Parameters) { try { arguments += "{"; switch (param.Type.ObjName.ToLower()) { default: return(string.Empty); case "string": arguments += "s:" + packet.ReadString(); break; case "int": arguments += "i:" + packet.ReadInteger(); break; case "boolean": arguments += "b:" + packet.ReadBoolean(); break; } arguments += "}"; } catch { _invalidStructures[packet.Destination] .Add(packet.Header); } } if (packet.Readable != 0) { arguments = string.Empty; } packet.Position = 0; return(arguments); }
protected void ScanForMessageReferences(ABCFile abc) { if (!FindMessageInstances()) { return; } if (_messageReferencesCache.Count > 0) { return; } var messageClasses = new Dictionary <string, ASClass>( OutgoingTypes.Count + IncomingTypes.Count); foreach (ASClass outClass in OutgoingTypes.Values) { messageClasses.Add( outClass.Instance.Type.ObjName, outClass); } foreach (ASClass inClass in IncomingTypes.Values) { messageClasses.Add( inClass.Instance.Type.ObjName, inClass); } foreach (ASClass asClass in abc.Classes) { ASInstance asInstance = asClass.Instance; if (asInstance.ClassInfo.HasFlag(ClassFlags.Interface)) { continue; } ScanForMessageReference(messageClasses, asClass, asClass.Constructor, 0); ScanForMessageReference(messageClasses, asClass, asClass.Instance.Constructor, 0); if (asInstance.Traits.Count < 1) { continue; } for (int i = 0; i < asInstance.Traits.Count; i++) { ASTrait trait = asInstance.Traits[i]; if (trait.TraitType != TraitType.Method) { continue; } var mgsTrait = (MethodGetterSetterTrait)trait.Data; ScanForMessageReference(messageClasses, asClass, mgsTrait.Method, i); } } }
private void WriteMessage(StreamWriter output, MessageItem message) { ASInstance instance = message.Class.Instance; string name = instance.QName.Name; string constructorSig = instance.Constructor.ToAS3(true); output.Write($"[{message.Id}, {message.Hash}] = {name}{constructorSig}"); if (!message.IsOutgoing && message.Parser != null) { output.Write($"[Parser: {message.Parser.Instance.QName.Name}]"); } output.WriteLine(); }
protected ASMethod FindVerifyMethod(ASInstance instance, ABCFile abc, out int rsaStart) { List <MethodGetterSetterTrait> methodTraits = instance.FindTraits <MethodGetterSetterTrait>(TraitType.Method); rsaStart = -1; foreach (MethodGetterSetterTrait mgsTrait in methodTraits) { ASMethod method = mgsTrait.Method; if (method.ReturnType.ObjName != "void") { continue; } if (method.Parameters.Count != 1) { continue; } using (var code = new FlashReader(method.Body.Bytecode)) { while (code.Position != code.Length) { OPCode op = code.ReadOP(); if (op != OPCode.GetLex) { continue; } int typeIndex = code.Read7BitEncodedInt(); ASMultiname type = abc.Constants.Multinames[typeIndex]; if (type?.ObjName == "RSAKey") { rsaStart = code.Position; return(method); } } } } return(null); }
public bool DisableClientEncryption() { ASInstance rc4 = ABCFiles[2].FindInstanceByName("ArcFour"); if (rc4 == null) { ABCFiles[2].FindInstanceByName("RC4"); } if (rc4 == null) { return(false); } int modifyCount = 0; foreach (ASTrait trait in rc4.Traits) { if (trait.TraitType != TraitType.Method) { continue; } var rc4Method = ((MethodGetterSetterTrait)trait.Data).Method; if (rc4Method.ReturnType.ObjName != "ByteArray") { continue; } if (rc4Method.Parameters.Count != 1) { continue; } if (rc4Method.Parameters[0].Type.ObjName != "ByteArray") { continue; } modifyCount++; InsertEarlyReturnLocal(rc4Method, 1); } return(modifyCount >= 2); }
public bool DisableExpirationDateCheck() { ABCFile abc = ABCFiles[2]; ASInstance windowContext = abc.FindInstanceByName("WindowContext"); if (windowContext == null) { return(false); } using (var inCode = new FlashReader(windowContext.Constructor.Body.Bytecode)) using (var outCode = new FlashWriter()) { int setLocal11Itterations = 0; while (inCode.Position != inCode.Length) { OPCode op = inCode.ReadOP(); outCode.WriteOP(op); if (op != OPCode.SetLocal) { continue; } int setLocalIndex = inCode.Read7BitEncodedInt(); outCode.Write7BitEncodedInt(setLocalIndex); if (setLocalIndex != 11 || (++setLocal11Itterations != 2)) { continue; } outCode.WriteOP(OPCode.ReturnVoid); outCode.Write(inCode.ToArray(), inCode.Position, inCode.Length - inCode.Position); windowContext.Constructor.Body.Bytecode = outCode.ToArray(); return(true); } } return(false); }
private string 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); } string structure = null; 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: { var callProperty = (CallPropertyIns)next; if (callProperty.ArgCount > 0) { ASMultiname propertyName = null; ASInstruction previous = code[i - 2]; switch (previous.OP) { case OPCode.GetLex: { var getLex = (GetLexIns)previous; propertyName = getLex.TypeName; break; } case OPCode.ConstructProp: { var 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); } string innerStructure = GetIncomingStructure(innerInstance, innerMethod); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; } else { if (!TryGetStructurePiece(callProperty.PropertyName, null, out char piece)) { return(null); } structure += piece; } break; } case OPCode.ConstructProp: { var constructProp = (ConstructPropIns)next; ASInstance innerInstance = abc.GetInstance(constructProp.PropertyName); string innerStructure = GetIncomingStructure(innerInstance, innerInstance.Constructor); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.ConstructSuper: { ASInstance superInstance = abc.GetInstance(instance.Super); string innerStructure = GetIncomingStructure(superInstance, superInstance.Constructor); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.CallSuper: { var callSuper = (CallSuperIns)next; ASInstance superInstance = abc.GetInstance(instance.Super); ASMethod superMethod = superInstance.GetMethod(callSuper.MethodName.Name, null, callSuper.ArgCount); string innerStructure = GetIncomingStructure(superInstance, superMethod); if (string.IsNullOrWhiteSpace(innerStructure)) { return(null); } structure += innerStructure; break; } case OPCode.CallPropVoid: { var callPropVoid = (CallPropVoidIns)next; if (callPropVoid.ArgCount != 0) { return(null); } if (!TryGetStructurePiece(callPropVoid.PropertyName, null, out char piece)) { return(null); } structure += piece; break; } default: return(null); } } return(structure); }
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); } }
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++; } } }
/// <summary> /// Returns the Incoming message's parser class. /// </summary> /// <param name="messageClass">The Incoming message class to extract the parser class from.</param> /// <returns></returns> public ASClass GetIncomingMessageParser(ASClass messageClass) { if (_messageParsers.ContainsKey(messageClass)) { return(_messageParsers[messageClass]); } ABCFile abc = messageClass.ABC; ASClass incomingMsgParserClass = null; ASInstance incomingMsgInstance = messageClass.Instance; try { ASInstance incomingMsgSuperInstance = abc.FindFirstInstanceByName( incomingMsgInstance.SuperType.Name); ASMultiname parserReturnType = incomingMsgSuperInstance .FindFirstGetter("parser", null).ReturnType; List <ASMethod> methods = incomingMsgInstance.FindMethodGetterSetterTraits() .Select(mgsTrait => mgsTrait.Method).ToList(); methods.Add(incomingMsgInstance.Constructor); foreach (ASMethod method in methods) { var referencedClasses = new List <ASClass>(); using (var inCode = new FlashReader(method.Body.Bytecode)) { while (inCode.IsDataAvailable) { OPCode op = 0; object[] values = inCode.ReadValuesUntilEither(out op, OPCode.FindPropStrict, OPCode.GetLex); if (values == null) { break; } var typeIndex = (int)values[0]; ASMultiname type = abc.Constants.Multinames[typeIndex]; List <ASClass> instances = abc.FindClassesByName(type.Name); referencedClasses.AddRange(instances); } } foreach (ASClass referencedClass in referencedClasses) { ASInstance referencedInstance = referencedClass.Instance; if (referencedInstance.ContainsInterface(parserReturnType.Name)) { incomingMsgParserClass = referencedClass; return(incomingMsgParserClass); } } } } finally { if (incomingMsgParserClass != null) { _messageParsers[messageClass] = incomingMsgParserClass; } } return(incomingMsgParserClass); }
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()); }
/// <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; } } } } }
public ASClass GetIncomingParser(ASInstance incomingInstance) { if (_incomingParsersCache.ContainsKey(incomingInstance)) { return(_incomingParsersCache[incomingInstance]); } ASClass parserClass = null; ABCFile abc = incomingInstance.ABC; try { using (var codeOut = new FlashReader( incomingInstance.Constructor.Body.Bytecode)) { while (codeOut.IsDataAvailable) { OPCode op = codeOut.ReadOP(); object[] values = codeOut.ReadValues(op); if (op != OPCode.GetLex) { continue; } var getLexIndex = (int)values[0]; ASMultiname getLexName = abc.Constants.Multinames[getLexIndex]; parserClass = abc.FindClassByName(getLexName.ObjName); if (parserClass != null) { return(parserClass); } break; } } ASInstance incomingSuperInstance = abc.FindInstanceByName( incomingInstance.SuperType.ObjName); ASMultiname parserReturnType = incomingSuperInstance .FindGetter("parser").Method.ReturnType; SlotConstantTrait parserSlot = incomingSuperInstance .FindSlot("*", parserReturnType.ObjName); foreach (ASTrait trait in incomingInstance.Traits) { if (trait.TraitType != TraitType.Method) { continue; } var mgsTrait = (MethodGetterSetterTrait)trait.Data; if (mgsTrait.Method.Parameters.Count != 0) { continue; } using (var codeOut = new FlashReader( mgsTrait.Method.Body.Bytecode)) { while (codeOut.IsDataAvailable) { OPCode op = codeOut.ReadOP(); object[] values = codeOut.ReadValues(op); if (op != OPCode.GetLex) { continue; } var getLexIndex = (int)values[0]; ASMultiname getLexType = abc.Constants.Multinames[getLexIndex]; if (getLexType.ObjName != parserSlot.ObjName) { continue; } parserClass = abc.FindClassByName(mgsTrait.Method.ReturnType.ObjName); if (parserClass != null) { return(parserClass); } break; } } } return(parserClass); } finally { if (parserClass != null) { _incomingParsersCache[incomingInstance] = parserClass; } } }
public bool BypassRemoteHostCheck() { ABCFile abc = ABCFiles[2]; ASInstance commManager = abc.FindInstanceByName("HabboCommunicationManager"); if (commManager == null) { return(false); } // The "host" value is always the first slot, for now. string hostValueSlotName = commManager.FindTraits <SlotConstantTrait>(TraitType.Slot) .Where(t => t.Type.ObjName == "String").ToArray()[0].ObjName; ASMethod initComponent = commManager.FindMethod("initComponent", "void").Method; if (initComponent == null) { return(false); } using (var inCode = new FlashReader(initComponent.Body.Bytecode)) using (var outCode = new FlashWriter(inCode.Length)) { int hostSlotIndex = abc.Constants.IndexOfMultiname(hostValueSlotName); while (inCode.Position != inCode.Length) { OPCode op = inCode.ReadOP(); outCode.WriteOP(op); if (op != OPCode.GetLocal_0) { continue; } op = inCode.ReadOP(); outCode.WriteOP(op); if (op != OPCode.CallPropVoid) { continue; } int callPropVoidIndex = inCode.Read7BitEncodedInt(); outCode.Write7BitEncodedInt(callPropVoidIndex); int callPropVoidArgCount = inCode.Read7BitEncodedInt(); outCode.Write7BitEncodedInt(callPropVoidArgCount); if (callPropVoidArgCount != 0) { continue; } int getPropertyNameIndex = abc.Constants .IndexOfMultiname("getProperty"); outCode.WriteOP(OPCode.GetLocal_0); outCode.WriteOP(OPCode.FindPropStrict); outCode.Write7BitEncodedInt(getPropertyNameIndex); outCode.WriteOP(OPCode.PushString); outCode.Write7BitEncodedInt(abc.Constants.AddString("connection.info.host")); outCode.WriteOP(OPCode.CallProperty); outCode.Write7BitEncodedInt(getPropertyNameIndex); outCode.Write7BitEncodedInt(1); outCode.WriteOP(OPCode.InitProperty); outCode.Write7BitEncodedInt(hostSlotIndex); outCode.Write(inCode.ToArray(), inCode.Position, inCode.Length - inCode.Position); do { op = inCode.ReadOP(); }while (op != OPCode.CallPropVoid); callPropVoidIndex = inCode.Read7BitEncodedInt(); ASMultiname callPropVoidName = abc.Constants.Multinames[callPropVoidIndex]; ASMethod connectMethod = commManager.FindMethod(callPropVoidName.ObjName, "void").Method; RemoveHostSuffix(abc, connectMethod); initComponent.Body.Bytecode = outCode.ToArray(); return(true); } } return(false); }
public bool ReplaceRSA(int exponent, string modulus) { ABCFile abc = ABCFiles[2]; int modulusIndex = abc.Constants.AddString(modulus); int exponentIndex = abc.Constants .AddString(exponent.ToString("x")); int rsaStart = 0; ASInstance commClass = abc.FindInstanceByName("HabboCommunicationDemo"); ASMethod verifier = FindVerifyMethod(commClass, abc, out rsaStart); using (var inCode = new FlashReader(verifier.Body.Bytecode)) using (var outCode = new FlashWriter(inCode.Length)) { bool searchingKeys = true; inCode.Position = rsaStart; outCode.Write(inCode.ToArray(), 0, rsaStart); while (inCode.Position != inCode.Length) { byte codeByte = inCode.ReadByte(); outCode.Write(codeByte); if (!searchingKeys) { outCode.Write(inCode.ToArray(), inCode.Position, inCode.Length - inCode.Position); break; } switch ((OPCode)codeByte) { case OPCode.GetLex: { outCode.Position--; outCode.WriteOP(OPCode.PushString); int typeIndex = inCode.Read7BitEncodedInt(); ASMultiname type = abc.Constants.Multinames[typeIndex]; inCode.ReadOP(); inCode.Read7BitEncodedInt(); inCode.Read7BitEncodedInt(); if (modulusIndex > 0) { outCode.Write7BitEncodedInt(modulusIndex); modulusIndex = -1; } else if (searchingKeys) { outCode.Write7BitEncodedInt(exponentIndex); searchingKeys = false; } break; } case OPCode.PushString: { int stringIndex = inCode.Read7BitEncodedInt(); string value = abc.Constants.Strings[stringIndex]; if (string.IsNullOrWhiteSpace(Modulus)) { Modulus = value; outCode.Write7BitEncodedInt(modulusIndex); } else if (string.IsNullOrWhiteSpace(Exponent)) { Exponent = value; outCode.Write7BitEncodedInt(exponentIndex); searchingKeys = false; } break; } default: continue; } } verifier.Body.Bytecode = outCode.ToArray(); if (!searchingKeys) { return(true); } } return(false); }