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].
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
- 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)’
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