I am currently trying to change the implementation of the get property, replacing it with a small amount of IL. I used this question as a reference: How do I replace a pointer to a pointer to a method in a class of my method inherited from a system class?
The only difference I have is that my method is declared via MethodBuilder:
MethodBuilder propertyGetBuilder = builder.DefineMethod ( dynamicFunctionName, MethodAttributes.Public, propertyInfo.PropertyType, Type.EmptyTypes ); ILGenerator propertyGetIlGenerator = propertyGetBuilder.GetILGenerator(); propertyGetIlGenerator.Emit(OpCodes.Ldarg_0); propertyGetIlGenerator.Emit(OpCodes.Ldstr, propertyInfo.Name); propertyGetIlGenerator.Emit(OpCodes.Ldstr, relationKeyField.Name); propertyGetIlGenerator.Emit(OpCodes.Ldstr, relationAttribute.RelationColumn); propertyGetIlGenerator.Emit(OpCodes.Call, loadRelationMethod); propertyGetIlGenerator.Emit(OpCodes.Ret);
This adds a new function to the generated type named BeforeGet{PropertyName}
After generating a new type, I instantiate it to make sure that the memory address exists: dynamic fakeType = Activator.CreateInstance(type);
I am retrieving propertyInfo GetMethod from an existing class and the newly created Type class of class FakeType BeforeGet{PropertyName} .
After that, both MethodInfo are used in this function:
RuntimeHelpers.PrepareMethod(methodA.MethodHandle); RuntimeHelpers.PrepareMethod(methodB.MethodHandle); unsafe { if (IntPtr.Size == 4) { int* inj = (int*)methodA.MethodHandle.Value.ToPointer() + 2; int* tar = (int*)methodB.MethodHandle.Value.ToPointer() + 2; #if DEBUG Console.WriteLine("\nVersion x86 Debug?\n"); byte* injInst = (byte*)*inj; byte* tarInst = (byte*)*tar; int* injSrc = (int*)(injInst + 1); int* tarSrc = (int*)(tarInst + 1); *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5); #else *tar = *inj; #endif } else { long* inj = (long*)methodA.MethodHandle.Value.ToPointer() + 1; long* tar = (long*)methodB.MethodHandle.Value.ToPointer() + 1; #if DEBUG Console.WriteLine("\nVersion x64 Debug\n"); byte* injInst = (byte*)*inj; byte* tarInst = (byte*)*tar; int* injSrc = (int*)(injInst + 1); int* tarSrc = (int*)(tarInst + 1); *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5); #else *tar = *inj; #endif } }
After running this code, I execute the following code in my Program: LoadedTag.Item.ItemID; Where LoadedTag is the class that was supposed to get the new implementation of Item Getter, but instead I got a null reference exception because the function was not replaced.
However, if I execute this code in a direct window, the ItemID is indeed set and the interception function is called.
I think the problem is that the garbage collector removes fakeType, which contains the actual function pointers used during method replacement. If so, how should I solve this?
Thanks in advance!
If necessary, please verify the full code, and I will post it on Github.