27

Continuing my reverse engineering education I've often wanted to be able to copy portions of x86 assembly code and call it from a high level language of my choice for testing.

Does anyone know of a method of calling a sequence of x86 instructions from within a C# method? I know that this can be done using C++ but I'm curious if it can be done in C#?

Note: I'm not talking about executing MSIL instructions. I'm talking about executing a series of raw x86 assembly instructions.

mmcdole
  • 91,488
  • 60
  • 186
  • 222

5 Answers5

47

Just to counter Brian's claim, rewritten code from leppie's answer link:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace DynamicX86
{
    class Program
    {
        const uint PAGE_EXECUTE_READWRITE = 0x40;
        const uint MEM_COMMIT = 0x1000;

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

        private delegate int IntReturner();

        static void Main(string[] args)
        {
            List<byte> bodyBuilder = new List<byte>();
            bodyBuilder.Add(0xb8);
            bodyBuilder.AddRange(BitConverter.GetBytes(42));
            bodyBuilder.Add(0xc3);
            byte[] body = bodyBuilder.ToArray();
            IntPtr buf = VirtualAlloc(IntPtr.Zero, (uint)body.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            Marshal.Copy(body, 0, buf, body.Length);

            IntReturner ptr = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
            Console.WriteLine(ptr());
        }
    }
}
okutane
  • 13,754
  • 10
  • 59
  • 67
5

Yes, see my detailed answer here
The main part is: (Without any P/Invoke or external reference)

public static unsafe int? InjectAndRunX86ASM(this Func<int> del, byte[] asm)
{
    if (del != null)
        fixed (byte* ptr = &asm[0])
        {
            FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
            FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance);

            _methodPtr.SetValue(del, ptr);
            _methodPtrAux.SetValue(del, ptr);

            return del();
        }
    else
        return null;
}

Which can be used as follows:

Func<int> del = () => 0;
byte[] asm_bytes = new byte[] { 0xb8, 0x15, 0x03, 0x00, 0x00, 0xbb, 0x42, 0x00, 0x00, 0x00, 0x03, 0xc3 };
// mov eax, 315h
// mov ebx, 42h
// add eax, ebx
// ret

int? res = del.InjectAndRunX86ASM(asm_bytes); // should be 789 + 66 = 855

EDIT: The newest version of C# (C#9) introduces the concept of 'delegate pointers', which allows you to do the following:

byte[] asm = {
    0x8D, 0x04, 0x11,   // lea eax, [rcx+rdx]
    0xC3                // ret
};

void* buffer = VirtualAlloc(null, asm.Length, 0x1000, 4);
var func = (delegate*<int, int, int>)buffer;
int dummy;

Marshal.Copy(asm, 0, (nint)buffer, asm.Length);
VirtualProtect(buffer, asm.Length, 0x20, &dummy);

Console.WriteLine(func(42, 378)); // call 'func' with (42, 378), which computes '420'

VirtualFree(buffer, 0, 0x8000);

You can find a complete example here: https://gist.github.com/Unknown6656/a42a810d4283208c3c21c632fb16c3f9

unknown6656
  • 2,765
  • 2
  • 36
  • 52
  • Are the Virtual* calls really necessary? Could the POH be used, instead? – user1969177 Jun 29 '21 at 15:58
  • 1
    I think they are necessary as you need to allocate a dedicated memory page and flag it as 'executable'. That's not possible to do using a simple heap- or stack allocation. Thus, you cannot simply use a `fixed` array, `stackalloc`, or the POH. – unknown6656 Jun 29 '21 at 16:59
  • It makes sense that arbitrary bytes cannot just be executed. It's just that InjectAndRunX86ASM method appears to not have this limitation. – user1969177 Jun 29 '21 at 23:13
0

I believe, you can add a managed C++ project to your solution and expose method with usage of asm instructions. You can reference that project from any .Net project (not just C#), so you can call that method from there.

okutane
  • 13,754
  • 10
  • 59
  • 67
0

Yes.

Just use P/Invoke on winapi functions.

WriteProcessMemory or find the pointer to your buffer. Enable the execute bit on page (don't remember the function for this).

CreateThread on the pointer. WaitForObject (if you want it to be single threaded).

Unknown
  • 45,913
  • 27
  • 138
  • 182
-1

No, but you can write assembly in C++ and call it from C#. See this example.

Brian
  • 25,523
  • 18
  • 82
  • 173