Is it possible to execute an x86 assembly sequence from within C#?

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


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());
        }
    }
}

Tags:

C#

Assembly