Skip to content

Commit

Permalink
Synclock position shifts in ClassReadingBinaryReader & begin better m…
Browse files Browse the repository at this point in the history
…ethod call resolving
  • Loading branch information
Sam committed Sep 10, 2020
1 parent 4b8b139 commit 233bea0
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Cpp2IL/Analysis/ASMAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// #define USE_NEW_ANALYSIS_METHOD
#define USE_NEW_ANALYSIS_METHOD

using System;
using System.Collections.Concurrent;
Expand Down
5 changes: 4 additions & 1 deletion Cpp2IL/Analysis/Actions/AllocateInstanceAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ namespace Cpp2IL.Analysis.Actions
public class AllocateInstanceAction : BaseAction
{
public TypeDefinition TypeCreated;
public LocalDefinition LocalReturned;

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 override Mono.Cecil.Cil.Instruction[] ToILInstructions()
Expand All @@ -31,7 +34,7 @@ public override string ToPsuedoCode()

public override string ToTextSummary()
{
return $"Allocates an instance of type {TypeCreated}";
return $"Allocates an instance of type {TypeCreated} and stores it as {LocalReturned.Name} in rax.";
}
}
}
20 changes: 19 additions & 1 deletion Cpp2IL/Analysis/Actions/CallManagedFunctionAction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Cpp2IL.Analysis.ResultModels;
using LibCpp2IL;
using Mono.Cecil;
Expand All @@ -14,7 +15,24 @@ public class CallManagedFunctionAction : BaseAction
public CallManagedFunctionAction(MethodAnalysis context, Instruction instruction) : base(context, instruction)
{
var jumpTarget = LibCpp2ILUtils.GetJumpTarget(instruction, context.MethodStart + instruction.PC);
SharedState.MethodsByAddress.TryGetValue(jumpTarget, out target);
var calledOn = context.GetLocalInReg("rcx");
var listOfCallableMethods = LibCpp2IlMain.GetListOfMethodImplementationsAtAddress(jumpTarget);

if (listOfCallableMethods == null) return;

if (calledOn?.Type == null) return;

//Direct instance methods take priority
var possibleTarget = listOfCallableMethods.FirstOrDefault(m => !m.IsStatic && m.parameterCount > 0 && Utils.DoTypesMatch(m.Parameters![0].Type, calledOn.Type));

//todo check args and null out

if (possibleTarget != null)
{
target = SharedState.UnmanagedToManagedMethods[possibleTarget];
return;
}
// SharedState.MethodsByAddress.TryGetValue(jumpTarget, out target);
}

