diff --git a/Cpp2IL/Analysis/ASMAnalyzer.cs b/Cpp2IL/Analysis/ASMAnalyzer.cs index eaa93cde..a34b2be0 100644 --- a/Cpp2IL/Analysis/ASMAnalyzer.cs +++ b/Cpp2IL/Analysis/ASMAnalyzer.cs @@ -712,6 +712,10 @@ private void CheckForSingleOpInstruction(Instruction instruction) case Mnemonic.Jne: Analysis.Actions.Add(new JumpIfNonZeroOrNonNullAction(Analysis, instruction)); break; + case Mnemonic.Ja: + //Jump if > + Analysis.Actions.Add(new JumpIfGreaterThanAction(Analysis, instruction)); + break; case Mnemonic.Jge: case Mnemonic.Jae: //JNC in Ghidra //Jump if >= @@ -865,6 +869,7 @@ private void CheckForTwoOpInstruction(Instruction instruction) Analysis.Actions.Add(new StaticFieldOffsetToRegAction(Analysis, instruction)); break; case Mnemonic.Mov when type1 == OpKind.Memory && type0 == OpKind.Register && memR != "rip" && instruction.MemoryIndex == Register.None && memOp is LocalDefinition local && local.Type?.IsArray == true: + case Mnemonic.Lea when type1 == OpKind.Memory && type0 == OpKind.Register && memR != "rip" && instruction.MemoryIndex == Register.None && memOp is LocalDefinition local2 && local2.Type?.IsArray == true: //Move reg, [reg+0x10] //Reading a field from an array at a fixed offset if (Il2CppArrayUtils.IsAtLeastFirstItemPtr(instruction.MemoryDisplacement)) diff --git a/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs b/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs index 8ee58499..d8978ffe 100644 --- a/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs +++ b/Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs @@ -132,6 +132,11 @@ public CallManagedFunctionAction(MethodAnalysis context, Instruction instruction if (ManagedMethodBeingCalled?.ReturnType is { } returnType && returnType.FullName != "System.Void") { + if (returnType is GenericParameter gp && _objectMethodBeingCalledOn?.Type != null) + { + returnType = MethodUtils.ResolveGenericParameterType(ManagedMethodBeingCalled, _objectMethodBeingCalledOn.Type, gp); + } + var destReg = Utils.ShouldBeInFloatingPointRegister(returnType) ? "xmm0" : "rax"; _returnedLocal = context.MakeLocal(returnType, reg: destReg); } diff --git a/Cpp2IL/Analysis/Actions/ConstantArrayOffsetToRegAction.cs b/Cpp2IL/Analysis/Actions/ConstantArrayOffsetToRegAction.cs index a75a5213..f3bde6e1 100644 --- a/Cpp2IL/Analysis/Actions/ConstantArrayOffsetToRegAction.cs +++ b/Cpp2IL/Analysis/Actions/ConstantArrayOffsetToRegAction.cs @@ -1,5 +1,6 @@ using Cpp2IL.Analysis.ResultModels; using Iced.Intel; +using Mono.Cecil; namespace Cpp2IL.Analysis.Actions { @@ -24,7 +25,10 @@ public ConstantArrayOffsetToRegAction(MethodAnalysis context, Instruction instru //Regardless of if we have an index local, we can still work out the type of the array and make a local. //Resolve() turns array types into non-array types - _destLocal = context.MakeLocal(_arrayLocal.Type.Resolve(), reg: destinationReg); + + var elementType = _arrayLocal.Type is ArrayType at ? at.ElementType : _arrayLocal.Type.Resolve(); + + _destLocal = context.MakeLocal(elementType, reg: destinationReg); } public override Mono.Cecil.Cil.Instruction[] ToILInstructions() diff --git a/Cpp2IL/Analysis/Actions/JumpIfGreaterThanAction.cs b/Cpp2IL/Analysis/Actions/JumpIfGreaterThanAction.cs new file mode 100644 index 00000000..aa373f04 --- /dev/null +++ b/Cpp2IL/Analysis/Actions/JumpIfGreaterThanAction.cs @@ -0,0 +1,32 @@ +using Cpp2IL.Analysis.ResultModels; +using Iced.Intel; + +namespace Cpp2IL.Analysis.Actions +{ + public class JumpIfGreaterThanAction : ConditionalJumpAction + { + public JumpIfGreaterThanAction(MethodAnalysis context, Instruction instruction) : base(context, instruction) + { + //All handled by base class + } + + public override Mono.Cecil.Cil.Instruction[] ToILInstructions() + { + throw new System.NotImplementedException(); + } + + protected override string GetPseudocodeCondition() + { + //Invert condition, so <=, not > + return $"({GetArgumentOnePseudocodeValue()} <= {GetArgumentTwoPseudocodeValue()})"; + } + + protected override string GetTextSummaryCondition() + { + if (associatedCompare == null) + return "the compare showed that it was greater than"; + + return $"{associatedCompare.ArgumentOne} is greater than {associatedCompare.ArgumentTwo}"; + } + } +} \ No newline at end of file diff --git a/Cpp2IL/Analysis/MethodUtils.cs b/Cpp2IL/Analysis/MethodUtils.cs index ec4c987e..ae510390 100644 --- a/Cpp2IL/Analysis/MethodUtils.cs +++ b/Cpp2IL/Analysis/MethodUtils.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Cpp2IL.Analysis.Actions; @@ -7,7 +6,6 @@ using Iced.Intel; using LibCpp2IL; using LibCpp2IL.Metadata; -using LibCpp2IL.Reflection; using Mono.Cecil; namespace Cpp2IL.Analysis @@ -49,6 +47,9 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con actualArgs.Add(context.GetOperandInRegister("r8") ?? context.GetOperandInRegister("xmm2")); actualArgs.Add(context.GetOperandInRegister("r9") ?? context.GetOperandInRegister("xmm3")); + if (actualArgs.FindLast(a => a is ConstantDefinition {Value: MethodReference ag} && ag.Name == method.Name && ag.DeclaringType == method.DeclaringType) is ConstantDefinition {Value: MethodReference actualGenericMethod}) + method = actualGenericMethod; + var tempArgs = new List(); foreach (var parameterData in method.Parameters!) { @@ -56,10 +57,11 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con var parameterType = parameterData.ParameterType; - if (parameterType is GenericParameter gp && beingCalledOn is GenericInstanceType git) + if (parameterType is GenericParameter gp) { - var genericIdx = git.ElementType.GenericParameters.ToList().FindIndex(g => g.Name == gp.FullName); - parameterType = git.GenericArguments[genericIdx]; + var temp = ResolveGenericParameterType(method, beingCalledOn, gp); + temp ??= parameterType; + parameterType = temp; } var arg = actualArgs.RemoveAndReturn(0); @@ -84,7 +86,8 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con tempArgs.Add(arg); } - if (failOnLeftoverArgs && actualArgs.Any(a => a != null && !context.IsEmptyRegArg(a) && !(a is LocalDefinition {KnownInitialValue: 0}))) + actualArgs = actualArgs.Where(a => a != null && !context.IsEmptyRegArg(a) && !(a is LocalDefinition {KnownInitialValue: 0})).ToList(); + if (failOnLeftoverArgs && actualArgs.Count > 0) { if (actualArgs.Count != 1 || !(actualArgs[0] is ConstantDefinition {Value: MethodReference reference}) || reference != method) { @@ -96,6 +99,27 @@ private static bool CheckParameters64(MethodReference method, MethodAnalysis con return true; } + internal static TypeReference? ResolveGenericParameterType(MethodReference method, TypeReference instance, GenericParameter gp) + { + var git = instance as GenericInstanceType; + if (git?.ElementType.GenericParameters.ToList().FindIndex(g => g.Name == gp.FullName) is { } genericIdx && genericIdx >= 0) + return git.GenericArguments[genericIdx]; + + if (method is GenericInstanceMethod gim && gim.ElementMethod.HasGenericParameters) + { + var p = gim.ElementMethod.GenericParameters.ToList(); + + if (git != null && git.ElementType.HasGenericParameters) + //Filter to generic params not specified in the type + p = p.Where(genericParam => git.ElementType.GenericParameters.All(gitP => gitP.FullName != genericParam.FullName)).ToList(); + + if (p.FindIndex(g => g.Name == gp.FullName) is { } methodGenericIdx && methodGenericIdx >= 0) + return gim.GenericArguments[methodGenericIdx]; + } + + return null; + } + private static bool CheckParameters32(Instruction associatedInstruction, MethodReference method, MethodAnalysis context, bool isInstance, TypeReference beingCalledOn, [NotNullWhen(true)] out List? arguments) { arguments = new List(); diff --git a/Cpp2IL/Il2CppArrayUtils.cs b/Cpp2IL/Il2CppArrayUtils.cs index 46a1dbe1..4609da14 100644 --- a/Cpp2IL/Il2CppArrayUtils.cs +++ b/Cpp2IL/Il2CppArrayUtils.cs @@ -8,7 +8,7 @@ namespace Cpp2IL { public static class Il2CppArrayUtils { - public static uint FirstItemOffset = (uint) (LibCpp2IlMain.ThePe!.is32Bit ? 0x10 : 0x28); + public static uint FirstItemOffset = (uint) (LibCpp2IlMain.ThePe!.is32Bit ? 0x10 : 0x20); //32-bit: //0x0: klass ptr //0x4: monitor ptr diff --git a/Cpp2IL/Program.cs b/Cpp2IL/Program.cs index 4afaa69b..e6a45214 100644 --- a/Cpp2IL/Program.cs +++ b/Cpp2IL/Program.cs @@ -435,7 +435,7 @@ private static void SaveHeaderDLLs(string outputPath) private static ConcurrentDictionary DoAssemblyCSharpAnalysis(string methodOutputDir, List<(TypeDefinition type, List methods)> methods, KeyFunctionAddresses keyFunctionAddresses, out int total) { - var assembly = Assemblies.Find(a => a.Name.Name == "Assembly-CSharp" || a.Name.Name == "CSharp3"); + var assembly = Assemblies.Find(a => a.Name.Name == "Assembly-CSharp" || a.Name.Name == "CSharp3" || a.Name.Name == "CSharp2"); if (assembly == null) {