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
- Name got mangled: Chapter 2
- Last call: name finally exported
- Exporting Functions Using Module-Definition File
- Exporting Functions from .NET Framework DLLs
- References
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:
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:
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:
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:
- The first requires to manually edit the Intermediate Language (IL) and indicate which function is to be exported.
- The second is to use a Nuget package called DllExport, which does the heavylifting for you.
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:
- Compile the code to a DLL (Class Library on Visual Studio)
- Decompile the DLL to retrieve the Intermediate Language IL) using the utility ildasm.exe
- Edit the IL to add the export descriptor that will instruct the assembler to export the function
- 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.
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