int __declspec(noinline) __stdcall MyAdd(int x, int y)
{
return x + y;
}
The C compiler will compile the code into assembly. Though the code which gets compiled may vary from compiler to platform, for x86 it will usually have this basic form:
Instruction Code Bytes Comment
------------------------------------------------------------------------------
mov eax,dword ptr [esp+8] ' 8B 44 24 08 Load the x into eax
mov ecx,dword ptr [esp+4] ' 8B 4C 24 04 Load the y into ecx
add eax,ecx ' 03 C1 Add eax and ecx, result goes into eax
ret 8 ' C2 08 00 Pop x and y off the stack, return eax
The instructions listed are disassembly copied from the VC++ debugger. The code bytes are what actually executes. The idea is to take those code bytes, write them into a native buffer, acquire a delegate for that buffer, and finally execute the delegate. Here is sample code to run these code bytes from C#:
using System;
using System.Runtime.InteropServices;
class Program
{
private delegate Int32 MyAdd(Int32 x, Int32 y);
private static void Main()
{
// A simple Add function
Byte[] myAddNativeCodeBytes = new Byte[]
{
0x8B, 0x44, 0x24, 0x08, // mov eax,dword ptr [esp+8]
0x8B, 0x4C, 0x24, 0x04, // mov ecx,dword ptr [esp+4]
0x03, 0xC1, // add eax,ecx
0xC2, 0x08, 0x00 // ret 8
};
// We need to push the code bytes into a native buffer
IntPtr myAddNativeCodeBytesPtr = IntPtr.Zero;
try
{
// Allocate the native buffer
myAddNativeCodeBytesPtr =
Marshal.AllocCoTaskMem(myAddNativeCodeBytes.Length);
// Push the code bytes over
Marshal.Copy(myAddNativeCodeBytes, 0,
myAddNativeCodeBytesPtr, myAddNativeCodeBytes.Length);
// Get a function pointer for the native code bytes
MyAdd myAdd = (MyAdd)Marshal.GetDelegateForFunctionPointer(
myAddNativeCodeBytesPtr, typeof(MyAdd));
// Call the native code bytes
Int32 result = myAdd(4, 5);
// Did it work?
Console.WriteLine("Result: {0}", result);
}
finally
{
// Free the native buffer
if (myAddNativeCodeBytesPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(myAddNativeCodeBytesPtr);
myAddNativeCodeBytesPtr = IntPtr.Zero;
}
}
}
}
In this sample I just used Marshal.AllocCoTaskMem(), but one should actually P/Invoke VirtualAllocEx and VirtualProtectEx to ensure the page where the code exists has PAGE_EXECUTE access. Additionally the above sample is targetted to my personal x86 machine, and will not run on x64 or any other platform for that matter.
Read more: Devin Jenson's WebLog