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.
1 2 3 4 5 6 7 8 9 10 |
#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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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.
1 2 3 4 5 6 7 8 9 |
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.
1 2 3 4 5 6 7 8 9 10 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#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 😉
One thought on “Converting an EXE to a DLL”