From 8a7f64ea3a783151f24493aa7be2b5005c2e4009 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:27:43 +0100 Subject: [PATCH 001/123] Use lowercase filename to support compilation on Linux using MinGW. --- MemoryModule.c | 2 +- MemoryModule.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 9c0cd02..344a6bd 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -35,7 +35,7 @@ #define POINTER_TYPE DWORD #endif -#include +#include #include #ifdef DEBUG_OUTPUT #include diff --git a/MemoryModule.h b/MemoryModule.h index 1757c7e..9b7a3e5 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -27,7 +27,7 @@ #ifndef __MEMORY_MODULE_HEADER #define __MEMORY_MODULE_HEADER -#include +#include typedef void *HMEMORYMODULE; From 0f6bdc7c16dd788bb6f40006d6b0676099c81ae2 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:30:25 +0100 Subject: [PATCH 002/123] Fixed potential resource leak of library handle (found by Coverity, CID 989315) --- MemoryModule.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 344a6bd..8541060 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -257,6 +257,7 @@ BuildImportTable(PMEMORYMODULE module) module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); if (module->modules == NULL) { + FreeLibrary(handle); result = 0; break; } @@ -284,6 +285,7 @@ BuildImportTable(PMEMORYMODULE module) } if (!result) { + FreeLibrary(handle); break; } } From 6a5d3d420eaac495ad12d4d64bda2d78d468846f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:32:42 +0100 Subject: [PATCH 003/123] Fixed potential memory leak if "realloc" fails. --- MemoryModule.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 8541060..a19aa7a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -239,6 +239,7 @@ BuildImportTable(PMEMORYMODULE module) { int result=1; unsigned char *codeBase = module->codeBase; + HMODULE * tmp; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); if (directory->Size > 0) { @@ -255,12 +256,13 @@ BuildImportTable(PMEMORYMODULE module) break; } - module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); - if (module->modules == NULL) { + tmp = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); + if (tmp == NULL) { FreeLibrary(handle); result = 0; break; } + module->modules = tmp; module->modules[module->numModules++] = handle; if (importDesc->OriginalFirstThunk) { From 2b846b727a64493c6242a9d83f5b47a47b4df0d1 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:36:27 +0100 Subject: [PATCH 004/123] Removed logically dead code (found by Coverity, CID 989316). --- MemoryModule.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index a19aa7a..fc10cb7 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -389,13 +389,6 @@ HMEMORYMODULE MemoryLoadLibrary(const void *data) // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); - if (DllEntry == 0) { -#if DEBUG_OUTPUT - OutputDebugString("Library has no entry point.\n"); -#endif - goto error; - } - // notify library about attaching to process successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); if (!successfull) { From c01e010793239f6c77f6d24823f7f159d5101c7e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:40:27 +0100 Subject: [PATCH 005/123] Reserve and commit memory in one step (fixes error found by Coverity, CID 989314). --- MemoryModule.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index fc10cb7..7ca2a3e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -323,16 +323,18 @@ HMEMORYMODULE MemoryLoadLibrary(const void *data) } // reserve memory for image of library + // XXX: is it correct to commit the complete memory region at once? + // calling DllEntry raises an exception if we don't... code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), old_header->OptionalHeader.SizeOfImage, - MEM_RESERVE, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { // try to allocate memory at arbitrary position code = (unsigned char *)VirtualAlloc(NULL, old_header->OptionalHeader.SizeOfImage, - MEM_RESERVE, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { #if DEBUG_OUTPUT @@ -348,13 +350,6 @@ HMEMORYMODULE MemoryLoadLibrary(const void *data) result->modules = NULL; result->initialized = 0; - // XXX: is it correct to commit the complete memory region at once? - // calling DllEntry raises an exception if we don't... - VirtualAlloc(code, - old_header->OptionalHeader.SizeOfImage, - MEM_COMMIT, - PAGE_READWRITE); - // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, From d9a3b238301acf8a81547606774580a6b3f481b0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 00:46:11 +0100 Subject: [PATCH 006/123] Use \LoadLibraryA" to fix potential error when compiling with UNICODE being defined (github issue #6) --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7ca2a3e..e882534 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -247,7 +247,7 @@ BuildImportTable(PMEMORYMODULE module) for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { POINTER_TYPE *thunkRef; FARPROC *funcRef; - HMODULE handle = LoadLibrary((LPCSTR) (codeBase + importDesc->Name)); + HMODULE handle = LoadLibraryA((LPCSTR) (codeBase + importDesc->Name)); if (handle == NULL) { #if DEBUG_OUTPUT OutputLastError("Can't load library"); From 1cc307a883c5f93a5586d208f92587af17eb8bad Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 01:02:09 +0100 Subject: [PATCH 007/123] Support compilation using MinGW on Linux. --- example/DllLoader/Makefile | 13 +++++++++++-- example/SampleDLL/Makefile | 17 ++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 182118d..55ff822 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -1,6 +1,15 @@ +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) +CC = i686-w64-mingw32-gcc +CXX = i686-w64-mingw32-g++ +LINK = i686-w64-mingw32-ld +else CC = gcc -CPP = g++ +CXX = g++ LINK = ld +endif + CFLAGS = -Wall -g LDFLAGS = @@ -10,7 +19,7 @@ DllLoader.exe: $(OBJ) $(CC) $(LDFLAGS) -o DllLoader.exe $(OBJ) %.o: %.cpp - $(CPP) $(CFLAGS) -c $< + $(CXX) $(CFLAGS) -c $< %.o: %.cc $(CC) $(CFLAGS) -c $< diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index 86c82d1..cd58a20 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -1,11 +1,22 @@ -CC = g++ +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) +CC = i686-w64-mingw32-gcc +CXX = i686-w64-mingw32-g++ +LINK = i686-w64-mingw32-ld +else +CC = gcc +CXX = g++ +LINK = ld +endif + CFLAGS = -Wall -g -DSAMPLEDLL_EXPORTS LDFLAGS = -shared OBJ = SampleDLL.o SampleDLL.dll: $(OBJ) - $(CC) $(LDFLAGS) -o SampleDLL.dll $(OBJ) + $(LINK) $(LDFLAGS) -o SampleDLL.dll $(OBJ) %.o: %.cpp - $(CC) $(CFLAGS) -c $< + $(CXX) $(CFLAGS) -c $< From 257a77c0e9f9d2392ff6a4da4d79ca46156ea5bf Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 01:07:52 +0100 Subject: [PATCH 008/123] Ignore more built files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5761abc..8cc774f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.o +*.obj +*.exe From c23d0642d6612a33da5c0e296c71dd617dbed40d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 01:09:49 +0100 Subject: [PATCH 009/123] Added/updated makefiles to build all sample files using one "make". --- Makefile | 17 +++++++++++++++++ example/DllLoader/Makefile | 4 ++++ example/Makefile | 17 +++++++++++++++++ example/SampleDLL/Makefile | 4 ++++ 4 files changed, 42 insertions(+) create mode 100644 Makefile create mode 100644 example/Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d41c588 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +SUBDIRS = example + +.PHONY: subdirs $(SUBDIRS) + +subdirs: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +CLEANDIRS = $(SUBDIRS:%=clean-%) + +clean: $(CLEANDIRS) +$(CLEANDIRS): + $(MAKE) -C $(@:clean-%=%) clean + +.PHONY: subdirs $(INSTALLDIRS) +.PHONY: clean diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 55ff822..2a67dd2 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -10,6 +10,7 @@ CXX = g++ LINK = ld endif +RM = rm CFLAGS = -Wall -g LDFLAGS = @@ -23,3 +24,6 @@ DllLoader.exe: $(OBJ) %.o: %.cc $(CC) $(CFLAGS) -c $< + +clean: + $(RM) -rf $(OBJ) DllLoader.exe diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..2852993 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,17 @@ +SUBDIRS = DllLoader SampleDLL + +.PHONY: subdirs $(SUBDIRS) + +subdirs: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +CLEANDIRS = $(SUBDIRS:%=clean-%) + +clean: $(CLEANDIRS) +$(CLEANDIRS): + $(MAKE) -C $(@:clean-%=%) clean + +.PHONY: subdirs $(INSTALLDIRS) +.PHONY: clean diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index cd58a20..14ab428 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -10,6 +10,7 @@ CXX = g++ LINK = ld endif +RM = rm CFLAGS = -Wall -g -DSAMPLEDLL_EXPORTS LDFLAGS = -shared @@ -20,3 +21,6 @@ SampleDLL.dll: $(OBJ) %.o: %.cpp $(CXX) $(CFLAGS) -c $< + +clean: + $(RM) -rf $(OBJ) SampleDLL.dll From 7ffe0e2b6666341eae86fdc9dd3c8e266c622c74 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 01:14:15 +0100 Subject: [PATCH 010/123] Support passing the platform to build for (e.g. "make PLATFORM=x86_64" for 64bit build), defaults to i686). --- example/DllLoader/Makefile | 9 ++++++--- example/SampleDLL/Makefile | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 2a67dd2..35c3d8f 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -1,9 +1,12 @@ UNAME := $(shell uname) ifeq ($(UNAME), Linux) -CC = i686-w64-mingw32-gcc -CXX = i686-w64-mingw32-g++ -LINK = i686-w64-mingw32-ld +ifndef PLATFORM +PLATFORM = i686 +endif +CC = $(PLATFORM)-w64-mingw32-gcc +CXX = $(PLATFORM)-w64-mingw32-g++ +LINK = $(PLATFORM)-w64-mingw32-ld else CC = gcc CXX = g++ diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index 14ab428..ec4a04b 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -1,9 +1,12 @@ UNAME := $(shell uname) ifeq ($(UNAME), Linux) -CC = i686-w64-mingw32-gcc -CXX = i686-w64-mingw32-g++ -LINK = i686-w64-mingw32-ld +ifndef PLATFORM +PLATFORM = i686 +endif +CC = $(PLATFORM)-w64-mingw32-gcc +CXX = $(PLATFORM)-w64-mingw32-g++ +LINK = $(PLATFORM)-w64-mingw32-ld else CC = gcc CXX = g++ From 0c19658eb12f3cf6361424c688a6f57bf8ae6198 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Mar 2013 01:16:14 +0100 Subject: [PATCH 011/123] Bump year in copyright --- MemoryModule.c | 4 ++-- MemoryModule.h | 4 ++-- doc/readme.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index e882534..d2a9f7e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2012 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2012 + * Portions created by Joachim Bauch are Copyright (C) 2004-2013 * Joachim Bauch. All Rights Reserved. * */ diff --git a/MemoryModule.h b/MemoryModule.h index 9b7a3e5..78e7a36 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2012 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2012 + * Portions created by Joachim Bauch are Copyright (C) 2004-2013 * Joachim Bauch. All Rights Reserved. * */ diff --git a/doc/readme.txt b/doc/readme.txt index c406ccd..e528b7a 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -543,4 +543,4 @@ Copyright ========== The MemoryModule library and this tutorial are -Copyright (c) 2004-2012 by Joachim Bauch. +Copyright (c) 2004-2013 by Joachim Bauch. From 44ae72da043ce6c519ba9b9194502a0363c13349 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 8 Mar 2013 23:57:07 +0100 Subject: [PATCH 012/123] Added API to delegate resolving of dependencies to custom methods (github issue #5, inspired by pull request #9) --- MemoryModule.c | 55 +++++++++++++++++++++++++++++++++++++++++--------- MemoryModule.h | 31 +++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index d2a9f7e..96020f4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -51,9 +51,13 @@ typedef struct { PIMAGE_NT_HEADERS headers; unsigned char *codeBase; - HMODULE *modules; + HCUSTOMMODULE *modules; int numModules; int initialized; + CustomLoadLibraryFunc loadLibrary; + CustomGetProcAddressFunc getProcAddress; + CustomFreeLibraryFunc freeLibrary; + void *userdata; } MEMORYMODULE, *PMEMORYMODULE; typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); @@ -239,7 +243,7 @@ BuildImportTable(PMEMORYMODULE module) { int result=1; unsigned char *codeBase = module->codeBase; - HMODULE * tmp; + HCUSTOMMODULE *tmp; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); if (directory->Size > 0) { @@ -247,7 +251,7 @@ BuildImportTable(PMEMORYMODULE module) for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { POINTER_TYPE *thunkRef; FARPROC *funcRef; - HMODULE handle = LoadLibraryA((LPCSTR) (codeBase + importDesc->Name)); + HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { #if DEBUG_OUTPUT OutputLastError("Can't load library"); @@ -256,9 +260,9 @@ BuildImportTable(PMEMORYMODULE module) break; } - tmp = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); + tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { - FreeLibrary(handle); + module->freeLibrary(handle, module->userdata); result = 0; break; } @@ -275,10 +279,10 @@ BuildImportTable(PMEMORYMODULE module) } for (; *thunkRef; thunkRef++, funcRef++) { if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { - *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); + *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); } else { PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); - *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name); + *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); } if (*funcRef == 0) { result = 0; @@ -287,7 +291,7 @@ BuildImportTable(PMEMORYMODULE module) } if (!result) { - FreeLibrary(handle); + module->freeLibrary(handle, module->userdata); break; } } @@ -296,7 +300,36 @@ BuildImportTable(PMEMORYMODULE module) return result; } +static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) +{ + HMODULE result = LoadLibraryA(filename); + if (result == NULL) { + return NULL; + } + + return (HCUSTOMMODULE) result; +} + +static FARPROC _GetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) +{ + return (FARPROC) GetProcAddress((HMODULE) module, name); +} + +static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) +{ + FreeLibrary((HMODULE) module); +} + HMEMORYMODULE MemoryLoadLibrary(const void *data) +{ + return MemoryLoadLibraryEx(data, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL); +} + +HMEMORYMODULE MemoryLoadLibraryEx(const void *data, + CustomLoadLibraryFunc loadLibrary, + CustomGetProcAddressFunc getProcAddress, + CustomFreeLibraryFunc freeLibrary, + void *userdata) { PMEMORYMODULE result; PIMAGE_DOS_HEADER dos_header; @@ -349,6 +382,10 @@ HMEMORYMODULE MemoryLoadLibrary(const void *data) result->numModules = 0; result->modules = NULL; result->initialized = 0; + result->loadLibrary = loadLibrary; + result->getProcAddress = getProcAddress; + result->freeLibrary = freeLibrary; + result->userdata = userdata; // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, @@ -463,7 +500,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) // free previously opened libraries for (i=0; inumModules; i++) { if (module->modules[i] != INVALID_HANDLE_VALUE) { - FreeLibrary(module->modules[i]); + module->freeLibrary(module->modules[i], module->userdata); } } diff --git a/MemoryModule.h b/MemoryModule.h index 78e7a36..fd5a913 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -31,14 +31,43 @@ typedef void *HMEMORYMODULE; +typedef void *HCUSTOMMODULE; + #ifdef __cplusplus extern "C" { #endif +typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); +typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); +typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); + +/** + * Load DLL from memory location. + * + * All dependencies are resolved using default LoadLibrary/GetProcAddress + * calls through the Windows API. + */ HMEMORYMODULE MemoryLoadLibrary(const void *); -FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); +/** + * Load DLL from memory location using custom dependency resolvers. + * + * Dependencies will be resolved using passed callback methods. + */ +HMEMORYMODULE MemoryLoadLibraryEx(const void *, + CustomLoadLibraryFunc, + CustomGetProcAddressFunc, + CustomFreeLibraryFunc, + void *); + +/** + * Get address of exported method. + */ +FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); +/** + * Free previously loaded DLL. + */ void MemoryFreeLibrary(HMEMORYMODULE); #ifdef __cplusplus From 6f4f2bdd5bee729598e5e3c28b973459342ee72f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 8 Mar 2013 23:58:49 +0100 Subject: [PATCH 013/123] Handle OOM case for result object. --- MemoryModule.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 96020f4..1b3af1f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -378,6 +378,14 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); + if (result == NULL) { +#if DEBUG_OUTPUT + OutputLastError("Can't reserve memory"); +#endif + VirtualFree(code, 0, MEM_RELEASE); + return NULL; + } + result->codeBase = code; result->numModules = 0; result->modules = NULL; From f7a34964fff931fcb9fccb6d24294eadb8199ac5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 9 Mar 2013 00:03:04 +0100 Subject: [PATCH 014/123] LoadLibrary returns NULL if loading failed --- example/DllLoader/DllLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index d849b46..c34cf6f 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -14,7 +14,7 @@ void LoadFromFile(void) { addNumberProc addNumber; HINSTANCE handle = LoadLibrary(DLL_FILE); - if (handle == INVALID_HANDLE_VALUE) + if (handle == NULL) return; addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); From c4e8de7d4facafaeb620692e5d7a1f6ce38ff90c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 9 Mar 2013 00:35:50 +0100 Subject: [PATCH 015/123] Use "SetLastError" to flag errors to caller while loading. --- MemoryModule.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 1b3af1f..4690a41 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -253,9 +253,7 @@ BuildImportTable(PMEMORYMODULE module) FARPROC *funcRef; HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { -#if DEBUG_OUTPUT - OutputLastError("Can't load library"); -#endif + SetLastError(ERROR_MOD_NOT_FOUND); result = 0; break; } @@ -263,6 +261,7 @@ BuildImportTable(PMEMORYMODULE module) tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_OUTOFMEMORY); result = 0; break; } @@ -292,6 +291,7 @@ BuildImportTable(PMEMORYMODULE module) if (!result) { module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_PROC_NOT_FOUND); break; } } @@ -341,17 +341,13 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { -#if DEBUG_OUTPUT - OutputDebugString("Not a valid executable file.\n"); -#endif + SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; if (old_header->Signature != IMAGE_NT_SIGNATURE) { -#if DEBUG_OUTPUT - OutputDebugString("No PE header found.\n"); -#endif + SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } @@ -370,18 +366,14 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { -#if DEBUG_OUTPUT - OutputLastError("Can't reserve memory"); -#endif + SetLastError(ERROR_OUTOFMEMORY); return NULL; } } result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); if (result == NULL) { -#if DEBUG_OUTPUT - OutputLastError("Can't reserve memory"); -#endif + SetLastError(ERROR_OUTOFMEMORY); VirtualFree(code, 0, MEM_RELEASE); return NULL; } @@ -432,9 +424,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // notify library about attaching to process successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); if (!successfull) { -#if DEBUG_OUTPUT - OutputDebugString("Can't attach library.\n"); -#endif + SetLastError(ERROR_DLL_INIT_FAILED); goto error; } result->initialized = 1; From 536a5978360eb967c02ed69118da773d8427d1cb Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 9 Mar 2013 00:37:11 +0100 Subject: [PATCH 016/123] Use "SetLastError" for errors in "GetProcAddress". --- MemoryModule.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 4690a41..8b81da4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -448,12 +448,14 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { // no export table found + SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { // DLL doesn't export anything + SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } @@ -469,11 +471,13 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) if (idx == -1) { // exported symbol not found + SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } if ((DWORD)idx > exports->NumberOfFunctions) { // name <-> ordinal number don't match + SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } From f210f677712996fd32cb2e50c9dd606d2cfa1e26 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 9 Mar 2013 00:39:08 +0100 Subject: [PATCH 017/123] Check against NULL, not INVALID_HANDLE_VALUE. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 8b81da4..c32b128 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -501,7 +501,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) if (module->modules != NULL) { // free previously opened libraries for (i=0; inumModules; i++) { - if (module->modules[i] != INVALID_HANDLE_VALUE) { + if (module->modules[i] != NULL) { module->freeLibrary(module->modules[i], module->userdata); } } From a199afce7c85f2b2c48499c5c60c8d8d46ee54c8 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 9 Mar 2013 00:42:29 +0100 Subject: [PATCH 018/123] Use spaces instead of tabs - sorry for the noise. --- MemoryModule.c | 732 ++++++++++++++++---------------- example/DllLoader/DllLoader.cpp | 80 ++-- example/SampleDLL/SampleDLL.cpp | 2 +- 3 files changed, 407 insertions(+), 407 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index c32b128..9930965 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -49,15 +49,15 @@ #include "MemoryModule.h" typedef struct { - PIMAGE_NT_HEADERS headers; - unsigned char *codeBase; - HCUSTOMMODULE *modules; - int numModules; - int initialized; - CustomLoadLibraryFunc loadLibrary; - CustomGetProcAddressFunc getProcAddress; - CustomFreeLibraryFunc freeLibrary; - void *userdata; + PIMAGE_NT_HEADERS headers; + unsigned char *codeBase; + HCUSTOMMODULE *modules; + int numModules; + int initialized; + CustomLoadLibraryFunc loadLibrary; + CustomGetProcAddressFunc getProcAddress; + CustomFreeLibraryFunc freeLibrary; + void *userdata; } MEMORYMODULE, *PMEMORYMODULE; typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); @@ -68,116 +68,116 @@ typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID static void OutputLastError(const char *msg) { - LPVOID tmp; - char *tmpmsg; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); - tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); - sprintf(tmpmsg, "%s: %s", msg, tmp); - OutputDebugString(tmpmsg); - LocalFree(tmpmsg); - LocalFree(tmp); + LPVOID tmp; + char *tmpmsg; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); + tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); + sprintf(tmpmsg, "%s: %s", msg, tmp); + OutputDebugString(tmpmsg); + LocalFree(tmpmsg); + LocalFree(tmp); } #endif static void CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { - int i, size; - unsigned char *codeBase = module->codeBase; - unsigned char *dest; - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); - for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { - if (section->SizeOfRawData == 0) { - // section doesn't contain data in the dll itself, but may define - // uninitialized data - size = old_headers->OptionalHeader.SectionAlignment; - if (size > 0) { - dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, - size, - MEM_COMMIT, - PAGE_READWRITE); - - section->Misc.PhysicalAddress = (POINTER_TYPE)dest; - memset(dest, 0, size); - } - - // section is empty - continue; - } - - // commit memory block and copy data from dll - dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, - section->SizeOfRawData, - MEM_COMMIT, - PAGE_READWRITE); - memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (POINTER_TYPE)dest; - } + int i, size; + unsigned char *codeBase = module->codeBase; + unsigned char *dest; + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { + if (section->SizeOfRawData == 0) { + // section doesn't contain data in the dll itself, but may define + // uninitialized data + size = old_headers->OptionalHeader.SectionAlignment; + if (size > 0) { + dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, + size, + MEM_COMMIT, + PAGE_READWRITE); + + section->Misc.PhysicalAddress = (POINTER_TYPE)dest; + memset(dest, 0, size); + } + + // section is empty + continue; + } + + // commit memory block and copy data from dll + dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, + section->SizeOfRawData, + MEM_COMMIT, + PAGE_READWRITE); + memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); + section->Misc.PhysicalAddress = (POINTER_TYPE)dest; + } } // Protection flags for memory pages (Executable, Readable, Writeable) static int ProtectionFlags[2][2][2] = { - { - // not executable - {PAGE_NOACCESS, PAGE_WRITECOPY}, - {PAGE_READONLY, PAGE_READWRITE}, - }, { - // executable - {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, - {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, - }, + { + // not executable + {PAGE_NOACCESS, PAGE_WRITECOPY}, + {PAGE_READONLY, PAGE_READWRITE}, + }, { + // executable + {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, + {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, + }, }; static void FinalizeSections(PMEMORYMODULE module) { - int i; - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + int i; + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 - POINTER_TYPE imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); + POINTER_TYPE imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else - #define imageOffset 0 + #define imageOffset 0 #endif - - // loop through all sections and change access flags - for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { - DWORD protect, oldProtect, size; - int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; - int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; - int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; - - if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { - // section is not needed any more and can safely be freed - VirtualFree((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); - continue; - } - - // determine protection flags based on characteristics - protect = ProtectionFlags[executable][readable][writeable]; - if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { - protect |= PAGE_NOCACHE; - } - - // determine size of region - size = section->SizeOfRawData; - if (size == 0) { - if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfInitializedData; - } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfUninitializedData; - } - } - - if (size > 0) { - // change memory access flags - if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) + + // loop through all sections and change access flags + for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { + DWORD protect, oldProtect, size; + int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; + int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; + int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; + + if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { + // section is not needed any more and can safely be freed + VirtualFree((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); + continue; + } + + // determine protection flags based on characteristics + protect = ProtectionFlags[executable][readable][writeable]; + if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { + protect |= PAGE_NOCACHE; + } + + // determine size of region + size = section->SizeOfRawData; + if (size == 0) { + if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfInitializedData; + } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfUninitializedData; + } + } + + if (size > 0) { + // change memory access flags + if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) #ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") + OutputLastError("Error protecting memory page") #endif - ; - } - } + ; + } + } #ifndef _WIN64 #undef imageOffset #endif @@ -186,118 +186,118 @@ FinalizeSections(PMEMORYMODULE module) static void PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { - DWORD i; - unsigned char *codeBase = module->codeBase; - - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); - if (directory->Size > 0) { - PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); - for (; relocation->VirtualAddress > 0; ) { - unsigned char *dest = codeBase + relocation->VirtualAddress; - unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); - for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { - DWORD *patchAddrHL; + DWORD i; + unsigned char *codeBase = module->codeBase; + + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); + if (directory->Size > 0) { + PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); + for (; relocation->VirtualAddress > 0; ) { + unsigned char *dest = codeBase + relocation->VirtualAddress; + unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); + for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { + DWORD *patchAddrHL; #ifdef _WIN64 - ULONGLONG *patchAddr64; + ULONGLONG *patchAddr64; #endif - int type, offset; - - // the upper 4 bits define the type of relocation - type = *relInfo >> 12; - // the lower 12 bits define the offset - offset = *relInfo & 0xfff; - - switch (type) - { - case IMAGE_REL_BASED_ABSOLUTE: - // skip relocation - break; - - case IMAGE_REL_BASED_HIGHLOW: - // change complete 32 bit address - patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += delta; - break; - + int type, offset; + + // the upper 4 bits define the type of relocation + type = *relInfo >> 12; + // the lower 12 bits define the offset + offset = *relInfo & 0xfff; + + switch (type) + { + case IMAGE_REL_BASED_ABSOLUTE: + // skip relocation + break; + + case IMAGE_REL_BASED_HIGHLOW: + // change complete 32 bit address + patchAddrHL = (DWORD *) (dest + offset); + *patchAddrHL += delta; + break; + #ifdef _WIN64 - case IMAGE_REL_BASED_DIR64: - patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += delta; - break; + case IMAGE_REL_BASED_DIR64: + patchAddr64 = (ULONGLONG *) (dest + offset); + *patchAddr64 += delta; + break; #endif - default: - //printf("Unknown relocation: %d\n", type); - break; - } - } + default: + //printf("Unknown relocation: %d\n", type); + break; + } + } - // advance to next relocation block - relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); - } - } + // advance to next relocation block + relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); + } + } } static int BuildImportTable(PMEMORYMODULE module) { - int result=1; - unsigned char *codeBase = module->codeBase; - HCUSTOMMODULE *tmp; - - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (directory->Size > 0) { - PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); - for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - POINTER_TYPE *thunkRef; - FARPROC *funcRef; - HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); - if (handle == NULL) { - SetLastError(ERROR_MOD_NOT_FOUND); - result = 0; - break; - } - - tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); - if (tmp == NULL) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_OUTOFMEMORY); - result = 0; - break; - } - module->modules = tmp; - - module->modules[module->numModules++] = handle; - if (importDesc->OriginalFirstThunk) { - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); - } else { - // no hint table - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); - } - for (; *thunkRef; thunkRef++, funcRef++) { - if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { - *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); - } else { - PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); - *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); - } - if (*funcRef == 0) { - result = 0; - break; - } - } - - if (!result) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_PROC_NOT_FOUND); - break; - } - } - } - - return result; + int result=1; + unsigned char *codeBase = module->codeBase; + HCUSTOMMODULE *tmp; + + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (directory->Size > 0) { + PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); + for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { + POINTER_TYPE *thunkRef; + FARPROC *funcRef; + HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); + if (handle == NULL) { + SetLastError(ERROR_MOD_NOT_FOUND); + result = 0; + break; + } + + tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); + if (tmp == NULL) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_OUTOFMEMORY); + result = 0; + break; + } + module->modules = tmp; + + module->modules[module->numModules++] = handle; + if (importDesc->OriginalFirstThunk) { + thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } else { + // no hint table + thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } + for (; *thunkRef; thunkRef++, funcRef++) { + if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { + *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); + } else { + PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); + *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); + } + if (*funcRef == 0) { + result = 0; + break; + } + } + + if (!result) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_PROC_NOT_FOUND); + break; + } + } + } + + return result; } static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) @@ -331,33 +331,33 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, CustomFreeLibraryFunc freeLibrary, void *userdata) { - PMEMORYMODULE result; - PIMAGE_DOS_HEADER dos_header; - PIMAGE_NT_HEADERS old_header; - unsigned char *code, *headers; - SIZE_T locationDelta; - DllEntryProc DllEntry; - BOOL successfull; - - dos_header = (PIMAGE_DOS_HEADER)data; - if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return NULL; - } - - old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; - if (old_header->Signature != IMAGE_NT_SIGNATURE) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return NULL; - } - - // reserve memory for image of library - // XXX: is it correct to commit the complete memory region at once? + PMEMORYMODULE result; + PIMAGE_DOS_HEADER dos_header; + PIMAGE_NT_HEADERS old_header; + unsigned char *code, *headers; + SIZE_T locationDelta; + DllEntryProc DllEntry; + BOOL successfull; + + dos_header = (PIMAGE_DOS_HEADER)data; + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + + old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; + if (old_header->Signature != IMAGE_NT_SIGNATURE) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + + // reserve memory for image of library + // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... - code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), - old_header->OptionalHeader.SizeOfImage, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); + code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), + old_header->OptionalHeader.SizeOfImage, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); if (code == NULL) { // try to allocate memory at arbitrary position @@ -365,155 +365,155 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (code == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return NULL; - } - } + if (code == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } + + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); + if (result == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + VirtualFree(code, 0, MEM_RELEASE); + return NULL; + } + + result->codeBase = code; + result->numModules = 0; + result->modules = NULL; + result->initialized = 0; + result->loadLibrary = loadLibrary; + result->getProcAddress = getProcAddress; + result->freeLibrary = freeLibrary; + result->userdata = userdata; + + // commit memory for headers + headers = (unsigned char *)VirtualAlloc(code, + old_header->OptionalHeader.SizeOfHeaders, + MEM_COMMIT, + PAGE_READWRITE); - result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); - if (result == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - VirtualFree(code, 0, MEM_RELEASE); - return NULL; - } - - result->codeBase = code; - result->numModules = 0; - result->modules = NULL; - result->initialized = 0; - result->loadLibrary = loadLibrary; - result->getProcAddress = getProcAddress; - result->freeLibrary = freeLibrary; - result->userdata = userdata; - - // commit memory for headers - headers = (unsigned char *)VirtualAlloc(code, - old_header->OptionalHeader.SizeOfHeaders, - MEM_COMMIT, - PAGE_READWRITE); - - // copy PE header to code - memcpy(headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); - result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; - - // update position - result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; - - // copy sections from DLL file block to new memory location - CopySections(data, old_header, result); - - // adjust base address of imported data - locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); - if (locationDelta != 0) { - PerformBaseRelocation(result, locationDelta); - } - - // load required dlls and adjust function table of imports - if (!BuildImportTable(result)) { - goto error; - } - - // mark memory pages depending on section headers and release - // sections that are marked as "discardable" - FinalizeSections(result); - - // 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; - } - result->initialized = 1; - } - - return (HMEMORYMODULE)result; + // copy PE header to code + memcpy(headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); + result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; + + // update position + result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; + + // copy sections from DLL file block to new memory location + CopySections(data, old_header, result); + + // adjust base address of imported data + locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); + if (locationDelta != 0) { + PerformBaseRelocation(result, locationDelta); + } + + // load required dlls and adjust function table of imports + if (!BuildImportTable(result)) { + goto error; + } + + // mark memory pages depending on section headers and release + // sections that are marked as "discardable" + FinalizeSections(result); + + // 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; + } + result->initialized = 1; + } + + return (HMEMORYMODULE)result; error: - // cleanup - MemoryFreeLibrary(result); - return NULL; + // cleanup + MemoryFreeLibrary(result); + return NULL; } FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) { - unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - int idx=-1; - DWORD i, *nameRef; - WORD *ordinal; - PIMAGE_EXPORT_DIRECTORY exports; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); - if (directory->Size == 0) { - // no export table found - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; - } - - exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); - if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { - // DLL doesn't export anything - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; - } - - // search function name in list of exported names - nameRef = (DWORD *) (codeBase + exports->AddressOfNames); - ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { - idx = *ordinal; - break; - } - } - - if (idx == -1) { - // exported symbol not found - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; - } - - if ((DWORD)idx > exports->NumberOfFunctions) { - // name <-> ordinal number don't match - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; - } - - // AddressOfFunctions contains the RVAs to the "real" functions - return (FARPROC) (codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); + unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; + int idx=-1; + DWORD i, *nameRef; + WORD *ordinal; + PIMAGE_EXPORT_DIRECTORY exports; + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); + if (directory->Size == 0) { + // no export table found + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } + + exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); + if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { + // DLL doesn't export anything + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } + + // search function name in list of exported names + nameRef = (DWORD *) (codeBase + exports->AddressOfNames); + ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); + for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { + if (stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { + idx = *ordinal; + break; + } + } + + if (idx == -1) { + // exported symbol not found + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } + + if ((DWORD)idx > exports->NumberOfFunctions) { + // name <-> ordinal number don't match + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } + + // AddressOfFunctions contains the RVAs to the "real" functions + return (FARPROC) (codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); } void MemoryFreeLibrary(HMEMORYMODULE mod) { - int i; - PMEMORYMODULE module = (PMEMORYMODULE)mod; - - if (module != NULL) { - if (module->initialized != 0) { - // notify library about detaching from process - DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); - (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); - module->initialized = 0; - } - - if (module->modules != NULL) { - // free previously opened libraries - for (i=0; inumModules; i++) { - if (module->modules[i] != NULL) { - module->freeLibrary(module->modules[i], module->userdata); - } - } - - free(module->modules); - } - - if (module->codeBase != NULL) { - // release memory of library - VirtualFree(module->codeBase, 0, MEM_RELEASE); - } - - HeapFree(GetProcessHeap(), 0, module); - } + int i; + PMEMORYMODULE module = (PMEMORYMODULE)mod; + + if (module != NULL) { + if (module->initialized != 0) { + // notify library about detaching from process + DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); + (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); + module->initialized = 0; + } + + if (module->modules != NULL) { + // free previously opened libraries + for (i=0; inumModules; i++) { + if (module->modules[i] != NULL) { + module->freeLibrary(module->modules[i], module->userdata); + } + } + + free(module->modules); + } + + if (module->codeBase != NULL) { + // release memory of library + VirtualFree(module->codeBase, 0, MEM_RELEASE); + } + + HeapFree(GetProcessHeap(), 0, module); + } } diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index c34cf6f..d723c93 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -12,59 +12,59 @@ typedef int (*addNumberProc)(int, int); void LoadFromFile(void) { - addNumberProc addNumber; - HINSTANCE handle = LoadLibrary(DLL_FILE); - if (handle == NULL) - return; + addNumberProc addNumber; + HINSTANCE handle = LoadLibrary(DLL_FILE); + if (handle == NULL) + return; - addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); - printf("From file: %d\n", addNumber(1, 2)); - FreeLibrary(handle); + addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); + printf("From file: %d\n", addNumber(1, 2)); + FreeLibrary(handle); } void LoadFromMemory(void) { - FILE *fp; - unsigned char *data=NULL; - size_t size; - HMEMORYMODULE module; - addNumberProc addNumber; - - fp = fopen(DLL_FILE, "rb"); - if (fp == NULL) - { - printf("Can't open DLL file \"%s\".", DLL_FILE); - goto exit; - } + FILE *fp; + unsigned char *data=NULL; + size_t size; + HMEMORYMODULE module; + addNumberProc addNumber; + + fp = fopen(DLL_FILE, "rb"); + if (fp == NULL) + { + printf("Can't open DLL file \"%s\".", DLL_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); + 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); - module = MemoryLoadLibrary(data); - if (module == NULL) - { - printf("Can't load library from memory.\n"); - goto exit; - } + module = MemoryLoadLibrary(data); + if (module == NULL) + { + printf("Can't load library from memory.\n"); + goto exit; + } - addNumber = (addNumberProc)MemoryGetProcAddress(module, "addNumbers"); - printf("From memory: %d\n", addNumber(1, 2)); - MemoryFreeLibrary(module); + addNumber = (addNumberProc)MemoryGetProcAddress(module, "addNumbers"); + printf("From memory: %d\n", addNumber(1, 2)); + MemoryFreeLibrary(module); exit: - if (data) - free(data); + if (data) + free(data); } int main(int argc, char* argv[]) { - LoadFromFile(); - printf("\n\n"); - LoadFromMemory(); - return 0; + LoadFromFile(); + printf("\n\n"); + LoadFromMemory(); + return 0; } diff --git a/example/SampleDLL/SampleDLL.cpp b/example/SampleDLL/SampleDLL.cpp index 342d371..7bf03ef 100644 --- a/example/SampleDLL/SampleDLL.cpp +++ b/example/SampleDLL/SampleDLL.cpp @@ -4,7 +4,7 @@ extern "C" { SAMPLEDLL_API int addNumbers(int a, int b) { - return a + b; + return a + b; } } From 132964d838ed9b93bd673dca38699a9e9853ba7e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 00:33:30 +0100 Subject: [PATCH 019/123] Store some resources in the DLL. --- example/SampleDLL/.gitignore | 1 + example/SampleDLL/Makefile | 8 +++++++- example/SampleDLL/SampleDLL.rc | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 example/SampleDLL/SampleDLL.rc diff --git a/example/SampleDLL/.gitignore b/example/SampleDLL/.gitignore index 41f4fda..ecc2285 100644 --- a/example/SampleDLL/.gitignore +++ b/example/SampleDLL/.gitignore @@ -1,2 +1,3 @@ *.o *.dll +*.res diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index ec4a04b..78c5e1e 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -7,17 +7,20 @@ endif CC = $(PLATFORM)-w64-mingw32-gcc CXX = $(PLATFORM)-w64-mingw32-g++ LINK = $(PLATFORM)-w64-mingw32-ld +RC = $(PLATFORM)-w64-mingw32-windres else CC = gcc CXX = g++ LINK = ld +RC = rc endif RM = rm CFLAGS = -Wall -g -DSAMPLEDLL_EXPORTS LDFLAGS = -shared +RCFLAGS = -O coff -OBJ = SampleDLL.o +OBJ = SampleDLL.o SampleDLL.res SampleDLL.dll: $(OBJ) $(LINK) $(LDFLAGS) -o SampleDLL.dll $(OBJ) @@ -25,5 +28,8 @@ SampleDLL.dll: $(OBJ) %.o: %.cpp $(CXX) $(CFLAGS) -c $< +%.res: %.rc + $(RC) $(RCFLAGS) -o $*.res $< + clean: $(RM) -rf $(OBJ) SampleDLL.dll diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc new file mode 100644 index 0000000..6f73854 --- /dev/null +++ b/example/SampleDLL/SampleDLL.rc @@ -0,0 +1,34 @@ +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "fancy.code" + VALUE "FileDescription", "SampleDLL" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "SampleDLL" + VALUE "LegalCopyright", "Copyright (c) 2013 Joachim Bauch" + VALUE "OriginalFilename", "SampleDLL.dll" + VALUE "ProductName", "MemoryModule" + VALUE "ProductVersion", "0.0.3" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +#define IDS_HELLO 1 +#define IDS_WORLD 20 + +STRINGTABLE +{ + IDS_HELLO, "Hello" + IDS_WORLD, "World!" +} From f4d15a53ac93a2d42121bb42c08ddf68272c3da4 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 00:43:57 +0100 Subject: [PATCH 020/123] Added memory module resource loading API. --- MemoryModule.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++ MemoryModule.h | 32 ++++++++ 2 files changed, 238 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 9930965..05dc648 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -37,6 +37,7 @@ #include #include +#include #ifdef DEBUG_OUTPUT #include #endif @@ -517,3 +518,208 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) HeapFree(GetProcessHeap(), 0, module); } } + +#define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) + +HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) +{ + return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE); +} + +static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( + void *root, + PIMAGE_RESOURCE_DIRECTORY resources, + LPCTSTR key) +{ + PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resources + 1); + PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL; + DWORD start; + DWORD end; + DWORD middle; + + if (!IS_INTRESOURCE(key) && key[0] == _T('#')) { + // special case: resource id given as string + _TCHAR *endpos = NULL; + long int tmpkey = (WORD) _tcstol((_TCHAR *) &key[1], &endpos, 10); + if (tmpkey <= 0xffff && _tcslen(endpos) == 0) { + key = MAKEINTRESOURCE(tmpkey); + } + } + + // entries are stored as ordered list of named entries, + // followed by an ordered list of id entries - we can do + // a binary search to find faster... + if (IS_INTRESOURCE(key)) { + WORD check = (WORD) (POINTER_TYPE) key; + start = resources->NumberOfNamedEntries; + end = start + resources->NumberOfIdEntries; + + while (end > start) { + WORD entryName; + middle = (start + end) >> 1; + entryName = (WORD) entries[middle].Name; + if (check < entryName) { + end = middle; + } else if (check > entryName) { + start = middle; + } else { + result = &entries[middle]; + break; + } + } + } else { + start = 0; + end = resources->NumberOfIdEntries; +#ifndef _UNICODE + _TCHAR *searchKey = NULL; + int searchKeyLength = 0; +#endif + while (end > start) { + // resource names are always stored using 16bit characters + middle = (start + end) >> 1; + PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); + int cmp; +#ifndef _UNICODE + if (searchKey == NULL || searchKeyLength < resourceString->Length) { + void *tmp = realloc(searchKey, resourceString->Length); + if (tmp == NULL) { + break; + } + + searchKey = (_TCHAR *) tmp; + } + wcstombs(searchKey, resourceString->NameString, resourceString->Length); + cmp = strncmp(key, searchKey, resourceString->Length); +#else + cmp = wcsncmp((_TCHAR *) key, resourceString->NameString, resourceString->Length); +#endif + if (cmp < 0) { + end = middle; + } else if (cmp > 0) { + start = middle; + } else { + result = &entries[middle]; + break; + } + } +#ifndef _UNICODE + free(searchKey); +#endif + } + + + return result; +} + +HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) +{ + unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE) module, IMAGE_DIRECTORY_ENTRY_RESOURCE); + PIMAGE_RESOURCE_DIRECTORY rootResources; + PIMAGE_RESOURCE_DIRECTORY nameResources; + PIMAGE_RESOURCE_DIRECTORY typeResources; + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType; + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName; + PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage; + if (directory->Size == 0) { + // no resource table found + SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); + return NULL; + } + + if (language == DEFAULT_LANGUAGE) { + // use language from current thread + language = LANGIDFROMLCID(GetThreadLocale()); + } + + // resources are stored as three-level tree + // - first node is the type + // - second node is the name + // - third node is the language + rootResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress); + foundType = _MemorySearchResourceEntry(rootResources, rootResources, type); + if (foundType == NULL) { + SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); + return NULL; + } + + typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); + foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); + if (foundName == NULL) { + SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); + return NULL; + } + + nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); + foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); + if (foundLanguage == NULL) { + // requested language not found, use first available + if (nameResources->NumberOfIdEntries == 0) { + SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); + return NULL; + } + + foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); + } + + return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); +} + +DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) +{ + PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + + return entry->Size; +} + +LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) +{ + unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; + PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + + return codeBase + entry->OffsetToData; +} + +int +MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) +{ + return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE); +} + +int +MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) +{ + if (maxsize == 0) { + return 0; + } + + HMEMORYRSRC resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); + if (resource == NULL) { + buffer[0] = 0; + return 0; + } + + PIMAGE_RESOURCE_DIR_STRING_U data = MemoryLoadResource(module, resource); + id = id & 0x0f; + while (id--) { + data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); + } + if (data->Length == 0) { + SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); + buffer[0] = 0; + return 0; + } + + DWORD size = data->Length; + if (size >= maxsize) { + size = maxsize; + } else { + buffer[size] = 0; + } +#ifdef _UNICODE + _tcsncpy(buffer, data->NameString, size); +#else + wcstombs(buffer, data->NameString, size); +#endif + return size; +} diff --git a/MemoryModule.h b/MemoryModule.h index fd5a913..7fbb22d 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -31,6 +31,8 @@ typedef void *HMEMORYMODULE; +typedef void *HMEMORYRSRC; + typedef void *HCUSTOMMODULE; #ifdef __cplusplus @@ -70,6 +72,36 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); */ void MemoryFreeLibrary(HMEMORYMODULE); +/** + * Find the location of a resource with the specified type and name. + */ +HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); + +/** + * Find the location of a resource with the specified type, name and language. + */ +HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); + +/** + * Get the size of the resource in bytes. + */ +DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); + +/** + * Get a pointer to the contents of the resource. + */ +LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); + +/** + * Load a string resource. + */ +int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); + +/** + * Load a string resource with a given language. + */ +int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); + #ifdef __cplusplus } #endif From 390efc33a1840cc3a3acbec14b6933c8171cca99 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 00:44:17 +0100 Subject: [PATCH 021/123] Use new resource loading API --- example/DllLoader/DllLoader.cpp | 48 +++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index d723c93..f65bb80 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -1,6 +1,7 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include #include @@ -13,12 +14,31 @@ typedef int (*addNumberProc)(int, int); void LoadFromFile(void) { addNumberProc addNumber; + HRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + _TCHAR buffer[100]; + HINSTANCE handle = LoadLibrary(DLL_FILE); if (handle == NULL) return; addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); printf("From file: %d\n", addNumber(1, 2)); + + resourceInfo = FindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + printf("FindResource returned 0x%p\n", resourceInfo); + + resourceSize = SizeofResource(handle, resourceInfo); + resourceData = LoadResource(handle, resourceInfo); + printf("Resource data: %ld bytes at 0x%p\n", resourceSize, resourceData); + + LoadString(handle, 1, buffer, sizeof(buffer)); + printf("String1: %s\n", buffer); + + LoadString(handle, 20, buffer, sizeof(buffer)); + printf("String2: %s\n", buffer); + FreeLibrary(handle); } @@ -27,8 +47,12 @@ void LoadFromMemory(void) FILE *fp; unsigned char *data=NULL; size_t size; - HMEMORYMODULE module; + HMEMORYMODULE handle; addNumberProc addNumber; + HMEMORYRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + _TCHAR buffer[100]; fp = fopen(DLL_FILE, "rb"); if (fp == NULL) @@ -44,16 +68,30 @@ void LoadFromMemory(void) fread(data, 1, size, fp); fclose(fp); - module = MemoryLoadLibrary(data); - if (module == NULL) + handle = MemoryLoadLibrary(data); + if (handle == NULL) { printf("Can't load library from memory.\n"); goto exit; } - addNumber = (addNumberProc)MemoryGetProcAddress(module, "addNumbers"); + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); printf("From memory: %d\n", addNumber(1, 2)); - MemoryFreeLibrary(module); + + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + printf("MemoryFindResource returned 0x%p\n", resourceInfo); + + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + printf("Memory resource data: %ld bytes at 0x%p\n", resourceSize, resourceData); + + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); + printf("String1: %s\n", buffer); + + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); + printf("String2: %s\n", buffer); + + MemoryFreeLibrary(handle); exit: if (data) From a064d0e63636b9d09db93949fa32720fc180ed32 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 01:02:10 +0100 Subject: [PATCH 022/123] Support unicode compilation --- example/DllLoader/DllLoader.cpp | 28 ++++++++++++++-------------- example/DllLoader/Makefile | 4 ++++ example/SampleDLL/Makefile | 4 ++++ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index f65bb80..944ac98 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -9,7 +9,7 @@ typedef int (*addNumberProc)(int, int); -#define DLL_FILE "..\\SampleDLL\\SampleDLL.dll" +#define DLL_FILE _T("..\\SampleDLL\\SampleDLL.dll") void LoadFromFile(void) { @@ -24,20 +24,20 @@ void LoadFromFile(void) return; addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); - printf("From file: %d\n", addNumber(1, 2)); + _tprintf(_T("From file: %d\n"), addNumber(1, 2)); resourceInfo = FindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); - printf("FindResource returned 0x%p\n", resourceInfo); + _tprintf(_T("FindResource returned 0x%p\n"), resourceInfo); resourceSize = SizeofResource(handle, resourceInfo); resourceData = LoadResource(handle, resourceInfo); - printf("Resource data: %ld bytes at 0x%p\n", resourceSize, resourceData); + _tprintf(_T("Resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); LoadString(handle, 1, buffer, sizeof(buffer)); - printf("String1: %s\n", buffer); + _tprintf(_T("String1: %s\n"), buffer); LoadString(handle, 20, buffer, sizeof(buffer)); - printf("String2: %s\n", buffer); + _tprintf(_T("String2: %s\n"), buffer); FreeLibrary(handle); } @@ -54,10 +54,10 @@ void LoadFromMemory(void) LPVOID resourceData; _TCHAR buffer[100]; - fp = fopen(DLL_FILE, "rb"); + fp = _tfopen(DLL_FILE, _T("rb")); if (fp == NULL) { - printf("Can't open DLL file \"%s\".", DLL_FILE); + _tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE); goto exit; } @@ -71,25 +71,25 @@ void LoadFromMemory(void) handle = MemoryLoadLibrary(data); if (handle == NULL) { - printf("Can't load library from memory.\n"); + _tprintf(_T("Can't load library from memory.\n")); goto exit; } addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); - printf("From memory: %d\n", addNumber(1, 2)); + _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); - printf("MemoryFindResource returned 0x%p\n", resourceInfo); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); resourceSize = MemorySizeofResource(handle, resourceInfo); resourceData = MemoryLoadResource(handle, resourceInfo); - printf("Memory resource data: %ld bytes at 0x%p\n", resourceSize, resourceData); + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); MemoryLoadString(handle, 1, buffer, sizeof(buffer)); - printf("String1: %s\n", buffer); + _tprintf(_T("String1: %s\n"), buffer); MemoryLoadString(handle, 20, buffer, sizeof(buffer)); - printf("String2: %s\n", buffer); + _tprintf(_T("String2: %s\n"), buffer); MemoryFreeLibrary(handle); diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 35c3d8f..92fbd0a 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -17,6 +17,10 @@ RM = rm CFLAGS = -Wall -g LDFLAGS = +ifdef UNICODE +CFLAGS += -DUNICODE -D_UNICODE +endif + OBJ = DllLoader.o ../../MemoryModule.o DllLoader.exe: $(OBJ) diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index 78c5e1e..6ab5629 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -20,6 +20,10 @@ CFLAGS = -Wall -g -DSAMPLEDLL_EXPORTS LDFLAGS = -shared RCFLAGS = -O coff +ifdef UNICODE +CFLAGS += -DUNICODE -D_UNICODE +endif + OBJ = SampleDLL.o SampleDLL.res SampleDLL.dll: $(OBJ) From 3c74a360e592082af1b4785ff1c2d9a5609f3994 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 01:15:52 +0100 Subject: [PATCH 023/123] Differ between UNICODE and _UNICODE. --- MemoryModule.c | 28 ++++++++++++++++------------ example/DllLoader/DllLoader.cpp | 6 +++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 05dc648..e3dbc1a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -537,11 +537,15 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( DWORD end; DWORD middle; - if (!IS_INTRESOURCE(key) && key[0] == _T('#')) { + if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string - _TCHAR *endpos = NULL; - long int tmpkey = (WORD) _tcstol((_TCHAR *) &key[1], &endpos, 10); - if (tmpkey <= 0xffff && _tcslen(endpos) == 0) { + TCHAR *endpos = NULL; +#if defined(UNICODE) + long int tmpkey = (WORD) wcstol((TCHAR *) &key[1], &endpos, 10); +#else + long int tmpkey = (WORD) strtol((TCHAR *) &key[1], &endpos, 10); +#endif + if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { key = MAKEINTRESOURCE(tmpkey); } } @@ -570,8 +574,8 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } else { start = 0; end = resources->NumberOfIdEntries; -#ifndef _UNICODE - _TCHAR *searchKey = NULL; +#if !defined(UNICODE) + char *searchKey = NULL; int searchKeyLength = 0; #endif while (end > start) { @@ -579,19 +583,19 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( middle = (start + end) >> 1; PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); int cmp; -#ifndef _UNICODE +#if !defined(UNICODE) if (searchKey == NULL || searchKeyLength < resourceString->Length) { void *tmp = realloc(searchKey, resourceString->Length); if (tmp == NULL) { break; } - searchKey = (_TCHAR *) tmp; + searchKey = (char *) tmp; } wcstombs(searchKey, resourceString->NameString, resourceString->Length); cmp = strncmp(key, searchKey, resourceString->Length); #else - cmp = wcsncmp((_TCHAR *) key, resourceString->NameString, resourceString->Length); + cmp = wcsncmp(key, resourceString->NameString, resourceString->Length); #endif if (cmp < 0) { end = middle; @@ -602,7 +606,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( break; } } -#ifndef _UNICODE +#if !defined(UNICODE) free(searchKey); #endif } @@ -716,8 +720,8 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO } else { buffer[size] = 0; } -#ifdef _UNICODE - _tcsncpy(buffer, data->NameString, size); +#if defined(UNICODE) + wcsncpy(buffer, data->NameString, size); #else wcstombs(buffer, data->NameString, size); #endif diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 944ac98..1afe8a0 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -9,7 +9,7 @@ typedef int (*addNumberProc)(int, int); -#define DLL_FILE _T("..\\SampleDLL\\SampleDLL.dll") +#define DLL_FILE TEXT("..\\SampleDLL\\SampleDLL.dll") void LoadFromFile(void) { @@ -17,7 +17,7 @@ void LoadFromFile(void) HRSRC resourceInfo; DWORD resourceSize; LPVOID resourceData; - _TCHAR buffer[100]; + TCHAR buffer[100]; HINSTANCE handle = LoadLibrary(DLL_FILE); if (handle == NULL) @@ -52,7 +52,7 @@ void LoadFromMemory(void) HMEMORYRSRC resourceInfo; DWORD resourceSize; LPVOID resourceData; - _TCHAR buffer[100]; + TCHAR buffer[100]; fp = _tfopen(DLL_FILE, _T("rb")); if (fp == NULL) From fa31e34ff9fb470adf7ac3bd50c11749dabf3ecf Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 01:25:07 +0100 Subject: [PATCH 024/123] Fixed compiler warnings in Visual Studio (github issue #8) --- MemoryModule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index e3dbc1a..85e9859 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -99,7 +99,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); - section->Misc.PhysicalAddress = (POINTER_TYPE)dest; + section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; memset(dest, 0, size); } @@ -113,7 +113,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (POINTER_TYPE)dest; + section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; } } @@ -217,13 +217,13 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) case IMAGE_REL_BASED_HIGHLOW: // change complete 32 bit address patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += delta; + *patchAddrHL += (DWORD) delta; break; #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += delta; + *patchAddr64 += (ULONGLONG) delta; break; #endif @@ -464,7 +464,7 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) nameRef = (DWORD *) (codeBase + exports->AddressOfNames); ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { + if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { idx = *ordinal; break; } From 54e3a298367addf44d76e5818f363c1c702aa65d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 01:25:56 +0100 Subject: [PATCH 025/123] Use same parameter type as in header file. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 85e9859..69fdd85 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -439,7 +439,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } -FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) +FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; int idx=-1; From fc6a58a78587b791b7fdb94eb076ad96afacf0c5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 12 Mar 2013 10:00:36 +0100 Subject: [PATCH 026/123] Changed variable definitions to fix compiler errors in Visual Studio. --- MemoryModule.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 69fdd85..a503301 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -572,17 +572,18 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } } else { - start = 0; - end = resources->NumberOfIdEntries; #if !defined(UNICODE) char *searchKey = NULL; int searchKeyLength = 0; #endif + start = 0; + end = resources->NumberOfIdEntries; while (end > start) { // resource names are always stored using 16bit characters - middle = (start + end) >> 1; - PIMAGE_RESOURCE_DIR_STRING_U resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); int cmp; + PIMAGE_RESOURCE_DIR_STRING_U resourceString; + middle = (start + end) >> 1; + resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); #if !defined(UNICODE) if (searchKey == NULL || searchKeyLength < resourceString->Length) { void *tmp = realloc(searchKey, resourceString->Length); @@ -693,17 +694,20 @@ MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) int MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) { + HMEMORYRSRC resource; + PIMAGE_RESOURCE_DIR_STRING_U data; + DWORD size; if (maxsize == 0) { return 0; } - HMEMORYRSRC resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); + resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); if (resource == NULL) { buffer[0] = 0; return 0; } - PIMAGE_RESOURCE_DIR_STRING_U data = MemoryLoadResource(module, resource); + data = MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); @@ -714,8 +718,8 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO return 0; } - DWORD size = data->Length; - if (size >= maxsize) { + size = data->Length; + if (size >= (DWORD) maxsize) { size = maxsize; } else { buffer[size] = 0; From 147fdde8485fa649d9a0b0231c184ccd8479bbf8 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 12 Apr 2013 18:35:12 +0200 Subject: [PATCH 027/123] Fixed potential endless loop while searching for resources (github issue #10). --- MemoryModule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index a503301..1eae4e7 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -563,9 +563,9 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( middle = (start + end) >> 1; entryName = (WORD) entries[middle].Name; if (check < entryName) { - end = middle; + end = (end != middle ? middle : middle-1); } else if (check > entryName) { - start = middle; + start = (start != middle ? middle : middle+1); } else { result = &entries[middle]; break; @@ -599,9 +599,9 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( cmp = wcsncmp(key, resourceString->NameString, resourceString->Length); #endif if (cmp < 0) { - end = middle; + end = (middle != end ? middle : middle-1); } else if (cmp > 0) { - start = middle; + start = (middle != start ? middle : middle+1); } else { result = &entries[middle]; break; From e75438a0060c4b94fb61fbe3cd7003c58e70de92 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 7 Dec 2013 18:16:14 +0100 Subject: [PATCH 028/123] Execute thread-local-storage callbacks (GitHub #11). Pull request by @glysbaysb, cleaned up and adjusted to match code style. --- MemoryModule.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 1eae4e7..e2b1fe8 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -184,6 +184,24 @@ FinalizeSections(PMEMORYMODULE module) #endif } +static void +ExecuteTLS(PMEMORYMODULE module) +{ + unsigned char *codeBase = module->codeBase; + + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); + if (directory->VirtualAddress > 0) { + PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); + PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; + if (callback) { + while (*callback) { + (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); + callback++; + } + } + } +} + static void PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { @@ -419,6 +437,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // sections that are marked as "discardable" FinalizeSections(result); + // TLS callbacks are executed BEFORE the main loading + ExecuteTLS(result); + // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); From f76963b8ea2ed448e903d4aa75671ee00d50e2bd Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 12 Dec 2013 10:14:51 +0100 Subject: [PATCH 029/123] Fixed copying too much into local headers. Reported by Sea Caspian (j.sea.caspian [at] gmail.com) --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index e2b1fe8..0bd2ee1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -413,7 +413,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, PAGE_READWRITE); // copy PE header to code - memcpy(headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); + memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; // update position From de7840af70504a4b0ba53fd40ad8b416ca11b5d8 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:07:49 +0200 Subject: [PATCH 030/123] Removed trailing whitespaces. --- MemoryModule.c | 48 ++++++++++++++++----------------- doc/readme.txt | 34 +++++++++++------------ example/DllLoader/DllLoader.cpp | 18 ++++++------- example/DllLoader/Makefile | 2 +- example/Makefile | 2 +- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 0bd2ee1..0e89a7f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -140,7 +140,7 @@ FinalizeSections(PMEMORYMODULE module) #else #define imageOffset 0 #endif - + // loop through all sections and change access flags for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { DWORD protect, oldProtect, size; @@ -185,10 +185,10 @@ FinalizeSections(PMEMORYMODULE module) } static void -ExecuteTLS(PMEMORYMODULE module) +ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; - + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); if (directory->VirtualAddress > 0) { PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); @@ -225,7 +225,7 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) type = *relInfo >> 12; // the lower 12 bits define the offset offset = *relInfo & 0xfff; - + switch (type) { case IMAGE_REL_BASED_ABSOLUTE: @@ -237,7 +237,7 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) patchAddrHL = (DWORD *) (dest + offset); *patchAddrHL += (DWORD) delta; break; - + #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: patchAddr64 = (ULONGLONG *) (dest + offset); @@ -325,7 +325,7 @@ static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) if (result == NULL) { return NULL; } - + return (HCUSTOMMODULE) result; } @@ -389,7 +389,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } } - + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); if (result == NULL) { SetLastError(ERROR_OUTOFMEMORY); @@ -411,7 +411,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); - + // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; @@ -557,7 +557,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( DWORD start; DWORD end; DWORD middle; - + if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string TCHAR *endpos = NULL; @@ -570,7 +570,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( key = MAKEINTRESOURCE(tmpkey); } } - + // entries are stored as ordered list of named entries, // followed by an ordered list of id entries - we can do // a binary search to find faster... @@ -578,7 +578,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( WORD check = (WORD) (POINTER_TYPE) key; start = resources->NumberOfNamedEntries; end = start + resources->NumberOfIdEntries; - + while (end > start) { WORD entryName; middle = (start + end) >> 1; @@ -611,7 +611,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (tmp == NULL) { break; } - + searchKey = (char *) tmp; } wcstombs(searchKey, resourceString->NameString, resourceString->Length); @@ -632,8 +632,8 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( free(searchKey); #endif } - - + + return result; } @@ -652,7 +652,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); return NULL; } - + if (language == DEFAULT_LANGUAGE) { // use language from current thread language = LANGIDFROMLCID(GetThreadLocale()); @@ -668,14 +668,14 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); return NULL; } - + typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); if (foundName == NULL) { SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); return NULL; } - + nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); if (foundLanguage == NULL) { @@ -684,17 +684,17 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); return NULL; } - + foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); } - + return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); } DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; - + return entry->Size; } @@ -702,7 +702,7 @@ LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; - + return codeBase + entry->OffsetToData; } @@ -721,13 +721,13 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO if (maxsize == 0) { return 0; } - + resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); if (resource == NULL) { buffer[0] = 0; return 0; } - + data = MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { @@ -738,7 +738,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO buffer[0] = 0; return 0; } - + size = data->Length; if (size >= (DWORD) maxsize) { size = maxsize; diff --git a/doc/readme.txt b/doc/readme.txt index e528b7a..3d90304 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -60,7 +60,7 @@ stub that normally just displays an error message about the program not being able to be run from DOS mode. Microsoft defines the DOS header as follows:: - + typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file @@ -114,14 +114,14 @@ about symbols, etc:: .. _OptionalHeader: -The `OptionalHeader` contains informations about the *logical* format of the library, +The `OptionalHeader` contains informations about the *logical* format of the library, including required OS version, memory requirements and entry points:: typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // - + WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; @@ -131,11 +131,11 @@ including required OS version, memory requirements and entry points:: DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; - + // // NT additional fields. // - + DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; @@ -247,25 +247,25 @@ When issuing the API call `LoadLibrary`, Windows basically performs these tasks: 2. Try to allocate a memory block of `PEHeader.OptionalHeader.SizeOfImage` bytes at position `PEHeader.OptionalHeader.ImageBase`. - + 3. Parse section headers and copy sections to their addresses. The destination address for each section, relative to the base of the allocated memory block, is stored in the `VirtualAddress` attribute of the `IMAGE_SECTION_HEADER` structure. - + 4. If the allocated memory block differs from `ImageBase`, various references in the code and/or data sections must be adjusted. This is called *Base relocation*. - + 5. The required imports for the library must be resolved by loading the corresponding libraries. - + 6. The memory regions of the different sections must be protected depending on the section's characteristics. Some sections are marked as *discardable* and therefore can be safely freed at this point. These sections normally contain temporary data that is only needed during the import, like the informations for the base relocation. - + 7. Now the library is loaded completely. It must be notified about this by calling the entry point using the flag `DLL_PROCESS_ATTACH`. @@ -363,7 +363,7 @@ as follows:: // -1 if bound, and real date\time stamp // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) // O.W. date/time stamp of DLL bound to (Old BIND) - + DWORD ForwarderChain; // -1 if no forwarders DWORD Name; DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) @@ -401,10 +401,10 @@ These flags can be one or a combination of IMAGE_SCN_MEM_EXECUTE The section contains data that can be executed. - + IMAGE_SCN_MEM_READ The section contains data that is readable. - + IMAGE_SCN_MEM_WRITE The section contains data that is writeable. @@ -428,7 +428,7 @@ In addition the section flags above, the following can be added: IMAGE_SCN_MEM_DISCARDABLE The data in this section can be freed after the import. Usually this is specified for relocation data. - + IMAGE_SCN_MEM_NOT_CACHED The data in this section must not get cached by Windows. Add the bit flag `PAGE_NOCACHE` to the protection flags above. @@ -444,7 +444,7 @@ to a process. The function at the entry point is defined as :: - + typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); So the last code we need to execute is @@ -497,7 +497,7 @@ To free the custom loaded library, perform the steps DllEntryProc entry = (DllEntryProc)(baseAddress + PEHeader->OptionalHeader.AddressOfEntryPoint); (*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0); - + - Free external libraries used to resolve imports. - Free allocated memory. @@ -510,7 +510,7 @@ MemoryModule is a C-library that can be used to load a DLL from memory. The interface is very similar to the standard methods for loading of libraries:: typedef void *HMEMORYMODULE; - + HMEMORYMODULE MemoryLoadLibrary(const void *); FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); void MemoryFreeLibrary(HMEMORYMODULE); diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 1afe8a0..3fda631 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -18,24 +18,24 @@ void LoadFromFile(void) DWORD resourceSize; LPVOID resourceData; TCHAR buffer[100]; - + HINSTANCE handle = LoadLibrary(DLL_FILE); if (handle == NULL) return; addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); _tprintf(_T("From file: %d\n"), addNumber(1, 2)); - + resourceInfo = FindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("FindResource returned 0x%p\n"), resourceInfo); - + resourceSize = SizeofResource(handle, resourceInfo); resourceData = LoadResource(handle, resourceInfo); _tprintf(_T("Resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); - + LoadString(handle, 1, buffer, sizeof(buffer)); _tprintf(_T("String1: %s\n"), buffer); - + LoadString(handle, 20, buffer, sizeof(buffer)); _tprintf(_T("String2: %s\n"), buffer); @@ -53,7 +53,7 @@ void LoadFromMemory(void) DWORD resourceSize; LPVOID resourceData; TCHAR buffer[100]; - + fp = _tfopen(DLL_FILE, _T("rb")); if (fp == NULL) { @@ -80,14 +80,14 @@ void LoadFromMemory(void) resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); - + resourceSize = MemorySizeofResource(handle, resourceInfo); resourceData = MemoryLoadResource(handle, resourceInfo); _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); - + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); _tprintf(_T("String1: %s\n"), buffer); - + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); _tprintf(_T("String2: %s\n"), buffer); diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 92fbd0a..dcfc263 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -15,7 +15,7 @@ endif RM = rm CFLAGS = -Wall -g -LDFLAGS = +LDFLAGS = ifdef UNICODE CFLAGS += -DUNICODE -D_UNICODE diff --git a/example/Makefile b/example/Makefile index 2852993..48b8e0b 100644 --- a/example/Makefile +++ b/example/Makefile @@ -10,7 +10,7 @@ $(SUBDIRS): CLEANDIRS = $(SUBDIRS:%=clean-%) clean: $(CLEANDIRS) -$(CLEANDIRS): +$(CLEANDIRS): $(MAKE) -C $(@:clean-%=%) clean .PHONY: subdirs $(INSTALLDIRS) From ce62f60a6e2b007bcd670deb74b3e3bcb62e040d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:09:31 +0200 Subject: [PATCH 031/123] Bump year in copyright. --- MemoryModule.c | 4 ++-- MemoryModule.h | 4 ++-- doc/readme.txt | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 0e89a7f..550520e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2013 + * Portions created by Joachim Bauch are Copyright (C) 2004-2014 * Joachim Bauch. All Rights Reserved. * */ diff --git a/MemoryModule.h b/MemoryModule.h index 7fbb22d..cabb48e 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2013 + * Portions created by Joachim Bauch are Copyright (C) 2004-2014 * Joachim Bauch. All Rights Reserved. * */ diff --git a/doc/readme.txt b/doc/readme.txt index 3d90304..08473df 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -543,4 +543,4 @@ Copyright ========== The MemoryModule library and this tutorial are -Copyright (c) 2004-2013 by Joachim Bauch. +Copyright (c) 2004-2014 by Joachim Bauch. diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 6f73854..52d538b 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -10,7 +10,7 @@ BEGIN VALUE "FileDescription", "SampleDLL" VALUE "FileVersion", "1.0" VALUE "InternalName", "SampleDLL" - VALUE "LegalCopyright", "Copyright (c) 2013 Joachim Bauch" + VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" VALUE "ProductVersion", "0.0.3" From 8d286f85667d9a9399e72e550fcc6af0a9296cb7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:09:56 +0200 Subject: [PATCH 032/123] Bump version number. --- MemoryModule.c | 2 +- MemoryModule.h | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 550520e..7fece47 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -1,6 +1,6 @@ /* * Memory DLL loading code - * Version 0.0.3 + * Version 0.0.4 * * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de diff --git a/MemoryModule.h b/MemoryModule.h index cabb48e..adeacb6 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -1,6 +1,6 @@ /* * Memory DLL loading code - * Version 0.0.3 + * Version 0.0.4 * * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 52d538b..2fa076b 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -13,7 +13,7 @@ BEGIN VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" - VALUE "ProductVersion", "0.0.3" + VALUE "ProductVersion", "0.0.4" END END From da78edc39bc96fb5653c5489c5a2b3e34166cde7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:14:21 +0200 Subject: [PATCH 033/123] Use markdown readme. --- readme.txt => readme.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) rename readme.txt => readme.md (67%) diff --git a/readme.txt b/readme.md similarity index 67% rename from readme.txt rename to readme.md index b826592..92d823c 100644 --- a/readme.txt +++ b/readme.md @@ -1,5 +1,8 @@ +MemoryModule +============ + The default windows API functions to load external libraries into a program -(LoadLibrary, LoadLibraryEx) only work with files on the filesystem. It's +(`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's therefore impossible to load a DLL from memory. But sometimes, you need exactly this functionality (e.g. you don't want to @@ -8,8 +11,8 @@ workarounds for this problems are to write the DLL into a temporary file first and import it from there. When the program terminates, the temporary file gets deleted. -MemoryModule is a library that can be used to load a DLL completely from +`MemoryModule` is a library that can be used to load a DLL completely from memory - without storing on the disk first. -See doc/readme.txt for more informations about the format of a DLL file and +See `doc/readme.txt` for more informations about the format of a DLL file and a tutorial how they can be loaded directly. From bb736dc160c6f70e940701e3f1cd5aea5911b36a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:19:36 +0200 Subject: [PATCH 034/123] Added explicit casts. --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7fece47..4fb4655 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -420,7 +420,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; // copy sections from DLL file block to new memory location - CopySections(data, old_header, result); + CopySections((const unsigned char *) data, old_header, result); // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); @@ -728,7 +728,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO return 0; } - data = MemoryLoadResource(module, resource); + data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); From b8125d0a6560fa68f10677eabe6eaaaa2529c3af Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:24:44 +0200 Subject: [PATCH 035/123] Compile everything with "g++" and link statically. --- example/DllLoader/Makefile | 6 +++--- example/SampleDLL/Makefile | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index dcfc263..84c8c68 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -4,18 +4,18 @@ ifeq ($(UNAME), Linux) ifndef PLATFORM PLATFORM = i686 endif -CC = $(PLATFORM)-w64-mingw32-gcc +CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ LINK = $(PLATFORM)-w64-mingw32-ld else -CC = gcc +CC = g++ CXX = g++ LINK = ld endif RM = rm CFLAGS = -Wall -g -LDFLAGS = +LDFLAGS = -static ifdef UNICODE CFLAGS += -DUNICODE -D_UNICODE diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index 6ab5629..d5e8085 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -4,12 +4,12 @@ ifeq ($(UNAME), Linux) ifndef PLATFORM PLATFORM = i686 endif -CC = $(PLATFORM)-w64-mingw32-gcc +CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ LINK = $(PLATFORM)-w64-mingw32-ld RC = $(PLATFORM)-w64-mingw32-windres else -CC = gcc +CC = g++ CXX = g++ LINK = ld RC = rc From 2d504b533e698b3816d399708b00f99e2fcc53ed Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 17:33:18 +0200 Subject: [PATCH 036/123] Check architecture of library to load. --- MemoryModule.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 4fb4655..a7eda08 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -370,6 +370,15 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } +#ifdef _WIN64 + if (old_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { +#else + if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { +#endif + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... From 5a448ce93ab91a5ac9456a456f6568f28a14f2e1 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 18:34:11 +0200 Subject: [PATCH 037/123] Support loading (and running) EXE files (fixes #7). --- MemoryModule.c | 50 +++++++++++++++++------ MemoryModule.h | 19 +++++++-- example/DllLoader/DllLoaderLoader.cpp | 57 +++++++++++++++++++++++++++ example/DllLoader/Makefile | 10 ++++- 4 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 example/DllLoader/DllLoaderLoader.cpp 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 From 1d55f777531bc7df46c70a73b9cf139c2770031f Mon Sep 17 00:00:00 2001 From: Dan Staples Date: Mon, 5 Jan 2015 20:28:02 -0500 Subject: [PATCH 038/123] small fix relating to searching IMAGE_RESOURCE_DIRECTORY_ENTRYs for named resources --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index fcb0081..bb43190 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -633,7 +633,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( int searchKeyLength = 0; #endif start = 0; - end = resources->NumberOfIdEntries; + end = resources->NumberOfNamedEntries; while (end > start) { // resource names are always stored using 16bit characters int cmp; From 52b0379749a29a17a4f588443ca6050994c16247 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:05:11 +0100 Subject: [PATCH 039/123] Added travis configuration. --- .travis.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..67de344 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +env: + - PLATFORM=x86_64 WINE=wine64 + - PLATFORM=i686 WINE=wine + +language: cpp + +cache: + - apt + +before_install: + - sudo apt-get update -qq + - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" + - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" + +script: + - make PLATFORM=$PLATFORM + - cd example/DllLoader + - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe + - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe From 3422b5791c7ebab00b164a5b72c8e74541e0973a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:20:35 +0100 Subject: [PATCH 040/123] Show build status. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 92d823c..ab35ac6 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,8 @@ MemoryModule ============ +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule) + The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's therefore impossible to load a DLL from memory. From b889c72727bb4e613249b2b0902b6dfae76baa99 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:22:03 +0100 Subject: [PATCH 041/123] Bump year in copyright. --- MemoryModule.c | 4 ++-- MemoryModule.h | 4 ++-- doc/readme.txt | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index fcb0081..3094133 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.4 * - * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2014 + * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ diff --git a/MemoryModule.h b/MemoryModule.h index e2fa2d3..9174ad2 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.4 * - * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2014 + * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ diff --git a/doc/readme.txt b/doc/readme.txt index 08473df..7e02c1b 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -543,4 +543,4 @@ Copyright ========== The MemoryModule library and this tutorial are -Copyright (c) 2004-2014 by Joachim Bauch. +Copyright (c) 2004-2015 by Joachim Bauch. diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 2fa076b..5a0da61 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -10,7 +10,7 @@ BEGIN VALUE "FileDescription", "SampleDLL" VALUE "FileVersion", "1.0" VALUE "InternalName", "SampleDLL" - VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" + VALUE "LegalCopyright", "Copyright (c) 2004-2015 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" VALUE "ProductVersion", "0.0.4" From 808c043fafec8a7d1726cf95d68a5f5c5c4191b0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:25:57 +0100 Subject: [PATCH 042/123] Fixed indentation. --- MemoryModule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 160eb31..83d2391 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -67,7 +67,7 @@ typedef struct { ExeEntryProc exeEntry; } MEMORYMODULE, *PMEMORYMODULE; -#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] +#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #ifdef DEBUG_OUTPUT static void @@ -637,7 +637,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( while (end > start) { // resource names are always stored using 16bit characters int cmp; - PIMAGE_RESOURCE_DIR_STRING_U resourceString; + PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); #if !defined(UNICODE) @@ -750,9 +750,9 @@ MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) int MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) { - HMEMORYRSRC resource; - PIMAGE_RESOURCE_DIR_STRING_U data; - DWORD size; + HMEMORYRSRC resource; + PIMAGE_RESOURCE_DIR_STRING_U data; + DWORD size; if (maxsize == 0) { return 0; } From 6212358a24a597a6b6405567d32aabb157039fef Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:34:28 +0100 Subject: [PATCH 043/123] Use function from tchar.h instead of #ifdef. --- MemoryModule.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 83d2391..602c505 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -596,11 +596,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string TCHAR *endpos = NULL; -#if defined(UNICODE) - long int tmpkey = (WORD) wcstol((TCHAR *) &key[1], &endpos, 10); -#else - long int tmpkey = (WORD) strtol((TCHAR *) &key[1], &endpos, 10); -#endif + long int tmpkey = (WORD) _tcstol((TCHAR *) &key[1], &endpos, 10); if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { key = MAKEINTRESOURCE(tmpkey); } From dacdbaba9a88d05a8d7dc840adcc74c3d5d8ed77 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:39:16 +0100 Subject: [PATCH 044/123] Deny loading any other architecture than 64bit if compiled for 64bit. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 602c505..6a661bc 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -377,7 +377,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } #ifdef _WIN64 - if (old_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { + if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { #else if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { #endif From 625aa470359b2e86d30c6670278658de3ea01729 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:46:34 +0100 Subject: [PATCH 045/123] Use "uintptr_t" instead of custom type. --- MemoryModule.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 6a661bc..9e99535 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -29,14 +29,9 @@ #pragma warning( disable : 4311 4312 ) #endif -#ifdef _WIN64 -#define POINTER_TYPE ULONGLONG -#else -#define POINTER_TYPE DWORD -#endif - #include #include +#include #include #ifdef DEBUG_OUTPUT #include @@ -103,7 +98,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); - section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; + section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; memset(dest, 0, size); } @@ -117,7 +112,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; + section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } } @@ -140,7 +135,7 @@ FinalizeSections(PMEMORYMODULE module) int i; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 - POINTER_TYPE imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); + uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else #define imageOffset 0 #endif @@ -154,7 +149,7 @@ FinalizeSections(PMEMORYMODULE module) if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { // section is not needed any more and can safely be freed - VirtualFree((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); + VirtualFree((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); continue; } @@ -176,7 +171,7 @@ FinalizeSections(PMEMORYMODULE module) if (size > 0) { // change memory access flags - if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) + if (VirtualProtect((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) #ifdef DEBUG_OUTPUT OutputLastError("Error protecting memory page") #endif @@ -275,7 +270,7 @@ BuildImportTable(PMEMORYMODULE module) if (directory->Size > 0) { PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - POINTER_TYPE *thunkRef; + uintptr_t *thunkRef; FARPROC *funcRef; HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { @@ -295,11 +290,11 @@ BuildImportTable(PMEMORYMODULE module) module->modules[module->numModules++] = handle; if (importDesc->OriginalFirstThunk) { - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk); + thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } else { // no hint table - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk); + thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } for (; *thunkRef; thunkRef++, funcRef++) { @@ -433,7 +428,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; // update position - result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; + result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location CopySections((const unsigned char *) data, old_header, result); @@ -606,7 +601,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( // followed by an ordered list of id entries - we can do // a binary search to find faster... if (IS_INTRESOURCE(key)) { - WORD check = (WORD) (POINTER_TYPE) key; + WORD check = (WORD) (uintptr_t) key; start = resources->NumberOfNamedEntries; end = start + resources->NumberOfIdEntries; @@ -708,7 +703,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ } nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); - foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); + foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (uintptr_t) language); if (foundLanguage == NULL) { // requested language not found, use first available if (nameResources->NumberOfIdEntries == 0) { From 4c08d8eb92abd37108315433b00e9338c090c72c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:54:48 +0100 Subject: [PATCH 046/123] Also build UNICODE versions. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 67de344..0de8cba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ env: - PLATFORM=x86_64 WINE=wine64 - PLATFORM=i686 WINE=wine + - UNICODE= + - UNICODE=1 language: cpp @@ -13,7 +15,7 @@ before_install: - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" script: - - make PLATFORM=$PLATFORM + - make PLATFORM=$PLATFORM UNICODE=$UNICODE - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe From dd5e818dfc57253d59c4ec0dd569fb4a29cd346e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:56:39 +0100 Subject: [PATCH 047/123] Need to specify build matrix differently. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0de8cba..2af19ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ env: - - PLATFORM=x86_64 WINE=wine64 - - PLATFORM=i686 WINE=wine - - UNICODE= - - UNICODE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE= + - PLATFORM=i686 WINE=wine UNICODE= + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 + - PLATFORM=i686 WINE=wine UNICODE=1 language: cpp From 927bd2a9f01b60be27e06b46d6bfc188a7ffef58 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 01:34:33 +0100 Subject: [PATCH 048/123] Link using "g++" to get reloc information. --- example/SampleDLL/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index d5e8085..ce3f65b 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -6,7 +6,7 @@ PLATFORM = i686 endif CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ -LINK = $(PLATFORM)-w64-mingw32-ld +LINK = $(PLATFORM)-w64-mingw32-g++ RC = $(PLATFORM)-w64-mingw32-windres else CC = g++ From aa6b93bab43430c91da8201ae18569a646b9e192 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 28 Feb 2015 23:01:44 +0100 Subject: [PATCH 049/123] Support section alignments that are smaller than the memory page size (fixes #20/#21). --- MemoryModule.c | 146 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 33 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 9e99535..d5e071e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -60,9 +60,19 @@ typedef struct { CustomFreeLibraryFunc freeLibrary; void *userdata; ExeEntryProc exeEntry; + DWORD pageSize; } MEMORYMODULE, *PMEMORYMODULE; +typedef struct { + LPVOID address; + LPVOID alignedAddress; + DWORD size; + DWORD characteristics; + BOOL last; +} SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; + #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] +#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) #ifdef DEBUG_OUTPUT static void @@ -98,6 +108,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); + // Always use position from file to support alignments smaller + // than page size. + dest = codeBase + section->VirtualAddress; section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; memset(dest, 0, size); } @@ -111,6 +124,10 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); + + // Always use position from file to support alignments smaller + // than page size. + dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } @@ -129,6 +146,63 @@ static int ProtectionFlags[2][2][2] = { }, }; +static DWORD +GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { + DWORD size = section->SizeOfRawData; + if (size == 0) { + if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfInitializedData; + } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfUninitializedData; + } + } + return size; +} + +static BOOL +FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { + DWORD protect, oldProtect; + int executable; + int readable; + int writeable; + + if (sectionData->size == 0) { + return TRUE; + } + + if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { + // section is not needed any more and can safely be freed + if (sectionData->address == sectionData->alignedAddress && + (sectionData->last || + module->headers->OptionalHeader.SectionAlignment == module->pageSize || + (sectionData->size % module->pageSize) == 0) + ) { + // Only allowed to decommit whole pages + VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT); + } + return TRUE; + } + + // determine protection flags based on characteristics + executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; + readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; + writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; + protect = ProtectionFlags[executable][readable][writeable]; + if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) { + protect |= PAGE_NOCACHE; + } + + // change memory access flags + if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { +#ifdef DEBUG_OUTPUT + OutputLastError("Error protecting memory page") +#endif + return FALSE; + } + + return TRUE; +} + static void FinalizeSections(PMEMORYMODULE module) { @@ -139,45 +213,41 @@ FinalizeSections(PMEMORYMODULE module) #else #define imageOffset 0 #endif + SECTIONFINALIZEDATA sectionData; + sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); + sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); + sectionData.size = GetRealSectionSize(module, section); + sectionData.characteristics = section->Characteristics; + sectionData.last = FALSE; + section++; // loop through all sections and change access flags - for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { - DWORD protect, oldProtect, size; - int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; - int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; - int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; - - if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { - // section is not needed any more and can safely be freed - VirtualFree((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); - continue; - } - - // determine protection flags based on characteristics - protect = ProtectionFlags[executable][readable][writeable]; - if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { - protect |= PAGE_NOCACHE; - } - - // determine size of region - size = section->SizeOfRawData; - if (size == 0) { - if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfInitializedData; - } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfUninitializedData; + for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { + LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); + LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); + DWORD sectionSize = GetRealSectionSize(module, section); + // Combine access flags of all sections that share a page + // TODO(fancycode): We currently share flags of a trailing large section + // with the page of a first small section. This should be optimized. + if (sectionData.alignedAddress == alignedAddress || (uintptr_t) sectionData.address + sectionData.size > (uintptr_t) alignedAddress) { + // Section shares page with previous + if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { + sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; + } else { + sectionData.characteristics |= section->Characteristics; } + sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t) sectionData.address; + continue; } - if (size > 0) { - // change memory access flags - if (VirtualProtect((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) -#ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") -#endif - ; - } + FinalizeSection(module, §ionData); + sectionData.address = sectionAddress; + sectionData.alignedAddress = alignedAddress; + sectionData.size = sectionSize; + sectionData.characteristics = section->Characteristics; } + sectionData.last = TRUE; + FinalizeSection(module, §ionData); #ifndef _WIN64 #undef imageOffset #endif @@ -358,6 +428,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, unsigned char *code, *headers; SIZE_T locationDelta; BOOL successfull; + SYSTEM_INFO sysInfo; dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { @@ -380,6 +451,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } + if (old_header->OptionalHeader.SectionAlignment & 1) { + // Only support section alignments that are a multiple of 2 + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... @@ -417,6 +494,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->freeLibrary = freeLibrary; result->userdata = userdata; + GetNativeSystemInfo(&sysInfo); + result->pageSize = sysInfo.dwPageSize; + // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, From d321abf8fa72bd1b768cb5f9bcf8150b04cb7cec Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 28 Feb 2015 23:59:06 +0100 Subject: [PATCH 050/123] Added more error handling, changed boolean variables to "BOOL", bail our early from functions where possible. --- MemoryModule.c | 287 +++++++++++++++++++++++++++---------------------- 1 file changed, 156 insertions(+), 131 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index d5e071e..658ed92 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -52,9 +52,9 @@ typedef struct { unsigned char *codeBase; HCUSTOMMODULE *modules; int numModules; - int initialized; - int isDLL; - int isRelocated; + BOOL initialized; + BOOL isDLL; + BOOL isRelocated; CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; @@ -90,7 +90,7 @@ OutputLastError(const char *msg) } #endif -static void +static BOOL CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { int i, size; @@ -107,6 +107,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO size, MEM_COMMIT, PAGE_READWRITE); + if (dest == NULL) { + return FALSE; + } // Always use position from file to support alignments smaller // than page size. @@ -124,6 +127,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); + if (dest == NULL) { + return FALSE; + } // Always use position from file to support alignments smaller // than page size. @@ -131,6 +137,8 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } + + return TRUE; } // Protection flags for memory pages (Executable, Readable, Writeable) @@ -162,9 +170,9 @@ GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { DWORD protect, oldProtect; - int executable; - int readable; - int writeable; + BOOL executable; + BOOL readable; + BOOL writeable; if (sectionData->size == 0) { return TRUE; @@ -203,7 +211,7 @@ FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { return TRUE; } -static void +static BOOL FinalizeSections(PMEMORYMODULE module) { int i; @@ -240,152 +248,164 @@ FinalizeSections(PMEMORYMODULE module) continue; } - FinalizeSection(module, §ionData); + if (!FinalizeSection(module, §ionData)) { + return FALSE; + } sectionData.address = sectionAddress; sectionData.alignedAddress = alignedAddress; sectionData.size = sectionSize; sectionData.characteristics = section->Characteristics; } sectionData.last = TRUE; - FinalizeSection(module, §ionData); + if (!FinalizeSection(module, §ionData)) { + return FALSE; + } #ifndef _WIN64 #undef imageOffset #endif + return TRUE; } -static void +static BOOL ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); - if (directory->VirtualAddress > 0) { - PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); - PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; - if (callback) { - while (*callback) { - (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); - callback++; - } + if (directory->VirtualAddress == 0) { + return TRUE; + } + + PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); + PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; + if (callback) { + while (*callback) { + (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); + callback++; } } + return TRUE; } -static int +static BOOL PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { - DWORD i; unsigned char *codeBase = module->codeBase; - int result = 0; + PIMAGE_BASE_RELOCATION relocation; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); - if (directory->Size > 0) { - PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); - for (; relocation->VirtualAddress > 0; ) { - unsigned char *dest = codeBase + relocation->VirtualAddress; - unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); - for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { - DWORD *patchAddrHL; + if (directory->Size == 0) { + return (delta == 0); + } + + relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); + for (; relocation->VirtualAddress > 0; ) { + DWORD i; + unsigned char *dest = codeBase + relocation->VirtualAddress; + unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); + for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { + DWORD *patchAddrHL; #ifdef _WIN64 - ULONGLONG *patchAddr64; + ULONGLONG *patchAddr64; #endif - int type, offset; + int type, offset; - // the upper 4 bits define the type of relocation - type = *relInfo >> 12; - // the lower 12 bits define the offset - offset = *relInfo & 0xfff; + // the upper 4 bits define the type of relocation + type = *relInfo >> 12; + // the lower 12 bits define the offset + offset = *relInfo & 0xfff; - switch (type) - { - case IMAGE_REL_BASED_ABSOLUTE: - // skip relocation - break; + switch (type) + { + case IMAGE_REL_BASED_ABSOLUTE: + // skip relocation + break; - case IMAGE_REL_BASED_HIGHLOW: - // change complete 32 bit address - patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += (DWORD) delta; - break; + case IMAGE_REL_BASED_HIGHLOW: + // change complete 32 bit address + patchAddrHL = (DWORD *) (dest + offset); + *patchAddrHL += (DWORD) delta; + break; #ifdef _WIN64 - case IMAGE_REL_BASED_DIR64: - patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += (ULONGLONG) delta; - break; + case IMAGE_REL_BASED_DIR64: + patchAddr64 = (ULONGLONG *) (dest + offset); + *patchAddr64 += (ULONGLONG) delta; + break; #endif - default: - //printf("Unknown relocation: %d\n", type); - break; - } + default: + //printf("Unknown relocation: %d\n", type); + break; } - - // advance to next relocation block - relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } - result = 1; + + // advance to next relocation block + relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } - return result; + return TRUE; } -static int +static BOOL BuildImportTable(PMEMORYMODULE module) { - int result=1; unsigned char *codeBase = module->codeBase; - HCUSTOMMODULE *tmp; + PIMAGE_IMPORT_DESCRIPTOR importDesc; + BOOL result = TRUE; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (directory->Size > 0) { - PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); - for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - uintptr_t *thunkRef; - FARPROC *funcRef; - HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); - if (handle == NULL) { - SetLastError(ERROR_MOD_NOT_FOUND); - result = 0; - break; - } + if (directory->Size == 0) { + return TRUE; + } - tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); - if (tmp == NULL) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_OUTOFMEMORY); - result = 0; - break; - } - module->modules = tmp; + importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); + for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { + uintptr_t *thunkRef; + FARPROC *funcRef; + HCUSTOMMODULE *tmp; + HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); + if (handle == NULL) { + SetLastError(ERROR_MOD_NOT_FOUND); + result = FALSE; + break; + } - module->modules[module->numModules++] = handle; - if (importDesc->OriginalFirstThunk) { - thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); + if (tmp == NULL) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_OUTOFMEMORY); + result = FALSE; + break; + } + module->modules = tmp; + + module->modules[module->numModules++] = handle; + if (importDesc->OriginalFirstThunk) { + thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } else { + // no hint table + thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } + for (; *thunkRef; thunkRef++, funcRef++) { + if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { + *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); } else { - // no hint table - thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); - } - for (; *thunkRef; thunkRef++, funcRef++) { - if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { - *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); - } else { - PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); - *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); - } - if (*funcRef == 0) { - result = 0; - break; - } + PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); + *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); } - - if (!result) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_PROC_NOT_FOUND); + if (*funcRef == 0) { + result = FALSE; break; } } + + if (!result) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_PROC_NOT_FOUND); + break; + } } return result; @@ -427,7 +447,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; SIZE_T locationDelta; - BOOL successfull; SYSTEM_INFO sysInfo; dos_header = (PIMAGE_DOS_HEADER)data; @@ -487,7 +506,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->codeBase = code; result->numModules = 0; result->modules = NULL; - result->initialized = 0; + result->initialized = FALSE; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; @@ -511,14 +530,16 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location - CopySections((const unsigned char *) data, old_header, result); + if (!CopySections((const unsigned char *) data, old_header, result)) { + goto error; + } // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { result->isRelocated = PerformBaseRelocation(result, locationDelta); } else { - result->isRelocated = 1; + result->isRelocated = TRUE; } // load required dlls and adjust function table of imports @@ -528,22 +549,26 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // mark memory pages depending on section headers and release // sections that are marked as "discardable" - FinalizeSections(result); + if (!FinalizeSections(result)) { + goto error; + } // TLS callbacks are executed BEFORE the main loading - ExecuteTLS(result); + if (!ExecuteTLS(result)) { + goto error; + } // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { 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); + BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); if (!successfull) { SetLastError(ERROR_DLL_INIT_FAILED); goto error; } - result->initialized = 1; + result->initialized = TRUE; } else { result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); } @@ -611,32 +636,32 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) int i; PMEMORYMODULE module = (PMEMORYMODULE)mod; - if (module != NULL) { - if (module->initialized != 0) { - // notify library about detaching from process - DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); - (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); - module->initialized = 0; - } + if (module == NULL) { + return; + } + if (module->initialized) { + // notify library about detaching from process + DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); + (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); + } - if (module->modules != NULL) { - // free previously opened libraries - for (i=0; inumModules; i++) { - if (module->modules[i] != NULL) { - module->freeLibrary(module->modules[i], module->userdata); - } + if (module->modules != NULL) { + // free previously opened libraries + for (i=0; inumModules; i++) { + if (module->modules[i] != NULL) { + module->freeLibrary(module->modules[i], module->userdata); } - - free(module->modules); } - if (module->codeBase != NULL) { - // release memory of library - VirtualFree(module->codeBase, 0, MEM_RELEASE); - } + free(module->modules); + } - HeapFree(GetProcessHeap(), 0, module); + if (module->codeBase != NULL) { + // release memory of library + VirtualFree(module->codeBase, 0, MEM_RELEASE); } + + HeapFree(GetProcessHeap(), 0, module); } int MemoryCallEntryPoint(HMEMORYMODULE mod) From 463447c1ed66359b91d3a6db16aa4f32bb1d5406 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 00:04:38 +0100 Subject: [PATCH 051/123] Reduced scope of variable. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 658ed92..fb17040 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -633,7 +633,6 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) void MemoryFreeLibrary(HMEMORYMODULE mod) { - int i; PMEMORYMODULE module = (PMEMORYMODULE)mod; if (module == NULL) { @@ -647,6 +646,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) if (module->modules != NULL) { // free previously opened libraries + int i; for (i=0; inumModules; i++) { if (module->modules[i] != NULL) { module->freeLibrary(module->modules[i], module->userdata); From 36574a5638f6b6ff7ec138003a2e3ef4710495db Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 00:32:38 +0100 Subject: [PATCH 052/123] Handle case where resource to load is NULL. --- MemoryModule.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index fb17040..8a348a1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -825,6 +825,9 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + if (entry == NULL) { + return 0; + } return entry->Size; } @@ -833,6 +836,9 @@ LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + if (entry == NULL) { + return NULL; + } return codeBase + entry->OffsetToData; } From 2da44d00e984e514965ab6d8b37d1e47635e89a5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:04:17 +0100 Subject: [PATCH 053/123] Run more tests with sample DLLs. --- .gitignore | 2 ++ .travis.yml | 1 + Makefile | 7 ++-- tests/LoadDll.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile | 82 ++++++++++++++++++++++++++++++++++++++++++ tests/SampleDLL.cpp | 10 ++++++ tests/SampleDLL.h | 11 ++++++ tests/SampleDLL.rc | 34 ++++++++++++++++++ tests/runtests.sh | 20 +++++++++++ 9 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 tests/LoadDll.cpp create mode 100644 tests/Makefile create mode 100644 tests/SampleDLL.cpp create mode 100644 tests/SampleDLL.h create mode 100644 tests/SampleDLL.rc create mode 100755 tests/runtests.sh diff --git a/.gitignore b/.gitignore index 8cc774f..6c07d24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.obj *.exe +tests/*.dll +tests/*.res diff --git a/.travis.yml b/.travis.yml index 2af19ce..9182c08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ script: - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe + - make test PLATFORM=$PLATFORM UNICODE=$UNICODE diff --git a/Makefile b/Makefile index d41c588..590c6e6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = example +SUBDIRS = example tests .PHONY: subdirs $(SUBDIRS) @@ -13,5 +13,8 @@ clean: $(CLEANDIRS) $(CLEANDIRS): $(MAKE) -C $(@:clean-%=%) clean +test: + $(MAKE) -C tests test + .PHONY: subdirs $(INSTALLDIRS) -.PHONY: clean +.PHONY: clean test diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp new file mode 100644 index 0000000..b5074a7 --- /dev/null +++ b/tests/LoadDll.cpp @@ -0,0 +1,88 @@ +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include "../MemoryModule.h" + +typedef int (*addNumberProc)(int, int); + +BOOL LoadFromMemory(char *filename) +{ + FILE *fp; + unsigned char *data=NULL; + size_t size; + HMEMORYMODULE handle; + addNumberProc addNumber; + HMEMORYRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + TCHAR buffer[100]; + BOOL result = TRUE; + + fp = fopen(filename, "rb"); + if (fp == NULL) + { + printf("Can't open DLL file \"%s\".", filename); + result = FALSE; + 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")); + result = FALSE; + goto exit; + } + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); + _tprintf(_T("String1: %s\n"), buffer); + + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); + _tprintf(_T("String2: %s\n"), buffer); + } else { + result = FALSE; + } + + MemoryFreeLibrary(handle); + +exit: + if (data) + free(data); + return result; +} + +int main(int argc, char* argv[]) +{ + if (argc < 2) { + fprintf(stderr, "USAGE: %s \n", argv[0]); + return 1; + } + + if (!LoadFromMemory(argv[1])) { + return 2; + } + + return 0; +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..aafc6db --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,82 @@ +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) +ifndef PLATFORM +PLATFORM = i686 +endif +CC = $(PLATFORM)-w64-mingw32-g++ +CXX = $(PLATFORM)-w64-mingw32-g++ +LD = $(PLATFORM)-w64-mingw32-ld +RC = $(PLATFORM)-w64-mingw32-windres +else +CC = g++ +CXX = g++ +LD = ld +RC = rc +endif + +RM = rm +CFLAGS = -Wall -g +LDFLAGS = +RCFLAGS = -O coff + +ifdef UNICODE +CFLAGS += -DUNICODE -D_UNICODE +endif + +CFLAGS_DLL = -DSAMPLEDLL_EXPORTS +CFLAGS_EXE = +LDFLAGS_DLL = -shared +LDFLAGS_EXE = -static + +TEST_DLLS = \ + test-align-128.dll \ + test-align-256.dll \ + test-align-512.dll \ + test-align-768.dll \ + test-align-1024.dll \ + test-align-2048.dll \ + test-align-3072.dll \ + test-align-4096.dll \ + test-align-100.dll \ + test-align-200.dll \ + test-align-300.dll \ + test-align-400.dll \ + test-align-500.dll \ + test-align-600.dll \ + test-align-800.dll \ + test-align-900.dll \ + test-align-1000.dll \ + test-relocate.dll \ + +LOADDLL_OBJ = LoadDll.o ../MemoryModule.o +DLL_OBJ = SampleDLL.o SampleDLL.res + +all: LoadDll.exe $(TEST_DLLS) + +LoadDll.exe: $(LOADDLL_OBJ) + $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o LoadDll.exe $(LOADDLL_OBJ) + +LoadDll.o: LoadDll.cpp + $(CXX) $(CFLAGS) $(CFLAGS_EXE) -c $< + +test-align-%.dll: $(DLL_OBJ) + $(LD) $(LDFLAGS_DLL) $(LDFLAGS) --file-alignment $* --section-alignment $* -o $@ $(DLL_OBJ) + +test-relocate.dll: $(DLL_OBJ) + $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o $@ $(DLL_OBJ) + +%.o: %.cpp + $(CXX) $(CFLAGS) $(CFLAGS_DLL) -c $< + +%.o: %.cc + $(CC) $(CFLAGS) $(CFLAGS_DLL) -c $< + +%.res: %.rc + $(RC) $(RCFLAGS) -o $*.res $< + +clean: + $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) + +test: all + ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/SampleDLL.cpp b/tests/SampleDLL.cpp new file mode 100644 index 0000000..7bf03ef --- /dev/null +++ b/tests/SampleDLL.cpp @@ -0,0 +1,10 @@ +#include "SampleDLL.h" + +extern "C" { + +SAMPLEDLL_API int addNumbers(int a, int b) +{ + return a + b; +} + +} diff --git a/tests/SampleDLL.h b/tests/SampleDLL.h new file mode 100644 index 0000000..2662c3c --- /dev/null +++ b/tests/SampleDLL.h @@ -0,0 +1,11 @@ +extern "C" { + +#ifdef SAMPLEDLL_EXPORTS +#define SAMPLEDLL_API __declspec(dllexport) +#else +#define SAMPLEDLL_API __declspec(dllimport) +#endif + +SAMPLEDLL_API int addNumbers(int a, int b); + +} diff --git a/tests/SampleDLL.rc b/tests/SampleDLL.rc new file mode 100644 index 0000000..5a0da61 --- /dev/null +++ b/tests/SampleDLL.rc @@ -0,0 +1,34 @@ +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "fancy.code" + VALUE "FileDescription", "SampleDLL" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "SampleDLL" + VALUE "LegalCopyright", "Copyright (c) 2004-2015 Joachim Bauch" + VALUE "OriginalFilename", "SampleDLL.dll" + VALUE "ProductName", "MemoryModule" + VALUE "ProductVersion", "0.0.4" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +#define IDS_HELLO 1 +#define IDS_WORLD 20 + +STRINGTABLE +{ + IDS_HELLO, "Hello" + IDS_WORLD, "World!" +} diff --git a/tests/runtests.sh b/tests/runtests.sh new file mode 100755 index 0000000..f998f13 --- /dev/null +++ b/tests/runtests.sh @@ -0,0 +1,20 @@ +#!/bin/bash +if [ "$1" = "x86_64" ]; then + export WINEPREFIX=${HOME}/.wine64/ +else + export WINEPREFIX=${HOME}/.wine/ +fi + +read -a TEST_DLLS <<< $2 + +for filename in "${TEST_DLLS[@]}" +do + : + echo "Testing $filename" + ./LoadDll.exe $filename + if [ "$?" != "0" ]; then + exit 1 + fi +done + +echo "${#TEST_DLLS[@]} tests completed successfully" From 31cbe89bfe9a007ffbdaba87435be30269bacad5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:08:48 +0100 Subject: [PATCH 054/123] Run tests before checking samples manually. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9182c08..108523e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ before_install: script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE + - make test PLATFORM=$PLATFORM UNICODE=$UNICODE - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe - - make test PLATFORM=$PLATFORM UNICODE=$UNICODE From d9dc0b02709ae1fff65e7d0183a7d8fe17965272 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:16:33 +0100 Subject: [PATCH 055/123] Setup additional environment flags for wine. --- tests/runtests.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/runtests.sh b/tests/runtests.sh index f998f13..57d70c6 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -1,9 +1,13 @@ #!/bin/bash -if [ "$1" = "x86_64" ]; then +PLATFORM=$1 +if [ "${PLATFORM}" = "x86_64" ]; then export WINEPREFIX=${HOME}/.wine64/ + WINE=wine64 else export WINEPREFIX=${HOME}/.wine/ + WINE=wine fi +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ read -a TEST_DLLS <<< $2 @@ -11,7 +15,7 @@ for filename in "${TEST_DLLS[@]}" do : echo "Testing $filename" - ./LoadDll.exe $filename + ${WINE} ./LoadDll.exe $filename if [ "$?" != "0" ]; then exit 1 fi From dc173cad6ddb7d3afe91b5f3d7b80be1d76df24c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:57:11 +0100 Subject: [PATCH 056/123] Disable alignment of 1000 bytes for now, failing in Travis. --- tests/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index aafc6db..f167a72 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -46,7 +46,6 @@ TEST_DLLS = \ test-align-600.dll \ test-align-800.dll \ test-align-900.dll \ - test-align-1000.dll \ test-relocate.dll \ LOADDLL_OBJ = LoadDll.o ../MemoryModule.o From 89e02fcd9edc6bfb82890757d4269d3fb5ec2186 Mon Sep 17 00:00:00 2001 From: Fr0sT-Brutal Date: Thu, 12 Mar 2015 20:11:05 +0300 Subject: [PATCH 057/123] Zero the memory allocated in the heap Using HEAP_ZERO_MEMORY parameter of HeapAlloc function we can fill all the struct contents with zeros thus removing possible bugs with uninitialized members and slightly shortening/speeding up the code --- MemoryModule.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 8a348a1..682b95d 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -496,7 +496,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } } - result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { SetLastError(ERROR_OUTOFMEMORY); VirtualFree(code, 0, MEM_RELEASE); @@ -504,9 +504,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } result->codeBase = code; - result->numModules = 0; - result->modules = NULL; - result->initialized = FALSE; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; From 82b11d57db127296eafc9029446d44c6c2b67772 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 13 Mar 2015 16:56:02 +0100 Subject: [PATCH 058/123] Call "VirtualFree" before setting error (fixes #23). --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 682b95d..2efb4f3 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -498,8 +498,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { - SetLastError(ERROR_OUTOFMEMORY); VirtualFree(code, 0, MEM_RELEASE); + SetLastError(ERROR_OUTOFMEMORY); return NULL; } From 48d3c5a7f6406b92b2cf8cf76bb6edcdd88e91b9 Mon Sep 17 00:00:00 2001 From: CoolOppo Date: Mon, 6 Apr 2015 15:39:48 -0400 Subject: [PATCH 059/123] Rename readme.txt to readme.rst Makes GitHub actually render the file correctly :unamused: --- doc/{readme.txt => readme.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/{readme.txt => readme.rst} (100%) diff --git a/doc/readme.txt b/doc/readme.rst similarity index 100% rename from doc/readme.txt rename to doc/readme.rst From 6276f4426dd6ff25c991fa33ab7140335a327e8b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 22:18:35 +0200 Subject: [PATCH 060/123] Support imports by ordinal value. Code based on pull-request #28. --- MemoryModule.c | 40 +++++++++++++++++++++++++--------------- MemoryModule.h | 3 ++- tests/LoadDll.cpp | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 2efb4f3..ba8f7b1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -584,9 +584,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - int idx=-1; - DWORD i, *nameRef; - WORD *ordinal; + int idx; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { @@ -602,20 +600,32 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) return NULL; } - // search function name in list of exported names - nameRef = (DWORD *) (codeBase + exports->AddressOfNames); - ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { - idx = *ordinal; - break; + if (HIWORD(name) == 0) { + // load function by ordinal value + if (LOWORD(name) < exports->Base) { + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; } - } - if (idx == -1) { - // exported symbol not found - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; + idx = LOWORD(name) - exports->Base; + } else { + // search function name in list of exported names + DWORD i; + DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); + WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); + idx = -1; + for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { + if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { + idx = *ordinal; + break; + } + } + + if (idx == -1) { + // exported symbol not found + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } } if ((DWORD)idx > exports->NumberOfFunctions) { diff --git a/MemoryModule.h b/MemoryModule.h index 9174ad2..c19255c 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -63,7 +63,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *, void *); /** - * Get address of exported method. + * Get address of exported method. Supports loading both by name and by + * ordinal value. */ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index b5074a7..7bf54c8 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -16,6 +16,7 @@ BOOL LoadFromMemory(char *filename) size_t size; HMEMORYMODULE handle; addNumberProc addNumber; + addNumberProc addNumber2; HMEMORYRSRC resourceInfo; DWORD resourceSize; LPVOID resourceData; @@ -45,9 +46,31 @@ BOOL LoadFromMemory(char *filename) goto exit; } + addNumber = (addNumberProc)MemoryGetProcAddress(handle, NULL); + if (addNumber != NULL) { + _tprintf(_T("MemoryGetProcAddress(NULL) returned %p\n"), addNumber); + result = FALSE; + goto exit; + } + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); + if (addNumber != NULL) { + _tprintf(_T("MemoryGetProcAddress(0xff) returned %p\n"), addNumber); + result = FALSE; + goto exit; + } + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + // the DLL only exports one function, try to load by ordinal value + addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); + if (addNumber != addNumber2) { + _tprintf(_T("MemoryGetProcAddress(0x01) returned %p (expected %p)\n"), addNumber2, addNumber); + result = FALSE; + goto exit; + } + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); From 83899ac7f79359131dbffb1c170c4e33919cf1fc Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 22:26:50 +0200 Subject: [PATCH 061/123] Use DWORD directly to avoid cast. --- MemoryModule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index ba8f7b1..b4fc5cc 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -584,7 +584,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - int idx; + DWORD idx; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { @@ -613,22 +613,23 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) DWORD i; DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - idx = -1; + BOOL found = FALSE; for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { idx = *ordinal; + found = TRUE; break; } } - if (idx == -1) { + if (!found) { // exported symbol not found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } } - if ((DWORD)idx > exports->NumberOfFunctions) { + if (idx > exports->NumberOfFunctions) { // name <-> ordinal number don't match SetLastError(ERROR_PROC_NOT_FOUND); return NULL; From db9c2389f2e2a083e8d6071f02ef6f0433782ec0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 23:56:49 +0200 Subject: [PATCH 062/123] Fix compilation of tests with UNICODE defined. --- tests/LoadDll.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 7bf54c8..4413f48 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -53,7 +53,7 @@ BOOL LoadFromMemory(char *filename) goto exit; } - addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); + addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); if (addNumber != NULL) { _tprintf(_T("MemoryGetProcAddress(0xff) returned %p\n"), addNumber); result = FALSE; @@ -64,7 +64,7 @@ BOOL LoadFromMemory(char *filename) _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); // the DLL only exports one function, try to load by ordinal value - addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); + addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); if (addNumber != addNumber2) { _tprintf(_T("MemoryGetProcAddress(0x01) returned %p (expected %p)\n"), addNumber2, addNumber); result = FALSE; From 78330cd2f1ceb61829d40d9e137e571070242146 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 23:59:29 +0200 Subject: [PATCH 063/123] Simplify package installation. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 108523e..7d08b80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,7 @@ cache: before_install: - sudo apt-get update -qq - - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" - - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" + - sudo apt-get install -qq wine gcc-mingw-w64-$PLATFORM g++-mingw-w64-$PLATFORM binutils-mingw-w64-$PLATFORM mingw-w64-dev script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 5a0c512885b944c13b47423485e6abb94519f958 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:02:25 +0200 Subject: [PATCH 064/123] Revert 78330cd2f1ceb61829d40d9e137e571070242146, package names don't match platform. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7d08b80..108523e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,8 @@ cache: before_install: - sudo apt-get update -qq - - sudo apt-get install -qq wine gcc-mingw-w64-$PLATFORM g++-mingw-w64-$PLATFORM binutils-mingw-w64-$PLATFORM mingw-w64-dev + - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" + - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 70c497701952c9557c4c268709f07658fd11f4aa Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:10:01 +0200 Subject: [PATCH 065/123] Switch to container-based infrastructure. --- .travis.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 108523e..629c752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +sudo: false + env: - PLATFORM=x86_64 WINE=wine64 UNICODE= - PLATFORM=i686 WINE=wine UNICODE= @@ -8,11 +10,19 @@ language: cpp cache: - apt + - ccache -before_install: - - sudo apt-get update -qq - - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" - - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" +addons: + apt: + packages: + - binutils-mingw-w64-i686 + - binutils-mingw-w64-x86-64 + - mingw-w64-dev + - g++-mingw-w64-i686 + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-i686 + - gcc-mingw-w64-x86-64 + - wine script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 8c3d253325ed718ef5d26a25964a4cd2e24b4ba3 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:32:13 +0200 Subject: [PATCH 066/123] Support building with cmake. --- .travis.yml | 21 ++++++++++----- CMakeLists.txt | 45 ++++++++++++++++++++++++++++++++ example/CMakeLists.txt | 2 ++ example/DllLoader/CMakeLists.txt | 26 ++++++++++++++++++ example/SampleDLL/CMakeLists.txt | 12 +++++++++ 5 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 example/CMakeLists.txt create mode 100644 example/DllLoader/CMakeLists.txt create mode 100644 example/SampleDLL/CMakeLists.txt diff --git a/.travis.yml b/.travis.yml index 629c752..e9dcb84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ sudo: false env: - - PLATFORM=x86_64 WINE=wine64 UNICODE= - - PLATFORM=i686 WINE=wine UNICODE= - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 - - PLATFORM=i686 WINE=wine UNICODE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE= + - PLATFORM=i686 WINE=wine UNICODE= CMAKE= + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE= + - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE= + - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE=1 + - PLATFORM=i686 WINE=wine UNICODE= CMAKE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE=1 + - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE=1 language: cpp @@ -17,6 +21,7 @@ addons: packages: - binutils-mingw-w64-i686 - binutils-mingw-w64-x86-64 + - cmake - mingw-w64-dev - g++-mingw-w64-i686 - g++-mingw-w64-x86-64 @@ -24,9 +29,13 @@ addons: - gcc-mingw-w64-x86-64 - wine +before_script: + - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -D UNICODE=$UNICODE -H. -B.; fi + script: - - make PLATFORM=$PLATFORM UNICODE=$UNICODE - - make test PLATFORM=$PLATFORM UNICODE=$UNICODE + - if [ -z "$CMAKE" ]; then make PLATFORM=$PLATFORM UNICODE=$UNICODE; fi + - if [ -z "$CMAKE" ]; then make test PLATFORM=$PLATFORM UNICODE=$UNICODE; fi + - if [ ! -z "$CMAKE" ]; then cmake --build .; fi - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..52aed26 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,45 @@ +project (MemoryModule) +cmake_minimum_required (VERSION 2.8.7) + +set (PLATFORM "x86_64" CACHE STRING "Platform to compile for") +message (STATUS "Compile for ${PLATFORM} platform") + +if (NOT MSVC) + set (CMAKE_SYSTEM_NAME Windows) + set (CMAKE_POSITION_INDEPENDENT_CODE False) + + set (COMPILER_PREFIX "${PLATFORM}-w64-mingw32") + set (CMAKE_C_COMPILER "${COMPILER_PREFIX}-gcc") + set (CMAKE_CXX_COMPILER "${COMPILER_PREFIX}-g++") + set (CMAKE_RC_COMPILER "${COMPILER_PREFIX}-windres") + set (CMAKE_AR "${COMPILER_PREFIX}-ar") + set (CMAKE_RANLIB "${COMPILER_PREFIX}-ranlib") + + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + + set (CMAKE_RC_COMPILE_OBJECT "${CMAKE_RC_COMPILER} -O coff -I${CMAKE_CURRENT_SOURCE_DIR} ") +endif () + +add_definitions ("-Wall") + +option(UNICODE "Compile with UNICODE support" OFF) +if (UNICODE) + message (STATUS "Compile with UNICODE support") + add_definitions ("-DUNICODE" "-D_UNICODE") +else () + message (STATUS "Compile without UNICODE support") +endif () + +add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) +if (NOT MSVC) + set_target_properties ("MemoryModule" PROPERTIES PREFIX "") +endif () + +add_subdirectory (example) + +enable_language (RC) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..dff006d --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory (DllLoader) +add_subdirectory (SampleDLL) diff --git a/example/DllLoader/CMakeLists.txt b/example/DllLoader/CMakeLists.txt new file mode 100644 index 0000000..c2be9a7 --- /dev/null +++ b/example/DllLoader/CMakeLists.txt @@ -0,0 +1,26 @@ +set (sources_dllloader + DllLoader.cpp +) + +set (sources_dllloaderloader + DllLoaderLoader.cpp +) + +if (NOT MSVC) + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-static") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-static") +endif () + +add_executable (DllLoader ${sources_dllloader}) +target_link_libraries ("DllLoader" "MemoryModule") +if (NOT MSVC) + set_target_properties ("DllLoader" PROPERTIES SUFFIX ".exe") + set_target_properties ("DllLoader" PROPERTIES LINK_FLAGS "-Wl,--image-base -Wl,0x20000000") +endif () + +add_executable (DllLoaderLoader ${sources_dllloaderloader}) +target_link_libraries ("DllLoaderLoader" "MemoryModule") +if (NOT MSVC) + set_target_properties ("DllLoaderLoader" PROPERTIES SUFFIX ".exe") + set_target_properties ("DllLoaderLoader" PROPERTIES LINK_FLAGS "-Wl,--image-base -Wl,0x10000000") +endif () diff --git a/example/SampleDLL/CMakeLists.txt b/example/SampleDLL/CMakeLists.txt new file mode 100644 index 0000000..e3a3af3 --- /dev/null +++ b/example/SampleDLL/CMakeLists.txt @@ -0,0 +1,12 @@ +set (sources + SampleDLL.cpp + SampleDLL.h + SampleDLL.rc +) + +add_definitions (-DSAMPLEDLL_EXPORTS) +add_library (SampleDLL MODULE ${sources}) +if (NOT MSVC) + set_target_properties ("SampleDLL" PROPERTIES PREFIX "") + set_target_properties ("SampleDLL" PROPERTIES SUFFIX ".dll") +endif () From a13ad18e11d5c20ab860202545659f117ddb1fc6 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:03:50 +0200 Subject: [PATCH 067/123] Added AppVeyor CI integration. --- CMakeLists.txt | 6 +++++- appveyor.yml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 52aed26..9ddd49a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,11 @@ if (NOT MSVC) set (CMAKE_RC_COMPILE_OBJECT "${CMAKE_RC_COMPILER} -O coff -I${CMAKE_CURRENT_SOURCE_DIR} ") endif () -add_definitions ("-Wall") +if (NOT MSVC) + add_definitions ("-Wall") +else () + add_definitions ("-W4") +endif () option(UNICODE "Compile with UNICODE support" OFF) if (UNICODE) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..24e01ac --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,44 @@ +version: #{build} + +os: + - Windows Server 2012 R2 + +environment: + matrix: + - GENERATOR: "Visual Studio 10 2010" + UNICODE: ON + - GENERATOR: "Visual Studio 10 2010" + UNICODE: OFF + - GENERATOR: "Visual Studio 11 2012" + UNICODE: ON + - GENERATOR: "Visual Studio 11 2012" + UNICODE: OFF + - GENERATOR: "Visual Studio 12 2013" + UNICODE: ON + - GENERATOR: "Visual Studio 12 2013" + UNICODE: OFF + +platform: + - x86 + - x64 + +configuration: + - Debug + +build: + verbosity: normal + +build_script: + - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } + - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild + - cmake --build build --config %CONFIGURATION% + +before_test: + - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ + - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ + - copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ + +test_script: + - cd build\example\DllLoader + - DllLoader.exe + - DllLoaderLoader.exe From 422f918c3384f7fe9e8ff1fe142338d690327b3c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:17:03 +0200 Subject: [PATCH 068/123] Declare variables at start of function. --- MemoryModule.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index b4fc5cc..b4ace84 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -270,14 +270,16 @@ static BOOL ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; + PIMAGE_TLS_DIRECTORY tls; + PIMAGE_TLS_CALLBACK* callback; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); if (directory->VirtualAddress == 0) { return TRUE; } - PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); - PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; + tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); + callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; if (callback) { while (*callback) { (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); From b4bf2f7c4aa2b98ba7c124ca8a00265c5bb0da09 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:28:43 +0200 Subject: [PATCH 069/123] Don't disable warnings about conversions. --- MemoryModule.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index b4ace84..35920a4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -24,11 +24,6 @@ * */ -#ifndef __GNUC__ -// disable warnings about pointer <-> DWORD conversions -#pragma warning( disable : 4311 4312 ) -#endif - #include #include #include From 62e357e51521c0c7f33ebdb437bf596b4d4a13b2 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 23:56:52 +0200 Subject: [PATCH 070/123] Added information about build status. --- appveyor.yml | 2 ++ readme.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 24e01ac..676f268 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,5 @@ +# Status available at +# https://ci.appveyor.com/project/fancycode/memorymodule version: #{build} os: diff --git a/readme.md b/readme.md index ab35ac6..607ddba 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ MemoryModule ============ -[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule) +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's From 8d5dbf39e84db977ea2bc1bca4010ec5ef167d6d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 23 Aug 2015 00:02:04 +0200 Subject: [PATCH 071/123] Show AppVeyor status of master branch. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 607ddba..aa9f497 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ MemoryModule ============ -[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx/branch/master?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's From d19707369a4410bfa45430d722bcc9b40f291e1f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 23 Aug 2015 00:22:42 +0200 Subject: [PATCH 072/123] Avoid (re-)allocations when searching for named resources. Also add tests to load resources by name. --- MemoryModule.c | 53 +++++++++++++-------- tests/LoadDll.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++ tests/SampleDLL.rc | 24 ++++++++++ 3 files changed, 174 insertions(+), 19 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 35920a4..567799a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -729,32 +729,45 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } } else { -#if !defined(UNICODE) - char *searchKey = NULL; - int searchKeyLength = 0; + LPCWSTR searchKey; + size_t searchKeyLen = _tcslen(key); +#if defined(UNICODE) + searchKey = key; +#else + // Resource names are always stored using 16bit characters, need to + // convert string we search for. +#define MAX_LOCAL_KEY_LENGTH 2048 + // In most cases resource names are short, so optimize for that by + // using a pre-allocated array. + wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; + LPWSTR _searchKey; + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t); + _searchKey = (LPWSTR) malloc(_searchKeySize); + if (_searchKey == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } else { + _searchKey = &_searchKeySpace[0]; + } + + mbstowcs(_searchKey, key, searchKeyLen); + _searchKey[searchKeyLen] = 0; + searchKey = _searchKey; #endif start = 0; end = resources->NumberOfNamedEntries; while (end > start) { - // resource names are always stored using 16bit characters int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); -#if !defined(UNICODE) - if (searchKey == NULL || searchKeyLength < resourceString->Length) { - void *tmp = realloc(searchKey, resourceString->Length); - if (tmp == NULL) { - break; - } - - searchKey = (char *) tmp; + cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); + if (cmp == 0) { + // Handle partial match + cmp = searchKeyLen - resourceString->Length; } - wcstombs(searchKey, resourceString->NameString, resourceString->Length); - cmp = strncmp(key, searchKey, resourceString->Length); -#else - cmp = wcsncmp(key, resourceString->NameString, resourceString->Length); -#endif if (cmp < 0) { end = (middle != end ? middle : middle-1); } else if (cmp > 0) { @@ -765,11 +778,13 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } #if !defined(UNICODE) - free(searchKey); + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + free(_searchKey); + } +#undef MAX_LOCAL_KEY_LENGTH #endif } - return result; } diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 4413f48..43cf8fd 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -9,6 +9,64 @@ typedef int (*addNumberProc)(int, int); +// Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708) +const char *sstrstr(const char *haystack, const char *needle, size_t length) { + size_t needle_length = strlen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (strncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +const wchar_t *swcsstr(const wchar_t *haystack, const wchar_t *needle, size_t length) { + size_t needle_length = wcslen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (wcsncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +BOOL CheckResourceStrings(LPVOID data, DWORD size, const char *first, const wchar_t *second) { + const char *first_pos; + const wchar_t *second_pos; + const wchar_t *src; + + if (data == NULL || size == 0) { + return FALSE; + } + + first_pos = sstrstr((const char *) data, first, size); + if (first_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't start with %s\n", first); + return FALSE; + } + + src = (const wchar_t *) (((const char *) data) + strlen(first) + 1); + second_pos = swcsstr(src, second, (size - strlen(first) - 1) / sizeof(wchar_t)); + if (second_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't continue with %S\n", second); + return FALSE; + } + + return TRUE; +} + BOOL LoadFromMemory(char *filename) { FILE *fp; @@ -88,6 +146,64 @@ BOOL LoadFromMemory(char *filename) result = FALSE; } + resourceInfo = MemoryFindResource(handle, _T("stringres"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is a ANSI string", L"This is a UNICODE string")) { + result = FALSE; + } + } else { + result = FALSE; + } + + resourceInfo = MemoryFindResource(handle, _T("stringres1"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 1", L"This is UNICODE string 1")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres2"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 2", L"This is UNICODE string 2")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres3"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 3", L"This is UNICODE string 3")) { + result = FALSE; + } + } else { + result = FALSE; + } + MemoryFreeLibrary(handle); exit: diff --git a/tests/SampleDLL.rc b/tests/SampleDLL.rc index 5a0da61..bbe5774 100644 --- a/tests/SampleDLL.rc +++ b/tests/SampleDLL.rc @@ -32,3 +32,27 @@ STRINGTABLE IDS_HELLO, "Hello" IDS_WORLD, "World!" } + +STRINGRES RCDATA +{ + "This is a ANSI string\0", + L"This is a UNICODE string\0", +} + +STRINGRES1 RCDATA +{ + "This is ANSI string 1\0", + L"This is UNICODE string 1\0", +} + +STRINGRES2 RCDATA +{ + "This is ANSI string 2\0", + L"This is UNICODE string 2\0", +} + +STRINGRES3 RCDATA +{ + "This is ANSI string 3\0", + L"This is UNICODE string 3\0", +} From 71643ae62bbe44cfb49baa95fd7b8da55c6d66b3 Mon Sep 17 00:00:00 2001 From: Vlatko Kosturjak Date: Sun, 18 Oct 2015 11:13:24 +0200 Subject: [PATCH 073/123] Use _wcsnicmp instead of wcsnicmp "These POSIX functions are deprecated. Use the ISO C++ conformant" https://msdn.microsoft.com/en-us/library/ms235324.aspx --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 567799a..cb888ed 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -763,7 +763,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); - cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); + cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match cmp = searchKeyLen - resourceString->Length; From 9df6e7dc93060287581f2f1add0ed84f1232d01c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 18:53:18 +0100 Subject: [PATCH 074/123] Add more error checking of return values. --- example/DllLoader/DllLoader.cpp | 12 ++++++++---- example/DllLoader/DllLoaderLoader.cpp | 12 ++++++++---- tests/LoadDll.cpp | 19 +++++++++++-------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 3fda631..fb41f76 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -1,5 +1,6 @@ #define WIN32_LEAN_AND_MEAN +#include #include #include #include @@ -46,7 +47,8 @@ void LoadFromMemory(void) { FILE *fp; unsigned char *data=NULL; - size_t size; + long size; + size_t read; HMEMORYMODULE handle; addNumberProc addNumber; HMEMORYRSRC resourceInfo; @@ -63,9 +65,12 @@ void LoadFromMemory(void) fseek(fp, 0, SEEK_END); size = ftell(fp); + assert(size >= 0); data = (unsigned char *)malloc(size); + assert(data != NULL); fseek(fp, 0, SEEK_SET); - fread(data, 1, size, fp); + read = fread(data, 1, size, fp); + assert(read == static_cast(size)); fclose(fp); handle = MemoryLoadLibrary(data); @@ -94,8 +99,7 @@ void LoadFromMemory(void) MemoryFreeLibrary(handle); exit: - if (data) - free(data); + free(data); } int main(int argc, char* argv[]) diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp index e49979e..8c56413 100644 --- a/example/DllLoader/DllLoaderLoader.cpp +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -1,5 +1,6 @@ #define WIN32_LEAN_AND_MEAN +#include #include #include #include @@ -13,7 +14,8 @@ int RunFromMemory(void) { FILE *fp; unsigned char *data=NULL; - size_t size; + long size; + size_t read; HMEMORYMODULE handle; int result = -1; @@ -26,9 +28,12 @@ int RunFromMemory(void) fseek(fp, 0, SEEK_END); size = ftell(fp); + assert(size >= 0); data = (unsigned char *)malloc(size); + assert(data != NULL); fseek(fp, 0, SEEK_SET); - fread(data, 1, size, fp); + read = fread(data, 1, size, fp); + assert(read == static_cast(size)); fclose(fp); handle = MemoryLoadLibrary(data); @@ -45,8 +50,7 @@ int RunFromMemory(void) MemoryFreeLibrary(handle); exit: - if (data) - free(data); + free(data); return result; } diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 43cf8fd..81d4811 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -1,5 +1,6 @@ #define WIN32_LEAN_AND_MEAN +#include #include #include #include @@ -60,7 +61,7 @@ BOOL CheckResourceStrings(LPVOID data, DWORD size, const char *first, const wcha src = (const wchar_t *) (((const char *) data) + strlen(first) + 1); second_pos = swcsstr(src, second, (size - strlen(first) - 1) / sizeof(wchar_t)); if (second_pos == NULL) { - fprintf(stderr, "ERROR: data doesn't continue with %S\n", second); + fwprintf(stderr, L"ERROR: data doesn't continue with %s\n", second); return FALSE; } @@ -71,8 +72,9 @@ BOOL LoadFromMemory(char *filename) { FILE *fp; unsigned char *data=NULL; - size_t size; - HMEMORYMODULE handle; + long size; + size_t read; + HMEMORYMODULE handle = NULL; addNumberProc addNumber; addNumberProc addNumber2; HMEMORYRSRC resourceInfo; @@ -91,9 +93,12 @@ BOOL LoadFromMemory(char *filename) fseek(fp, 0, SEEK_END); size = ftell(fp); + assert(size > 0); data = (unsigned char *)malloc(size); + assert(data != NULL); fseek(fp, 0, SEEK_SET); - fread(data, 1, size, fp); + read = fread(data, 1, size, fp); + assert(read == static_cast(size)); fclose(fp); handle = MemoryLoadLibrary(data); @@ -204,11 +209,9 @@ BOOL LoadFromMemory(char *filename) result = FALSE; } - MemoryFreeLibrary(handle); - exit: - if (data) - free(data); + MemoryFreeLibrary(handle); + free(data); return result; } From bc048535848f8b83c916a7b27588c3696e759165 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:26:29 +0100 Subject: [PATCH 075/123] Add some checks to prevent overruns on broken input. --- MemoryModule.c | 89 +++++++++++++++++++++------ MemoryModule.h | 9 +-- doc/readme.rst | 2 +- example/DllLoader/DllLoader.cpp | 2 +- example/DllLoader/DllLoaderLoader.cpp | 2 +- tests/LoadDll.cpp | 2 +- 6 files changed, 80 insertions(+), 26 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index cb888ed..c1cc9d6 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -68,6 +68,7 @@ typedef struct { #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) +#define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) #ifdef DEBUG_OUTPUT static void @@ -86,9 +87,19 @@ OutputLastError(const char *msg) #endif static BOOL -CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) +CheckSize(size_t size, size_t expected) { + if (size < expected) { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + + return TRUE; +} + +static BOOL +CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { - int i, size; + int i, section_size; unsigned char *codeBase = module->codeBase; unsigned char *dest; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); @@ -96,10 +107,10 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO if (section->SizeOfRawData == 0) { // section doesn't contain data in the dll itself, but may define // uninitialized data - size = old_headers->OptionalHeader.SectionAlignment; - if (size > 0) { + section_size = old_headers->OptionalHeader.SectionAlignment; + if (section_size > 0) { dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, - size, + section_size, MEM_COMMIT, PAGE_READWRITE); if (dest == NULL) { @@ -110,13 +121,17 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO // than page size. dest = codeBase + section->VirtualAddress; section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; - memset(dest, 0, size); + memset(dest, 0, section_size); } // section is empty continue; } + if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) { + return FALSE; + } + // commit memory block and copy data from dll dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, section->SizeOfRawData, @@ -285,7 +300,7 @@ ExecuteTLS(PMEMORYMODULE module) } static BOOL -PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) +PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) { unsigned char *codeBase = module->codeBase; PIMAGE_BASE_RELOCATION relocation; @@ -428,30 +443,43 @@ static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) FreeLibrary((HMODULE) module); } -HMEMORYMODULE MemoryLoadLibrary(const void *data) +HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size) { - return MemoryLoadLibraryEx(data, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL); + return MemoryLoadLibraryEx(data, size, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL); } -HMEMORYMODULE MemoryLoadLibraryEx(const void *data, +#include + +HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, CustomFreeLibraryFunc freeLibrary, void *userdata) { - PMEMORYMODULE result; + PMEMORYMODULE result = NULL; PIMAGE_DOS_HEADER dos_header; PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; - SIZE_T locationDelta; + ptrdiff_t locationDelta; SYSTEM_INFO sysInfo; + PIMAGE_SECTION_HEADER section; + DWORD i; + size_t optionalSectionSize; + size_t lastSectionEnd = 0; + size_t alignedImageSize; + if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) { + return NULL; + } dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } + if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) { + return NULL; + } old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; if (old_header->Signature != IMAGE_NT_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); @@ -473,18 +501,41 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } + section = IMAGE_FIRST_SECTION(old_header); + optionalSectionSize = old_header->OptionalHeader.SectionAlignment; + for (i=0; iFileHeader.NumberOfSections; i++, section++) { + size_t endOfSection; + if (section->SizeOfRawData == 0) { + // Section without data in the DLL + endOfSection = section->VirtualAddress + optionalSectionSize; + } else { + endOfSection = section->VirtualAddress + section->SizeOfRawData; + } + + if (endOfSection > lastSectionEnd) { + lastSectionEnd = endOfSection; + } + } + + GetNativeSystemInfo(&sysInfo); + alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); + if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), - old_header->OptionalHeader.SizeOfImage, + alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { // try to allocate memory at arbitrary position code = (unsigned char *)VirtualAlloc(NULL, - old_header->OptionalHeader.SizeOfImage, + alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { @@ -506,10 +557,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->getProcAddress = getProcAddress; result->freeLibrary = freeLibrary; result->userdata = userdata; - - GetNativeSystemInfo(&sysInfo); result->pageSize = sysInfo.dwPageSize; + if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) { + goto error; + } + // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, @@ -524,12 +577,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location - if (!CopySections((const unsigned char *) data, old_header, result)) { + if (!CopySections((const unsigned char *) data, size, old_header, result)) { goto error; } // adjust base address of imported data - locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); + locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { result->isRelocated = PerformBaseRelocation(result, locationDelta); } else { diff --git a/MemoryModule.h b/MemoryModule.h index c19255c..2cd4867 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -44,19 +44,20 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); /** - * Load EXE/DLL from memory location. + * Load EXE/DLL from memory location with the given size. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. */ -HMEMORYMODULE MemoryLoadLibrary(const void *); +HMEMORYMODULE MemoryLoadLibrary(const void *, size_t); /** - * Load EXE/DLL from memory location using custom dependency resolvers. + * Load EXE/DLL from memory location with the given size using custom dependency + * resolvers. * * Dependencies will be resolved using passed callback methods. */ -HMEMORYMODULE MemoryLoadLibraryEx(const void *, +HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t, CustomLoadLibraryFunc, CustomGetProcAddressFunc, CustomFreeLibraryFunc, diff --git a/doc/readme.rst b/doc/readme.rst index 7e02c1b..ba6513c 100644 --- a/doc/readme.rst +++ b/doc/readme.rst @@ -511,7 +511,7 @@ The interface is very similar to the standard methods for loading of libraries:: typedef void *HMEMORYMODULE; - HMEMORYMODULE MemoryLoadLibrary(const void *); + HMEMORYMODULE MemoryLoadLibrary(const void *, size_t); FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); void MemoryFreeLibrary(HMEMORYMODULE); diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index fb41f76..8ca743f 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -73,7 +73,7 @@ void LoadFromMemory(void) assert(read == static_cast(size)); fclose(fp); - handle = MemoryLoadLibrary(data); + handle = MemoryLoadLibrary(data, size); if (handle == NULL) { _tprintf(_T("Can't load library from memory.\n")); diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp index 8c56413..0fe774e 100644 --- a/example/DllLoader/DllLoaderLoader.cpp +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -36,7 +36,7 @@ int RunFromMemory(void) assert(read == static_cast(size)); fclose(fp); - handle = MemoryLoadLibrary(data); + handle = MemoryLoadLibrary(data, size); if (handle == NULL) { _tprintf(_T("Can't load library from memory.\n")); diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 81d4811..67b55d0 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -101,7 +101,7 @@ BOOL LoadFromMemory(char *filename) assert(read == static_cast(size)); fclose(fp); - handle = MemoryLoadLibrary(data); + handle = MemoryLoadLibrary(data, size); if (handle == NULL) { _tprintf(_T("Can't load library from memory.\n")); From 583e1b4a93b8955864b5596c41c513c264b6ec38 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:34:14 +0100 Subject: [PATCH 076/123] Fixed warning about unreferenced parameters. --- MemoryModule.c | 4 ++++ example/DllLoader/DllLoader.cpp | 2 +- example/DllLoader/DllLoaderLoader.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index c1cc9d6..4121751 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -425,6 +425,7 @@ BuildImportTable(PMEMORYMODULE module) static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) { + UNREFERENCED_PARAMETER(userdata); HMODULE result = LoadLibraryA(filename); if (result == NULL) { return NULL; @@ -435,11 +436,13 @@ static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) static FARPROC _GetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) { + UNREFERENCED_PARAMETER(userdata); return (FARPROC) GetProcAddress((HMODULE) module, name); } static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) { + UNREFERENCED_PARAMETER(userdata); FreeLibrary((HMODULE) module); } @@ -897,6 +900,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { + UNREFERENCED_PARAMETER(module); PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; if (entry == NULL) { return 0; diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 8ca743f..b56f70f 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -102,7 +102,7 @@ void LoadFromMemory(void) free(data); } -int main(int argc, char* argv[]) +int main() { LoadFromFile(); printf("\n\n"); diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp index 0fe774e..14bcb4b 100644 --- a/example/DllLoader/DllLoaderLoader.cpp +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -54,7 +54,7 @@ int RunFromMemory(void) return result; } -int main(int argc, char* argv[]) +int main() { return RunFromMemory(); } From 15983313f417289b3783356b0b89aa629d138a56 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:38:30 +0100 Subject: [PATCH 077/123] Removed debug include. --- MemoryModule.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 4121751..7e14c9e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -451,8 +451,6 @@ HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size) return MemoryLoadLibraryEx(data, size, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL); } -#include - HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, From 394fae8d513d662bf8b208ee39c6e020d16f0889 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:39:47 +0100 Subject: [PATCH 078/123] Initialize variable (to make MSVC happy). --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7e14c9e..7386544 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -635,7 +635,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - DWORD idx; + DWORD idx = 0; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { From 5bda2104b9c38a8355c3d415859e0ee9d73ef2fb Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:43:35 +0100 Subject: [PATCH 079/123] Define "_CRT_SECURE_NO_WARNINGS" when compiling examples/tests. --- example/DllLoader/DllLoader.cpp | 3 +++ example/DllLoader/DllLoaderLoader.cpp | 3 +++ tests/LoadDll.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index b56f70f..4ff1a20 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -1,4 +1,7 @@ #define WIN32_LEAN_AND_MEAN +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif #include #include diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp index 14bcb4b..b7174f5 100644 --- a/example/DllLoader/DllLoaderLoader.cpp +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -1,4 +1,7 @@ #define WIN32_LEAN_AND_MEAN +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif #include #include diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 67b55d0..07a2538 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -1,4 +1,7 @@ #define WIN32_LEAN_AND_MEAN +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif #include #include From cddc54a671a6618777e2b251b336fff730cac36b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 21:51:29 +0100 Subject: [PATCH 080/123] Fixed syntax error on MSVC. --- MemoryModule.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7386544..eb3470d 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -425,8 +425,9 @@ BuildImportTable(PMEMORYMODULE module) static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) { + HMODULE result; UNREFERENCED_PARAMETER(userdata); - HMODULE result = LoadLibraryA(filename); + result = LoadLibraryA(filename); if (result == NULL) { return NULL; } @@ -898,8 +899,9 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { + PIMAGE_RESOURCE_DATA_ENTRY entry; UNREFERENCED_PARAMETER(module); - PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; if (entry == NULL) { return 0; } From cc562219afd5f7e4c946d7dc0b08ba3b4efabd4b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 22:07:30 +0100 Subject: [PATCH 081/123] Fix C4055 on MSVC. --- MemoryModule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index eb3470d..aefda09 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -610,7 +610,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { if (result->isDLL) { - DllEntryProc DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); + DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); // notify library about attaching to process BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); if (!successfull) { @@ -619,7 +619,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } result->initialized = TRUE; } else { - result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); + result->exeEntry = (ExeEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); } } else { result->exeEntry = NULL; @@ -688,7 +688,7 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) } // AddressOfFunctions contains the RVAs to the "real" functions - return (FARPROC) (codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); + return (FARPROC)(LPVOID)(codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); } void MemoryFreeLibrary(HMEMORYMODULE mod) @@ -700,7 +700,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) } if (module->initialized) { // notify library about detaching from process - DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); + DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } From 2e193f153a44c05f50ec9f59c66a17e9bd8a4055 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 22:13:27 +0100 Subject: [PATCH 082/123] Also build on MSVC 2015. --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 676f268..8fb52dd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ version: #{build} os: - - Windows Server 2012 R2 + - Visual Studio 2015 environment: matrix: @@ -19,6 +19,10 @@ environment: UNICODE: ON - GENERATOR: "Visual Studio 12 2013" UNICODE: OFF + - GENERATOR: "Visual Studio 14 2015" + UNICODE: ON + - GENERATOR: "Visual Studio 14 2015" + UNICODE: OFF platform: - x86 From 905ad75e824f5e4ee40ef15f1f8e01dfcd41aeff Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 27 Jan 2016 00:38:37 +0100 Subject: [PATCH 083/123] Expose default callback functions. This was suggested in #33. --- MemoryModule.c | 8 ++++---- MemoryModule.h | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index aefda09..131da91 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -423,7 +423,7 @@ BuildImportTable(PMEMORYMODULE module) return result; } -static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) +HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR filename, void *userdata) { HMODULE result; UNREFERENCED_PARAMETER(userdata); @@ -435,13 +435,13 @@ static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) return (HCUSTOMMODULE) result; } -static FARPROC _GetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) +FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) { UNREFERENCED_PARAMETER(userdata); return (FARPROC) GetProcAddress((HMODULE) module, name); } -static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) +void MemoryDefaultFreeLibrary(HCUSTOMMODULE module, void *userdata) { UNREFERENCED_PARAMETER(userdata); FreeLibrary((HMODULE) module); @@ -449,7 +449,7 @@ static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size) { - return MemoryLoadLibraryEx(data, size, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL); + return MemoryLoadLibraryEx(data, size, MemoryDefaultLoadLibrary, MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, NULL); } HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, diff --git a/MemoryModule.h b/MemoryModule.h index 2cd4867..d8f3938 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -117,6 +117,30 @@ int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); */ int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); +/** + * Default implementation of CustomLoadLibraryFunc that calls LoadLibraryA + * internally to load an additional libary. + * + * This is the default as used by MemoryLoadLibrary. + */ +HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR, void *); + +/** + * Default implementation of CustomGetProcAddressFunc that calls GetProcAddress + * internally to get the address of an exported function. + * + * This is the default as used by MemoryLoadLibrary. + */ +FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE, LPCSTR, void *); + +/** + * Default implementation of CustomFreeLibraryFunc that calls FreeLibrary + * internally to release an additional libary. + * + * This is the default as used by MemoryLoadLibrary. + */ +void MemoryDefaultFreeLibrary(HCUSTOMMODULE, void *); + #ifdef __cplusplus } #endif From d9a6bb9c8ff94796ef7700341f8960c5aa4499b0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 27 Jan 2016 00:44:43 +0100 Subject: [PATCH 084/123] Explicitly include "stdint.h" to make sure "uintptr_t" is defined (fixes #34). --- MemoryModule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/MemoryModule.c b/MemoryModule.c index 131da91..3156add 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef DEBUG_OUTPUT #include From d88817fbf7debbd0a0c2f5cc6e193f3a38f1d114 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 27 Jan 2016 00:57:06 +0100 Subject: [PATCH 085/123] Disable C4055 warning (data -> function pointer conversion). --- MemoryModule.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 3156add..cabaabb 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -33,6 +33,11 @@ #include #endif +#if _MSC_VER +// Disable warning about data -> function pointer conversion +#pragma warning(disable:4055) +#endif + #ifndef IMAGE_SIZEOF_BASE_RELOCATION // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!? #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) From d46b74d00d3fd31f20f34e7c5808cfb6414e658f Mon Sep 17 00:00:00 2001 From: Joan Karadimov Date: Thu, 21 Jan 2016 01:45:07 +0200 Subject: [PATCH 086/123] Pass alloc/free functions to MemoryLoadLibraryEx --- MemoryModule.c | 51 ++++++++++++++++++++++++++++++++++++-------------- MemoryModule.h | 20 ++++++++++++++++++++ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index cabaabb..d8d3f3a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -56,6 +56,8 @@ typedef struct { BOOL initialized; BOOL isDLL; BOOL isRelocated; + CustomAllocFunc alloc; + CustomFreeFunc free; CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; @@ -115,10 +117,11 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade // uninitialized data section_size = old_headers->OptionalHeader.SectionAlignment; if (section_size > 0) { - dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, + dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, section_size, MEM_COMMIT, - PAGE_READWRITE); + PAGE_READWRITE, + module->userdata); if (dest == NULL) { return FALSE; } @@ -139,10 +142,11 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade } // commit memory block and copy data from dll - dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, + dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_COMMIT, - PAGE_READWRITE); + PAGE_READWRITE, + module->userdata); if (dest == NULL) { return FALSE; } @@ -202,7 +206,7 @@ FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { (sectionData->size % module->pageSize) == 0) ) { // Only allowed to decommit whole pages - VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT); + module->free(sectionData->address, sectionData->size, MEM_DECOMMIT, module->userdata); } return TRUE; } @@ -429,6 +433,18 @@ BuildImportTable(PMEMORYMODULE module) return result; } +LPVOID MemoryDefaultAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) +{ + UNREFERENCED_PARAMETER(userdata); + return VirtualAlloc(address, size, allocationType, protect); +} + +BOOL MemoryDefaultFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType, void* userdata) +{ + UNREFERENCED_PARAMETER(userdata); + return VirtualFree(lpAddress, dwSize, dwFreeType); +} + HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR filename, void *userdata) { HMODULE result; @@ -455,10 +471,12 @@ void MemoryDefaultFreeLibrary(HCUSTOMMODULE module, void *userdata) HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size) { - return MemoryLoadLibraryEx(data, size, MemoryDefaultLoadLibrary, MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, NULL); + return MemoryLoadLibraryEx(data, size, MemoryDefaultAlloc, MemoryDefaultFree, MemoryDefaultLoadLibrary, MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, NULL); } HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, + CustomAllocFunc allocMemory, + CustomFreeFunc freeMemory, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, CustomFreeLibraryFunc freeLibrary, @@ -535,17 +553,19 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... - code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), + code = (unsigned char *)allocMemory((LPVOID)(old_header->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); + PAGE_READWRITE, + userdata); if (code == NULL) { // try to allocate memory at arbitrary position - code = (unsigned char *)VirtualAlloc(NULL, + code = (unsigned char *)allocMemory(NULL, alignedImageSize, MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); + PAGE_READWRITE, + userdata); if (code == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; @@ -554,13 +574,15 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { - VirtualFree(code, 0, MEM_RELEASE); + freeMemory(code, 0, MEM_RELEASE, userdata); SetLastError(ERROR_OUTOFMEMORY); return NULL; } result->codeBase = code; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; + result->alloc = allocMemory; + result->free = freeMemory; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; result->freeLibrary = freeLibrary; @@ -572,10 +594,11 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } // commit memory for headers - headers = (unsigned char *)VirtualAlloc(code, + headers = (unsigned char *)allocMemory(code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, - PAGE_READWRITE); + PAGE_READWRITE, + userdata); // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); @@ -724,7 +747,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) if (module->codeBase != NULL) { // release memory of library - VirtualFree(module->codeBase, 0, MEM_RELEASE); + module->free(module->codeBase, 0, MEM_RELEASE, module->userdata); } HeapFree(GetProcessHeap(), 0, module); diff --git a/MemoryModule.h b/MemoryModule.h index d8f3938..a728f6b 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -39,6 +39,8 @@ typedef void *HCUSTOMMODULE; extern "C" { #endif +typedef LPVOID (*CustomAllocFunc)(LPVOID, SIZE_T, DWORD, DWORD, void*); +typedef BOOL (*CustomFreeFunc)(LPVOID, SIZE_T, DWORD, void*); typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); @@ -58,6 +60,8 @@ HMEMORYMODULE MemoryLoadLibrary(const void *, size_t); * Dependencies will be resolved using passed callback methods. */ HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t, + CustomAllocFunc, + CustomFreeFunc, CustomLoadLibraryFunc, CustomGetProcAddressFunc, CustomFreeLibraryFunc, @@ -117,6 +121,22 @@ int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); */ int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); +/** +* Default implementation of CustomAllocFunc that calls VirtualAlloc +* internally to allocate memory for a library +* +* This is the default as used by MemoryLoadLibrary. +*/ +LPVOID MemoryDefaultAlloc(LPVOID, SIZE_T, DWORD, DWORD, void *); + +/** +* Default implementation of CustomFreeFunc that calls VirtualFree +* internally to free the memory used by a library +* +* This is the default as used by MemoryLoadLibrary. +*/ +BOOL MemoryDefaultFree(LPVOID, SIZE_T, DWORD, void *); + /** * Default implementation of CustomLoadLibraryFunc that calls LoadLibraryA * internally to load an additional libary. From bc38a6b01d578a638f5a3a75452859e80f6ddb79 Mon Sep 17 00:00:00 2001 From: Joan Karadimov Date: Fri, 12 Feb 2016 11:41:34 +0200 Subject: [PATCH 087/123] Extract a `ReadLibrary` function in DllLoader.cpp --- example/DllLoader/DllLoader.cpp | 59 +++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 4ff1a20..dc22ac4 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -46,12 +46,48 @@ void LoadFromFile(void) FreeLibrary(handle); } +void* ReadLibrary(long* pSize) { + long read; + void* result; + FILE* fp; + + fp = _tfopen(DLL_FILE, _T("rb")); + if (fp == NULL) + { + _tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE); + return NULL; + } + + fseek(fp, 0, SEEK_END); + *pSize = ftell(fp); + if (*pSize < 0) + { + fclose(fp); + return NULL; + } + + result = (unsigned char *)malloc(*pSize); + if (result == NULL) + { + return NULL; + } + + fseek(fp, 0, SEEK_SET); + read = fread(result, 1, *pSize, fp); + fclose(fp); + if (read != static_cast(*pSize)) + { + free(result); + return NULL; + } + + return result; +} + void LoadFromMemory(void) { - FILE *fp; - unsigned char *data=NULL; + void *data; long size; - size_t read; HMEMORYMODULE handle; addNumberProc addNumber; HMEMORYRSRC resourceInfo; @@ -59,23 +95,12 @@ void LoadFromMemory(void) LPVOID resourceData; TCHAR buffer[100]; - fp = _tfopen(DLL_FILE, _T("rb")); - if (fp == NULL) + data = ReadLibrary(&size); + if (data == NULL) { - _tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE); - goto exit; + return; } - fseek(fp, 0, SEEK_END); - size = ftell(fp); - assert(size >= 0); - data = (unsigned char *)malloc(size); - assert(data != NULL); - fseek(fp, 0, SEEK_SET); - read = fread(data, 1, size, fp); - assert(read == static_cast(size)); - fclose(fp); - handle = MemoryLoadLibrary(data, size); if (handle == NULL) { From a1fb42d4c570061ee50f5ec46dc39608b8db0d49 Mon Sep 17 00:00:00 2001 From: Joan Karadimov Date: Sat, 13 Feb 2016 14:40:05 +0200 Subject: [PATCH 088/123] Add some tests for the custom free and alloc functions --- example/DllLoader/DllLoader.cpp | 150 ++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index dc22ac4..973f5b4 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -130,11 +130,161 @@ void LoadFromMemory(void) free(data); } +#define MAX_CALLS 20 + +struct CallList { + int current_alloc_call, current_free_call; + CustomAllocFunc alloc_calls[MAX_CALLS]; + CustomFreeFunc free_calls[MAX_CALLS]; +}; + +LPVOID MemoryFailingAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) +{ + UNREFERENCED_PARAMETER(address); + UNREFERENCED_PARAMETER(size); + UNREFERENCED_PARAMETER(allocationType); + UNREFERENCED_PARAMETER(protect); + UNREFERENCED_PARAMETER(userdata); + return NULL; +} + +LPVOID MemoryMockAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) +{ + CallList* calls = (CallList*)userdata; + CustomAllocFunc current_func = calls->alloc_calls[calls->current_alloc_call++]; + assert(current_func != NULL); + return current_func(address, size, allocationType, protect, NULL); +} + +BOOL MemoryMockFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType, void* userdata) +{ + CallList* calls = (CallList*)userdata; + CustomFreeFunc current_func = calls->free_calls[calls->current_free_call++]; + assert(current_func != NULL); + return current_func(lpAddress, dwSize, dwFreeType, NULL); +} + +void InitFuncs(void** funcs, va_list args) { + for (int i = 0; ; i++) { + assert(i < MAX_CALLS); + funcs[i] = va_arg(args, void*); + if (funcs[i] == NULL) break; + } +} + +void InitAllocFuncs(CallList* calls, ...) { + va_list args; + va_start(args, calls); + InitFuncs((void**)calls->alloc_calls, args); + va_end(args); + calls->current_alloc_call = 0; +} + +void InitFreeFuncs(CallList* calls, ...) { + va_list args; + va_start(args, calls); + InitFuncs((void**)calls->free_calls, args); + va_end(args); + calls->current_free_call = 0; +} + +void InitFreeFunc(CallList* calls, CustomFreeFunc freeFunc) { + for (int i = 0; i < MAX_CALLS; i++) { + calls->free_calls[i] = freeFunc; + } + calls->current_free_call = 0; +} + +void TestFailingAllocation(void *data, long size) { + CallList expected_calls; + HMEMORYMODULE handle; + + InitAllocFuncs(&expected_calls, MemoryFailingAlloc, MemoryFailingAlloc, NULL); + InitFreeFuncs(&expected_calls, NULL); + + handle = MemoryLoadLibraryEx( + data, size, MemoryMockAlloc, MemoryMockFree, MemoryDefaultLoadLibrary, + MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, &expected_calls); + + assert(handle == NULL); + assert(GetLastError() == ERROR_OUTOFMEMORY); + assert(expected_calls.current_free_call == 0); + + MemoryFreeLibrary(handle); + assert(expected_calls.current_free_call == 0); +} + +void TestCleanupAfterFailingAllocation(void *data, long size) { + CallList expected_calls; + HMEMORYMODULE handle; + int free_calls_after_loading; + + InitAllocFuncs(&expected_calls, + MemoryDefaultAlloc, + MemoryDefaultAlloc, + MemoryDefaultAlloc, + MemoryDefaultAlloc, + MemoryFailingAlloc, + NULL); + InitFreeFuncs(&expected_calls, MemoryDefaultFree, NULL); + + handle = MemoryLoadLibraryEx( + data, size, MemoryMockAlloc, MemoryMockFree, MemoryDefaultLoadLibrary, + MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, &expected_calls); + + free_calls_after_loading = expected_calls.current_free_call; + + MemoryFreeLibrary(handle); + assert(expected_calls.current_free_call == free_calls_after_loading); +} + +void TestFreeAfterDefaultAlloc(void *data, long size) { + CallList expected_calls; + HMEMORYMODULE handle; + int free_calls_after_loading; + + // Note: free might get called internally multiple times + InitFreeFunc(&expected_calls, MemoryDefaultFree); + + handle = MemoryLoadLibraryEx( + data, size, MemoryDefaultAlloc, MemoryMockFree, MemoryDefaultLoadLibrary, + MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, &expected_calls); + + assert(handle != NULL); + free_calls_after_loading = expected_calls.current_free_call; + + MemoryFreeLibrary(handle); + assert(expected_calls.current_free_call == free_calls_after_loading + 1); +} + +void TestCustomAllocAndFree(void) +{ + void *data; + long size; + + data = ReadLibrary(&size); + if (data == NULL) + { + return; + } + + _tprintf(_T("Test MemoryLoadLibraryEx after initially failing allocation function\n")); + TestFailingAllocation(data, size); + _tprintf(_T("Test cleanup after MemoryLoadLibraryEx with failing allocation function\n")); + TestCleanupAfterFailingAllocation(data, size); + _tprintf(_T("Test custom free function after MemoryLoadLibraryEx\n")); + TestFreeAfterDefaultAlloc(data, size); + + free(data); +} + int main() { LoadFromFile(); printf("\n\n"); LoadFromMemory(); + printf("\n\n"); + TestCustomAllocAndFree(); return 0; } From c174ed117759d97d278f3d469547c0838b7284cb Mon Sep 17 00:00:00 2001 From: Youhei Sakurai Date: Tue, 13 Sep 2016 00:50:13 +0900 Subject: [PATCH 089/123] Remove stdint.h for VC++9.0 (VS2008) --- MemoryModule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index d8d3f3a..200e60f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #ifdef DEBUG_OUTPUT #include From 164b21ac07c38e92da65b7163d501afb73e5377a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 21:38:19 +0200 Subject: [PATCH 090/123] Move AppVeyor test code to script. --- appveyor.yml | 21 +++++---------------- scripts/run-appveyor.bat | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 scripts/run-appveyor.bat diff --git a/appveyor.yml b/appveyor.yml index 8fb52dd..c64b8b9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,20 +31,9 @@ platform: configuration: - Debug -build: - verbosity: normal +install: + - call scripts\run-appveyor.bat -build_script: - - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } - - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild - - cmake --build build --config %CONFIGURATION% - -before_test: - - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ - - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ - - copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ - -test_script: - - cd build\example\DllLoader - - DllLoader.exe - - DllLoaderLoader.exe +build: off +test: off +deploy: off diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat new file mode 100644 index 0000000..2b2eb13 --- /dev/null +++ b/scripts/run-appveyor.bat @@ -0,0 +1,36 @@ +@echo off +setlocal + +if /I "%PLATFORM" == "x64" ( + set CMAKE_GEN_SUFFIX= Win64 +) else ( + set CMAKE_GEN_SUFFIX= +) + +echo. +echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Building ... +cmake --build build --config %CONFIGURATION% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Copying generated files ... +copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ > NUL +copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ > NUL +copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ > NUL + +cd build\example\DllLoader + +echo. +echo Running DllLoader.exe ... +DllLoader.exe +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo Running DllLoaderLoader.exe ... +DllLoaderLoader.exe +if %errorlevel% neq 0 exit /b %errorlevel% From af2c521cf2734bb372e78625f699836b19a13202 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 21:41:34 +0200 Subject: [PATCH 091/123] Added .gitattributes file. --- .gitattributes | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a725a5d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto + +# Native line endings. +*.c text +*.cpp text +*.h text +*.rc text + +# Windows line endings. +*.bat text eol=crlf +*.eln text eol=crlf From d19c62ed8204e8a1906e5c4ae07ca86291185d13 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:27:02 +0200 Subject: [PATCH 092/123] Fixed detection of x64 platform. --- scripts/run-appveyor.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 2b2eb13..4390e3a 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -1,7 +1,7 @@ @echo off setlocal -if /I "%PLATFORM" == "x64" ( +if /I "%PLATFORM%" == "x64" ( set CMAKE_GEN_SUFFIX= Win64 ) else ( set CMAKE_GEN_SUFFIX= From 1d19f9f750b632ad3b8b85de821dfd447869100b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:43:01 +0200 Subject: [PATCH 093/123] Pass PLATFORM/UNICODE to cmake. --- scripts/run-appveyor.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 4390e3a..cb34169 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -9,7 +9,7 @@ if /I "%PLATFORM%" == "x64" ( echo. echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... -cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -H. -Bbuild if %errorlevel% neq 0 exit /b %errorlevel% echo. From b26476ff8d932a2794131cf45ef71c4adedb5189 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 12 Sep 2016 18:05:00 +0200 Subject: [PATCH 094/123] Also run CI against Visual Studio 9. --- appveyor.yml | 4 ++++ scripts/run-appveyor.bat | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index c64b8b9..4282d88 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,10 @@ os: environment: matrix: + - GENERATOR: "Visual Studio 9 2008" + UNICODE: ON + - GENERATOR: "Visual Studio 9 2008" + UNICODE: OFF - GENERATOR: "Visual Studio 10 2010" UNICODE: ON - GENERATOR: "Visual Studio 10 2010" diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index cb34169..0bc2943 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -3,6 +3,10 @@ setlocal if /I "%PLATFORM%" == "x64" ( set CMAKE_GEN_SUFFIX= Win64 + if /I "%GENERATOR%" == "Visual Studio 9 2008" ( + echo Skipping %CONFIGURATION% build using %GENERATOR%%CMAKE_GEN_SUFFIX% on %PLATFORM% + exit 0 + ) ) else ( set CMAKE_GEN_SUFFIX= ) From de5dbce7701c73f748f49e31152c988843759383 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 22:51:39 +0200 Subject: [PATCH 095/123] Error on some type conversion warnings. --- CMakeLists.txt | 1 + MemoryModule.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ddd49a..e2a3676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ endif () if (NOT MSVC) add_definitions ("-Wall") else () + # Show level 4 warnings. add_definitions ("-W4") endif () diff --git a/MemoryModule.c b/MemoryModule.c index 200e60f..3a6162a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -35,6 +35,10 @@ #if _MSC_VER // Disable warning about data -> function pointer conversion #pragma warning(disable:4055) + // C4244: conversion from 'uintptr_t' to 'DWORD', possible loss of data. +#pragma warning(error: 4244) +// C4267: conversion from 'size_t' to 'int', possible loss of data. +#pragma warning(error: 4267) #endif #ifndef IMAGE_SIZEOF_BASE_RELOCATION From 03cd7c91d98963f30a95d639a1d7865be2afc20a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 19 Sep 2016 23:59:33 +0200 Subject: [PATCH 096/123] Fixed alignment of values/addresses on 64bit systems. --- MemoryModule.c | 90 +++++++++++++++++++++++++++++++++++++++++++---- tests/Makefile | 12 +++++-- tests/TestSuite.c | 17 +++++++++ 3 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 tests/TestSuite.c diff --git a/MemoryModule.c b/MemoryModule.c index 3a6162a..60511d4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -39,6 +39,8 @@ #pragma warning(error: 4244) // C4267: conversion from 'size_t' to 'int', possible loss of data. #pragma warning(error: 4267) + +#define inline __inline #endif #ifndef IMAGE_SIZEOF_BASE_RELOCATION @@ -78,8 +80,21 @@ typedef struct { } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] -#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) -#define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) + +static inline uintptr_t +AlignValueDown(uintptr_t value, uintptr_t alignment) { + return value & ~(alignment - 1); +} + +static inline LPVOID +AlignAddressDown(LPVOID address, uintptr_t alignment) { + return (LPVOID) AlignValueDown((uintptr_t) address, alignment); +} + +static inline size_t +AlignValueUp(size_t value, size_t alignment) { + return (value + alignment - 1) & ~(alignment - 1); +} #ifdef DEBUG_OUTPUT static void @@ -246,7 +261,7 @@ FinalizeSections(PMEMORYMODULE module) #endif SECTIONFINALIZEDATA sectionData; sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); - sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); + sectionData.alignedAddress = AlignAddressDown(sectionData.address, module->pageSize); sectionData.size = GetRealSectionSize(module, section); sectionData.characteristics = section->Characteristics; sectionData.last = FALSE; @@ -255,7 +270,7 @@ FinalizeSections(PMEMORYMODULE module) // loop through all sections and change access flags for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); - LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); + LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize); DWORD sectionSize = GetRealSectionSize(module, section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section @@ -547,8 +562,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } GetNativeSystemInfo(&sysInfo); - alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); - if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) { + alignedImageSize = AlignValueUp(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); + if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } @@ -998,3 +1013,66 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO #endif return size; } + +#ifdef TESTSUITE +#include +#include + +#ifndef PRIxPTR +#ifdef _WIN64 +#define PRIxPTR "I64x" +#else +#define PRIxPTR "x" +#endif +#endif + +static const uintptr_t AlignValueDownTests[][3] = { + {16, 16, 16}, + {17, 16, 16}, + {32, 16, 32}, + {33, 16, 32}, +#ifdef _WIN64 + {0x12345678abcd1000, 0x1000, 0x12345678abcd1000}, + {0x12345678abcd101f, 0x1000, 0x12345678abcd1000}, +#endif + {0, 0, 0}, +}; + +static const uintptr_t AlignValueUpTests[][3] = { + {16, 16, 16}, + {17, 16, 32}, + {32, 16, 32}, + {33, 16, 48}, +#ifdef _WIN64 + {0x12345678abcd1000, 0x1000, 0x12345678abcd1000}, + {0x12345678abcd101f, 0x1000, 0x12345678abcd2000}, +#endif + {0, 0, 0}, +}; + +BOOL MemoryModuleTestsuite() { + BOOL success = TRUE; + for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + const uintptr_t* tests = AlignValueDownTests[idx]; + uintptr_t value = AlignValueDown(tests[0], tests[1]); + if (value != tests[2]) { + printf("AlignValueDown failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n", + tests[0], tests[1], tests[2], value); + success = FALSE; + } + } + for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + const uintptr_t* tests = AlignValueUpTests[idx]; + uintptr_t value = AlignValueUp(tests[0], tests[1]); + if (value != tests[2]) { + printf("AlignValueUp failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n", + tests[0], tests[1], tests[2], value); + success = FALSE; + } + } + if (success) { + printf("OK\n"); + } + return success; +} +#endif diff --git a/tests/Makefile b/tests/Makefile index f167a72..9df5da5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -16,7 +16,7 @@ RC = rc endif RM = rm -CFLAGS = -Wall -g +CFLAGS = -Wall -g -DTESTSUITE LDFLAGS = RCFLAGS = -O coff @@ -49,13 +49,20 @@ TEST_DLLS = \ test-relocate.dll \ LOADDLL_OBJ = LoadDll.o ../MemoryModule.o +TESTSUITE_OBJ = TestSuite.o ../MemoryModule.o DLL_OBJ = SampleDLL.o SampleDLL.res -all: LoadDll.exe $(TEST_DLLS) +all: prepare_testsuite LoadDll.exe TestSuite.exe $(TEST_DLLS) + +prepare_testsuite: + rm -f $(TESTSUITE_OBJ) LoadDll.exe: $(LOADDLL_OBJ) $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o LoadDll.exe $(LOADDLL_OBJ) +TestSuite.exe: $(TESTSUITE_OBJ) + $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -o TestSuite.exe $(TESTSUITE_OBJ) + LoadDll.o: LoadDll.cpp $(CXX) $(CFLAGS) $(CFLAGS_EXE) -c $< @@ -78,4 +85,5 @@ clean: $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) test: all + ./TestSuite.exe ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/TestSuite.c b/tests/TestSuite.c new file mode 100644 index 0000000..be3e519 --- /dev/null +++ b/tests/TestSuite.c @@ -0,0 +1,17 @@ +#define WIN32_LEAN_AND_MEAN +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include + +extern BOOL MemoryModuleTestsuite(); + +int main(int argc, char* argv[]) +{ + if (!MemoryModuleTestsuite()) { + return 1; + } + + return 0; +} From 6c2c3e2feee12d97af18f43f7a5dcaad9b5e69ea Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:08:53 +0200 Subject: [PATCH 097/123] Fix more potential conversion issues on 64bit. --- MemoryModule.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 60511d4..52c8637 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -74,7 +74,7 @@ typedef struct { typedef struct { LPVOID address; LPVOID alignedAddress; - DWORD size; + SIZE_T size; DWORD characteristics; BOOL last; } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; @@ -192,7 +192,7 @@ static int ProtectionFlags[2][2][2] = { }, }; -static DWORD +static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { DWORD size = section->SizeOfRawData; if (size == 0) { @@ -202,7 +202,7 @@ GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { size = module->headers->OptionalHeader.SizeOfUninitializedData; } } - return size; + return (SIZE_T) size; } static BOOL @@ -271,7 +271,7 @@ FinalizeSections(PMEMORYMODULE module) for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize); - DWORD sectionSize = GetRealSectionSize(module, section); + SIZE_T sectionSize = GetRealSectionSize(module, section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section // with the page of a first small section. This should be optimized. @@ -282,7 +282,7 @@ FinalizeSections(PMEMORYMODULE module) } else { sectionData.characteristics |= section->Characteristics; } - sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t) sectionData.address; + sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t) sectionSize)) - (uintptr_t) sectionData.address; continue; } @@ -868,7 +868,11 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match - cmp = searchKeyLen - resourceString->Length; + if (searchKeyLen > resourceString->Length) { + cmp = 1; + } else if (searchKeyLen < resourceString->Length) { + cmp = -1; + } } if (cmp < 0) { end = (middle != end ? middle : middle-1); From 097403a8addca6553355484836c4aa7941c8f1c6 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:14:56 +0200 Subject: [PATCH 098/123] Added wrapper to run wine/wine64. --- tests/Makefile | 2 +- tests/runtests.sh | 10 +--------- tests/runwine.sh | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 10 deletions(-) create mode 100755 tests/runwine.sh diff --git a/tests/Makefile b/tests/Makefile index 9df5da5..626611f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -85,5 +85,5 @@ clean: $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) test: all - ./TestSuite.exe + ./runwine.sh $(PLATFORM) TestSuite.exe ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/runtests.sh b/tests/runtests.sh index 57d70c6..a2c6520 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -1,13 +1,5 @@ #!/bin/bash PLATFORM=$1 -if [ "${PLATFORM}" = "x86_64" ]; then - export WINEPREFIX=${HOME}/.wine64/ - WINE=wine64 -else - export WINEPREFIX=${HOME}/.wine/ - WINE=wine -fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ read -a TEST_DLLS <<< $2 @@ -15,7 +7,7 @@ for filename in "${TEST_DLLS[@]}" do : echo "Testing $filename" - ${WINE} ./LoadDll.exe $filename + ./runwine.sh "${PLATFORM}" ./LoadDll.exe $filename if [ "$?" != "0" ]; then exit 1 fi diff --git a/tests/runwine.sh b/tests/runwine.sh new file mode 100755 index 0000000..eaee1fc --- /dev/null +++ b/tests/runwine.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eu +PLATFORM=$1 +shift + +if [ "${PLATFORM}" = "x86_64" ]; then + export WINEPREFIX=${HOME}/.wine64/ + WINE=wine64 +else + export WINEPREFIX=${HOME}/.wine/ + WINE=wine +fi +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ + +exec ${WINE} $@ From caf917707b22c66ab27528d6cfba97815f6ac162 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 00:54:28 +0200 Subject: [PATCH 099/123] Replace defines with static consts. --- MemoryModule.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 52c8637..3711f8a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -257,7 +257,7 @@ FinalizeSections(PMEMORYMODULE module) #ifdef _WIN64 uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else - #define imageOffset 0 + static const uintptr_t imageOffset = 0; #endif SECTIONFINALIZEDATA sectionData; sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); @@ -298,9 +298,6 @@ FinalizeSections(PMEMORYMODULE module) if (!FinalizeSection(module, §ionData)) { return FALSE; } -#ifndef _WIN64 -#undef imageOffset -#endif return TRUE; } @@ -838,7 +835,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( #else // Resource names are always stored using 16bit characters, need to // convert string we search for. -#define MAX_LOCAL_KEY_LENGTH 2048 + static const size_t MAX_LOCAL_KEY_LENGTH = 2048; // In most cases resource names are short, so optimize for that by // using a pre-allocated array. wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; @@ -887,7 +884,6 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { free(_searchKey); } -#undef MAX_LOCAL_KEY_LENGTH #endif } From 4074f1e6abd4c519f4181692fc8d631999178a44 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:00:39 +0200 Subject: [PATCH 100/123] Simplify conditional compiled code a bit. --- MemoryModule.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 3711f8a..9162abb 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -96,10 +96,12 @@ AlignValueUp(size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } -#ifdef DEBUG_OUTPUT -static void +static inline void OutputLastError(const char *msg) { +#ifndef DEBUG_OUTPUT + UNREFERENCED_PARAMETER(msg); +#else LPVOID tmp; char *tmpmsg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -109,8 +111,8 @@ OutputLastError(const char *msg) OutputDebugString(tmpmsg); LocalFree(tmpmsg); LocalFree(tmp); -} #endif +} static BOOL CheckSize(size_t size, size_t expected) { @@ -240,9 +242,7 @@ FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { // change memory access flags if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { -#ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") -#endif + OutputLastError("Error protecting memory page"); return FALSE; } @@ -341,16 +341,10 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) unsigned char *dest = codeBase + relocation->VirtualAddress; unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { - DWORD *patchAddrHL; -#ifdef _WIN64 - ULONGLONG *patchAddr64; -#endif - int type, offset; - // the upper 4 bits define the type of relocation - type = *relInfo >> 12; + int type = *relInfo >> 12; // the lower 12 bits define the offset - offset = *relInfo & 0xfff; + int offset = *relInfo & 0xfff; switch (type) { @@ -360,14 +354,18 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) case IMAGE_REL_BASED_HIGHLOW: // change complete 32 bit address - patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += (DWORD) delta; + { + DWORD *patchAddrHL = (DWORD *) (dest + offset); + *patchAddrHL += (DWORD) delta; + } break; #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: - patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += (ULONGLONG) delta; + { + ULONGLONG *patchAddr64 = (ULONGLONG *) (dest + offset); + *patchAddr64 += (ULONGLONG) delta; + } break; #endif @@ -528,10 +526,11 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } #ifdef _WIN64 - if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { + static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; #else - if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { + static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_I386; #endif + if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } From 49a82873f7d546bb0a08131f94c1fd5982ce8d1b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:03:54 +0200 Subject: [PATCH 101/123] Use "size_t" instead of "long" for sizes. --- example/DllLoader/DllLoader.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 973f5b4..9f0bfd9 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -46,8 +46,8 @@ void LoadFromFile(void) FreeLibrary(handle); } -void* ReadLibrary(long* pSize) { - long read; +void* ReadLibrary(size_t* pSize) { + size_t read; void* result; FILE* fp; @@ -59,8 +59,8 @@ void* ReadLibrary(long* pSize) { } fseek(fp, 0, SEEK_END); - *pSize = ftell(fp); - if (*pSize < 0) + *pSize = static_cast(ftell(fp)); + if (*pSize == 0) { fclose(fp); return NULL; @@ -75,7 +75,7 @@ void* ReadLibrary(long* pSize) { fseek(fp, 0, SEEK_SET); read = fread(result, 1, *pSize, fp); fclose(fp); - if (read != static_cast(*pSize)) + if (read != *pSize) { free(result); return NULL; @@ -87,7 +87,7 @@ void* ReadLibrary(long* pSize) { void LoadFromMemory(void) { void *data; - long size; + size_t size; HMEMORYMODULE handle; addNumberProc addNumber; HMEMORYRSRC resourceInfo; @@ -195,7 +195,7 @@ void InitFreeFunc(CallList* calls, CustomFreeFunc freeFunc) { calls->current_free_call = 0; } -void TestFailingAllocation(void *data, long size) { +void TestFailingAllocation(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; @@ -214,7 +214,7 @@ void TestFailingAllocation(void *data, long size) { assert(expected_calls.current_free_call == 0); } -void TestCleanupAfterFailingAllocation(void *data, long size) { +void TestCleanupAfterFailingAllocation(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; int free_calls_after_loading; @@ -238,7 +238,7 @@ void TestCleanupAfterFailingAllocation(void *data, long size) { assert(expected_calls.current_free_call == free_calls_after_loading); } -void TestFreeAfterDefaultAlloc(void *data, long size) { +void TestFreeAfterDefaultAlloc(void *data, size_t size) { CallList expected_calls; HMEMORYMODULE handle; int free_calls_after_loading; @@ -260,7 +260,7 @@ void TestFreeAfterDefaultAlloc(void *data, long size) { void TestCustomAllocAndFree(void) { void *data; - long size; + size_t size; data = ReadLibrary(&size); if (data == NULL) From e2826eb9565e764707a906814d4c4463f1f1b63c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:15:26 +0200 Subject: [PATCH 102/123] Fix MSVC compiler error. --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 9162abb..4d72a5d 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -526,9 +526,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } #ifdef _WIN64 - static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; + static const int HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; #else - static const WORD HOST_MACHINE = IMAGE_FILE_MACHINE_I386; + static const int HOST_MACHINE = IMAGE_FILE_MACHINE_I386; #endif if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); From d9dcc0eb8c764f15bf5f8e0578d37577abf2102d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:17:12 +0200 Subject: [PATCH 103/123] Don't use "static const ", breaks on MSVC. --- MemoryModule.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 4d72a5d..a032d52 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -48,6 +48,12 @@ #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) #endif +#ifdef _WIN64 +#define HOST_MACHINE IMAGE_FILE_MACHINE_AMD64 +#else +#define HOST_MACHINE IMAGE_FILE_MACHINE_I386 +#endif + #include "MemoryModule.h" typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); @@ -525,11 +531,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, return NULL; } -#ifdef _WIN64 - static const int HOST_MACHINE = IMAGE_FILE_MACHINE_AMD64; -#else - static const int HOST_MACHINE = IMAGE_FILE_MACHINE_I386; -#endif if (old_header->FileHeader.Machine != HOST_MACHINE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; From 5ce3707c7d9d6f3dfcde8b848a96986ef2e6c5dd Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:23:24 +0200 Subject: [PATCH 104/123] MSVC again - "static const" can not be used as array size. --- MemoryModule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index a032d52..7e6c1a5 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -835,7 +835,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( #else // Resource names are always stored using 16bit characters, need to // convert string we search for. - static const size_t MAX_LOCAL_KEY_LENGTH = 2048; +#define MAX_LOCAL_KEY_LENGTH 2048 // In most cases resource names are short, so optimize for that by // using a pre-allocated array. wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; @@ -884,6 +884,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { free(_searchKey); } +#undef MAX_LOCAL_KEY_LENGTH #endif } From 8d609dc2a240a70450642112ee52e7012dfbea2b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 01:34:42 +0200 Subject: [PATCH 105/123] Use script to run wine. --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9dcb84..f9ef247 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ sudo: false env: - - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE= - - PLATFORM=i686 WINE=wine UNICODE= CMAKE= - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE= - - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE= - - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE=1 - - PLATFORM=i686 WINE=wine UNICODE= CMAKE=1 - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE=1 - - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE=1 + - PLATFORM=x86_64 UNICODE= CMAKE= + - PLATFORM=i686 UNICODE= CMAKE= + - PLATFORM=x86_64 UNICODE=1 CMAKE= + - PLATFORM=i686 UNICODE=1 CMAKE= + - PLATFORM=x86_64 UNICODE= CMAKE=1 + - PLATFORM=i686 UNICODE= CMAKE=1 + - PLATFORM=x86_64 UNICODE=1 CMAKE=1 + - PLATFORM=i686 UNICODE=1 CMAKE=1 language: cpp @@ -37,5 +37,5 @@ script: - if [ -z "$CMAKE" ]; then make test PLATFORM=$PLATFORM UNICODE=$UNICODE; fi - if [ ! -z "$CMAKE" ]; then cmake --build .; fi - cd example/DllLoader - - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe + - ../../tests/runwine.sh $PLATFORM ./DllLoader.exe + - ../../tests/runwine.sh $PLATFORM ./DllLoaderLoader.exe From 6c4ab3589d59ca389756f4ad7aca947d3566f4cb Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:18:42 +0200 Subject: [PATCH 106/123] Added testcase to load image above 32bit. --- example/DllLoader/DllLoader.cpp | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 9f0bfd9..4355ea8 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -257,6 +257,55 @@ void TestFreeAfterDefaultAlloc(void *data, size_t size) { assert(expected_calls.current_free_call == free_calls_after_loading + 1); } +#ifdef _WIN64 + +LPVOID MemoryAllocHigh(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata) +{ + int* counter = static_cast(userdata); + if (*counter == 0) { + // Make sure the image gets loaded to an address above 32bit. + uintptr_t offset = 0x10000000000; + address = (LPVOID) ((uintptr_t) address + offset); + } + (*counter)++; + return MemoryDefaultAlloc(address, size, allocationType, protect, NULL); +} + +void TestAllocHighMemory(void *data, size_t size) { + HMEMORYMODULE handle; + int counter = 0; + addNumberProc addNumber; + HMEMORYRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + TCHAR buffer[100]; + + handle = MemoryLoadLibraryEx( + data, size, MemoryAllocHigh, MemoryDefaultFree, MemoryDefaultLoadLibrary, + MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, &counter); + + assert(handle != NULL); + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); + _tprintf(_T("String1: %s\n"), buffer); + + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); + _tprintf(_T("String2: %s\n"), buffer); + + MemoryFreeLibrary(handle); +} +#endif // _WIN64 + void TestCustomAllocAndFree(void) { void *data; @@ -274,6 +323,10 @@ void TestCustomAllocAndFree(void) TestCleanupAfterFailingAllocation(data, size); _tprintf(_T("Test custom free function after MemoryLoadLibraryEx\n")); TestFreeAfterDefaultAlloc(data, size); +#ifdef _WIN64 + _tprintf(_T("Test allocating in high memory\n")); + TestAllocHighMemory(data, size); +#endif free(data); } From f5c9db8b5c7dd23deb67c1ca4bc67f3d29d2a82b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:36:55 +0200 Subject: [PATCH 107/123] Simplfy some casting code, updated comments about 32/64 bit. --- MemoryModule.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7e6c1a5..13a371f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -102,6 +102,11 @@ AlignValueUp(size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } +static inline void* +OffsetPointer(void* data, ptrdiff_t offset) { + return (void*) ((uintptr_t) data + offset); +} + static inline void OutputLastError(const char *msg) { @@ -153,9 +158,11 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade } // Always use position from file to support alignments smaller - // than page size. + // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; - section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; + // NOTE: On 64bit systems we truncate to 32bit here but expand + // again later when "PhysicalAddress" is used. + section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); memset(dest, 0, section_size); } @@ -178,10 +185,12 @@ CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_heade } // Always use position from file to support alignments smaller - // than page size. + // than page size (allocation above will align to page size). dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; + // NOTE: On 64bit systems we truncate to 32bit here but expand + // again later when "PhysicalAddress" is used. + section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff); } return TRUE; @@ -261,7 +270,9 @@ FinalizeSections(PMEMORYMODULE module) int i; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 - uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); + // "PhysicalAddress" might have been truncated to 32bit above, expand to + // 64bits again. + uintptr_t imageOffset = ((uintptr_t) module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else static const uintptr_t imageOffset = 0; #endif @@ -345,7 +356,7 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) for (; relocation->VirtualAddress > 0; ) { DWORD i; unsigned char *dest = codeBase + relocation->VirtualAddress; - unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); + unsigned short *relInfo = (unsigned short*) OffsetPointer(relocation, IMAGE_SIZEOF_BASE_RELOCATION); for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { // the upper 4 bits define the type of relocation int type = *relInfo >> 12; @@ -382,7 +393,7 @@ PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) } // advance to next relocation block - relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); + relocation = (PIMAGE_BASE_RELOCATION) OffsetPointer(relocation, relocation->SizeOfBlock); } return TRUE; } @@ -861,7 +872,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; - resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); + resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(root, entries[middle].Name & 0x7FFFFFFF); cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match @@ -993,7 +1004,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { - data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); + data = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(data, (data->Length + 1) * sizeof(WCHAR)); } if (data->Length == 0) { SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); From 184113ca0964709cfe6544e2d5f2b9a11c1832ce Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 20 Sep 2016 22:58:17 +0200 Subject: [PATCH 108/123] Also build and run testsuite on cmake CI tests. --- .travis.yml | 4 +++- CMakeLists.txt | 9 +++++++++ MemoryModule.c | 6 +++--- scripts/run-appveyor.bat | 10 +++++++++- tests/CMakeLists.txt | 14 ++++++++++++++ tests/TestSuite.c | 2 ++ 6 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/CMakeLists.txt diff --git a/.travis.yml b/.travis.yml index f9ef247..3c45d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ addons: - wine before_script: - - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -D UNICODE=$UNICODE -H. -B.; fi + - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi script: - if [ -z "$CMAKE" ]; then make PLATFORM=$PLATFORM UNICODE=$UNICODE; fi @@ -39,3 +39,5 @@ script: - cd example/DllLoader - ../../tests/runwine.sh $PLATFORM ./DllLoader.exe - ../../tests/runwine.sh $PLATFORM ./DllLoaderLoader.exe + - cd ../../tests + - ./runwine.sh $PLATFORM ./TestSuite.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index e2a3676..e3ba63c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,11 +40,20 @@ else () message (STATUS "Compile without UNICODE support") endif () +option(TESTSUITE "Compile with TESTSUITE support" OFF) +if (TESTSUITE) + message (STATUS "Compile with TESTSUITE support") + add_definitions ("-DTESTSUITE") +else () + message (STATUS "Compile without TESTSUITE support") +endif () + add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) if (NOT MSVC) set_target_properties ("MemoryModule" PROPERTIES PREFIX "") endif () add_subdirectory (example) +add_subdirectory (tests) enable_language (RC) diff --git a/MemoryModule.c b/MemoryModule.c index 13a371f..cf38388 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -1028,7 +1028,6 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO #ifdef TESTSUITE #include -#include #ifndef PRIxPTR #ifdef _WIN64 @@ -1064,7 +1063,8 @@ static const uintptr_t AlignValueUpTests[][3] = { BOOL MemoryModuleTestsuite() { BOOL success = TRUE; - for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + size_t idx; + for (idx = 0; AlignValueDownTests[idx][0]; ++idx) { const uintptr_t* tests = AlignValueDownTests[idx]; uintptr_t value = AlignValueDown(tests[0], tests[1]); if (value != tests[2]) { @@ -1073,7 +1073,7 @@ BOOL MemoryModuleTestsuite() { success = FALSE; } } - for (size_t idx = 0; AlignValueDownTests[idx][0]; ++idx) { + for (idx = 0; AlignValueDownTests[idx][0]; ++idx) { const uintptr_t* tests = AlignValueUpTests[idx]; uintptr_t value = AlignValueUp(tests[0], tests[1]); if (value != tests[2]) { diff --git a/scripts/run-appveyor.bat b/scripts/run-appveyor.bat index 0bc2943..6662d99 100644 --- a/scripts/run-appveyor.bat +++ b/scripts/run-appveyor.bat @@ -13,7 +13,7 @@ if /I "%PLATFORM%" == "x64" ( echo. echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ... -cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -H. -Bbuild +cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -DTESTSUITE=ON -H. -Bbuild if %errorlevel% neq 0 exit /b %errorlevel% echo. @@ -26,6 +26,7 @@ echo Copying generated files ... copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ > NUL copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ > NUL copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ > NUL +copy /y build\tests\%CONFIGURATION%\TestSuite.exe build\tests\ > NUL cd build\example\DllLoader @@ -38,3 +39,10 @@ echo. echo Running DllLoaderLoader.exe ... DllLoaderLoader.exe if %errorlevel% neq 0 exit /b %errorlevel% + +cd ..\..\tests + +echo. +echo Running TestSuite.exe ... +TestSuite.exe +if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..8b1007f --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +set (sources_testsuite + TestSuite.c +) + +if (NOT MSVC) + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-static") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-static") +endif () + +add_executable (TestSuite ${sources_testsuite}) +target_link_libraries ("TestSuite" "MemoryModule") +if (NOT MSVC) + set_target_properties ("TestSuite" PROPERTIES SUFFIX ".exe") +endif () diff --git a/tests/TestSuite.c b/tests/TestSuite.c index be3e519..f4bd325 100644 --- a/tests/TestSuite.c +++ b/tests/TestSuite.c @@ -9,6 +9,8 @@ extern BOOL MemoryModuleTestsuite(); int main(int argc, char* argv[]) { + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); if (!MemoryModuleTestsuite()) { return 1; } From 2bbbc205d6758d47df81c2bd40ef252413b669ba Mon Sep 17 00:00:00 2001 From: Friedrich von Never Date: Sat, 15 Jul 2017 18:56:54 +0700 Subject: [PATCH 109/123] readme: fix the doc file name --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index aa9f497..4e9d82d 100644 --- a/readme.md +++ b/readme.md @@ -16,5 +16,5 @@ file gets deleted. `MemoryModule` is a library that can be used to load a DLL completely from memory - without storing on the disk first. -See `doc/readme.txt` for more informations about the format of a DLL file and +See `doc/readme.rst` for more informations about the format of a DLL file and a tutorial how they can be loaded directly. From 0884dccfa70ccbb857e44e250fb772931e479580 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 20:15:22 +0100 Subject: [PATCH 110/123] Update mingw -dev package for Trusty. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c45d20..737c970 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,8 @@ addons: - binutils-mingw-w64-i686 - binutils-mingw-w64-x86-64 - cmake - - mingw-w64-dev + - mingw-w64-i686-dev + - mingw-w64-x86-64-dev - g++-mingw-w64-i686 - g++-mingw-w64-x86-64 - gcc-mingw-w64-i686 From 98b95eca4cc467fedded96386bcadaba3addf18e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 21:02:26 +0100 Subject: [PATCH 111/123] Implement binary search for looking up exports by name. Code based on #74 which contained code from py2exe. --- MemoryModule.c | 73 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index cf38388..59a5844 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -22,6 +22,12 @@ * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * + * + * THeller: Added binary search in MemoryGetProcAddress function + * (#define USE_BINARY_SEARCH to enable it). This gives a very large + * speedup for libraries that exports lots of functions. + * + * These portions are Copyright (C) 2013 Thomas Heller. */ #include @@ -56,6 +62,11 @@ #include "MemoryModule.h" +struct ExportNameEntry { + LPCSTR name; + WORD idx; +}; + typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); typedef int (WINAPI *ExeEntryProc)(void); @@ -72,6 +83,7 @@ typedef struct { CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; + struct ExportNameEntry *nameExportsTable; void *userdata; ExeEntryProc exeEntry; DWORD pageSize; @@ -688,12 +700,27 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, return NULL; } -FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) +static int _compare(const void *a, const void *b) +{ + const struct ExportNameEntry *p1 = (const struct ExportNameEntry*) a; + const struct ExportNameEntry *p2 = (const struct ExportNameEntry*) b; + return _stricmp(p1->name, p2->name); +} + +static int _find(const void *a, const void *b) +{ + LPCSTR *name = (LPCSTR *) a; + const struct ExportNameEntry *p = (const struct ExportNameEntry*) b; + return _stricmp(*name, p->name); +} + +FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) { - unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; + PMEMORYMODULE module = (PMEMORYMODULE)mod; + unsigned char *codeBase = module->codeBase; DWORD idx = 0; PIMAGE_EXPORT_DIRECTORY exports; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { // no export table found SetLastError(ERROR_PROC_NOT_FOUND); @@ -715,25 +742,44 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) } idx = LOWORD(name) - exports->Base; + } else if (!exports->NumberOfNames) { + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; } else { - // search function name in list of exported names - DWORD i; - DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); - WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - BOOL found = FALSE; - for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { - idx = *ordinal; - found = TRUE; - break; + const struct ExportNameEntry *found; + + // Lazily build name table and sort it by names + if (!module->nameExportsTable) { + DWORD i; + DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); + WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); + struct ExportNameEntry *entry = (struct ExportNameEntry*) malloc(exports->NumberOfNames * sizeof(struct ExportNameEntry)); + module->nameExportsTable = entry; + if (!entry) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; } + for (i=0; iNumberOfNames; i++, nameRef++, ordinal++, entry++) { + entry->name = (const char *) (codeBase + (*nameRef)); + entry->idx = *ordinal; + } + qsort(module->nameExportsTable, + exports->NumberOfNames, + sizeof(struct ExportNameEntry), _compare); } + // search function name in list of exported names with binary search + found = (const struct ExportNameEntry*) bsearch(&name, + module->nameExportsTable, + exports->NumberOfNames, + sizeof(struct ExportNameEntry), _find); if (!found) { // exported symbol not found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } + + idx = found->idx; } if (idx > exports->NumberOfFunctions) { @@ -759,6 +805,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } + free(module->nameExportsTable); if (module->modules != NULL) { // free previously opened libraries int i; From ac78ea10e7ba666ae24b753a1564c8c93ccff4bd Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 2 Nov 2017 21:37:14 +0100 Subject: [PATCH 112/123] Add test that loads a dll with lots of exports. --- .gitignore | 3 ++ tests/LoadDll.cpp | 75 +++++++++++++++++++++++++++++++++++++-- tests/Makefile | 7 ++++ tests/generate-exports.sh | 52 +++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100755 tests/generate-exports.sh diff --git a/.gitignore b/.gitignore index 6c07d24..508c3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ *.exe tests/*.dll tests/*.res + +tests/SampleExports.cpp +tests/SampleExports.h diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 07a2538..8cb215b 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -11,6 +11,7 @@ #include "../MemoryModule.h" +typedef int (*addProc)(int); typedef int (*addNumberProc)(int, int); // Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708) @@ -127,6 +128,11 @@ BOOL LoadFromMemory(char *filename) } addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + if (!addNumber) { + _tprintf(_T("MemoryGetProcAddress(\"addNumber\") returned NULL\n")); + result = FALSE; + goto exit; + } _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); // the DLL only exports one function, try to load by ordinal value @@ -218,6 +224,65 @@ BOOL LoadFromMemory(char *filename) return result; } +BOOL LoadExportsFromMemory(char *filename) +{ + FILE *fp; + unsigned char *data=NULL; + long size; + size_t read; + HMEMORYMODULE handle = NULL; + int i; + BOOL result = TRUE; + + fp = fopen(filename, "rb"); + if (fp == NULL) + { + printf("Can't open DLL file \"%s\".", filename); + result = FALSE; + goto exit; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + assert(size > 0); + data = (unsigned char *)malloc(size); + assert(data != NULL); + fseek(fp, 0, SEEK_SET); + read = fread(data, 1, size, fp); + assert(read == static_cast(size)); + fclose(fp); + + handle = MemoryLoadLibrary(data, size); + if (handle == NULL) + { + _tprintf(_T("Can't load library from memory.\n")); + result = FALSE; + goto exit; + } + + for (i = 1; i <= 100; i++) { + char name[100]; + sprintf(name, "add%d", i); + addProc addNumber = (addProc)MemoryGetProcAddress(handle, name); + if (!addNumber) { + _tprintf(_T("MemoryGetProcAddress(\"%s\") returned NULL\n"), name); + result = FALSE; + goto exit; + } + int result = addNumber(1); + if (result != 1 + i) { + _tprintf(_T("(\"%s\") returned %d, expected %d\n"), name, result, 1 + i); + result = FALSE; + goto exit; + } + _tprintf(_T("%s: %d\n"), name, result); + } +exit: + MemoryFreeLibrary(handle); + free(data); + return result; +} + int main(int argc, char* argv[]) { if (argc < 2) { @@ -225,8 +290,14 @@ int main(int argc, char* argv[]) return 1; } - if (!LoadFromMemory(argv[1])) { - return 2; + if (!strstr((const char *) argv[1], "exports")) { + if (!LoadFromMemory(argv[1])) { + return 2; + } + } else { + if (!LoadExportsFromMemory(argv[1])) { + return 2; + } } return 0; diff --git a/tests/Makefile b/tests/Makefile index 626611f..014cc80 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,6 +47,7 @@ TEST_DLLS = \ test-align-800.dll \ test-align-900.dll \ test-relocate.dll \ + test-exports.dll LOADDLL_OBJ = LoadDll.o ../MemoryModule.o TESTSUITE_OBJ = TestSuite.o ../MemoryModule.o @@ -72,6 +73,12 @@ test-align-%.dll: $(DLL_OBJ) test-relocate.dll: $(DLL_OBJ) $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o $@ $(DLL_OBJ) +test-exports.dll: SampleExports.o + $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -o $@ SampleExports.o + +SampleExports.cpp: generate-exports.sh + ./generate-exports.sh + %.o: %.cpp $(CXX) $(CFLAGS) $(CFLAGS_DLL) -c $< diff --git a/tests/generate-exports.sh b/tests/generate-exports.sh new file mode 100755 index 0000000..974b2a6 --- /dev/null +++ b/tests/generate-exports.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +## +## Generate header file. +## + +cat > SampleExports.h << EOF +extern "C" { + +#ifdef SAMPLEDLL_EXPORTS +#define SAMPLEDLL_API __declspec(dllexport) +#else +#define SAMPLEDLL_API __declspec(dllimport) +#endif + +EOF + +for i in `seq 1 100`; +do +cat >> SampleExports.h << EOF +SAMPLEDLL_API int add$i(int a); +EOF +done + +cat >> SampleExports.h << EOF +} +EOF + + +## +## Generate source file. +## + +cat > SampleExports.cpp << EOF +#include "SampleExports.h" + +extern "C" { +EOF + +for i in `seq 1 100 | sort -R`; +do +cat >> SampleExports.cpp << EOF +SAMPLEDLL_API int add$i(int a) +{ + return a + $i; +} +EOF +done + +cat >> SampleExports.cpp << EOF +} +EOF From 9e295953a8b056036525c4274fb1ddf91dbb85c7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:31:28 +0100 Subject: [PATCH 113/123] Prevent memory of library from spanning over 4GB bounaries. Based on code from #67 / #79, fixes #63. --- MemoryModule.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 59a5844..05646e1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -70,6 +70,13 @@ struct ExportNameEntry { typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); typedef int (WINAPI *ExeEntryProc)(void); +#ifdef _WIN64 +typedef struct POINTER_LIST { + struct POINTER_LIST *next; + void *address; +} POINTER_LIST; +#endif + typedef struct { PIMAGE_NT_HEADERS headers; unsigned char *codeBase; @@ -87,6 +94,9 @@ typedef struct { void *userdata; ExeEntryProc exeEntry; DWORD pageSize; +#ifdef _WIN64 + POINTER_LIST *blockedMemory; +#endif } MEMORYMODULE, *PMEMORYMODULE; typedef struct { @@ -137,6 +147,21 @@ OutputLastError(const char *msg) #endif } +#ifdef _WIN64 +static void +FreePointerList(POINTER_LIST *head, CustomFreeFunc freeMemory, void *userdata) +{ + POINTER_LIST *node = head; + while (node) { + POINTER_LIST *next; + freeMemory(node->address, 0, MEM_RELEASE, userdata); + next = node->next; + free(node); + node = next; + } +} +#endif + static BOOL CheckSize(size_t size, size_t expected) { if (size < expected) { @@ -535,6 +560,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, size_t optionalSectionSize; size_t lastSectionEnd = 0; size_t alignedImageSize; +#ifdef _WIN64 + POINTER_LIST *blockedMemory = NULL; +#endif if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) { return NULL; @@ -610,9 +638,40 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, } } +#ifdef _WIN64 + // Memory block may not span 4 GB boundaries. + while ((((uintptr_t) code) >> 32) < (((uintptr_t) (code + alignedImageSize)) >> 32)) { + POINTER_LIST *node = (POINTER_LIST*) malloc(sizeof(POINTER_LIST)); + if (!node) { + freeMemory(code, 0, MEM_RELEASE, userdata); + FreePointerList(blockedMemory, freeMemory, userdata); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + node->next = blockedMemory; + node->address = code; + blockedMemory = node; + + code = (unsigned char *)allocMemory(NULL, + alignedImageSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE, + userdata); + if (code == NULL) { + FreePointerList(blockedMemory, freeMemory, userdata); + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } +#endif + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { freeMemory(code, 0, MEM_RELEASE, userdata); +#ifdef _WIN64 + FreePointerList(blockedMemory, freeMemory, userdata); +#endif SetLastError(ERROR_OUTOFMEMORY); return NULL; } @@ -626,6 +685,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, result->freeLibrary = freeLibrary; result->userdata = userdata; result->pageSize = sysInfo.dwPageSize; +#ifdef _WIN64 + result->blockedMemory = blockedMemory; +#endif if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) { goto error; @@ -823,6 +885,9 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) module->free(module->codeBase, 0, MEM_RELEASE, module->userdata); } +#ifdef _WIN64 + FreePointerList(module->blockedMemory, module->free, module->userdata); +#endif HeapFree(GetProcessHeap(), 0, module); } From 9ecfeb025d9d13160038518df7dc69973fb6ee0f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:41:25 +0100 Subject: [PATCH 114/123] Remove all object files on clean. --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 014cc80..028bcad 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -89,7 +89,7 @@ SampleExports.cpp: generate-exports.sh $(RC) $(RCFLAGS) -o $*.res $< clean: - $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) + $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) $(TESTSUITE_OBJ) SampleExports.o test: all ./runwine.sh $(PLATFORM) TestSuite.exe From 663ddca84b9ef35ca6fd1e705599f30d8d1cda32 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:49:55 +0100 Subject: [PATCH 115/123] Update WINEPATH for Trusty. --- tests/runwine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runwine.sh b/tests/runwine.sh index eaee1fc..c56fa27 100755 --- a/tests/runwine.sh +++ b/tests/runwine.sh @@ -10,6 +10,6 @@ else export WINEPREFIX=${HOME}/.wine/ WINE=wine fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/;/usr/${PLATFORM}-w64-mingw32/lib exec ${WINE} $@ From 0acf4e7785d547ac37ddbf339aa00cb4f7a2b07d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 20:52:52 +0100 Subject: [PATCH 116/123] Fix typo. --- tests/runwine.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runwine.sh b/tests/runwine.sh index c56fa27..826b8c3 100755 --- a/tests/runwine.sh +++ b/tests/runwine.sh @@ -10,6 +10,6 @@ else export WINEPREFIX=${HOME}/.wine/ WINE=wine fi -export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/;/usr/${PLATFORM}-w64-mingw32/lib +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.8/:/usr/${PLATFORM}-w64-mingw32/lib exec ${WINE} $@ From e7d53b53e0e9111cb1910940a98df375c25e655c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 21:48:58 +0100 Subject: [PATCH 117/123] Only install packages necessary for job. --- .travis.yml | 100 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 737c970..0ea5624 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,82 @@ sudo: false -env: - - PLATFORM=x86_64 UNICODE= CMAKE= - - PLATFORM=i686 UNICODE= CMAKE= - - PLATFORM=x86_64 UNICODE=1 CMAKE= - - PLATFORM=i686 UNICODE=1 CMAKE= - - PLATFORM=x86_64 UNICODE= CMAKE=1 - - PLATFORM=i686 UNICODE= CMAKE=1 - - PLATFORM=x86_64 UNICODE=1 CMAKE=1 - - PLATFORM=i686 UNICODE=1 CMAKE=1 +matrix: + include: + - env: PLATFORM=x86_64 UNICODE= CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE= CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE=1 CMAKE= + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE= CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE= CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - cmake + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-x86-64 + - cmake + - mingw-w64-x86-64-dev + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - wine:amd64 + - env: PLATFORM=i686 UNICODE=1 CMAKE=1 + addons: + apt: + packages: + - binutils-mingw-w64-i686 + - cmake + - mingw-w64-i686-dev + - g++-mingw-w64-i686 + - gcc-mingw-w64-i686 + - wine:i386 language: cpp @@ -16,20 +84,6 @@ cache: - apt - ccache -addons: - apt: - packages: - - binutils-mingw-w64-i686 - - binutils-mingw-w64-x86-64 - - cmake - - mingw-w64-i686-dev - - mingw-w64-x86-64-dev - - g++-mingw-w64-i686 - - g++-mingw-w64-x86-64 - - gcc-mingw-w64-i686 - - gcc-mingw-w64-x86-64 - - wine - before_script: - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi From 403a31e7bbc28967334c081311fa6779588cd033 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 14 Feb 2018 21:54:42 +0100 Subject: [PATCH 118/123] Run with sudo enabled. This fixes an issue where running wine fails on i386 with /usr/bin/wine: error while loading shared libraries: libwine.so.1: cannot create shared object descriptor: Operation not permitted --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0ea5624..93c6273 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: false +sudo: true matrix: include: From 060f0bd73608e4233a881ca566dd538ecba78bc1 Mon Sep 17 00:00:00 2001 From: Scavanger Date: Thu, 8 Mar 2018 13:23:39 +0100 Subject: [PATCH 119/123] Search for function names should be case sensitive --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 05646e1..9f95a70 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -766,14 +766,14 @@ static int _compare(const void *a, const void *b) { const struct ExportNameEntry *p1 = (const struct ExportNameEntry*) a; const struct ExportNameEntry *p2 = (const struct ExportNameEntry*) b; - return _stricmp(p1->name, p2->name); + return strcmp(p1->name, p2->name); } static int _find(const void *a, const void *b) { LPCSTR *name = (LPCSTR *) a; const struct ExportNameEntry *p = (const struct ExportNameEntry*) b; - return _stricmp(*name, p->name); + return strcmp(*name, p->name); } FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) From a15e0769b01f59a0f5f33ab411bc3db6e59864a1 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Fri, 18 May 2018 00:37:57 -0600 Subject: [PATCH 120/123] Make .h file accessible to superprojects As is, you need to add_subdirectory and also add the include, this kills two birds with one stone --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ba63c..cfddbfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ else () endif () add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) +target_include_directories(MemoryModule PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") if (NOT MSVC) set_target_properties ("MemoryModule" PROPERTIES PREFIX "") endif () From d1a08247332aa24dec8491df77fb5ca2efd6530a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 13:49:51 +0100 Subject: [PATCH 121/123] Fix version for AppVeyor. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4282d88..5bc1608 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ # Status available at # https://ci.appveyor.com/project/fancycode/memorymodule -version: #{build} +version: 1.0.{build} os: - Visual Studio 2015 From 9f379524076322f7875175f251b38e9c4083600a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 15:07:24 +0100 Subject: [PATCH 122/123] Switch to Xenial for CI runs. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 93c6273..2a0f624 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,6 +80,8 @@ matrix: language: cpp +dist: xenial + cache: - apt - ccache From 316aa59c48cd6ab1c10b8a1a99bc1e7aa6f719f4 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 24 Feb 2019 15:17:41 +0100 Subject: [PATCH 123/123] Get latest stable version of Wine when testing. --- .travis.yml | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a0f624..0bb4efe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: true matrix: include: - - env: PLATFORM=x86_64 UNICODE= CMAKE= + - env: PLATFORM=x86_64 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -10,8 +10,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE= CMAKE= + - env: PLATFORM=i686 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -19,8 +18,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE=1 CMAKE= + - env: PLATFORM=x86_64 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -28,8 +26,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE=1 CMAKE= + - env: PLATFORM=i686 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -37,8 +34,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE= CMAKE=1 + - env: PLATFORM=x86_64 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -46,8 +42,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE= CMAKE=1 + - env: PLATFORM=i686 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -56,8 +51,7 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 - - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 + - env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:amd64 addons: apt: packages: @@ -66,8 +60,7 @@ matrix: - mingw-w64-x86-64-dev - g++-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - - wine:amd64 - - env: PLATFORM=i686 UNICODE=1 CMAKE=1 + - env: PLATFORM=i686 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:i386 addons: apt: packages: @@ -76,7 +69,6 @@ matrix: - mingw-w64-i686-dev - g++-mingw-w64-i686 - gcc-mingw-w64-i686 - - wine:i386 language: cpp @@ -87,6 +79,9 @@ cache: - ccache before_script: + - curl https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - + - echo "deb https://dl.winehq.org/wine-builds/ubuntu/ xenial main" | sudo tee /etc/apt/sources.list.d/winehq.list + - sudo apt-get -y update && sudo apt-get -y install --install-recommends $WINE_PACKAGE - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -DUNICODE=$UNICODE -DTESTSUITE=ON -H. -B.; fi script: