From 9df6e7dc93060287581f2f1add0ed84f1232d01c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 18:53:18 +0100 Subject: [PATCH 01/50] 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 02/50] 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 03/50] 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 04/50] 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 05/50] 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 06/50] 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 07/50] 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 08/50] 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 09/50] 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 10/50] 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 11/50] 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 12/50] 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 13/50] 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 14/50] 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 15/50] 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 16/50] 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 17/50] 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 18/50] 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 19/50] 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 20/50] 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 21/50] 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 22/50] 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 23/50] 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 24/50] 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 25/50] 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 26/50] 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 27/50] 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 28/50] 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 29/50] 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 30/50] 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 31/50] 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 32/50] 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 33/50] 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 34/50] 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 35/50] 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 36/50] 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 37/50] 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 38/50] 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 39/50] 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 40/50] 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 41/50] 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 42/50] 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 43/50] 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 44/50] 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 45/50] 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 46/50] 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 47/50] 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 48/50] 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 49/50] 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 50/50] 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: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy