I have read quite a bit about the possibilities of overwriting C#/.NET methods at runtime. After looking at some example code, there is one question that I am not able to answer. A very simple PoC for runtime method replacement could look like this:
class Program
{
public static void A(int x)
{
Console.WriteLine("A: " + x);
}
public static void B(int x)
{
Console.WriteLine("B: " + x);
}
internal static void Main(string[] args)
{
MethodInfo a = null;
MethodInfo b = null;
foreach(MethodInfo mi in typeof(Program).GetMethods())
{
if (mi.Name == "A" || mi.Name == "B")
{
// make sure methods are jitted
RuntimeHelpers.PrepareMethod(mi.MethodHandle);
}
if (mi.Name == "A") a = mi;
if (mi.Name == "B") b = mi;
}
unsafe
{
if (IntPtr.Size == 4) // x86
{
int* inj = (int*)a.MethodHandle.Value.ToPointer() + 2;
int* tar = (int*)b.MethodHandle.Value.ToPointer() + 2;
*tar = *inj;
}
else // x64
{
ulong* inj = (ulong*)a.MethodHandle.Value.ToPointer() + 1;
ulong* tar = (ulong*)b.MethodHandle.Value.ToPointer() + 1;
*tar = *inj;
}
}
Program.A(0);
Program.B(1);
Console.ReadLine();
}
}
As one would expect, the call to A(0) and B(1)
now prints:
A: 0
A: 1
So far so good. However, I have also seen an example, where it seems that no differentiation is made between x86/x64 code:
...
int* inj = (int*)(a.MethodHandle.Value.ToPointer() + 8);
int* tar = (int*)(b.MethodHandle.Value.ToPointer() + 8);
...
In this case 8 is added to the pointer. Could somebody explain the reason behind this? Additionally, what exactly does this pointer offset mean? If somebody can recommend good reading materials about C#/.NET/CLR internals, please let me know.
Thanks