Search code examples
c#memoryeip

C# Get EIP the memory address


I'm trying to find the memory address of what the (EIP) Instruction Pointer is executing. I have a very simple program:

internal class Program
{
    private static void Main(string[] args)
    {
        var sample = new Sample();
        var val = sample.GenericMethod("Nippies");
        Console.ReadLine();
    }
}

public class Sample
{
    public int GenericMethod<T>(T input)
    {
        //How can I get the current memory address
        var currentMemoryAddress = "";
        Console.WriteLine(currentMemoryAddress );
        return 5;
    }
}

TBH I'm trying to obtain the address of the GenericMethod<T> but generic methods aren't stored conventionally in the method tables, they're built at runtime.
So I figured I if I could print out the address of one of the current lines being executed I would be a lot closer to figuring it out.

How can I obtain the memory address of the instructions at a specific line?


Solution

  • The GetNativeOffset method of stackframe does it. With the somewhat surprising result that values for string and integer specializations are the same, and different for Guid.

    enter image description here

    Here is a better method, which retrieves the actual EIP register value. I found the assembly bits here, and adjusted it for the question at hand.

    using ByteToFunc;
    using System;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    
    namespace eip
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                var vals = Sample.GenericMethod("Nibbles");
                var valg = Sample.GenericMethod(Guid.NewGuid());
                var vali = Sample.GenericMethod(42);
                Console.ReadLine();
            }
        }
    
        public class Sample
        {
            /* trap values: bad beef is bad food */
            public static int[] EipEspEbpEsiEdiEbxHolder = new[] { 0xBADF00D, 0xBADBEEF, 0xBADF00D, 0xBADBEEF, 0xBADF00D, 0xBADBEEF };
    
            public static int GenericMethod<T>(T input)
            {
                //How can I get the current memory address
                var subjectAddress = GetAddress(nameof(Sample.SubjectMethod));
                var holderAddress = GetEipEspEbpEsiEdiEbxHolder();
                var captureRegisters = FuncGenerator.Generate<Action<int>, ActionInt>(
                    new byte[0].Concat(new byte[]
                    {
                        0xE8, 0x1C, 0x00, 0x00, 0x00  // call 28
                    })
                    .Concat(new byte[]
                    {
                        // save EIP, ESP, EBP, ESI, EDI to temp array
                        0x83, 0xC0, 0x1B, // add eax,0x1B (27 bytes)
                        0x89, 0x02,       // mov DWORD PTR [edx],eax
                        0x89, 0x62, 0x04, // mov DWORD PTR [edx+0x4],esp
                        0x89, 0x6A, 0x08, // mov DWORD PTR [edx+0x8],ebp
                        0x89, 0x72, 0x0C, // mov DWORD PTR [edx+0xc],esi
                        0x89, 0x7A, 0x10, // mov DWORD PTR [edx+0x10],edi
                        0x89, 0x5A, 0x14, // mov DWORD PTR [edx+0x14],ebx
                    })
                    .Concat(new byte[]
                    {
                        0xB8, // mov eax
                    })
                    .Concat(subjectAddress)
                    .Concat(new byte[]
                    {
                        0xFF, 0xD0 // call eax
                    })
                    .Concat(new byte[]
                    {
                        0xC3 //retn
                    })
                    .Concat(new byte[]
                    {
                        // Helper function for getting EIP as it is inaccessible directly on x86_32
                        0x8B, 0x04, 0x24, // mov eax,DWORD PTR [esp]
                        0xC3 //retn
                    })
                    .ToArray()
                );
    
                captureRegisters(holderAddress);
                Console.WriteLine($"EIP = { EipEspEbpEsiEdiEbxHolder[0].ToString("X") }");
                return 5;
            }
    
            public static int SubjectMethod()
            {
                return 5;
            }
    
            private static int GetEipEspEbpEsiEdiEbxHolder()
            {
                unsafe
                {
                    var typedReference = __makeref(EipEspEbpEsiEdiEbxHolder);
                    int* fieldAddress = (int*)*(int*)*(int*)&typedReference;
                    return (int)fieldAddress + 8;
                }
            }
    
            private static byte[] GetAddress(string name)
            {
                return BitConverter.GetBytes((int)GetRawAddress(name)).ToArray();
            }
    
            private static IntPtr GetRawAddress(string name)
            {
                var methodHandle = typeof(Sample).GetMethod(name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).MethodHandle;
                RuntimeHelpers.PrepareMethod(methodHandle);
                return methodHandle.GetFunctionPointer();
            }
        }
    }
    
    

    To compile and run, you can use a simple Console project, and add the FuncGenerator class by afish from here: https://gist.github.com/afish/8fd6cf8f8c196901b5e1a5ee1000ee68

    Result: three different values for EIP, which should be expected.

    enter image description here