private bool CheckParameters(Il2CppMethodDefinition method, MethodAnalysis context, bool isInstance) { var actualArgs = new List <IAnalysedOperand>(); if (!isInstance) { actualArgs.Add(context.GetOperandInRegister("rcx") ?? context.GetOperandInRegister("xmm0")); } actualArgs.Add(context.GetOperandInRegister("rdx") ?? context.GetOperandInRegister("xmm1")); actualArgs.Add(context.GetOperandInRegister("r8") ?? context.GetOperandInRegister("xmm2")); actualArgs.Add(context.GetOperandInRegister("r9") ?? context.GetOperandInRegister("xmm3")); foreach (var parameterData in method.Parameters !) { if (actualArgs.Count(a => a != null) == 0) { return(false); } var arg = actualArgs.RemoveAndReturn(0); switch (arg) { case ConstantDefinition cons when cons.Type.FullName != parameterData.Type.ToString(): //Constant type mismatch case LocalDefinition local when !Utils.IsManagedTypeAnInstanceOfCppOne(parameterData.Type, local.Type !): //Local type mismatch return(false); } } if (actualArgs.Any(a => a != null && !context.IsEmptyRegArg(a))) { return(false); //Left over args - it's probably not this one } return(true); }
public GlobalMethodRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); MethodData = LibCpp2IlMain.GetMethodDefinitionByGlobalAddress(globalAddress); var(type, genericParams) = Utils.TryLookupTypeDefByName(MethodData !.DeclaringType.FullName); if (type == null) { Console.WriteLine("Failed to lookup managed type for declaring type of " + MethodData.GlobalKey + ", which is " + MethodData.DeclaringType.FullName); return; } ResolvedMethod = type.Methods.FirstOrDefault(m => m.Name == MethodData.Name); if (ResolvedMethod == null) { return; } var destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; var name = ResolvedMethod.Name; ConstantWritten = context.MakeConstant(typeof(MethodDefinition), ResolvedMethod, name, destReg); }
public LoadVirtualFunctionPointerAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { regReadFrom = Utils.GetRegisterNameNew(instruction.MemoryBase); var inReg = context.GetOperandInRegister(regReadFrom); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) { return; } classReadFrom = klass.backingType; var readOffset = instruction.MemoryDisplacement; methodPointerRead = Utils.GetMethodFromReadKlassOffset((int)readOffset); if (methodPointerRead == null) { return; } var regPutInto = Utils.GetRegisterNameNew(instruction.Op0Register); if (regPutInto == "rsp") { //todo how do we handle this kind of instruction - does it even exist? // var stackOffset = Utils.GetOperandMemoryOffset(instruction.Operands[0]); // context.PushToStack(context.MakeConstant(typeof(MethodDefinition), methodPointerRead), stackOffset); } else { destinationConstant = context.MakeConstant(typeof(MethodDefinition), methodPointerRead, reg: regPutInto); } }
public ComparisonAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var r0 = Utils.GetRegisterNameNew(instruction.Op0Register); var r1 = Utils.GetRegisterNameNew(instruction.Op1Register); var ripBasedAddr = instruction.GetRipBasedInstructionMemoryAddress(); if (r0 != "rsp") { ArgumentOne = instruction.Op0Kind == OpKind.Register ? context.GetOperandInRegister(r0) : instruction.Op0Kind.IsImmediate() ? context.MakeConstant(typeof(int), instruction.GetImmediate(0)) : LibCpp2IlMain.GetAnyGlobalByAddress(ripBasedAddr).Offset == ripBasedAddr ? context.MakeConstant(typeof(GlobalIdentifier), LibCpp2IlMain.GetAnyGlobalByAddress(ripBasedAddr)) : context.MakeConstant(typeof(UnknownGlobalAddr), new UnknownGlobalAddr(ripBasedAddr)); } if (r1 != "rsp") { ArgumentTwo = instruction.Op1Kind == OpKind.Register ? context.GetOperandInRegister(r1) : instruction.Op1Kind.IsImmediate() ? context.MakeConstant(typeof(int), instruction.GetImmediate(1)) : LibCpp2IlMain.GetAnyGlobalByAddress(ripBasedAddr).Offset == ripBasedAddr ? context.MakeConstant(typeof(GlobalIdentifier), LibCpp2IlMain.GetAnyGlobalByAddress(ripBasedAddr)) : context.MakeConstant(typeof(UnknownGlobalAddr), new UnknownGlobalAddr(ripBasedAddr)); } }
public RegToRegMoveAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { originalReg = Utils.GetRegisterNameNew(instruction.Op1Register); newReg = Utils.GetRegisterNameNew(instruction.Op0Register); beingMoved = context.GetOperandInRegister(originalReg); context.SetRegContent(newReg, beingMoved); }
public InterfaceOffsetsReadAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var regName = Utils.GetRegisterNameNew(instruction.MemoryBase); var regConstant = context.GetConstantInReg(regName); _loadedFor = (Il2CppClassIdentifier)regConstant.Value; InterfaceOffsets = _loadedFor.backingType.InterfaceOffsets; _destReg = Utils.GetRegisterNameNew(instruction.Op0Register); _destinationConst = context.MakeConstant(typeof(Il2CppInterfaceOffset[]), InterfaceOffsets, reg: _destReg); }
public AllocateInstanceAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var constant = context.GetConstantInReg("rcx"); if (constant == null || constant.Type != typeof(TypeDefinition)) { return; } TypeCreated = (TypeDefinition)constant.Value; LocalReturned = context.MakeLocal(TypeCreated, reg: "rax"); }
public LocateSpecificInterfaceOffsetAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var secondOpName = Utils.GetRegisterNameNew(instruction.Op1Register); var secondOp = context.GetConstantInReg(secondOpName); _interfaceType = (TypeDefinition)secondOp.Value; offsetReads = (InterfaceOffsetsReadAction)context.Actions.Last(a => a is InterfaceOffsetsReadAction); var cppType = SharedState.MonoToCppTypeDefs[_interfaceType]; _matchingInterfaceOffset = offsetReads.InterfaceOffsets.First(i => i.type == cppType); }
public GlobalStringRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); ResolvedString = LibCpp2IlMain.GetLiteralByAddress(globalAddress); if (ResolvedString == null) { return; } var destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; ConstantWritten = context.MakeConstant(typeof(string), ResolvedString, null, destReg); }
public GlobalTypeRefToConstantAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var globalAddress = instruction.GetRipBasedInstructionMemoryAddress(); var typeData = LibCpp2IlMain.GetTypeGlobalByAddress(globalAddress); var(type, genericParams) = Utils.TryLookupTypeDefByName(typeData !.ToString()); ResolvedType = type; if (ResolvedType == null) { return; } _destReg = instruction.Op0Kind == OpKind.Register ? Utils.GetRegisterNameNew(instruction.Op0Register) : null; var name = ResolvedType.Name; ConstantWritten = context.MakeConstant(typeof(TypeDefinition), ResolvedType, name, _destReg); }
public ClassPointerLoadAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { destReg = Utils.GetRegisterNameNew(instruction.Op0Register); if (instruction.Op0Register == Register.RSP) { Console.WriteLine("WARNING: CLASS POINTER LOAD DEST IS STACK."); } var sourceReg = Utils.GetRegisterNameNew(instruction.MemoryBase); var inReg = context.GetOperandInRegister(sourceReg); localCopiedFrom = inReg is LocalDefinition local ? local : inReg is ConstantDefinition cons && cons.Value is NewSafeCastResult result ? result.original : null; if (localCopiedFrom == null) { return; } var cppTypeDef = SharedState.MonoToCppTypeDefs[localCopiedFrom.Type !];
public CallManagedFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var jumpTarget = instruction.NearBranchTarget; var objectMethodBeingCalledOn = context.GetLocalInReg("rcx"); var listOfCallableMethods = LibCpp2IlMain.GetManagedMethodImplementationsAtAddress(jumpTarget); if (listOfCallableMethods == null) { return; } Il2CppMethodDefinition possibleTarget = null; if (objectMethodBeingCalledOn?.Type != null) { //Direct instance methods take priority possibleTarget = listOfCallableMethods.FirstOrDefault(m => !m.IsStatic && Utils.AreManagedAndCppTypesEqual(LibCpp2ILUtils.WrapType(m.DeclaringType !), objectMethodBeingCalledOn.Type) && CheckParameters(m, context, true)); //todo check args and null out if (possibleTarget == null) { //Base class instance methods possibleTarget = listOfCallableMethods.FirstOrDefault(m => !m.IsStatic && Utils.IsManagedTypeAnInstanceOfCppOne(LibCpp2ILUtils.WrapType(m.DeclaringType !), objectMethodBeingCalledOn.Type) && CheckParameters(m, context, true)); } //check args again. } //Check static methods if (possibleTarget == null) { possibleTarget = listOfCallableMethods.FirstOrDefault(m => m.IsStatic && CheckParameters(m, context, false)); } if (possibleTarget != null) { target = SharedState.UnmanagedToManagedMethods[possibleTarget]; return; } // SharedState.MethodsByAddress.TryGetValue(jumpTarget, out target); }
public JumpIfNonZeroOrNonNullAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { jumpTarget = instruction.NearBranchTarget; if (jumpTarget > instruction.NextIP && jumpTarget < context.AbsoluteMethodEnd) { isIfStatement = true; if (!context.IdentifiedIfStatementStarts.Contains(jumpTarget)) { context.IdentifiedIfStatementStarts.Add(jumpTarget); } } associatedCompare = (ComparisonAction)context.Actions.LastOrDefault(a => a is ComparisonAction); if (associatedCompare != null) { nullMode = associatedCompare.ArgumentOne == associatedCompare.ArgumentTwo; } }
public LoadInterfaceMethodDataAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { if (context.GetConstantInReg("rcx") is {} castConstant && castConstant.Value is NewSafeCastResult castResult && context.GetConstantInReg("rdx") is {} interfaceConstant && interfaceConstant.Value is TypeDefinition interfaceType && context.GetConstantInReg("r8") is {} slotConstant && slotConstant.Value is int slot && context.Actions.FirstOrDefault(a => a is LocateSpecificInterfaceOffsetAction) is LocateSpecificInterfaceOffsetAction locator ) { _invokedOn = castResult.original; _interfaceType = interfaceType; _slotNumber = slot; resolvedMethod = SharedState.VirtualMethodsBySlot[(ushort)(locator._matchingInterfaceOffset.offset + _slotNumber)]; _resultConstant = context.MakeConstant(typeof(MethodDefinition), resolvedMethod, reg: "rax"); } }
public CallManagedFunctionInRegAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var regName = Utils.GetRegisterNameNew(instruction.MemoryBase); var operand = context.GetConstantInReg(regName); _targetMethod = (MethodDefinition)operand.Value; if (!_targetMethod.IsStatic) { _instanceCalledOn = context.GetLocalInReg("rcx"); if (_instanceCalledOn == null) { var cons = context.GetConstantInReg("rcx"); if (cons?.Value is NewSafeCastResult castResult) { _instanceCalledOn = castResult.original; } } } }
public CallVirtualMethodAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var inReg = context.GetOperandInRegister(Utils.GetRegisterNameNew(instruction.MemoryBase)); if (!(inReg is ConstantDefinition cons) || !(cons.Value is Il2CppClassIdentifier klass)) { return; } var classReadFrom = klass.backingType; var readOffset = instruction.MemoryDisplacement; Called = Utils.GetMethodFromReadKlassOffset((int)readOffset); if (Called == null) { return; } CalledOn = context.GetLocalInReg("rcx"); }
public SafeCastAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { var inReg = context.GetOperandInRegister("rcx"); castSource = inReg is LocalDefinition local ? local : inReg is ConstantDefinition cons && cons.Value is NewSafeCastResult result ? result.original : null; var destOp = context.GetOperandInRegister("rdx"); if (destOp is ConstantDefinition cons2 && cons2.Type == typeof(TypeDefinition)) { destinationType = (TypeDefinition)cons2.Value; } if (destinationType == null || castSource == null) { return; } _castResult = context.MakeConstant(typeof(NewSafeCastResult), new NewSafeCastResult { castTo = destinationType, original = castSource }, reg: "rax"); }
public ActionAllocateInstance(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public ReturnFromFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public StackToRegCopyAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public ConstantToFieldAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { constantValue = instruction.GetImmediate(1); }
public CallInitMethodAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public LookupNativeFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public BaseAction(MethodAnalysis context, Instruction instruction) { }
public ArrayOffsetToLocalAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public FieldToLocalAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public ClearRegAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { regCleared = Utils.GetRegisterNameNew(instruction.Op0Register); context.ZeroRegister(regCleared); }
public CallNativeMethodFailureAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public InstanceVirtualMethodCallAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }
public ConstantToStackAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) { }