public override Mono.Cecil.Cil.Instruction[] ToILInstructions()
Expand Down
7 changes: 7 additions & 0 deletions Cpp2IL/Analysis/Actions/GlobalMethodRefToConstantAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public GlobalMethodRefToConstantAction(MethodAnalysis context, Instruction instr
var globalAddress = context.MethodStart + LibCpp2ILUtils.GetOffsetFromMemoryAccess(instruction, instruction.Operands[1]);
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;
Expand Down
4 changes: 3 additions & 1 deletion Cpp2IL/AssemblyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,12 @@ private static List<CppMethodData> ProcessTypeContents(Il2CppMetadata metadata,
var methodDefinition = new MethodDefinition(methodName, (MethodAttributes) methodDef.flags,
ilTypeDefinition.Module.ImportReference(Utils.TryLookupTypeDefByName("System.Void").Item1));

SharedState.UnmanagedToManagedMethods[methodDef] = methodDefinition;

var offsetInRam = cppAssembly.GetMethodPointer(methodDef.methodIndex, methodId, imageDef.assemblyIndex, methodDef.token);


long offsetInFile = offsetInRam == 0 ? 0 : cppAssembly.MapVirtualAddressToRaw(offsetInRam);
var offsetInFile = offsetInRam == 0 ? 0 : cppAssembly.MapVirtualAddressToRaw(offsetInRam);
typeMetaText.Append($"\n\tMethod: {methodName}:\n")
.Append($"\t\tFile Offset 0x{offsetInFile:X8}\n")
.Append($"\t\tRam Offset 0x{offsetInRam:x8}\n")
Expand Down
4 changes: 2 additions & 2 deletions Cpp2IL/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ public static void Main(string[] args)
Console.WriteLine("\tPass 1: Creating empty types...");

Assemblies = AssemblyBuilder.CreateAssemblies(LibCpp2IlMain.TheMetadata!, resolver, moduleParams);

Utils.BuildPrimitiveMappings();

Console.WriteLine("\tPass 2: Setting parents and handling inheritance...");

Expand Down Expand Up @@ -287,8 +289,6 @@ public static void Main(string[] args)

#endregion

Utils.BuildPrimitiveMappings();

Console.WriteLine("Saving Header DLLs to " + outputPath + "...");

GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;
Expand Down
17 changes: 9 additions & 8 deletions Cpp2IL/SharedState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,25 @@ namespace Cpp2IL
public static class SharedState
{
//Virt methods
internal static Dictionary<ushort, MethodDefinition> VirtualMethodsBySlot = new Dictionary<ushort, MethodDefinition>();
internal static readonly Dictionary<ushort, MethodDefinition> VirtualMethodsBySlot = new Dictionary<ushort, MethodDefinition>();

//Methods
internal static Dictionary<ulong, MethodDefinition> MethodsByAddress = new Dictionary<ulong, MethodDefinition>();
internal static Dictionary<long, MethodDefinition> MethodsByIndex = new Dictionary<long, MethodDefinition>();
internal static readonly Dictionary<ulong, MethodDefinition> MethodsByAddress = new Dictionary<ulong, MethodDefinition>();
internal static readonly Dictionary<long, MethodDefinition> MethodsByIndex = new Dictionary<long, MethodDefinition>();
internal static readonly Dictionary<Il2CppMethodDefinition, MethodDefinition> UnmanagedToManagedMethods = new Dictionary<Il2CppMethodDefinition, MethodDefinition>();

//Generic params
internal static Dictionary<long, GenericParameter> GenericParamsByIndex = new Dictionary<long, GenericParameter>();
internal static readonly Dictionary<long, GenericParameter> GenericParamsByIndex = new Dictionary<long, GenericParameter>();

//Type defs
internal static Dictionary<long, TypeDefinition> TypeDefsByIndex = new Dictionary<long, TypeDefinition>();
internal static List<TypeDefinition> AllTypeDefinitions = new List<TypeDefinition>();
internal static Dictionary<TypeDefinition, Il2CppTypeDefinition> MonoToCppTypeDefs = new Dictionary<TypeDefinition, Il2CppTypeDefinition>();
internal static readonly Dictionary<long, TypeDefinition> TypeDefsByIndex = new Dictionary<long, TypeDefinition>();
internal static readonly List<TypeDefinition> AllTypeDefinitions = new List<TypeDefinition>();
internal static readonly Dictionary<TypeDefinition, Il2CppTypeDefinition> MonoToCppTypeDefs = new Dictionary<TypeDefinition, Il2CppTypeDefinition>();
internal static Dictionary<Il2CppTypeDefinition, TypeDefinition> CppToMonoTypeDefs = new Dictionary<Il2CppTypeDefinition, TypeDefinition>();


//Fields
internal static Dictionary<TypeDefinition, List<FieldInType>> FieldsByType = new Dictionary<TypeDefinition, List<FieldInType>>();
internal static readonly Dictionary<TypeDefinition, List<FieldInType>> FieldsByType = new Dictionary<TypeDefinition, List<FieldInType>>();

//Globals
internal static readonly List<GlobalIdentifier> Globals = new List<GlobalIdentifier>();
Expand Down
88 changes: 55 additions & 33 deletions Cpp2IL/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using LibCpp2IL;
using LibCpp2IL.Metadata;
using LibCpp2IL.PE;
using LibCpp2IL.Reflection;
using Mono.Cecil;
using SharpDisasm;
using SharpDisasm.Udis86;
Expand All @@ -15,17 +16,20 @@ namespace Cpp2IL
{
public static class Utils
{
//Disable these because they're initialised in BuildPrimitiveMappings
// ReSharper disable NotNullMemberIsNotInitialized
private static TypeDefinition StringReference;
private static TypeDefinition Int64Reference;
private static TypeDefinition SingleReference;
private static TypeDefinition Int32Reference;
private static TypeDefinition UInt32Reference;
private static TypeDefinition BooleanReference;
// ReSharper restore NotNullMemberIsNotInitialized

private static Dictionary<string, TypeDefinition> primitiveTypeMappings = new Dictionary<string, TypeDefinition>();
private static readonly Dictionary<string, Tuple<TypeDefinition, string[]>> _cachedTypeDefsByName = new Dictionary<string, Tuple<TypeDefinition, string[]>>();

private static Dictionary<string, ulong> PrimitiveSizes = new Dictionary<string, ulong>(14)
private static readonly Dictionary<string, ulong> PrimitiveSizes = new Dictionary<string, ulong>(14)
{
{"Byte", 1},
{"SByte", 1},
Expand All @@ -45,12 +49,12 @@ public static class Utils

public static void BuildPrimitiveMappings()
{
StringReference = TryLookupTypeDefByName("System.String").Item1;
Int64Reference = TryLookupTypeDefByName("System.Int64").Item1;
SingleReference = TryLookupTypeDefByName("System.Single").Item1;
Int32Reference = TryLookupTypeDefByName("System.Int32").Item1;
UInt32Reference = TryLookupTypeDefByName("System.UInt32").Item1;
BooleanReference = TryLookupTypeDefByName("System.Boolean").Item1;
StringReference = TryLookupTypeDefKnownNotGeneric("System.String");
Int64Reference = TryLookupTypeDefKnownNotGeneric("System.Int64");
SingleReference = TryLookupTypeDefKnownNotGeneric("System.Single");
Int32Reference = TryLookupTypeDefKnownNotGeneric("System.Int32");
UInt32Reference = TryLookupTypeDefKnownNotGeneric("System.UInt32");
BooleanReference = TryLookupTypeDefKnownNotGeneric("System.Boolean");

primitiveTypeMappings = new Dictionary<string, TypeDefinition>
{
Expand All @@ -63,47 +67,66 @@ public static void BuildPrimitiveMappings()
};
}

public static bool DoTypesMatch(Il2CppTypeReflectionData cppType, TypeDefinition managedType)
{
if (!cppType.isType && !cppType.isArray && !cppType.isGenericType) return false;

if (cppType.isType && !cppType.isGenericType) return cppType.baseType.FullName == managedType.FullName;

if (cppType.isType && cppType.isGenericType)
{
if (!managedType.HasGenericParameters || managedType.GenericParameters.Count != cppType.genericParams.Length) return false;

for (var i = 0; i < managedType.GenericParameters.Count; i++)
{

}
}

return false;
}

public static TypeReference ImportTypeInto(MemberReference importInto, Il2CppType toImport, PE theDll, Il2CppMetadata metadata)
{
var moduleDefinition = importInto.Module;
switch (toImport.type)
{
case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:
return moduleDefinition.ImportReference(typeof(object));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Object"));
case Il2CppTypeEnum.IL2CPP_TYPE_VOID:
return moduleDefinition.ImportReference(typeof(void));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Void"));
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
return moduleDefinition.ImportReference(typeof(bool));
return moduleDefinition.ImportReference(BooleanReference);
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
return moduleDefinition.ImportReference(typeof(char));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Char"));
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
return moduleDefinition.ImportReference(typeof(sbyte));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.SByte"));
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
return moduleDefinition.ImportReference(typeof(byte));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Byte"));
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
return moduleDefinition.ImportReference(typeof(short));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Int16"));
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
return moduleDefinition.ImportReference(typeof(ushort));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.UInt16"));
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
return moduleDefinition.ImportReference(typeof(int));
return moduleDefinition.ImportReference(Int32Reference);
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
return moduleDefinition.ImportReference(typeof(uint));
return moduleDefinition.ImportReference(UInt32Reference);
case Il2CppTypeEnum.IL2CPP_TYPE_I:
return moduleDefinition.ImportReference(typeof(IntPtr));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.IntPtr"));
case Il2CppTypeEnum.IL2CPP_TYPE_U:
return moduleDefinition.ImportReference(typeof(UIntPtr));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.UIntPtr"));
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
return moduleDefinition.ImportReference(typeof(long));
return moduleDefinition.ImportReference(Int64Reference);
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
return moduleDefinition.ImportReference(typeof(ulong));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.UInt64"));
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
return moduleDefinition.ImportReference(typeof(float));
return moduleDefinition.ImportReference(SingleReference);
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
return moduleDefinition.ImportReference(typeof(double));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Double"));
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
return moduleDefinition.ImportReference(typeof(string));
return moduleDefinition.ImportReference(StringReference);
case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:
return moduleDefinition.ImportReference(typeof(TypedReference));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.TypedReference"));
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
{
Expand Down Expand Up @@ -191,7 +214,7 @@ public static TypeReference ImportTypeInto(MemberReference importInto, Il2CppTyp
}

default:
return moduleDefinition.ImportReference(typeof(object));
return moduleDefinition.ImportReference(TryLookupTypeDefKnownNotGeneric("System.Object"));
}
}

Expand All @@ -214,7 +237,7 @@ public static bool CheckForNullCheckAtIndex(ulong offsetInRam, PE cppAssembly, L

//Disassemble 5 bytes at that destination (it should be a call)
var bytes = cppAssembly.raw.SubArray((int) cppAssembly.MapVirtualAddressToRaw(addrOfCall), 5);
var callInstruction = LibCpp2ILUtils.DisassembleBytes(LibCpp2IlMain.ThePe.is32Bit, bytes).First();
var callInstruction = LibCpp2ILUtils.DisassembleBytes(LibCpp2IlMain.ThePe!.is32Bit, bytes).First();

//Make sure it *is* a call
if (callInstruction.Mnemonic != ud_mnemonic_code.UD_Icall) return false;
Expand Down Expand Up @@ -245,12 +268,11 @@ public static int CheckForInitCallAtIndex(ulong offsetInRam, List<Instruction> i
var instructionsInRange = instructions.GetRange(idx, 4);
var actualPattern = instructionsInRange.Select(i => i.Mnemonic).ToArray();

ulong callAddr;
if (!alternativePattern.SequenceEqual(actualPattern)) return 0;

try
{
callAddr = LibCpp2ILUtils.GetJumpTarget(instructionsInRange[2], offsetInRam + instructionsInRange[2].PC);
var callAddr = LibCpp2ILUtils.GetJumpTarget(instructionsInRange[2], offsetInRam + instructionsInRange[2].PC);
return callAddr == kfe.il2cpp_codegen_initialize_method ? 3 : 0;
}
catch (Exception)
Expand Down Expand Up @@ -380,7 +402,7 @@ private static Tuple<TypeDefinition, string[]> InternalTryLookupTypeDefByName(st
return new Tuple<TypeDefinition, string[]>(definedType, genericParams);
}

public static TypeReference MakeGenericType(this TypeReference self, params TypeReference[] arguments)
private static TypeReference MakeGenericType(this TypeReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
Expand Down Expand Up @@ -467,7 +489,7 @@ public static StringBuilder AppendGenerics(this StringBuilder builder, string[]
return builder;
}

public static bool IsAssignableFrom(this TypeReference reference, TypeReference? other)
public static bool IsAssignableFrom(this TypeReference? reference, TypeReference? other)
{
if (reference == null || other == null) return false;

Expand Down Expand Up @@ -501,7 +523,7 @@ public static bool IsAssignableFrom(this TypeReference reference, TypeReference?
return null;
}

public static bool ShouldBeInFloatingPointRegister(TypeReference type)
public static bool ShouldBeInFloatingPointRegister(TypeReference? type)
{
if (type == null) return false;

Expand Down Expand Up @@ -541,7 +563,7 @@ public static string UpscaleRegisters(string replaceIn)
return "rcx";

//R9d, etc.
if (replaceIn[0] == 'r' && replaceIn[replaceIn.Length - 1] == 'd')
if (replaceIn[0] == 'r' && replaceIn[^1] == 'd')
return replaceIn.Substring(0, replaceIn.Length - 1);

return UpscaleRegex.Replace(replaceIn, "$1r$2");
Expand Down
Loading

0 comments on commit 233bea0

Please sign in to comment.