Converting an EXE to a DLL

I’ve been doing some crazy experiments on running an EXE as a DLL. Here are some parts of my research.

Case #1

Let’s take a simple example like a MessageBox.

#include <windows.h>

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow) 
{
	MessageBox(NULL, L"@OsandaMalith", L"https://osandamalith.com", MB_ICONINFORMATION | MB_OKCANCEL);
  
}

After compiling to an EXE we have to change the characteristics under NT Header->File Header to a DLL file. I will use the value 0x2000 | 0x2| 0x100 = 0x2102.

#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


Next, I created an export table manually. So I added a new section as ‘.edata’ with 0x40300040 as the characteristics since I only want it to be readable. You can call the name of the section as whatever you want.

Make sure to point the RVA on the Export Directory RVA and enter the Export Directory Size.

Now we have to create an Export Directory with an EAT. In this case, I manually created using the hex editor by giving the exact offsets and addresses. You can, of course, come up with a nice tool to automate this painful process.

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

Here’s a diagram explaining the Export Directory inside the raw file. I hope this helps. I am creating an export function name as ‘Run’, the DLL name is ‘abc.dll’ and it doesn’t really matter in this specific case. If you have a look at the offset of AddressOfNames which has the LSB as 0x2C and at the raw offset, 0x1962C contains the Name RVA 0x1E03A which then again points to 0x1963A which contains the string “Run”. Likewise, if you understand the relationship it’s easy to manually tweak this directory and create your own entries in the raw file.

The EAT must look like this if all goes well in order. Now point the Function RVA to the OEP or to the DLL Entry point. Our exported function name is ‘Run’.

We need to create a new DLLEntry point and point the AddressOfEntryPoint to our newly created DLLEntry point. DLLEntry can be something simple like this. Once the process is attached we will call the OEP. I will use a code cave in this case. You can add a separate section if you prefer.

DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD	
	.if reason == DLL_PROCESS_ATTACH
		invoke OEP
	.endif
	
	mov  eax,TRUE
	ret

DllEntry endp

Let’s write this in raw assembly.

push    ebp
mov     ebp, esp
cmp     dword ptr [ebp+0Ch], 1
jnz     @exit  
call    0040124E    ;OEP

@exit:                           
mov     eax, 1
leave
retn    0Ch

That’s it! Now we can run our DLL using Rundll32 by calling our exported function.

You can play download the file from here.

Case #2

I was experimenting with apps which has a GUI. For this, we will have to perform function redirection to redirect the GetModuleHandle API of the target in our loading EXE and then call the OEP. I’ve created an export table manually and exported the RVA of the OEP as “Run”. Like before first I made the EXE a DLL by adding the DLLEntry and changing the PE headers.

#include <windows.h>
/*
 * @OsandaMalith
 * https://osandamalith.com
 */
#define GetModuleHandleVA  0x0100108C 

HMODULE ghDll;

HMODULE WINAPI MyGetModuleHandleA( __in_opt LPCSTR lpModuleName) {
	if(!lpModuleName)
		return ghDll;
	return ::GetModuleHandleA(lpModuleName);
}

int _tmain(int argc, _TCHAR* argv[]) {
	
	HMODULE hDll = LoadLibraryA("mine.dll");
	ghDll = hDll;
	{
		DWORD old;
		FARPROC* pGetModuleHandleA = (FARPROC*)((UCHAR*) hDll + (GetModuleHandleVA - (UINT)GetModuleHandleA("mine.dll")));
		VirtualProtect((LPVOID)pGetModuleHandleA,sizeof(FARPROC),PAGE_EXECUTE_READWRITE,&old);
		*pGetModuleHandleA = (FARPROC)MyGetModuleHandleA;
	}

	int (*OEP)();
	*(FARPROC*)&OEP = (FARPROC)((UCHAR*)GetProcAddress(hDll, "Run"));
	OEP(); 

	return 0;
}

For this example, I used the game Minesweeper.

These are 2 simple examples. I hope these might come in handy in you know 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.