Skip to content

Commit 5a210e0

Browse files
authored
Merge pull request #42 from BepInEx/fix-field-default-value-fetching
Resolve Class::GetDefaultFieldValue through ICall
2 parents 9f73743 + d79a401 commit 5a210e0

File tree

1 file changed

+43
-9
lines changed

1 file changed

+43
-9
lines changed

Il2CppInterop.Runtime/Injection/InjectorHelpers.cs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace Il2CppInterop.Runtime.Injection
2222
{
2323
internal static unsafe class InjectorHelpers
2424
{
25+
internal static Assembly Il2CppMscorlib = typeof(Il2CppSystem.Type).Assembly;
2526
internal static INativeAssemblyStruct InjectedAssembly;
2627
internal static INativeImageStruct InjectedImage;
2728
internal static ProcessModule Il2CppModule = Process.GetCurrentProcess()
@@ -329,19 +330,52 @@ private static d_ClassFromIl2CppType FindClassFromIl2CppType()
329330
private static d_ClassGetFieldDefaultValue ClassGetFieldDefaultValueDetour = new(hkClassGetFieldDefaultValue);
330331
internal static d_ClassGetFieldDefaultValue ClassGetFieldDefaultValue;
331332
internal static d_ClassGetFieldDefaultValue ClassGetFieldDefaultValueOriginal;
332-
private static d_ClassGetFieldDefaultValue FindClassGetFieldDefaultValue()
333+
private static d_ClassGetFieldDefaultValue FindClassGetFieldDefaultValue(bool forceICallMethod = false)
333334
{
334-
var getStaticFieldValueAPI = GetIl2CppExport(nameof(IL2CPP.il2cpp_field_static_get_value));
335-
Logger.Instance.LogTrace("il2cpp_field_static_get_value: 0x{GetStaticFieldValueApiAddress}", getStaticFieldValueAPI.ToInt64().ToString("X2"));
335+
// NOTE: In some cases this pointer will be MetadataCache::GetFieldDefaultValueForField due to Field::GetDefaultFieldValue being
336+
// inlined but we'll treat it the same even though it doesn't receive the type parameter the RDX register
337+
// doesn't get cleared so we still get the same parameters
338+
var classGetDefaultFieldValue = IntPtr.Zero;
336339

337-
var getStaticFieldValue = XrefScannerLowLevel.JumpTargets(getStaticFieldValueAPI).Single();
338-
Logger.Instance.LogTrace("Field::StaticGetValue: 0x{GetStaticFieldValueAddress}", getStaticFieldValue.ToInt64().ToString("X2"));
340+
if (forceICallMethod)
341+
{
342+
// MonoField isn't present on 2021.2.0+
343+
var monoFieldType = Il2CppMscorlib.GetTypes().SingleOrDefault((x) => x.Name is "MonoField");
344+
if (monoFieldType == null)
345+
throw new Exception($"Unity {Il2CppInteropRuntime.Instance.UnityVersion} is not supported at the moment: MonoField isn't present in Il2Cppmscorlib.dll for unity version, unable to fetch icall");
346+
347+
var monoFieldGetValueInternalThunk = GetIl2CppMethodPointer(monoFieldType.GetMethod(nameof(Il2CppSystem.Reflection.MonoField.GetValueInternal)));
348+
Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::thunk_GetValueInternal: 0x{MonoFieldGetValueInternalThunkAddress}", monoFieldGetValueInternalThunk.ToInt64().ToString("X2"));
349+
350+
var monoFieldGetValueInternal = XrefScannerLowLevel.JumpTargets(monoFieldGetValueInternalThunk).Single();
351+
Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::GetValueInternal: 0x{MonoFieldGetValueInternalAddress}", monoFieldGetValueInternal.ToInt64().ToString("X2"));
352+
353+
// Field::GetValueObject could be inlined with Field::GetValueObjectForThread
354+
var fieldGetValueObject = XrefScannerLowLevel.JumpTargets(monoFieldGetValueInternal).Single();
355+
Logger.Instance.LogTrace("Field::GetValueObject: 0x{FieldGetValueObjectAddress}", fieldGetValueObject.ToInt64().ToString("X2"));
339356

340-
var getStaticFieldValueInternal = XrefScannerLowLevel.JumpTargets(getStaticFieldValue).Last();
341-
Logger.Instance.LogTrace("Field::StaticGetValueInternal: 0x{GetStaticFieldValueInternalAddress}", getStaticFieldValueInternal.ToInt64().ToString("X2"));
357+
var fieldGetValueObjectForThread = XrefScannerLowLevel.JumpTargets(fieldGetValueObject).Last();
358+
Logger.Instance.LogTrace("Field::GetValueObjectForThread: 0x{FieldGetValueObjectForThreadAddress}", fieldGetValueObjectForThread.ToInt64().ToString("X2"));
342359

343-
var getStaticFieldValueInternalTargets = XrefScannerLowLevel.JumpTargets(getStaticFieldValueInternal).ToArray();
344-
var classGetDefaultFieldValue = getStaticFieldValueInternalTargets.Length == 3 ? getStaticFieldValueInternalTargets.Last() : getStaticFieldValueInternalTargets.First();
360+
classGetDefaultFieldValue = XrefScannerLowLevel.JumpTargets(fieldGetValueObjectForThread).ElementAt(2);
361+
}
362+
else
363+
{
364+
var getStaticFieldValueAPI = GetIl2CppExport(nameof(IL2CPP.il2cpp_field_static_get_value));
365+
Logger.Instance.LogTrace("il2cpp_field_static_get_value: 0x{GetStaticFieldValueApiAddress}", getStaticFieldValueAPI.ToInt64().ToString("X2"));
366+
367+
var getStaticFieldValue = XrefScannerLowLevel.JumpTargets(getStaticFieldValueAPI).Single();
368+
Logger.Instance.LogTrace("Field::StaticGetValue: 0x{GetStaticFieldValueAddress}", getStaticFieldValue.ToInt64().ToString("X2"));
369+
370+
var getStaticFieldValueInternal = XrefScannerLowLevel.JumpTargets(getStaticFieldValue).Last();
371+
Logger.Instance.LogTrace("Field::StaticGetValueInternal: 0x{GetStaticFieldValueInternalAddress}", getStaticFieldValueInternal.ToInt64().ToString("X2"));
372+
373+
var getStaticFieldValueInternalTargets = XrefScannerLowLevel.JumpTargets(getStaticFieldValueInternal).ToArray();
374+
375+
if (getStaticFieldValueInternalTargets.Length == 0) return FindClassGetFieldDefaultValue(true);
376+
377+
classGetDefaultFieldValue = getStaticFieldValueInternalTargets.Length == 3 ? getStaticFieldValueInternalTargets.Last() : getStaticFieldValueInternalTargets.First();
378+
}
345379
Logger.Instance.LogTrace("Class::GetDefaultFieldValue: 0x{ClassGetDefaultFieldValueAddress}", classGetDefaultFieldValue.ToInt64().ToString("X2"));
346380

347381
ClassGetFieldDefaultValueOriginal = Detour.Apply(classGetDefaultFieldValue, ClassGetFieldDefaultValueDetour);

0 commit comments

Comments
 (0)