Skip to content

Commit 5a448ce

Browse files
committed
Support loading (and running) EXE files (fixes #7).
1 parent 2d504b5 commit 5a448ce

File tree

4 files changed

+119
-17
lines changed

4 files changed

+119
-17
lines changed

MemoryModule.c

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,24 @@
4949

5050
#include "MemoryModule.h"
5151

52+
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
53+
typedef int (WINAPI *ExeEntryProc)(void);
54+
5255
typedef struct {
5356
PIMAGE_NT_HEADERS headers;
5457
unsigned char *codeBase;
5558
HCUSTOMMODULE *modules;
5659
int numModules;
5760
int initialized;
61+
int isDLL;
62+
int isRelocated;
5863
CustomLoadLibraryFunc loadLibrary;
5964
CustomGetProcAddressFunc getProcAddress;
6065
CustomFreeLibraryFunc freeLibrary;
6166
void *userdata;
67+
ExeEntryProc exeEntry;
6268
} MEMORYMODULE, *PMEMORYMODULE;
6369

64-
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
65-
6670
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
6771

6872
#ifdef DEBUG_OUTPUT
@@ -202,11 +206,12 @@ ExecuteTLS(PMEMORYMODULE module)
202206
}
203207
}
204208

205-
static void
209+
static int
206210
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
207211
{
208212
DWORD i;
209213
unsigned char *codeBase = module->codeBase;
214+
int result = 0;
210215

211216
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
212217
if (directory->Size > 0) {
@@ -254,7 +259,9 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
254259
// advance to next relocation block
255260
relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock);
256261
}
262+
result = 1;
257263
}
264+
return result;
258265
}
259266

260267
static int
@@ -355,7 +362,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
355362
PIMAGE_NT_HEADERS old_header;
356363
unsigned char *code, *headers;
357364
SIZE_T locationDelta;
358-
DllEntryProc DllEntry;
359365
BOOL successfull;
360366

361367
dos_header = (PIMAGE_DOS_HEADER)data;
@@ -410,6 +416,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
410416
result->numModules = 0;
411417
result->modules = NULL;
412418
result->initialized = 0;
419+
result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0;
413420
result->loadLibrary = loadLibrary;
414421
result->getProcAddress = getProcAddress;
415422
result->freeLibrary = freeLibrary;
@@ -434,7 +441,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
434441
// adjust base address of imported data
435442
locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase);
436443
if (locationDelta != 0) {
437-
PerformBaseRelocation(result, locationDelta);
444+
result->isRelocated = PerformBaseRelocation(result, locationDelta);
445+
} else {
446+
result->isRelocated = 1;
438447
}
439448

440449
// load required dlls and adjust function table of imports
@@ -451,14 +460,20 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
451460

452461
// get entry point of loaded library
453462
if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) {
454-
DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint);
455-
// notify library about attaching to process
456-
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
457-
if (!successfull) {
458-
SetLastError(ERROR_DLL_INIT_FAILED);
459-
goto error;
463+
if (result->isDLL) {
464+
DllEntryProc DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint);
465+
// notify library about attaching to process
466+
successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
467+
if (!successfull) {
468+
SetLastError(ERROR_DLL_INIT_FAILED);
469+
goto error;
470+
}
471+
result->initialized = 1;
472+
} else {
473+
result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint);
460474
}
461-
result->initialized = 1;
475+
} else {
476+
result->exeEntry = NULL;
462477
}
463478

464479
return (HMEMORYMODULE)result;
@@ -549,6 +564,17 @@ void MemoryFreeLibrary(HMEMORYMODULE mod)
549564
}
550565
}
551566

567+
int MemoryCallEntryPoint(HMEMORYMODULE mod)
568+
{
569+
PMEMORYMODULE module = (PMEMORYMODULE)mod;
570+
571+
if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) {
572+
return -1;
573+
}
574+
575+
return module->exeEntry();
576+
}
577+
552578
#define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
553579

554580
HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type)

MemoryModule.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
4444
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
4545

4646
/**
47-
* Load DLL from memory location.
47+
* Load EXE/DLL from memory location.
4848
*
4949
* All dependencies are resolved using default LoadLibrary/GetProcAddress
5050
* calls through the Windows API.
5151
*/
5252
HMEMORYMODULE MemoryLoadLibrary(const void *);
5353

