Exporting functions from DLL using the actual function name

In this post I describe the adventure I had in figuring out how I could export a function from a DLL (compiled for 32bit architecture) using the actual name of this function. This post attempts to document in a better way what was found on a stackoverflow thread [1]. Additionally, you can find a summary of steps required to export a function from an unmanaged assembly DLL - a binary created with .NET Framework and written in C# (Csharp), documented in detail by xpn in “RunDLL32 your .NET (AKA DLL exports from .NET)”.

This post is split in the following sections:

Name got mangled: Chapter 1

The number one result I got while searching on how I could export a function from DLL came from Microsoft [2]. We can export a function from DLL using the keyword __declspec(dllexport). Looks and it is straightforward, indeed. I wrote the following code in order to generate a DLL that exports the function DoSomeMagic. After compiling this code, I opened the DLL on CFF Explorer to have a look at the exported function.

#include <windows.h>
#include <debugapi.h>

#define DllExport __declspec(dllexport)

DllExport void WINAPI DoSomeMagic(void)
{
    OutputDebugStringA("DoSomeMagic was executed");
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch(fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            OutputDebugStringA("DllMain was executed");
            break;
        case DLL_PROCESS_DETACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
            break;
    }

    return 1;
}

Τhe linker decorates the name of the function and thus it looks like this on CFF Explorer:

export1

We observe that the function was exported with the name ?DoSomeMagic@@YGXXZ. This means that if we want to call/execute this function, we’ll have to call it in this way. I didn’t like it so I chase how it could be exported with the actual name.

Name got mangled: Chapter 2

What if we change the definition of the function to:

extern “C” DllExport void WINAPI DoSomeMagic(void)

In this case, the name of the exported function is _DoSomeMagic@0 as shown in CFF Explorer:

export2

Last call: name finally exported

There is an even more straightforward way of configuring a function to be exported with its actual name and this is not by creating a definition file. By creating a #pragma comment 3, we can tell the linker about the naming convention of the function we export. By implementing the pragma comment, the initial code changes to:

#include <windows.h>
#include <debugapi.h>

#define DllExport comment(linker, "/EXPORT:DoSomeMagic=?DoSomeMagic@@YGXXZ")

void WINAPI DoSomeMagic(void)
{
    #pragma DllExport
    OutputDebugStringA("DoSomeMagic was executed");
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch(fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            OutputDebugStringA("DllMain was executed");
            break;
        case DLL_PROCESS_DETACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
            break;
    }

    return TRUE;
}

The output from CFF Explorer shows the function is finally exported with its actual name:

export3

We can now call the exported function by its name. Assuming we call the DLL test.dll, we can call the function using runll32.exe:

rundll32.exe test.dll, DoSomeMagic

Exporting Functions Using Module-Definition File

If you choose the path to have the imports in a separate file, a definitions file (.DEF) is the way to go.

The following file instructs the linker that the function DoSomeMagic be exported:

EXPORTS
	DoSomeMagic PRIVATE

In order to compile the source code into a DLL from command line prompt using the Microsoft compiler you would do something like:

cl.exe /nologo source.cpp /LD /link /DEF:defitions.def

If you prefer the GUI version, go to ‘Solution Explorer’, right click on ‘Source Files’ -> Add -> ‘Module’ search for ‘module’ and select ‘Module-Definition File (.def)’

Exporting Functions from .NET Framework DLLs

As mentioned in the introduction of this post, this section provides a summary of the steps required to export a function from a DLL that is written with .NET Framework in C# - Csharp and is documented in xpn’s detailed post “RunDLL32 your .NET (AKA DLL exports from .NET)”.

There are two approaches:

Manually Editing the Intermediate Language

Presuming you have the source code listed later and you want to export the function TestFunc, you need to perform these steps:

  1. Compile the code to a DLL (Class Library on Visual Studio)
  2. Decompile the DLL to retrieve the Intermediate Language IL) using the utility ildasm.exe
  3. Edit the IL to add the export descriptor that will instruct the assembler to export the function
  4. Compile the IL to a DLL library using the native utility ilasm.exe

If you use Visual Studio, select navigate to Tools -> Command Line -> Developer Command Prompt to open a command prompt that gives you access to developer tools.

The source code of the DLL:

using System;
using System.Windows;

namespace TestNamespace
{
    public class TestProject
    {
        public static void TestFunc()
        {

            MessageBox.Show("Test");
        }
    }
}

Using the DllExport Nuget Package

To avoid the manual work, you can simply download and use the relevant Nuget package (Nugets are used on a per project basis). The soure code of the Nuget is located at this link.

To activate the window that will allow you to select configuration options, run the batch (.bat) file that is located in the *packages\DllExport.* directory and is named *DllExport.bat*. After this is successfully configured, you should see the batch file copied a little backward, to your project directory. If the file is not there the compile will fail with a relevant error message. Last step is to include the *[DllExport]* string just before the name of the function that is to be exported.

References

[1] https://stackoverflow.com/questions/538134/exporting-functions-from-a-dll-with-dllexport

[2] https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport?view=vs-2019

[3] https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=vs-2019

[4] https://github.com/3F/DllExport

tags: #Windows API