Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cross-compile DLL with exported functions

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?

like image 430
n00b Avatar asked Sep 28 '18 16:09

n00b


People also ask

What is a DLL export?

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.

Why is cross compiling so hard?

"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.


1 Answers

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
like image 63
Dexter CD Avatar answered Oct 19 '22 23:10

Dexter CD