33

Is there some method of using C source mixed with inline asm (this is not C++ code) in a C# app? I'm not picky about how it gets done, if it requires compiling the C/asm into a DLL alongside the C# app, so be it. I'm aware there's no provision for using assembly inside C#, hence this question.

Sample code of what I'm trying to incorporate:

SomeFunc(unsigned char *outputData, unsigned char *inputData, unsigned long inputDataLength)
{
    _asm
    {
        //Assembly code that processes inputData and stores result in outputData
    }
}

There are some pointer/variable declarations in the C code before that function is declared, but beyond that it's all inline assembly, the declarations are used in the assembly code if that effects anything.

Objective is to pass 'inputData' from C# and then have access to 'outputData' in the C# program in some fashion. Normally we'd just rewrite the assembler code in native C# but we're on a tight schedule for getting a prototype together and don't see any reason to reinvent the wheel right away if we can temporarily use the existing C/assembly code in some fashion.

Tigress
  • 353
  • 1
  • 3
  • 5
  • Though I'm not sure how, I think you have to make your not-c# code into a dll and call it. You can't just slap in code for another language. By the way you can use pointers in c#, but seeing you just want to use existing code, don't bother (also I would verbally abuse you if you did) – gunr2171 Sep 16 '13 at 19:54
  • Compiling the C/asm into a DLL is probably the easiest option (it's technically possible to allocate writable|executable memory and go that route, but there's not much point unless your code is dynamic). You already gave your own answer though, so I don't really get this question. Use a DLL, problem solved, right? – harold Sep 16 '13 at 19:55
  • I've used C dlls in c# code, its pretty straight forward, just make sure you use the Marshall `CDecl` – Sayse Sep 16 '13 at 20:00
  • Well, if you want to get technical, sure I answered my own question by saying 'use a DLL' but I was expecting there to be pitfalls and gotchas with said approach. All examples I found so far were dealing with managed C++ code, no mention of C with inline assembly, and I was unsure if a C compiler would build a proper DLL that was usable with a C# app. – Tigress Sep 16 '13 at 20:48
  • 1
    Ok if you put it that way.. I suppose it's a bit of a pitfall/gotcha that you can't just add it as a reference as with managed DLLs. – harold Sep 17 '13 at 08:23
  • Using inline assembly in C# is not a good idea. The concept of.NET IL is to be portable. Of you use online assembly then your code will not run on machines with different architecture such as ARM. – Stavros Dimopoulos Dec 03 '20 at 08:08

1 Answers1

40

It's actually very easy and does not even require reflection.

        [SuppressUnmanagedCodeSecurity]
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate int AssemblyAddFunction(int x, int y);

        [DllImport("kernel32.dll")]
        private static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

        ....................................

        byte[] assembledCode =
        {
            0x55,               // 0 push ebp            
            0x8B, 0x45, 0x08,   // 1 mov  eax, [ebp+8]   
            0x8B, 0x55, 0x0C,   // 4 mov  edx, [ebp+12]  
            0x01, 0xD0,         // 7 add  eax, edx       
            0x5D,               // 9 pop  ebp            
            0xC3                // A ret                 
        };

        int returnValue;
        unsafe
        {
            fixed (byte* ptr = assembledCode)
            {
                var memoryAddress = (IntPtr) ptr;

                // Mark memory as EXECUTE_READWRITE to prevent DEP exceptions
                if (!VirtualProtectEx(Process.GetCurrentProcess().Handle, memoryAddress,
                    (UIntPtr) assembledCode.Length, 0x40 /* EXECUTE_READWRITE */, out uint _))
                {
                    throw new Win32Exception();
                }

                var myAssemblyFunction = Marshal.GetDelegateForFunctionPointer<AssemblyAddFunction>(memoryAddress);
                returnValue = myAssemblyFunction(10, -15);
            }               
        }

        Console.WriteLine($"Return value: {returnValue}"); // Prints -5

I have written a blog post on this: https://esozbek.me/inline-assembly-in-csharp-and-dotnet/

Enes Sadık Özbek
  • 993
  • 10
  • 17
  • I tried to use this segment of code. I keep getting a huge number for the returnValue. It does not give me -5. Any idea why? I copied the code exact. – Brandon Dodds Feb 16 '20 at 14:52
  • 1
    Ensure you are compiling it for 32bit – Enes Sadık Özbek Feb 17 '20 at 05:26
  • 2
    this is the real answer to the question. the other just show how to use dll written in c\c++ that use asm. this is show how to use c# and asm altough this is kind of dirty. because unlike c\c++ which actualy compile the code as is. but anyway this is a good trick – eli chen Apr 24 '20 at 11:30
  • 2
    For 64bit try to replace with: 0x8d, 0x04, 0x11, //lea eax, DWORD PTR [rcx+rdx] 0xC3 //ret – oddbear Oct 16 '20 at 13:12
  • 4
    After: `0x55, // 0 push ebp` it needs: `0x8b, 0xec, // 1 mov ebp, esp` Otherwise it fails in NET Core – Christian Ohle Jan 05 '21 at 12:11
  • @EnesSadıkÖzbek This is really interesting. Given fasm.net hasn't been updated in many years, do you have a suggestion for a replacement, or further places to look\read up? – BJury Jun 23 '22 at 19:28
  • That's not really inline assembly, more like inline hex. True inline assembly gives you access to all the features of an assembler, including syntax checking, labels, maybe macros. Not to mention the potential security issue with making an entire 4K page both writable and executable, or how UWP applications might not be allowed to use VirtualProtect. – Dwedit Jul 01 '23 at 17:18
  • 1
    VirtualProtecting a pinned array is INSANELY unsafe since the GC allocator may pack multiple arrays in one page – Jessie Lesbian Aug 01 '23 at 13:26