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 string GetOutgoingStructure(ASCode code, Local getLocal) { string structure = null; for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction == getLocal) { break; } if (!Local.IsGetLocal(instruction.OP)) { continue; } var 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; } var callPropVoid = (CallPropVoidIns)next; if (callPropVoid.PropertyName.Name != "push") { continue; } ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetProperty) { ASClass classToCheck = Class; var getProperty = (GetPropertyIns)previous; ASMultiname propertyName = getProperty.PropertyName; ASInstruction beforeGetProp = code[i - 2]; if (beforeGetProp.OP == OPCode.GetLex) { var getLex = (GetLexIns)beforeGetProp; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetStructurePiece(propertyName, classToCheck, out char piece)) { return(null); } structure += piece; } } } return(structure); }
private ASMultiname GetTraitType(ASContainer container, ASMultiname traitName) { if (container == null) { return(traitName); } return(container.GetTraits(TraitKind.Slot, TraitKind.Constant, TraitKind.Getter) .FirstOrDefault(t => t.QName == traitName)?.Type); }
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); }
protected void ResolveMultiname(ASMachine machine, ASMultiname multiname) { if (multiname.IsNameNeeded) { object name = machine.Values.Pop(); } if (multiname.IsNamespaceNeeded) { object @namespace = machine.Values.Pop(); } }
protected int ResolveMultinamePops(ASMultiname multiname) { int popCount = 0; if (multiname.IsNameNeeded) { popCount++; } if (multiname.IsNamespaceNeeded) { popCount++; } return(popCount); }
public void Write(ASMultiname multiname) { if (multiname?.Kind == MultinameKind.TypeName) { Write(multiname.QName); Write(multiname.TypeIndices.Count); foreach (ASMultiname type in multiname.GetTypes()) { Write(type); } } else if (multiname == null || HGame.IsValidIdentifier(multiname.Name, true)) { Write(multiname?.Name ?? "*"); } }
protected virtual void WriteMultinameHashData(BinaryWriter hashInput, ASMultiname asMultiname) { hashInput.Write((byte)asMultiname.MultinameType); switch (asMultiname.ObjName) { case "int": case "Class": case "Array": case "String": case "Boolean": case "Function": { hashInput.Write(asMultiname.ObjName); break; } } }
private bool TryGetStructurePiece(ASMultiname multiname, ASClass @class, out char piece) { ASMultiname returnValueType = multiname; if (@class != null) { returnValueType = GetTraitType(@class, multiname) ?? GetTraitType(@class.Instance, multiname); } switch (returnValueType.Name.ToLower()) { case "int": case "readint": case "gettimer": piece = 'i'; break; case "byte": case "readbyte": piece = 'b'; break; case "double": case "readdouble": piece = 'd'; break; case "string": case "readstring": piece = 's'; break; case "boolean": case "readboolean": piece = 'B'; break; case "array": piece = char.MinValue; break; default: { if (!IsOutgoing && !HGame.IsValidIdentifier(returnValueType.Name, true)) { piece = 'i'; // This reference call is most likely towards 'readInt' } else { piece = char.MinValue; } break; } } return(piece != char.MinValue); }
private bool TryGetPacketValue(ASMultiname multiname, ASClass @class, out PacketValue value) { ASMultiname returnValueType = multiname; if (@class != null) { returnValueType = GetTraitType(@class, multiname) ?? GetTraitType(@class.Instance, multiname); } switch (returnValueType.Name.ToLower()) { case "int": case "readint": case "gettimer": value = PacketValue.Integer; break; case "byte": case "readbyte": value = PacketValue.Byte; break; case "double": case "readdouble": value = PacketValue.Double; break; case "string": case "readstring": value = PacketValue.String; break; case "boolean": case "readboolean": value = PacketValue.Boolean; break; case "array": value = PacketValue.Unknown; break; default: { if (!IsOutgoing && !HGame.IsValidIdentifier(returnValueType.Name, true)) { value = PacketValue.Integer; // This reference call is most likely towards 'readInt' } else { value = PacketValue.Unknown; } break; } } return(value != PacketValue.Unknown); }
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); }
/// <summary> /// Modifies the "ClientHelloMessageComposer" (Packet 4000) class /// to send the current environment instead of the protocol revision. /// </summary> public void PatchClientHelloMessageComposer() { var abc = _flash.AbcGame; // Grab ClientHelloMessageComposer. var composerClass = MessagesOutgoing[4000].Clazz; // Find CommunicationUtils. var communicationUtilsClass = _lookup.Get(HabboClass.CommunicationUtils); var communicationUtilsMethod = communicationUtilsClass.Traits .AsParallel() .FirstOrDefault(x => x.IsStatic && x.Kind == TraitKind.Method && x.Method.Parameters.Count == 2 && x.Method.Parameters[1].IsOptional && x.Method.ReturnType.Name.Equals("String")); if (communicationUtilsMethod == null) { throw new ApplicationException("Unable to find communicationUtilsMethod."); } // Find com.sulake.habbo.communication.demo:IncomingMessages. var incomingMessagesClass = _lookup.Get(HabboClass.IncomingMessages); var incomingMessagesMethod = incomingMessagesClass.Instance.Traits .AsParallel() .Where(x => x.Kind == TraitKind.Method && x.Method.Parameters.Count == 1 && x.Method.Parameters[0].Type.Name.Equals("Event") && x.Method.Parameters[0].IsOptional && x.Method.ReturnType.Name.Equals("void")) .Select(x => x.Method) .FirstOrDefault(); if (incomingMessagesMethod == null) { throw new ApplicationException("Unable to find incomingMessagesMethod."); } var incomingMessagesCode = incomingMessagesMethod.Body.ParseCode(); // Modify the method of IncomingMessages. var constructComposer = incomingMessagesCode .Where(x => x.OP == OPCode.ConstructProp && ((ConstructPropIns)x).PropertyName.NameIndex == composerClass.QName.NameIndex) .Cast <ConstructPropIns>() .First(); // IncomingMessages: Add an argument when constructing the message. constructComposer.ArgCount = 1; // IncomingMessages: Add the argument value. incomingMessagesCode.InsertRange(incomingMessagesCode.IndexOf(constructComposer), new ASInstruction[] { new GetLexIns(abc, abc.Pool.Multinames.IndexOf(communicationUtilsClass.QName)), new PushStringIns(abc, "environment"), new CallPropertyIns(abc, communicationUtilsMethod.QNameIndex, 1), new CoerceSIns() }); // IncomingMessages: Increase stack. incomingMessagesMethod.Body.MaxStack += 4; incomingMessagesMethod.Body.Code = incomingMessagesCode.ToArray(); // Modify the constructor of ClientHelloMessageComposer. var composerConstructor = composerClass.Instance.Constructor; var composerCode = composerConstructor.Body.ParseCode(); // ClientHelloMessageComposer: Add "String" parameter. composerConstructor.Parameters.Add(new ASParameter(abc.Pool, composerConstructor) { TypeIndex = abc.Pool.GetMultinameIndex("String") }); // ClientHelloMessageComposer: Add "environmentId" variable. var composerSlotQName = new ASMultiname(abc.Pool) { NameIndex = abc.Pool.AddConstant("environmentId"), Kind = MultinameKind.QName, NamespaceIndex = 1 }; var composerSlot = new ASTrait(abc) { Kind = TraitKind.Slot, QNameIndex = abc.Pool.AddConstant(composerSlotQName), TypeIndex = abc.Pool.GetMultinameIndex("String") }; composerClass.Instance.Traits.Add(composerSlot); // ClientHelloMessageComposer: Set parameter of constructor to "environmentId". composerCode.InsertRange(composerCode.Count - 1, new ASInstruction[] { new GetLocal1Ins(), new FindPropertyIns(abc, composerSlot.QNameIndex), new SwapIns(), new SetPropertyIns(abc, composerSlot.QNameIndex), }); composerConstructor.Body.LocalCount = 2; composerConstructor.Body.MaxStack = 2; composerConstructor.Body.Code = composerCode.ToArray(); // Modify the method that returns packet as array. var getArrayMethod = composerClass.Instance.Traits .AsParallel() .First(x => x.Kind == TraitKind.Method && x.Method.Parameters.Count == 0 && x.Method.ReturnType.Name.Equals("Array")); var getArrayCode = getArrayMethod.Method.Body.ParseCode(); // getArray: Remove everything until constructing array. getArrayCode.Clear(); getArrayCode.AddRange(new ASInstruction[] { new GetLocal0Ins(), new PushScopeIns(), new PushStringIns(abc, Revision), new PushStringIns(abc, RevisionProtocol), new PushIntIns(abc, 3), // Android. new PushIntIns(abc, 1), new GetLexIns(abc, composerSlot.QNameIndex), new NewArrayIns(5), new ReturnValueIns(), }); // getArray: Apply patch. getArrayMethod.Method.Body.MaxStack = 5; getArrayMethod.Method.Body.LocalCount = 1; getArrayMethod.Method.Body.Code = getArrayCode.ToArray(); // ClientHelloMessageComposer: Clean class. composerClass.Instance.Traits.Remove(composerClass.Instance.Traits.First(x => x.Kind == TraitKind.Slot && x.QNameIndex != composerSlot.QNameIndex)); }
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 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 FindMessageInstances() { if (OutgoingTypes.Count > 0 && IncomingTypes.Count > 0) { return(true); } ABCFile abc = ABCFiles[2]; ASClass habboMessages = abc.FindClassByName("HabboMessages"); if (habboMessages == null || habboMessages.Traits.Count < 2) { return(false); } ASTrait incomingMap = habboMessages.Traits[0]; ASTrait outgoingMap = habboMessages.Traits[1]; using (var mapReader = new FlashReader( habboMessages.Constructor.Body.Bytecode.ToArray())) { while (mapReader.Position != mapReader.Length) { OPCode op = mapReader.ReadOP(); if (op != OPCode.GetLex) { continue; } int mapTypeIndex = mapReader.Read7BitEncodedInt(); bool isOutgoing = (mapTypeIndex == outgoingMap.TypeIndex); bool isIncoming = (mapTypeIndex == incomingMap.TypeIndex); if (!isOutgoing && !isIncoming) { continue; } op = mapReader.ReadOP(); if (op != OPCode.PushShort && op != OPCode.PushByte) { continue; } ushort header = 0; if (op == OPCode.PushByte) { header = mapReader.ReadByte(); } else { header = (ushort)mapReader.Read7BitEncodedInt(); } op = mapReader.ReadOP(); if (op != OPCode.GetLex) { continue; } int messageTypeIndex = mapReader.Read7BitEncodedInt(); ASMultiname messageType = abc.Constants.Multinames[messageTypeIndex]; ASClass messageInstance = abc.FindClassByName(messageType.ObjName); if (isOutgoing) { OutgoingTypes[header] = messageInstance; } else if (isIncoming) { IncomingTypes[header] = messageInstance; } } } return(OutgoingTypes.Count > 0 && IncomingTypes.Count > 0); }
protected void ScanForMessageReference(Dictionary <string, ASClass> messageClasses, ASClass asClass, ASMethod method, int traitIndex, int messageRefCount = 0) { ABCFile abc = asClass.ABC; ASClass messageClass = null; using (var outCode = new FlashReader(method.Body.Bytecode)) { while (outCode.IsDataAvailable) { OPCode op = outCode.ReadOP(); object[] values = outCode.ReadValues(op); switch (op) { case OPCode.NewFunction: { var newFuncIndex = (int)values[0]; ASMethod newFuncMethod = abc.Methods[newFuncIndex]; ScanForMessageReference(messageClasses, asClass, newFuncMethod, traitIndex, messageRefCount); break; } case OPCode.ConstructProp: { var constructPropIndex = (int)values[0]; if (messageClass != null) { ASMultiname constructPropType = abc.Constants.Multinames[constructPropIndex]; if (constructPropType.ObjName == messageClass.Instance.Type.ObjName) { if (!_messageReferencesCache.ContainsKey(messageClass)) { _messageReferencesCache[messageClass] = new List <Tuple <ASMethod, int> >(); } _messageReferencesCache[messageClass].Add( new Tuple <ASMethod, int>(method, (traitIndex + (++messageRefCount)))); } messageClass = null; } break; } case OPCode.FindPropStrict: { var findPropStrictIndex = (int)values[0]; string findPropStrictObjName = abc.Constants .Multinames[findPropStrictIndex].ObjName; if (messageClasses.ContainsKey(findPropStrictObjName)) { messageClass = messageClasses[findPropStrictObjName]; // Incoming messages currently not supported. if (IncomingTypes.ContainsValue(messageClass)) { messageClass = null; } } break; } } } } }
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); }
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()); }
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; } } } } }
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); }
/// <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()); }
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); }
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); }