Model: Implement MethodInvoker and MethodBase.Invoker
This commit is contained in:
@@ -38,6 +38,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
// List of all methods ordered by their MethodDefinitionIndex
|
// List of all methods ordered by their MethodDefinitionIndex
|
||||||
public MethodBase[] MethodsByDefinitionIndex { get; }
|
public MethodBase[] MethodsByDefinitionIndex { get; }
|
||||||
|
|
||||||
|
// List of all Method.Invoke functions by invoker index
|
||||||
|
public MethodInvoker[] MethodInvokers { get; }
|
||||||
|
|
||||||
// List of all generated CustomAttributeData objects by their instanceIndex into AttributeTypeIndices
|
// List of all generated CustomAttributeData objects by their instanceIndex into AttributeTypeIndices
|
||||||
public ConcurrentDictionary<int, CustomAttributeData> AttributesByIndices { get; } = new ConcurrentDictionary<int, CustomAttributeData>();
|
public ConcurrentDictionary<int, CustomAttributeData> AttributesByIndices { get; } = new ConcurrentDictionary<int, CustomAttributeData>();
|
||||||
|
|
||||||
@@ -60,6 +63,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||||
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
||||||
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
||||||
|
MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length];
|
||||||
|
|
||||||
// Recursively create hierarchy of assemblies and types from TypeDefs
|
// Recursively create hierarchy of assemblies and types from TypeDefs
|
||||||
// No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex)
|
// No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex)
|
||||||
@@ -100,6 +104,17 @@ namespace Il2CppInspector.Reflection
|
|||||||
GenericMethods.Add(spec, concreteMethod);
|
GenericMethods.Add(spec, concreteMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create method invokers (one per signature, in invoker index order)
|
||||||
|
foreach (var method in MethodsByDefinitionIndex) {
|
||||||
|
var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition);
|
||||||
|
if (index != -1) {
|
||||||
|
if (MethodInvokers[index] == null)
|
||||||
|
MethodInvokers[index] = new MethodInvoker(method);
|
||||||
|
|
||||||
|
method.Invoker = MethodInvokers[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get generic arguments from either a type or method instanceIndex from a MethodSpec
|
// Get generic arguments from either a type or method instanceIndex from a MethodSpec
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ namespace Il2CppInspector.Reflection
|
|||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
public (ulong Start, ulong End)? VirtualAddress { get; }
|
public (ulong Start, ulong End)? VirtualAddress { get; }
|
||||||
|
|
||||||
|
// Method.Invoke implementation
|
||||||
|
public MethodInvoker Invoker { get; set; }
|
||||||
|
|
||||||
// Information/flags about the method
|
// Information/flags about the method
|
||||||
public MethodAttributes Attributes { get; protected set; }
|
public MethodAttributes Attributes { get; protected set; }
|
||||||
|
|
||||||
|
|||||||
64
Il2CppInspector/Reflection/MethodInvoker.cs
Normal file
64
Il2CppInspector/Reflection/MethodInvoker.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Reflection
|
||||||
|
{
|
||||||
|
// Class representing a MethodBase.Invoke() method for a specific signature
|
||||||
|
// Every IL2CPP invoker has the signature:
|
||||||
|
// void* RuntimeInvoker_{RequiresObject (True/False)}{ReturnType}_{ParameterTypes}
|
||||||
|
// (Il2CppMethodPointer pointer, const RuntimeMethod* methodMetadata, void* obj, void** args)
|
||||||
|
public class MethodInvoker
|
||||||
|
{
|
||||||
|
// IL2CPP invoker index
|
||||||
|
public int Index { get; }
|
||||||
|
|
||||||
|
// Virtual address of the invoker function
|
||||||
|
public (ulong Start, ulong End) VirtualAddress { get; }
|
||||||
|
|
||||||
|
// If false, the first argument to the called function pointers must be the object instance
|
||||||
|
public bool IsStatic { get; }
|
||||||
|
|
||||||
|
// Return type
|
||||||
|
public TypeInfo ReturnType { get; }
|
||||||
|
|
||||||
|
// Argument types
|
||||||
|
public TypeInfo[] ParameterTypes { get; }
|
||||||
|
|
||||||
|
// Find the correct method invoker for a method with a specific signature
|
||||||
|
public MethodInvoker(MethodBase exampleMethod) {
|
||||||
|
var model = exampleMethod.Assembly.Model;
|
||||||
|
var package = exampleMethod.Assembly.Model.Package;
|
||||||
|
|
||||||
|
Index = package.GetInvokerIndex(exampleMethod.DeclaringType.Assembly.ModuleDefinition, exampleMethod.Definition);
|
||||||
|
IsStatic = exampleMethod.IsStatic;
|
||||||
|
|
||||||
|
ReturnType = exampleMethod.IsConstructor ? model.TypesByFullName["System.Void"] : mapParameterType(model, ((MethodInfo) exampleMethod).ReturnType);
|
||||||
|
ParameterTypes = exampleMethod.DeclaredParameters.Select(p => mapParameterType(model, p.ParameterType)).ToArray();
|
||||||
|
|
||||||
|
var start = package.MethodInvokePointers[Index];
|
||||||
|
VirtualAddress = (start & 0xffff_ffff_ffff_fffe, package.FunctionAddresses[start]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The invokers use Object for all reference types, and SByte for booleans
|
||||||
|
private TypeInfo mapParameterType(Il2CppModel model, TypeInfo type) => type switch {
|
||||||
|
{ IsValueType: false } => model.TypesByFullName["System.Object"],
|
||||||
|
{ FullName: "System.Boolean" } => model.TypesByFullName["System.SByte"],
|
||||||
|
_ => type
|
||||||
|
};
|
||||||
|
|
||||||
|
public string Name => $"RunTimeInvoker_{!IsStatic}{ReturnType.BaseName}_" + string.Join("_", ParameterTypes.Select(p => p.BaseName));
|
||||||
|
|
||||||
|
// Display as a C++ method signature
|
||||||
|
public string Signature => Name + "(Il2CppMethodPointer pointer, const RuntimeMethod* methodMetadata, void* obj, void** args)";
|
||||||
|
|
||||||
|
public override string ToString() => Signature;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user