diff --git a/MemoryModule.c b/MemoryModule.c index a7eda08..fcb0081 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -49,20 +49,24 @@ #include "MemoryModule.h" +typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); +typedef int (WINAPI *ExeEntryProc)(void); + typedef struct { PIMAGE_NT_HEADERS headers; unsigned char *codeBase; HCUSTOMMODULE *modules; int numModules; int initialized; + int isDLL; + int isRelocated; CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; void *userdata; + ExeEntryProc exeEntry; } MEMORYMODULE, *PMEMORYMODULE; -typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); - #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #ifdef DEBUG_OUTPUT @@ -202,11 +206,12 @@ ExecuteTLS(PMEMORYMODULE module) } } -static void +static int PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { DWORD i; unsigned char *codeBase = module->codeBase; + int result = 0; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); if (directory->Size > 0) { @@ -254,7 +259,9 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) // advance to next relocation block relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } + result = 1; } + return result; } static int @@ -355,7 +362,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; SIZE_T locationDelta; - DllEntryProc DllEntry; BOOL successfull; dos_header = (PIMAGE_DOS_HEADER)data; @@ -410,6 +416,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->numModules = 0; result->modules = NULL; result->initialized = 0; + result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; result->freeLibrary = freeLibrary; @@ -434,7 +441,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { - PerformBaseRelocation(result, locationDelta); + result->isRelocated = PerformBaseRelocation(result, locationDelta); + } else { + result->isRelocated = 1; } // load required dlls and adjust function table of imports @@ -451,14 +460,20 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { - DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); - // notify library about attaching to process - successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); - if (!successfull) { - SetLastError(ERROR_DLL_INIT_FAILED); - goto error; + if (result->isDLL) { + DllEntryProc DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); + // notify library about attaching to process + successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); + if (!successfull) { + SetLastError(ERROR_DLL_INIT_FAILED); + goto error; + } + result->initialized = 1; + } else { + result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); } - result->initialized = 1; + } else { + result->exeEntry = NULL; } return (HMEMORYMODULE)result; @@ -549,6 +564,17 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) } } +int MemoryCallEntryPoint(HMEMORYMODULE mod) +{ + PMEMORYMODULE module = (PMEMORYMODULE)mod; + + if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) { + return -1; + } + + return module->exeEntry(); +} + #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) diff --git a/MemoryModule.h b/MemoryModule.h index adeacb6..e2fa2d3 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -44,7 +44,7 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); /** - * Load DLL from memory location. + * Load EXE/DLL from memory location. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. @@ -52,7 +52,7 @@ typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); HMEMORYMODULE MemoryLoadLibrary(const void *); /** - * Load DLL from memory location using custom dependency resolvers. + * Load EXE/DLL from memory location using custom dependency resolvers. * * Dependencies will be resolved using passed callback methods. */ @@ -68,10 +68,23 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *, FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); /** - * Free previously loaded DLL. + * Free previously loaded EXE/DLL. */ void MemoryFreeLibrary(HMEMORYMODULE); +/** + * Execute entry point (EXE only). The entry point can only be executed + * if the EXE has been loaded to the correct base address or it could + * be relocated (i.e. relocation information have not been stripped by + * the linker). + * + * Important: calling this function will not return, i.e. once the loaded + * EXE finished running, the process will terminate. + * + * Returns a negative value if the entry point could not be executed. + */ +int MemoryCallEntryPoint(HMEMORYMODULE); + /** * Find the location of a resource with the specified type and name. */ diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp new file mode 100644 index 0000000..e49979e --- /dev/null +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -0,0 +1,57 @@ +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include "../../MemoryModule.h" + +#define EXE_FILE TEXT("DllLoader.exe") + +int RunFromMemory(void) +{ + FILE *fp; + unsigned char *data=NULL; + size_t size; + HMEMORYMODULE handle; + int result = -1; + + fp = _tfopen(EXE_FILE, _T("rb")); + if (fp == NULL) + { + _tprintf(_T("Can't open executable \"%s\"."), EXE_FILE); + goto exit; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + data = (unsigned char *)malloc(size); + fseek(fp, 0, SEEK_SET); + fread(data, 1, size, fp); + fclose(fp); + + handle = MemoryLoadLibrary(data); + if (handle == NULL) + { + _tprintf(_T("Can't load library from memory.\n")); + goto exit; + } + + result = MemoryCallEntryPoint(handle); + if (result < 0) { + _tprintf(_T("Could not execute entry point: %d\n"), result); + } + MemoryFreeLibrary(handle); + +exit: + if (data) + free(data); + return result; +} + +int main(int argc, char* argv[]) +{ + return RunFromMemory(); +} + diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 84c8c68..65b5382 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -22,9 +22,15 @@ CFLAGS += -DUNICODE -D_UNICODE endif OBJ = DllLoader.o ../../MemoryModule.o +OBJ_LOADER = DllLoaderLoader.o ../../MemoryModule.o + +all: DllLoader.exe DllLoaderLoader.exe DllLoader.exe: $(OBJ) - $(CC) $(LDFLAGS) -o DllLoader.exe $(OBJ) + $(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o DllLoader.exe $(OBJ) + +DllLoaderLoader.exe: $(OBJ_LOADER) + $(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x10000000 -o DllLoaderLoader.exe $(OBJ_LOADER) %.o: %.cpp $(CXX) $(CFLAGS) -c $< @@ -33,4 +39,4 @@ DllLoader.exe: $(OBJ) $(CC) $(CFLAGS) -c $< clean: - $(RM) -rf $(OBJ) DllLoader.exe + $(RM) -rf $(OBJ) $(OBJ_LOADER) DllLoader.exe DllLoaderLoader.exe