0xd4d / dnlib

Reads and writes .NET assemblies and modules
MIT License
2.16k stars 584 forks source link

How to export managed method? #172

Closed CreateAndInject closed 6 years ago

CreateAndInject commented 6 years ago
        public static void Test()
        {
            var module= ModuleDefMD.Load(@"C:\cl.dll");
            var method = module.Types[1].Methods[0];
            method.ExportInfo = new MethodExportInfo();
            module.Write("cl.dll");
            var handle = LoadLibrary("cl.dll"); //----   handle=0  ---
            var value = Get(); //---  BadImageFormatException ---
        }
        [DllImport("cl.dll")]
        public static extern int Get();
        [DllImport("kernel32")]
        public static extern int LoadLibrary(string name);

cl.dll (x86)

public static class Demo
{
    public static int Get()
    {
        return 7;
    }
}

If remove "method.ExportInfo = new MethodExportInfo();", handle is not 0.

0xd4d commented 6 years ago

Did you read the documentation? :)

You have to change the calling convention to cdecl or similar.

There's also a missing piece of info in the documentation, you have to clear the COR20 header flag "IL Only".

I have only tested this code by calling from unmanaged code (eg. C++), not calling it from managed code. I tried a quick hack and updated the MethodExportInfo.Options to None (it defaults to FromUnmanaged) but it also didn't work. Is it supposed to work?

... change call conv here...

// clear IL only flag
var options = new ModuleWriterOptions(module);
options.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly;
0xd4d commented 6 years ago

Also you should update the call conv in the DllImport to match the call conv you changed the method to.

0xd4d commented 6 years ago

And don't forget to make sure your test EXE targets x86 or x64 (should be the same as cl.dll)

CreateAndInject commented 6 years ago

Yes, I have read the documentation. but it still have error after changing calling convention, so I delete it. When I clear IL only, handle=LoadLibrary(..) is not 0, but when calling Get(), I get: ExecutionEngineException

CreateAndInject commented 6 years ago

There's a "jitDumper3.Core.dll" in JitDumper3, it's a C# dll, and export a managed method "Injection" by ilasm, and I can use DllImport to call it from C#.

0xd4d commented 6 years ago

This fatal execution engine exception is thrown when debugging with VS. I don't get the exception when I use dnSpy or when I run it from the command line.

CreateAndInject commented 6 years ago

It seems if cl.dll is debug, vs will throw an exception, but if cl.dll is release, vs is ok.