5454
/**
55-
* Load DLL from memory location using custom dependency resolvers.
55+
* Load EXE/DLL from memory location using custom dependency resolvers.
5656
*
5757
* Dependencies will be resolved using passed callback methods.
5858
*/
@@ -68,10 +68,23 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *,
6868
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
6969

7070
/**
71-
* Free previously loaded DLL.
71+
* Free previously loaded EXE/DLL.
7272
*/
7373
void MemoryFreeLibrary(HMEMORYMODULE);
7474

75+
/**
76+
* Execute entry point (EXE only). The entry point can only be executed
77+
* if the EXE has been loaded to the correct base address or it could
78+
* be relocated (i.e. relocation information have not been stripped by
79+
* the linker).
80+
*
81+
* Important: calling this function will not return, i.e. once the loaded
82+
* EXE finished running, the process will terminate.
83+
*
84+
* Returns a negative value if the entry point could not be executed.
85+
*/
86+
int MemoryCallEntryPoint(HMEMORYMODULE);
87+
7588
/**
7689
* Find the location of a resource with the specified type and name.
7790
*/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#define WIN32_LEAN_AND_MEAN
2+
3+
#include <windows.h>
4+
#include <tchar.h>
5+
#include <stdio.h>
6+
#include <malloc.h>
7+
8+
#include "../../MemoryModule.h"
9+
10+
#define EXE_FILE TEXT("DllLoader.exe")
11+
12+
int RunFromMemory(void)
13+
{
14+
FILE *fp;
15+
unsigned char *data=NULL;
16+
size_t size;
17+
HMEMORYMODULE handle;
18+
int result = -1;
19+
20+
fp = _tfopen(EXE_FILE, _T("rb"));
21+
if (fp == NULL)
22+
{
23+
_tprintf(_T("Can't open executable \"%s\"."), EXE_FILE);
24+
goto exit;
25+
}
26+
27+
fseek(fp, 0, SEEK_END);
28+
size = ftell(fp);
29+
data = (unsigned char *)malloc(size);
30+
fseek(fp, 0, SEEK_SET);
31+
fread(data, 1, size, fp);
32+
fclose(fp);
33+
34+
handle = MemoryLoadLibrary(data);
35+
if (handle == NULL)
36+
{
37+
_tprintf(_T("Can't load library from memory.\n"));
38+
goto exit;
39+
}
40+
41+
result = MemoryCallEntryPoint(handle);
42+
if (result < 0) {
43+
_tprintf(_T("Could not execute entry point: %d\n"), result);
44+
}
45+
MemoryFreeLibrary(handle);
46+
47+
exit:
48+
if (data)
49+
free(data);
50+
return result;
51+
}
52+
53+
int main(int argc, char* argv[])
54+
{
55+
return RunFromMemory();
56+
}
57+

example/DllLoader/Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,15 @@ CFLAGS += -DUNICODE -D_UNICODE
2222
endif
2323

2424
OBJ = DllLoader.o ../../MemoryModule.o
25+
OBJ_LOADER = DllLoaderLoader.o ../../MemoryModule.o
26+
27+
all: DllLoader.exe DllLoaderLoader.exe
2528

2629
DllLoader.exe: $(OBJ)
27-
$(CC) $(LDFLAGS) -o DllLoader.exe $(OBJ)
30+
$(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o DllLoader.exe $(OBJ)
31+
32+
DllLoaderLoader.exe: $(OBJ_LOADER)
33+
$(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x10000000 -o DllLoaderLoader.exe $(OBJ_LOADER)
2834

2935
%.o: %.cpp
3036
$(CXX) $(CFLAGS) -c $<
@@ -33,4 +39,4 @@ DllLoader.exe: $(OBJ)
3339
$(CC) $(CFLAGS) -c $<
3440

3541
clean:
36-
$(RM) -rf $(OBJ) DllLoader.exe
42+
$(RM) -rf $(OBJ) $(OBJ_LOADER) DllLoader.exe DllLoaderLoader.exe

0 commit comments

Comments
 (0)