From de7840af70504a4b0ba53fd40ad8b416ca11b5d8 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:07:49 +0200 Subject: [PATCH 01/94] Removed trailing whitespaces. --- MemoryModule.c | 48 ++++++++++++++++----------------- doc/readme.txt | 34 +++++++++++------------ example/DllLoader/DllLoader.cpp | 18 ++++++------- example/DllLoader/Makefile | 2 +- example/Makefile | 2 +- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 0bd2ee1..0e89a7f 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -140,7 +140,7 @@ FinalizeSections(PMEMORYMODULE module) #else #define imageOffset 0 #endif - + // loop through all sections and change access flags for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { DWORD protect, oldProtect, size; @@ -185,10 +185,10 @@ FinalizeSections(PMEMORYMODULE module) } static void -ExecuteTLS(PMEMORYMODULE module) +ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; - + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); if (directory->VirtualAddress > 0) { PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); @@ -225,7 +225,7 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) type = *relInfo >> 12; // the lower 12 bits define the offset offset = *relInfo & 0xfff; - + switch (type) { case IMAGE_REL_BASED_ABSOLUTE: @@ -237,7 +237,7 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) patchAddrHL = (DWORD *) (dest + offset); *patchAddrHL += (DWORD) delta; break; - + #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: patchAddr64 = (ULONGLONG *) (dest + offset); @@ -325,7 +325,7 @@ static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) if (result == NULL) { return NULL; } - + return (HCUSTOMMODULE) result; } @@ -389,7 +389,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } } - + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); if (result == NULL) { SetLastError(ERROR_OUTOFMEMORY); @@ -411,7 +411,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); - + // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; @@ -557,7 +557,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( DWORD start; DWORD end; DWORD middle; - + if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string TCHAR *endpos = NULL; @@ -570,7 +570,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( key = MAKEINTRESOURCE(tmpkey); } } - + // entries are stored as ordered list of named entries, // followed by an ordered list of id entries - we can do // a binary search to find faster... @@ -578,7 +578,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( WORD check = (WORD) (POINTER_TYPE) key; start = resources->NumberOfNamedEntries; end = start + resources->NumberOfIdEntries; - + while (end > start) { WORD entryName; middle = (start + end) >> 1; @@ -611,7 +611,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (tmp == NULL) { break; } - + searchKey = (char *) tmp; } wcstombs(searchKey, resourceString->NameString, resourceString->Length); @@ -632,8 +632,8 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( free(searchKey); #endif } - - + + return result; } @@ -652,7 +652,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); return NULL; } - + if (language == DEFAULT_LANGUAGE) { // use language from current thread language = LANGIDFROMLCID(GetThreadLocale()); @@ -668,14 +668,14 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); return NULL; } - + typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); if (foundName == NULL) { SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); return NULL; } - + nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); if (foundLanguage == NULL) { @@ -684,17 +684,17 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); return NULL; } - + foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); } - + return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); } DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; - + return entry->Size; } @@ -702,7 +702,7 @@ LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; - + return codeBase + entry->OffsetToData; } @@ -721,13 +721,13 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO if (maxsize == 0) { return 0; } - + resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language); if (resource == NULL) { buffer[0] = 0; return 0; } - + data = MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { @@ -738,7 +738,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO buffer[0] = 0; return 0; } - + size = data->Length; if (size >= (DWORD) maxsize) { size = maxsize; diff --git a/doc/readme.txt b/doc/readme.txt index e528b7a..3d90304 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -60,7 +60,7 @@ stub that normally just displays an error message about the program not being able to be run from DOS mode. Microsoft defines the DOS header as follows:: - + typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file @@ -114,14 +114,14 @@ about symbols, etc:: .. _OptionalHeader: -The `OptionalHeader` contains informations about the *logical* format of the library, +The `OptionalHeader` contains informations about the *logical* format of the library, including required OS version, memory requirements and entry points:: typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // - + WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; @@ -131,11 +131,11 @@ including required OS version, memory requirements and entry points:: DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; - + // // NT additional fields. // - + DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; @@ -247,25 +247,25 @@ When issuing the API call `LoadLibrary`, Windows basically performs these tasks: 2. Try to allocate a memory block of `PEHeader.OptionalHeader.SizeOfImage` bytes at position `PEHeader.OptionalHeader.ImageBase`. - + 3. Parse section headers and copy sections to their addresses. The destination address for each section, relative to the base of the allocated memory block, is stored in the `VirtualAddress` attribute of the `IMAGE_SECTION_HEADER` structure. - + 4. If the allocated memory block differs from `ImageBase`, various references in the code and/or data sections must be adjusted. This is called *Base relocation*. - + 5. The required imports for the library must be resolved by loading the corresponding libraries. - + 6. The memory regions of the different sections must be protected depending on the section's characteristics. Some sections are marked as *discardable* and therefore can be safely freed at this point. These sections normally contain temporary data that is only needed during the import, like the informations for the base relocation. - + 7. Now the library is loaded completely. It must be notified about this by calling the entry point using the flag `DLL_PROCESS_ATTACH`. @@ -363,7 +363,7 @@ as follows:: // -1 if bound, and real date\time stamp // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) // O.W. date/time stamp of DLL bound to (Old BIND) - + DWORD ForwarderChain; // -1 if no forwarders DWORD Name; DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) @@ -401,10 +401,10 @@ These flags can be one or a combination of IMAGE_SCN_MEM_EXECUTE The section contains data that can be executed. - + IMAGE_SCN_MEM_READ The section contains data that is readable. - + IMAGE_SCN_MEM_WRITE The section contains data that is writeable. @@ -428,7 +428,7 @@ In addition the section flags above, the following can be added: IMAGE_SCN_MEM_DISCARDABLE The data in this section can be freed after the import. Usually this is specified for relocation data. - + IMAGE_SCN_MEM_NOT_CACHED The data in this section must not get cached by Windows. Add the bit flag `PAGE_NOCACHE` to the protection flags above. @@ -444,7 +444,7 @@ to a process. The function at the entry point is defined as :: - + typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); So the last code we need to execute is @@ -497,7 +497,7 @@ To free the custom loaded library, perform the steps DllEntryProc entry = (DllEntryProc)(baseAddress + PEHeader->OptionalHeader.AddressOfEntryPoint); (*entry)((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, 0); - + - Free external libraries used to resolve imports. - Free allocated memory. @@ -510,7 +510,7 @@ MemoryModule is a C-library that can be used to load a DLL from memory. The interface is very similar to the standard methods for loading of libraries:: typedef void *HMEMORYMODULE; - + HMEMORYMODULE MemoryLoadLibrary(const void *); FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); void MemoryFreeLibrary(HMEMORYMODULE); diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 1afe8a0..3fda631 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -18,24 +18,24 @@ void LoadFromFile(void) DWORD resourceSize; LPVOID resourceData; TCHAR buffer[100]; - + HINSTANCE handle = LoadLibrary(DLL_FILE); if (handle == NULL) return; addNumber = (addNumberProc)GetProcAddress(handle, "addNumbers"); _tprintf(_T("From file: %d\n"), addNumber(1, 2)); - + resourceInfo = FindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("FindResource returned 0x%p\n"), resourceInfo); - + resourceSize = SizeofResource(handle, resourceInfo); resourceData = LoadResource(handle, resourceInfo); _tprintf(_T("Resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); - + LoadString(handle, 1, buffer, sizeof(buffer)); _tprintf(_T("String1: %s\n"), buffer); - + LoadString(handle, 20, buffer, sizeof(buffer)); _tprintf(_T("String2: %s\n"), buffer); @@ -53,7 +53,7 @@ void LoadFromMemory(void) DWORD resourceSize; LPVOID resourceData; TCHAR buffer[100]; - + fp = _tfopen(DLL_FILE, _T("rb")); if (fp == NULL) { @@ -80,14 +80,14 @@ void LoadFromMemory(void) resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); - + resourceSize = MemorySizeofResource(handle, resourceInfo); resourceData = MemoryLoadResource(handle, resourceInfo); _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); - + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); _tprintf(_T("String1: %s\n"), buffer); - + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); _tprintf(_T("String2: %s\n"), buffer); diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 92fbd0a..dcfc263 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -15,7 +15,7 @@ endif RM = rm CFLAGS = -Wall -g -LDFLAGS = +LDFLAGS = ifdef UNICODE CFLAGS += -DUNICODE -D_UNICODE diff --git a/example/Makefile b/example/Makefile index 2852993..48b8e0b 100644 --- a/example/Makefile +++ b/example/Makefile @@ -10,7 +10,7 @@ $(SUBDIRS): CLEANDIRS = $(SUBDIRS:%=clean-%) clean: $(CLEANDIRS) -$(CLEANDIRS): +$(CLEANDIRS): $(MAKE) -C $(@:clean-%=%) clean .PHONY: subdirs $(INSTALLDIRS) From ce62f60a6e2b007bcd670deb74b3e3bcb62e040d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:09:31 +0200 Subject: [PATCH 02/94] Bump year in copyright. --- MemoryModule.c | 4 ++-- MemoryModule.h | 4 ++-- doc/readme.txt | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 0e89a7f..550520e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2013 + * Portions created by Joachim Bauch are Copyright (C) 2004-2014 * Joachim Bauch. All Rights Reserved. * */ diff --git a/MemoryModule.h b/MemoryModule.h index 7fbb22d..cabb48e 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.3 * - * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2013 + * Portions created by Joachim Bauch are Copyright (C) 2004-2014 * Joachim Bauch. All Rights Reserved. * */ diff --git a/doc/readme.txt b/doc/readme.txt index 3d90304..08473df 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -543,4 +543,4 @@ Copyright ========== The MemoryModule library and this tutorial are -Copyright (c) 2004-2013 by Joachim Bauch. +Copyright (c) 2004-2014 by Joachim Bauch. diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 6f73854..52d538b 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -10,7 +10,7 @@ BEGIN VALUE "FileDescription", "SampleDLL" VALUE "FileVersion", "1.0" VALUE "InternalName", "SampleDLL" - VALUE "LegalCopyright", "Copyright (c) 2013 Joachim Bauch" + VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" VALUE "ProductVersion", "0.0.3" From 8d286f85667d9a9399e72e550fcc6af0a9296cb7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:09:56 +0200 Subject: [PATCH 03/94] Bump version number. --- MemoryModule.c | 2 +- MemoryModule.h | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 550520e..7fece47 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -1,6 +1,6 @@ /* * Memory DLL loading code - * Version 0.0.3 + * Version 0.0.4 * * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de diff --git a/MemoryModule.h b/MemoryModule.h index cabb48e..adeacb6 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -1,6 +1,6 @@ /* * Memory DLL loading code - * Version 0.0.3 + * Version 0.0.4 * * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 52d538b..2fa076b 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -13,7 +13,7 @@ BEGIN VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" - VALUE "ProductVersion", "0.0.3" + VALUE "ProductVersion", "0.0.4" END END From da78edc39bc96fb5653c5489c5a2b3e34166cde7 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:14:21 +0200 Subject: [PATCH 04/94] Use markdown readme. --- readme.txt => readme.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) rename readme.txt => readme.md (67%) diff --git a/readme.txt b/readme.md similarity index 67% rename from readme.txt rename to readme.md index b826592..92d823c 100644 --- a/readme.txt +++ b/readme.md @@ -1,5 +1,8 @@ +MemoryModule +============ + The default windows API functions to load external libraries into a program -(LoadLibrary, LoadLibraryEx) only work with files on the filesystem. It's +(`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's therefore impossible to load a DLL from memory. But sometimes, you need exactly this functionality (e.g. you don't want to @@ -8,8 +11,8 @@ workarounds for this problems are to write the DLL into a temporary file first and import it from there. When the program terminates, the temporary file gets deleted. -MemoryModule is a library that can be used to load a DLL completely from +`MemoryModule` is a library that can be used to load a DLL completely from memory - without storing on the disk first. -See doc/readme.txt for more informations about the format of a DLL file and +See `doc/readme.txt` for more informations about the format of a DLL file and a tutorial how they can be loaded directly. From bb736dc160c6f70e940701e3f1cd5aea5911b36a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:19:36 +0200 Subject: [PATCH 05/94] Added explicit casts. --- MemoryModule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 7fece47..4fb4655 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -420,7 +420,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; // copy sections from DLL file block to new memory location - CopySections(data, old_header, result); + CopySections((const unsigned char *) data, old_header, result); // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); @@ -728,7 +728,7 @@ MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WO return 0; } - data = MemoryLoadResource(module, resource); + data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource); id = id & 0x0f; while (id--) { data = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) data) + (data->Length + 1) * sizeof(WCHAR)); From b8125d0a6560fa68f10677eabe6eaaaa2529c3af Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 14:24:44 +0200 Subject: [PATCH 06/94] Compile everything with "g++" and link statically. --- example/DllLoader/Makefile | 6 +++--- example/SampleDLL/Makefile | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index dcfc263..84c8c68 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -4,18 +4,18 @@ ifeq ($(UNAME), Linux) ifndef PLATFORM PLATFORM = i686 endif -CC = $(PLATFORM)-w64-mingw32-gcc +CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ LINK = $(PLATFORM)-w64-mingw32-ld else -CC = gcc +CC = g++ CXX = g++ LINK = ld endif RM = rm CFLAGS = -Wall -g -LDFLAGS = +LDFLAGS = -static ifdef UNICODE CFLAGS += -DUNICODE -D_UNICODE diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index 6ab5629..d5e8085 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -4,12 +4,12 @@ ifeq ($(UNAME), Linux) ifndef PLATFORM PLATFORM = i686 endif -CC = $(PLATFORM)-w64-mingw32-gcc +CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ LINK = $(PLATFORM)-w64-mingw32-ld RC = $(PLATFORM)-w64-mingw32-windres else -CC = gcc +CC = g++ CXX = g++ LINK = ld RC = rc From 2d504b533e698b3816d399708b00f99e2fcc53ed Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 17:33:18 +0200 Subject: [PATCH 07/94] Check architecture of library to load. --- MemoryModule.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index 4fb4655..a7eda08 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -370,6 +370,15 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } +#ifdef _WIN64 + if (old_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { +#else + if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { +#endif + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... From 5a448ce93ab91a5ac9456a456f6568f28a14f2e1 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 21 Sep 2014 18:34:11 +0200 Subject: [PATCH 08/94] Support loading (and running) EXE files (fixes #7). --- MemoryModule.c | 50 +++++++++++++++++------ MemoryModule.h | 19 +++++++-- example/DllLoader/DllLoaderLoader.cpp | 57 +++++++++++++++++++++++++++ example/DllLoader/Makefile | 10 ++++- 4 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 example/DllLoader/DllLoaderLoader.cpp diff --git a/MemoryModule.c b/MemoryModule.c index a7eda08..fcb0081 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -49,20 +49,24 @@ #include "MemoryModule.h" +typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); +typedef int (WINAPI *ExeEntryProc)(void); + typedef struct { PIMAGE_NT_HEADERS headers; unsigned char *codeBase; HCUSTOMMODULE *modules; int numModules; int initialized; + int isDLL; + int isRelocated; CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; void *userdata; + ExeEntryProc exeEntry; } MEMORYMODULE, *PMEMORYMODULE; -typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); - #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #ifdef DEBUG_OUTPUT @@ -202,11 +206,12 @@ ExecuteTLS(PMEMORYMODULE module) } } -static void +static int PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { DWORD i; unsigned char *codeBase = module->codeBase; + int result = 0; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); if (directory->Size > 0) { @@ -254,7 +259,9 @@ PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) // advance to next relocation block relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } + result = 1; } + return result; } static int @@ -355,7 +362,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; SIZE_T locationDelta; - DllEntryProc DllEntry; BOOL successfull; dos_header = (PIMAGE_DOS_HEADER)data; @@ -410,6 +416,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->numModules = 0; result->modules = NULL; result->initialized = 0; + result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; result->freeLibrary = freeLibrary; @@ -434,7 +441,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { - PerformBaseRelocation(result, locationDelta); + result->isRelocated = PerformBaseRelocation(result, locationDelta); + } else { + result->isRelocated = 1; } // load required dlls and adjust function table of imports @@ -451,14 +460,20 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { - DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); - // notify library about attaching to process - successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); - if (!successfull) { - SetLastError(ERROR_DLL_INIT_FAILED); - goto error; + if (result->isDLL) { + DllEntryProc DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); + // notify library about attaching to process + successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); + if (!successfull) { + SetLastError(ERROR_DLL_INIT_FAILED); + goto error; + } + result->initialized = 1; + } else { + result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); } - result->initialized = 1; + } else { + result->exeEntry = NULL; } return (HMEMORYMODULE)result; @@ -549,6 +564,17 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) } } +int MemoryCallEntryPoint(HMEMORYMODULE mod) +{ + PMEMORYMODULE module = (PMEMORYMODULE)mod; + + if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) { + return -1; + } + + return module->exeEntry(); +} + #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) diff --git a/MemoryModule.h b/MemoryModule.h index adeacb6..e2fa2d3 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -44,7 +44,7 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); /** - * Load DLL from memory location. + * Load EXE/DLL from memory location. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. @@ -52,7 +52,7 @@ typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); HMEMORYMODULE MemoryLoadLibrary(const void *); /** - * Load DLL from memory location using custom dependency resolvers. + * Load EXE/DLL from memory location using custom dependency resolvers. * * Dependencies will be resolved using passed callback methods. */ @@ -68,10 +68,23 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *, FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); /** - * Free previously loaded DLL. + * Free previously loaded EXE/DLL. */ void MemoryFreeLibrary(HMEMORYMODULE); +/** + * Execute entry point (EXE only). The entry point can only be executed + * if the EXE has been loaded to the correct base address or it could + * be relocated (i.e. relocation information have not been stripped by + * the linker). + * + * Important: calling this function will not return, i.e. once the loaded + * EXE finished running, the process will terminate. + * + * Returns a negative value if the entry point could not be executed. + */ +int MemoryCallEntryPoint(HMEMORYMODULE); + /** * Find the location of a resource with the specified type and name. */ diff --git a/example/DllLoader/DllLoaderLoader.cpp b/example/DllLoader/DllLoaderLoader.cpp new file mode 100644 index 0000000..e49979e --- /dev/null +++ b/example/DllLoader/DllLoaderLoader.cpp @@ -0,0 +1,57 @@ +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include "../../MemoryModule.h" + +#define EXE_FILE TEXT("DllLoader.exe") + +int RunFromMemory(void) +{ + FILE *fp; + unsigned char *data=NULL; + size_t size; + HMEMORYMODULE handle; + int result = -1; + + fp = _tfopen(EXE_FILE, _T("rb")); + if (fp == NULL) + { + _tprintf(_T("Can't open executable \"%s\"."), EXE_FILE); + goto exit; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + data = (unsigned char *)malloc(size); + fseek(fp, 0, SEEK_SET); + fread(data, 1, size, fp); + fclose(fp); + + handle = MemoryLoadLibrary(data); + if (handle == NULL) + { + _tprintf(_T("Can't load library from memory.\n")); + goto exit; + } + + result = MemoryCallEntryPoint(handle); + if (result < 0) { + _tprintf(_T("Could not execute entry point: %d\n"), result); + } + MemoryFreeLibrary(handle); + +exit: + if (data) + free(data); + return result; +} + +int main(int argc, char* argv[]) +{ + return RunFromMemory(); +} + diff --git a/example/DllLoader/Makefile b/example/DllLoader/Makefile index 84c8c68..65b5382 100644 --- a/example/DllLoader/Makefile +++ b/example/DllLoader/Makefile @@ -22,9 +22,15 @@ CFLAGS += -DUNICODE -D_UNICODE endif OBJ = DllLoader.o ../../MemoryModule.o +OBJ_LOADER = DllLoaderLoader.o ../../MemoryModule.o + +all: DllLoader.exe DllLoaderLoader.exe DllLoader.exe: $(OBJ) - $(CC) $(LDFLAGS) -o DllLoader.exe $(OBJ) + $(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o DllLoader.exe $(OBJ) + +DllLoaderLoader.exe: $(OBJ_LOADER) + $(CC) $(LDFLAGS) -Wl,--image-base -Wl,0x10000000 -o DllLoaderLoader.exe $(OBJ_LOADER) %.o: %.cpp $(CXX) $(CFLAGS) -c $< @@ -33,4 +39,4 @@ DllLoader.exe: $(OBJ) $(CC) $(CFLAGS) -c $< clean: - $(RM) -rf $(OBJ) DllLoader.exe + $(RM) -rf $(OBJ) $(OBJ_LOADER) DllLoader.exe DllLoaderLoader.exe From 1d55f777531bc7df46c70a73b9cf139c2770031f Mon Sep 17 00:00:00 2001 From: Dan Staples Date: Mon, 5 Jan 2015 20:28:02 -0500 Subject: [PATCH 09/94] small fix relating to searching IMAGE_RESOURCE_DIRECTORY_ENTRYs for named resources --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index fcb0081..bb43190 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -633,7 +633,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( int searchKeyLength = 0; #endif start = 0; - end = resources->NumberOfIdEntries; + end = resources->NumberOfNamedEntries; while (end > start) { // resource names are always stored using 16bit characters int cmp; From 52b0379749a29a17a4f588443ca6050994c16247 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:05:11 +0100 Subject: [PATCH 10/94] Added travis configuration. --- .travis.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..67de344 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +env: + - PLATFORM=x86_64 WINE=wine64 + - PLATFORM=i686 WINE=wine + +language: cpp + +cache: + - apt + +before_install: + - sudo apt-get update -qq + - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" + - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" + +script: + - make PLATFORM=$PLATFORM + - cd example/DllLoader + - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe + - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe From 3422b5791c7ebab00b164a5b72c8e74541e0973a Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:20:35 +0100 Subject: [PATCH 11/94] Show build status. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 92d823c..ab35ac6 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,8 @@ MemoryModule ============ +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule) + The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's therefore impossible to load a DLL from memory. From b889c72727bb4e613249b2b0902b6dfae76baa99 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:22:03 +0100 Subject: [PATCH 12/94] Bump year in copyright. --- MemoryModule.c | 4 ++-- MemoryModule.h | 4 ++-- doc/readme.txt | 2 +- example/SampleDLL/SampleDLL.rc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index fcb0081..3094133 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.4 * - * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2014 + * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ diff --git a/MemoryModule.h b/MemoryModule.h index e2fa2d3..9174ad2 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -2,7 +2,7 @@ * Memory DLL loading code * Version 0.0.4 * - * Copyright (c) 2004-2014 by Joachim Bauch / mail@joachim-bauch.de + * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version @@ -19,7 +19,7 @@ * * The Initial Developer of the Original Code is Joachim Bauch. * - * Portions created by Joachim Bauch are Copyright (C) 2004-2014 + * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ diff --git a/doc/readme.txt b/doc/readme.txt index 08473df..7e02c1b 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -543,4 +543,4 @@ Copyright ========== The MemoryModule library and this tutorial are -Copyright (c) 2004-2014 by Joachim Bauch. +Copyright (c) 2004-2015 by Joachim Bauch. diff --git a/example/SampleDLL/SampleDLL.rc b/example/SampleDLL/SampleDLL.rc index 2fa076b..5a0da61 100644 --- a/example/SampleDLL/SampleDLL.rc +++ b/example/SampleDLL/SampleDLL.rc @@ -10,7 +10,7 @@ BEGIN VALUE "FileDescription", "SampleDLL" VALUE "FileVersion", "1.0" VALUE "InternalName", "SampleDLL" - VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch" + VALUE "LegalCopyright", "Copyright (c) 2004-2015 Joachim Bauch" VALUE "OriginalFilename", "SampleDLL.dll" VALUE "ProductName", "MemoryModule" VALUE "ProductVersion", "0.0.4" From 808c043fafec8a7d1726cf95d68a5f5c5c4191b0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:25:57 +0100 Subject: [PATCH 13/94] Fixed indentation. --- MemoryModule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 160eb31..83d2391 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -67,7 +67,7 @@ typedef struct { ExeEntryProc exeEntry; } MEMORYMODULE, *PMEMORYMODULE; -#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] +#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #ifdef DEBUG_OUTPUT static void @@ -637,7 +637,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( while (end > start) { // resource names are always stored using 16bit characters int cmp; - PIMAGE_RESOURCE_DIR_STRING_U resourceString; + PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); #if !defined(UNICODE) @@ -750,9 +750,9 @@ MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) int MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) { - HMEMORYRSRC resource; - PIMAGE_RESOURCE_DIR_STRING_U data; - DWORD size; + HMEMORYRSRC resource; + PIMAGE_RESOURCE_DIR_STRING_U data; + DWORD size; if (maxsize == 0) { return 0; } From 6212358a24a597a6b6405567d32aabb157039fef Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:34:28 +0100 Subject: [PATCH 14/94] Use function from tchar.h instead of #ifdef. --- MemoryModule.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 83d2391..602c505 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -596,11 +596,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string TCHAR *endpos = NULL; -#if defined(UNICODE) - long int tmpkey = (WORD) wcstol((TCHAR *) &key[1], &endpos, 10); -#else - long int tmpkey = (WORD) strtol((TCHAR *) &key[1], &endpos, 10); -#endif + long int tmpkey = (WORD) _tcstol((TCHAR *) &key[1], &endpos, 10); if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { key = MAKEINTRESOURCE(tmpkey); } From dacdbaba9a88d05a8d7dc840adcc74c3d5d8ed77 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:39:16 +0100 Subject: [PATCH 15/94] Deny loading any other architecture than 64bit if compiled for 64bit. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 602c505..6a661bc 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -377,7 +377,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } #ifdef _WIN64 - if (old_header->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { + if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { #else if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { #endif From 625aa470359b2e86d30c6670278658de3ea01729 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:46:34 +0100 Subject: [PATCH 16/94] Use "uintptr_t" instead of custom type. --- MemoryModule.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 6a661bc..9e99535 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -29,14 +29,9 @@ #pragma warning( disable : 4311 4312 ) #endif -#ifdef _WIN64 -#define POINTER_TYPE ULONGLONG -#else -#define POINTER_TYPE DWORD -#endif - #include #include +#include #include #ifdef DEBUG_OUTPUT #include @@ -103,7 +98,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); - section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; + section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; memset(dest, 0, size); } @@ -117,7 +112,7 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); - section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest; + section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } } @@ -140,7 +135,7 @@ FinalizeSections(PMEMORYMODULE module) int i; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 - POINTER_TYPE imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); + uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else #define imageOffset 0 #endif @@ -154,7 +149,7 @@ FinalizeSections(PMEMORYMODULE module) if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { // section is not needed any more and can safely be freed - VirtualFree((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); + VirtualFree((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); continue; } @@ -176,7 +171,7 @@ FinalizeSections(PMEMORYMODULE module) if (size > 0) { // change memory access flags - if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) + if (VirtualProtect((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) #ifdef DEBUG_OUTPUT OutputLastError("Error protecting memory page") #endif @@ -275,7 +270,7 @@ BuildImportTable(PMEMORYMODULE module) if (directory->Size > 0) { PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - POINTER_TYPE *thunkRef; + uintptr_t *thunkRef; FARPROC *funcRef; HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); if (handle == NULL) { @@ -295,11 +290,11 @@ BuildImportTable(PMEMORYMODULE module) module->modules[module->numModules++] = handle; if (importDesc->OriginalFirstThunk) { - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk); + thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } else { // no hint table - thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk); + thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } for (; *thunkRef; thunkRef++, funcRef++) { @@ -433,7 +428,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; // update position - result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; + result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location CopySections((const unsigned char *) data, old_header, result); @@ -606,7 +601,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( // followed by an ordered list of id entries - we can do // a binary search to find faster... if (IS_INTRESOURCE(key)) { - WORD check = (WORD) (POINTER_TYPE) key; + WORD check = (WORD) (uintptr_t) key; start = resources->NumberOfNamedEntries; end = start + resources->NumberOfIdEntries; @@ -708,7 +703,7 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ } nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); - foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (POINTER_TYPE) language); + foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (uintptr_t) language); if (foundLanguage == NULL) { // requested language not found, use first available if (nameResources->NumberOfIdEntries == 0) { From 4c08d8eb92abd37108315433b00e9338c090c72c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:54:48 +0100 Subject: [PATCH 17/94] Also build UNICODE versions. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 67de344..0de8cba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ env: - PLATFORM=x86_64 WINE=wine64 - PLATFORM=i686 WINE=wine + - UNICODE= + - UNICODE=1 language: cpp @@ -13,7 +15,7 @@ before_install: - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" script: - - make PLATFORM=$PLATFORM + - make PLATFORM=$PLATFORM UNICODE=$UNICODE - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe From dd5e818dfc57253d59c4ec0dd569fb4a29cd346e Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 00:56:39 +0100 Subject: [PATCH 18/94] Need to specify build matrix differently. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0de8cba..2af19ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ env: - - PLATFORM=x86_64 WINE=wine64 - - PLATFORM=i686 WINE=wine - - UNICODE= - - UNICODE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE= + - PLATFORM=i686 WINE=wine UNICODE= + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 + - PLATFORM=i686 WINE=wine UNICODE=1 language: cpp From 927bd2a9f01b60be27e06b46d6bfc188a7ffef58 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 27 Feb 2015 01:34:33 +0100 Subject: [PATCH 19/94] Link using "g++" to get reloc information. --- example/SampleDLL/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/SampleDLL/Makefile b/example/SampleDLL/Makefile index d5e8085..ce3f65b 100644 --- a/example/SampleDLL/Makefile +++ b/example/SampleDLL/Makefile @@ -6,7 +6,7 @@ PLATFORM = i686 endif CC = $(PLATFORM)-w64-mingw32-g++ CXX = $(PLATFORM)-w64-mingw32-g++ -LINK = $(PLATFORM)-w64-mingw32-ld +LINK = $(PLATFORM)-w64-mingw32-g++ RC = $(PLATFORM)-w64-mingw32-windres else CC = g++ From aa6b93bab43430c91da8201ae18569a646b9e192 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 28 Feb 2015 23:01:44 +0100 Subject: [PATCH 20/94] Support section alignments that are smaller than the memory page size (fixes #20/#21). --- MemoryModule.c | 146 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 33 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 9e99535..d5e071e 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -60,9 +60,19 @@ typedef struct { CustomFreeLibraryFunc freeLibrary; void *userdata; ExeEntryProc exeEntry; + DWORD pageSize; } MEMORYMODULE, *PMEMORYMODULE; +typedef struct { + LPVOID address; + LPVOID alignedAddress; + DWORD size; + DWORD characteristics; + BOOL last; +} SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; + #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] +#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) #ifdef DEBUG_OUTPUT static void @@ -98,6 +108,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO MEM_COMMIT, PAGE_READWRITE); + // Always use position from file to support alignments smaller + // than page size. + dest = codeBase + section->VirtualAddress; section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; memset(dest, 0, size); } @@ -111,6 +124,10 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); + + // Always use position from file to support alignments smaller + // than page size. + dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } @@ -129,6 +146,63 @@ static int ProtectionFlags[2][2][2] = { }, }; +static DWORD +GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { + DWORD size = section->SizeOfRawData; + if (size == 0) { + if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfInitializedData; + } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + size = module->headers->OptionalHeader.SizeOfUninitializedData; + } + } + return size; +} + +static BOOL +FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { + DWORD protect, oldProtect; + int executable; + int readable; + int writeable; + + if (sectionData->size == 0) { + return TRUE; + } + + if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { + // section is not needed any more and can safely be freed + if (sectionData->address == sectionData->alignedAddress && + (sectionData->last || + module->headers->OptionalHeader.SectionAlignment == module->pageSize || + (sectionData->size % module->pageSize) == 0) + ) { + // Only allowed to decommit whole pages + VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT); + } + return TRUE; + } + + // determine protection flags based on characteristics + executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; + readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; + writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; + protect = ProtectionFlags[executable][readable][writeable]; + if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) { + protect |= PAGE_NOCACHE; + } + + // change memory access flags + if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { +#ifdef DEBUG_OUTPUT + OutputLastError("Error protecting memory page") +#endif + return FALSE; + } + + return TRUE; +} + static void FinalizeSections(PMEMORYMODULE module) { @@ -139,45 +213,41 @@ FinalizeSections(PMEMORYMODULE module) #else #define imageOffset 0 #endif + SECTIONFINALIZEDATA sectionData; + sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); + sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); + sectionData.size = GetRealSectionSize(module, section); + sectionData.characteristics = section->Characteristics; + sectionData.last = FALSE; + section++; // loop through all sections and change access flags - for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { - DWORD protect, oldProtect, size; - int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; - int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; - int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; - - if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { - // section is not needed any more and can safely be freed - VirtualFree((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); - continue; - } - - // determine protection flags based on characteristics - protect = ProtectionFlags[executable][readable][writeable]; - if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { - protect |= PAGE_NOCACHE; - } - - // determine size of region - size = section->SizeOfRawData; - if (size == 0) { - if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfInitializedData; - } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - size = module->headers->OptionalHeader.SizeOfUninitializedData; + for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { + LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); + LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); + DWORD sectionSize = GetRealSectionSize(module, section); + // Combine access flags of all sections that share a page + // TODO(fancycode): We currently share flags of a trailing large section + // with the page of a first small section. This should be optimized. + if (sectionData.alignedAddress == alignedAddress || (uintptr_t) sectionData.address + sectionData.size > (uintptr_t) alignedAddress) { + // Section shares page with previous + if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { + sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; + } else { + sectionData.characteristics |= section->Characteristics; } + sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t) sectionData.address; + continue; } - if (size > 0) { - // change memory access flags - if (VirtualProtect((LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) -#ifdef DEBUG_OUTPUT - OutputLastError("Error protecting memory page") -#endif - ; - } + FinalizeSection(module, §ionData); + sectionData.address = sectionAddress; + sectionData.alignedAddress = alignedAddress; + sectionData.size = sectionSize; + sectionData.characteristics = section->Characteristics; } + sectionData.last = TRUE; + FinalizeSection(module, §ionData); #ifndef _WIN64 #undef imageOffset #endif @@ -358,6 +428,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, unsigned char *code, *headers; SIZE_T locationDelta; BOOL successfull; + SYSTEM_INFO sysInfo; dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { @@ -380,6 +451,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, return NULL; } + if (old_header->OptionalHeader.SectionAlignment & 1) { + // Only support section alignments that are a multiple of 2 + SetLastError(ERROR_BAD_EXE_FORMAT); + return NULL; + } + // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... @@ -417,6 +494,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->freeLibrary = freeLibrary; result->userdata = userdata; + GetNativeSystemInfo(&sysInfo); + result->pageSize = sysInfo.dwPageSize; + // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, From d321abf8fa72bd1b768cb5f9bcf8150b04cb7cec Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 28 Feb 2015 23:59:06 +0100 Subject: [PATCH 21/94] Added more error handling, changed boolean variables to "BOOL", bail our early from functions where possible. --- MemoryModule.c | 287 +++++++++++++++++++++++++++---------------------- 1 file changed, 156 insertions(+), 131 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index d5e071e..658ed92 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -52,9 +52,9 @@ typedef struct { unsigned char *codeBase; HCUSTOMMODULE *modules; int numModules; - int initialized; - int isDLL; - int isRelocated; + BOOL initialized; + BOOL isDLL; + BOOL isRelocated; CustomLoadLibraryFunc loadLibrary; CustomGetProcAddressFunc getProcAddress; CustomFreeLibraryFunc freeLibrary; @@ -90,7 +90,7 @@ OutputLastError(const char *msg) } #endif -static void +static BOOL CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { int i, size; @@ -107,6 +107,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO size, MEM_COMMIT, PAGE_READWRITE); + if (dest == NULL) { + return FALSE; + } // Always use position from file to support alignments smaller // than page size. @@ -124,6 +127,9 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); + if (dest == NULL) { + return FALSE; + } // Always use position from file to support alignments smaller // than page size. @@ -131,6 +137,8 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } + + return TRUE; } // Protection flags for memory pages (Executable, Readable, Writeable) @@ -162,9 +170,9 @@ GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { DWORD protect, oldProtect; - int executable; - int readable; - int writeable; + BOOL executable; + BOOL readable; + BOOL writeable; if (sectionData->size == 0) { return TRUE; @@ -203,7 +211,7 @@ FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { return TRUE; } -static void +static BOOL FinalizeSections(PMEMORYMODULE module) { int i; @@ -240,152 +248,164 @@ FinalizeSections(PMEMORYMODULE module) continue; } - FinalizeSection(module, §ionData); + if (!FinalizeSection(module, §ionData)) { + return FALSE; + } sectionData.address = sectionAddress; sectionData.alignedAddress = alignedAddress; sectionData.size = sectionSize; sectionData.characteristics = section->Characteristics; } sectionData.last = TRUE; - FinalizeSection(module, §ionData); + if (!FinalizeSection(module, §ionData)) { + return FALSE; + } #ifndef _WIN64 #undef imageOffset #endif + return TRUE; } -static void +static BOOL ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); - if (directory->VirtualAddress > 0) { - PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); - PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; - if (callback) { - while (*callback) { - (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); - callback++; - } + if (directory->VirtualAddress == 0) { + return TRUE; + } + + PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); + PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; + if (callback) { + while (*callback) { + (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); + callback++; } } + return TRUE; } -static int +static BOOL PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { - DWORD i; unsigned char *codeBase = module->codeBase; - int result = 0; + PIMAGE_BASE_RELOCATION relocation; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); - if (directory->Size > 0) { - PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); - for (; relocation->VirtualAddress > 0; ) { - unsigned char *dest = codeBase + relocation->VirtualAddress; - unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); - for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { - DWORD *patchAddrHL; + if (directory->Size == 0) { + return (delta == 0); + } + + relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); + for (; relocation->VirtualAddress > 0; ) { + DWORD i; + unsigned char *dest = codeBase + relocation->VirtualAddress; + unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); + for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { + DWORD *patchAddrHL; #ifdef _WIN64 - ULONGLONG *patchAddr64; + ULONGLONG *patchAddr64; #endif - int type, offset; + int type, offset; - // the upper 4 bits define the type of relocation - type = *relInfo >> 12; - // the lower 12 bits define the offset - offset = *relInfo & 0xfff; + // the upper 4 bits define the type of relocation + type = *relInfo >> 12; + // the lower 12 bits define the offset + offset = *relInfo & 0xfff; - switch (type) - { - case IMAGE_REL_BASED_ABSOLUTE: - // skip relocation - break; + switch (type) + { + case IMAGE_REL_BASED_ABSOLUTE: + // skip relocation + break; - case IMAGE_REL_BASED_HIGHLOW: - // change complete 32 bit address - patchAddrHL = (DWORD *) (dest + offset); - *patchAddrHL += (DWORD) delta; - break; + case IMAGE_REL_BASED_HIGHLOW: + // change complete 32 bit address + patchAddrHL = (DWORD *) (dest + offset); + *patchAddrHL += (DWORD) delta; + break; #ifdef _WIN64 - case IMAGE_REL_BASED_DIR64: - patchAddr64 = (ULONGLONG *) (dest + offset); - *patchAddr64 += (ULONGLONG) delta; - break; + case IMAGE_REL_BASED_DIR64: + patchAddr64 = (ULONGLONG *) (dest + offset); + *patchAddr64 += (ULONGLONG) delta; + break; #endif - default: - //printf("Unknown relocation: %d\n", type); - break; - } + default: + //printf("Unknown relocation: %d\n", type); + break; } - - // advance to next relocation block - relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } - result = 1; + + // advance to next relocation block + relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } - return result; + return TRUE; } -static int +static BOOL BuildImportTable(PMEMORYMODULE module) { - int result=1; unsigned char *codeBase = module->codeBase; - HCUSTOMMODULE *tmp; + PIMAGE_IMPORT_DESCRIPTOR importDesc; + BOOL result = TRUE; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (directory->Size > 0) { - PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); - for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - uintptr_t *thunkRef; - FARPROC *funcRef; - HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); - if (handle == NULL) { - SetLastError(ERROR_MOD_NOT_FOUND); - result = 0; - break; - } + if (directory->Size == 0) { + return TRUE; + } - tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); - if (tmp == NULL) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_OUTOFMEMORY); - result = 0; - break; - } - module->modules = tmp; + importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); + for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { + uintptr_t *thunkRef; + FARPROC *funcRef; + HCUSTOMMODULE *tmp; + HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata); + if (handle == NULL) { + SetLastError(ERROR_MOD_NOT_FOUND); + result = FALSE; + break; + } - module->modules[module->numModules++] = handle; - if (importDesc->OriginalFirstThunk) { - thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); + if (tmp == NULL) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_OUTOFMEMORY); + result = FALSE; + break; + } + module->modules = tmp; + + module->modules[module->numModules++] = handle; + if (importDesc->OriginalFirstThunk) { + thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } else { + // no hint table + thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); + funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); + } + for (; *thunkRef; thunkRef++, funcRef++) { + if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { + *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); } else { - // no hint table - thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); - funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); - } - for (; *thunkRef; thunkRef++, funcRef++) { - if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { - *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata); - } else { - PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); - *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); - } - if (*funcRef == 0) { - result = 0; - break; - } + PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); + *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata); } - - if (!result) { - module->freeLibrary(handle, module->userdata); - SetLastError(ERROR_PROC_NOT_FOUND); + if (*funcRef == 0) { + result = FALSE; break; } } + + if (!result) { + module->freeLibrary(handle, module->userdata); + SetLastError(ERROR_PROC_NOT_FOUND); + break; + } } return result; @@ -427,7 +447,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; SIZE_T locationDelta; - BOOL successfull; SYSTEM_INFO sysInfo; dos_header = (PIMAGE_DOS_HEADER)data; @@ -487,7 +506,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->codeBase = code; result->numModules = 0; result->modules = NULL; - result->initialized = 0; + result->initialized = FALSE; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; @@ -511,14 +530,16 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location - CopySections((const unsigned char *) data, old_header, result); + if (!CopySections((const unsigned char *) data, old_header, result)) { + goto error; + } // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { result->isRelocated = PerformBaseRelocation(result, locationDelta); } else { - result->isRelocated = 1; + result->isRelocated = TRUE; } // load required dlls and adjust function table of imports @@ -528,22 +549,26 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, // mark memory pages depending on section headers and release // sections that are marked as "discardable" - FinalizeSections(result); + if (!FinalizeSections(result)) { + goto error; + } // TLS callbacks are executed BEFORE the main loading - ExecuteTLS(result); + if (!ExecuteTLS(result)) { + goto error; + } // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { if (result->isDLL) { DllEntryProc DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); // notify library about attaching to process - successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); + BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); if (!successfull) { SetLastError(ERROR_DLL_INIT_FAILED); goto error; } - result->initialized = 1; + result->initialized = TRUE; } else { result->exeEntry = (ExeEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); } @@ -611,32 +636,32 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) int i; PMEMORYMODULE module = (PMEMORYMODULE)mod; - if (module != NULL) { - if (module->initialized != 0) { - // notify library about detaching from process - DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); - (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); - module->initialized = 0; - } + if (module == NULL) { + return; + } + if (module->initialized) { + // notify library about detaching from process + DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); + (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); + } - if (module->modules != NULL) { - // free previously opened libraries - for (i=0; inumModules; i++) { - if (module->modules[i] != NULL) { - module->freeLibrary(module->modules[i], module->userdata); - } + if (module->modules != NULL) { + // free previously opened libraries + for (i=0; inumModules; i++) { + if (module->modules[i] != NULL) { + module->freeLibrary(module->modules[i], module->userdata); } - - free(module->modules); } - if (module->codeBase != NULL) { - // release memory of library - VirtualFree(module->codeBase, 0, MEM_RELEASE); - } + free(module->modules); + } - HeapFree(GetProcessHeap(), 0, module); + if (module->codeBase != NULL) { + // release memory of library + VirtualFree(module->codeBase, 0, MEM_RELEASE); } + + HeapFree(GetProcessHeap(), 0, module); } int MemoryCallEntryPoint(HMEMORYMODULE mod) From 463447c1ed66359b91d3a6db16aa4f32bb1d5406 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 00:04:38 +0100 Subject: [PATCH 22/94] Reduced scope of variable. --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 658ed92..fb17040 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -633,7 +633,6 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) void MemoryFreeLibrary(HMEMORYMODULE mod) { - int i; PMEMORYMODULE module = (PMEMORYMODULE)mod; if (module == NULL) { @@ -647,6 +646,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod) if (module->modules != NULL) { // free previously opened libraries + int i; for (i=0; inumModules; i++) { if (module->modules[i] != NULL) { module->freeLibrary(module->modules[i], module->userdata); From 36574a5638f6b6ff7ec138003a2e3ef4710495db Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 00:32:38 +0100 Subject: [PATCH 23/94] Handle case where resource to load is NULL. --- MemoryModule.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MemoryModule.c b/MemoryModule.c index fb17040..8a348a1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -825,6 +825,9 @@ HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR typ DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + if (entry == NULL) { + return 0; + } return entry->Size; } @@ -833,6 +836,9 @@ LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; + if (entry == NULL) { + return NULL; + } return codeBase + entry->OffsetToData; } From 2da44d00e984e514965ab6d8b37d1e47635e89a5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:04:17 +0100 Subject: [PATCH 24/94] Run more tests with sample DLLs. --- .gitignore | 2 ++ .travis.yml | 1 + Makefile | 7 ++-- tests/LoadDll.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile | 82 ++++++++++++++++++++++++++++++++++++++++++ tests/SampleDLL.cpp | 10 ++++++ tests/SampleDLL.h | 11 ++++++ tests/SampleDLL.rc | 34 ++++++++++++++++++ tests/runtests.sh | 20 +++++++++++ 9 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 tests/LoadDll.cpp create mode 100644 tests/Makefile create mode 100644 tests/SampleDLL.cpp create mode 100644 tests/SampleDLL.h create mode 100644 tests/SampleDLL.rc create mode 100755 tests/runtests.sh diff --git a/.gitignore b/.gitignore index 8cc774f..6c07d24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.obj *.exe +tests/*.dll +tests/*.res diff --git a/.travis.yml b/.travis.yml index 2af19ce..9182c08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ script: - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe + - make test PLATFORM=$PLATFORM UNICODE=$UNICODE diff --git a/Makefile b/Makefile index d41c588..590c6e6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = example +SUBDIRS = example tests .PHONY: subdirs $(SUBDIRS) @@ -13,5 +13,8 @@ clean: $(CLEANDIRS) $(CLEANDIRS): $(MAKE) -C $(@:clean-%=%) clean +test: + $(MAKE) -C tests test + .PHONY: subdirs $(INSTALLDIRS) -.PHONY: clean +.PHONY: clean test diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp new file mode 100644 index 0000000..b5074a7 --- /dev/null +++ b/tests/LoadDll.cpp @@ -0,0 +1,88 @@ +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include "../MemoryModule.h" + +typedef int (*addNumberProc)(int, int); + +BOOL LoadFromMemory(char *filename) +{ + FILE *fp; + unsigned char *data=NULL; + size_t size; + HMEMORYMODULE handle; + addNumberProc addNumber; + HMEMORYRSRC resourceInfo; + DWORD resourceSize; + LPVOID resourceData; + TCHAR buffer[100]; + BOOL result = TRUE; + + fp = fopen(filename, "rb"); + if (fp == NULL) + { + printf("Can't open DLL file \"%s\".", filename); + result = FALSE; + goto exit; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + data = (unsigned char *)malloc(size); + fseek(fp, 0, SEEK_SET); + fread(data, 1, size, fp); + fclose(fp); + + handle = MemoryLoadLibrary(data); + if (handle == NULL) + { + _tprintf(_T("Can't load library from memory.\n")); + result = FALSE; + goto exit; + } + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); + _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + + MemoryLoadString(handle, 1, buffer, sizeof(buffer)); + _tprintf(_T("String1: %s\n"), buffer); + + MemoryLoadString(handle, 20, buffer, sizeof(buffer)); + _tprintf(_T("String2: %s\n"), buffer); + } else { + result = FALSE; + } + + MemoryFreeLibrary(handle); + +exit: + if (data) + free(data); + return result; +} + +int main(int argc, char* argv[]) +{ + if (argc < 2) { + fprintf(stderr, "USAGE: %s \n", argv[0]); + return 1; + } + + if (!LoadFromMemory(argv[1])) { + return 2; + } + + return 0; +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..aafc6db --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,82 @@ +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) +ifndef PLATFORM +PLATFORM = i686 +endif +CC = $(PLATFORM)-w64-mingw32-g++ +CXX = $(PLATFORM)-w64-mingw32-g++ +LD = $(PLATFORM)-w64-mingw32-ld +RC = $(PLATFORM)-w64-mingw32-windres +else +CC = g++ +CXX = g++ +LD = ld +RC = rc +endif + +RM = rm +CFLAGS = -Wall -g +LDFLAGS = +RCFLAGS = -O coff + +ifdef UNICODE +CFLAGS += -DUNICODE -D_UNICODE +endif + +CFLAGS_DLL = -DSAMPLEDLL_EXPORTS +CFLAGS_EXE = +LDFLAGS_DLL = -shared +LDFLAGS_EXE = -static + +TEST_DLLS = \ + test-align-128.dll \ + test-align-256.dll \ + test-align-512.dll \ + test-align-768.dll \ + test-align-1024.dll \ + test-align-2048.dll \ + test-align-3072.dll \ + test-align-4096.dll \ + test-align-100.dll \ + test-align-200.dll \ + test-align-300.dll \ + test-align-400.dll \ + test-align-500.dll \ + test-align-600.dll \ + test-align-800.dll \ + test-align-900.dll \ + test-align-1000.dll \ + test-relocate.dll \ + +LOADDLL_OBJ = LoadDll.o ../MemoryModule.o +DLL_OBJ = SampleDLL.o SampleDLL.res + +all: LoadDll.exe $(TEST_DLLS) + +LoadDll.exe: $(LOADDLL_OBJ) + $(CC) $(LDFLAGS_EXE) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o LoadDll.exe $(LOADDLL_OBJ) + +LoadDll.o: LoadDll.cpp + $(CXX) $(CFLAGS) $(CFLAGS_EXE) -c $< + +test-align-%.dll: $(DLL_OBJ) + $(LD) $(LDFLAGS_DLL) $(LDFLAGS) --file-alignment $* --section-alignment $* -o $@ $(DLL_OBJ) + +test-relocate.dll: $(DLL_OBJ) + $(CXX) $(LDFLAGS_DLL) $(LDFLAGS) -Wl,--image-base -Wl,0x20000000 -o $@ $(DLL_OBJ) + +%.o: %.cpp + $(CXX) $(CFLAGS) $(CFLAGS_DLL) -c $< + +%.o: %.cc + $(CC) $(CFLAGS) $(CFLAGS_DLL) -c $< + +%.res: %.rc + $(RC) $(RCFLAGS) -o $*.res $< + +clean: + $(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) + +test: all + ./runtests.sh $(PLATFORM) "$(TEST_DLLS)" diff --git a/tests/SampleDLL.cpp b/tests/SampleDLL.cpp new file mode 100644 index 0000000..7bf03ef --- /dev/null +++ b/tests/SampleDLL.cpp @@ -0,0 +1,10 @@ +#include "SampleDLL.h" + +extern "C" { + +SAMPLEDLL_API int addNumbers(int a, int b) +{ + return a + b; +} + +} diff --git a/tests/SampleDLL.h b/tests/SampleDLL.h new file mode 100644 index 0000000..2662c3c --- /dev/null +++ b/tests/SampleDLL.h @@ -0,0 +1,11 @@ +extern "C" { + +#ifdef SAMPLEDLL_EXPORTS +#define SAMPLEDLL_API __declspec(dllexport) +#else +#define SAMPLEDLL_API __declspec(dllimport) +#endif + +SAMPLEDLL_API int addNumbers(int a, int b); + +} diff --git a/tests/SampleDLL.rc b/tests/SampleDLL.rc new file mode 100644 index 0000000..5a0da61 --- /dev/null +++ b/tests/SampleDLL.rc @@ -0,0 +1,34 @@ +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "fancy.code" + VALUE "FileDescription", "SampleDLL" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "SampleDLL" + VALUE "LegalCopyright", "Copyright (c) 2004-2015 Joachim Bauch" + VALUE "OriginalFilename", "SampleDLL.dll" + VALUE "ProductName", "MemoryModule" + VALUE "ProductVersion", "0.0.4" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +#define IDS_HELLO 1 +#define IDS_WORLD 20 + +STRINGTABLE +{ + IDS_HELLO, "Hello" + IDS_WORLD, "World!" +} diff --git a/tests/runtests.sh b/tests/runtests.sh new file mode 100755 index 0000000..f998f13 --- /dev/null +++ b/tests/runtests.sh @@ -0,0 +1,20 @@ +#!/bin/bash +if [ "$1" = "x86_64" ]; then + export WINEPREFIX=${HOME}/.wine64/ +else + export WINEPREFIX=${HOME}/.wine/ +fi + +read -a TEST_DLLS <<< $2 + +for filename in "${TEST_DLLS[@]}" +do + : + echo "Testing $filename" + ./LoadDll.exe $filename + if [ "$?" != "0" ]; then + exit 1 + fi +done + +echo "${#TEST_DLLS[@]} tests completed successfully" From 31cbe89bfe9a007ffbdaba87435be30269bacad5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:08:48 +0100 Subject: [PATCH 25/94] Run tests before checking samples manually. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9182c08..108523e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ before_install: script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE + - make test PLATFORM=$PLATFORM UNICODE=$UNICODE - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe - - make test PLATFORM=$PLATFORM UNICODE=$UNICODE From d9dc0b02709ae1fff65e7d0183a7d8fe17965272 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:16:33 +0100 Subject: [PATCH 26/94] Setup additional environment flags for wine. --- tests/runtests.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/runtests.sh b/tests/runtests.sh index f998f13..57d70c6 100755 --- a/tests/runtests.sh +++ b/tests/runtests.sh @@ -1,9 +1,13 @@ #!/bin/bash -if [ "$1" = "x86_64" ]; then +PLATFORM=$1 +if [ "${PLATFORM}" = "x86_64" ]; then export WINEPREFIX=${HOME}/.wine64/ + WINE=wine64 else export WINEPREFIX=${HOME}/.wine/ + WINE=wine fi +export WINEPATH=/usr/lib/gcc/${PLATFORM}-w64-mingw32/4.6/ read -a TEST_DLLS <<< $2 @@ -11,7 +15,7 @@ for filename in "${TEST_DLLS[@]}" do : echo "Testing $filename" - ./LoadDll.exe $filename + ${WINE} ./LoadDll.exe $filename if [ "$?" != "0" ]; then exit 1 fi From dc173cad6ddb7d3afe91b5f3d7b80be1d76df24c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 1 Mar 2015 01:57:11 +0100 Subject: [PATCH 27/94] Disable alignment of 1000 bytes for now, failing in Travis. --- tests/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index aafc6db..f167a72 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -46,7 +46,6 @@ TEST_DLLS = \ test-align-600.dll \ test-align-800.dll \ test-align-900.dll \ - test-align-1000.dll \ test-relocate.dll \ LOADDLL_OBJ = LoadDll.o ../MemoryModule.o From 89e02fcd9edc6bfb82890757d4269d3fb5ec2186 Mon Sep 17 00:00:00 2001 From: Fr0sT-Brutal Date: Thu, 12 Mar 2015 20:11:05 +0300 Subject: [PATCH 28/94] Zero the memory allocated in the heap Using HEAP_ZERO_MEMORY parameter of HeapAlloc function we can fill all the struct contents with zeros thus removing possible bugs with uninitialized members and slightly shortening/speeding up the code --- MemoryModule.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 8a348a1..682b95d 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -496,7 +496,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } } - result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); + result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { SetLastError(ERROR_OUTOFMEMORY); VirtualFree(code, 0, MEM_RELEASE); @@ -504,9 +504,6 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, } result->codeBase = code; - result->numModules = 0; - result->modules = NULL; - result->initialized = FALSE; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; From 82b11d57db127296eafc9029446d44c6c2b67772 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 13 Mar 2015 16:56:02 +0100 Subject: [PATCH 29/94] Call "VirtualFree" before setting error (fixes #23). --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 682b95d..2efb4f3 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -498,8 +498,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { - SetLastError(ERROR_OUTOFMEMORY); VirtualFree(code, 0, MEM_RELEASE); + SetLastError(ERROR_OUTOFMEMORY); return NULL; } From 48d3c5a7f6406b92b2cf8cf76bb6edcdd88e91b9 Mon Sep 17 00:00:00 2001 From: CoolOppo Date: Mon, 6 Apr 2015 15:39:48 -0400 Subject: [PATCH 30/94] Rename readme.txt to readme.rst Makes GitHub actually render the file correctly :unamused: --- doc/{readme.txt => readme.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/{readme.txt => readme.rst} (100%) diff --git a/doc/readme.txt b/doc/readme.rst similarity index 100% rename from doc/readme.txt rename to doc/readme.rst From 6276f4426dd6ff25c991fa33ab7140335a327e8b Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 22:18:35 +0200 Subject: [PATCH 31/94] Support imports by ordinal value. Code based on pull-request #28. --- MemoryModule.c | 40 +++++++++++++++++++++++++--------------- MemoryModule.h | 3 ++- tests/LoadDll.cpp | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 2efb4f3..ba8f7b1 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -584,9 +584,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - int idx=-1; - DWORD i, *nameRef; - WORD *ordinal; + int idx; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { @@ -602,20 +600,32 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) return NULL; } - // search function name in list of exported names - nameRef = (DWORD *) (codeBase + exports->AddressOfNames); - ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { - if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { - idx = *ordinal; - break; + if (HIWORD(name) == 0) { + // load function by ordinal value + if (LOWORD(name) < exports->Base) { + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; } - } - if (idx == -1) { - // exported symbol not found - SetLastError(ERROR_PROC_NOT_FOUND); - return NULL; + idx = LOWORD(name) - exports->Base; + } else { + // search function name in list of exported names + DWORD i; + DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); + WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); + idx = -1; + for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { + if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { + idx = *ordinal; + break; + } + } + + if (idx == -1) { + // exported symbol not found + SetLastError(ERROR_PROC_NOT_FOUND); + return NULL; + } } if ((DWORD)idx > exports->NumberOfFunctions) { diff --git a/MemoryModule.h b/MemoryModule.h index 9174ad2..c19255c 100644 --- a/MemoryModule.h +++ b/MemoryModule.h @@ -63,7 +63,8 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *, void *); /** - * Get address of exported method. + * Get address of exported method. Supports loading both by name and by + * ordinal value. */ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index b5074a7..7bf54c8 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -16,6 +16,7 @@ BOOL LoadFromMemory(char *filename) size_t size; HMEMORYMODULE handle; addNumberProc addNumber; + addNumberProc addNumber2; HMEMORYRSRC resourceInfo; DWORD resourceSize; LPVOID resourceData; @@ -45,9 +46,31 @@ BOOL LoadFromMemory(char *filename) goto exit; } + addNumber = (addNumberProc)MemoryGetProcAddress(handle, NULL); + if (addNumber != NULL) { + _tprintf(_T("MemoryGetProcAddress(NULL) returned %p\n"), addNumber); + result = FALSE; + goto exit; + } + + addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); + if (addNumber != NULL) { + _tprintf(_T("MemoryGetProcAddress(0xff) returned %p\n"), addNumber); + result = FALSE; + goto exit; + } + addNumber = (addNumberProc)MemoryGetProcAddress(handle, "addNumbers"); _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); + // the DLL only exports one function, try to load by ordinal value + addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); + if (addNumber != addNumber2) { + _tprintf(_T("MemoryGetProcAddress(0x01) returned %p (expected %p)\n"), addNumber2, addNumber); + result = FALSE; + goto exit; + } + resourceInfo = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION); _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); From 83899ac7f79359131dbffb1c170c4e33919cf1fc Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 22:26:50 +0200 Subject: [PATCH 32/94] Use DWORD directly to avoid cast. --- MemoryModule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index ba8f7b1..b4fc5cc 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -584,7 +584,7 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; - int idx; + DWORD idx; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { @@ -613,22 +613,23 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) DWORD i; DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); - idx = -1; + BOOL found = FALSE; for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { idx = *ordinal; + found = TRUE; break; } } - if (idx == -1) { + if (!found) { // exported symbol not found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } } - if ((DWORD)idx > exports->NumberOfFunctions) { + if (idx > exports->NumberOfFunctions) { // name <-> ordinal number don't match SetLastError(ERROR_PROC_NOT_FOUND); return NULL; From db9c2389f2e2a083e8d6071f02ef6f0433782ec0 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 23:56:49 +0200 Subject: [PATCH 33/94] Fix compilation of tests with UNICODE defined. --- tests/LoadDll.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 7bf54c8..4413f48 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -53,7 +53,7 @@ BOOL LoadFromMemory(char *filename) goto exit; } - addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); + addNumber = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0xff)); if (addNumber != NULL) { _tprintf(_T("MemoryGetProcAddress(0xff) returned %p\n"), addNumber); result = FALSE; @@ -64,7 +64,7 @@ BOOL LoadFromMemory(char *filename) _tprintf(_T("From memory: %d\n"), addNumber(1, 2)); // the DLL only exports one function, try to load by ordinal value - addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); + addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast(0x01)); if (addNumber != addNumber2) { _tprintf(_T("MemoryGetProcAddress(0x01) returned %p (expected %p)\n"), addNumber2, addNumber); result = FALSE; From 78330cd2f1ceb61829d40d9e137e571070242146 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Fri, 21 Aug 2015 23:59:29 +0200 Subject: [PATCH 34/94] Simplify package installation. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 108523e..7d08b80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,7 @@ cache: before_install: - sudo apt-get update -qq - - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" - - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" + - sudo apt-get install -qq wine gcc-mingw-w64-$PLATFORM g++-mingw-w64-$PLATFORM binutils-mingw-w64-$PLATFORM mingw-w64-dev script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 5a0c512885b944c13b47423485e6abb94519f958 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:02:25 +0200 Subject: [PATCH 35/94] Revert 78330cd2f1ceb61829d40d9e137e571070242146, package names don't match platform. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7d08b80..108523e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,8 @@ cache: before_install: - sudo apt-get update -qq - - sudo apt-get install -qq wine gcc-mingw-w64-$PLATFORM g++-mingw-w64-$PLATFORM binutils-mingw-w64-$PLATFORM mingw-w64-dev + - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" + - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 70c497701952c9557c4c268709f07658fd11f4aa Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:10:01 +0200 Subject: [PATCH 36/94] Switch to container-based infrastructure. --- .travis.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 108523e..629c752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +sudo: false + env: - PLATFORM=x86_64 WINE=wine64 UNICODE= - PLATFORM=i686 WINE=wine UNICODE= @@ -8,11 +10,19 @@ language: cpp cache: - apt + - ccache -before_install: - - sudo apt-get update -qq - - sh -c "if [ '$PLATFORM' = 'i686' ]; then sudo apt-get install -qq wine gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev; fi" - - sh -c "if [ '$PLATFORM' = 'x86_64' ]; then sudo apt-get install -qq wine gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev; fi" +addons: + apt: + packages: + - binutils-mingw-w64-i686 + - binutils-mingw-w64-x86-64 + - mingw-w64-dev + - g++-mingw-w64-i686 + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-i686 + - gcc-mingw-w64-x86-64 + - wine script: - make PLATFORM=$PLATFORM UNICODE=$UNICODE From 8c3d253325ed718ef5d26a25964a4cd2e24b4ba3 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 00:32:13 +0200 Subject: [PATCH 37/94] Support building with cmake. --- .travis.yml | 21 ++++++++++----- CMakeLists.txt | 45 ++++++++++++++++++++++++++++++++ example/CMakeLists.txt | 2 ++ example/DllLoader/CMakeLists.txt | 26 ++++++++++++++++++ example/SampleDLL/CMakeLists.txt | 12 +++++++++ 5 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 example/CMakeLists.txt create mode 100644 example/DllLoader/CMakeLists.txt create mode 100644 example/SampleDLL/CMakeLists.txt diff --git a/.travis.yml b/.travis.yml index 629c752..e9dcb84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ sudo: false env: - - PLATFORM=x86_64 WINE=wine64 UNICODE= - - PLATFORM=i686 WINE=wine UNICODE= - - PLATFORM=x86_64 WINE=wine64 UNICODE=1 - - PLATFORM=i686 WINE=wine UNICODE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE= + - PLATFORM=i686 WINE=wine UNICODE= CMAKE= + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE= + - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE= + - PLATFORM=x86_64 WINE=wine64 UNICODE= CMAKE=1 + - PLATFORM=i686 WINE=wine UNICODE= CMAKE=1 + - PLATFORM=x86_64 WINE=wine64 UNICODE=1 CMAKE=1 + - PLATFORM=i686 WINE=wine UNICODE=1 CMAKE=1 language: cpp @@ -17,6 +21,7 @@ addons: packages: - binutils-mingw-w64-i686 - binutils-mingw-w64-x86-64 + - cmake - mingw-w64-dev - g++-mingw-w64-i686 - g++-mingw-w64-x86-64 @@ -24,9 +29,13 @@ addons: - gcc-mingw-w64-x86-64 - wine +before_script: + - if [ ! -z "$CMAKE" ]; then cmake -DPLATFORM=$PLATFORM -D UNICODE=$UNICODE -H. -B.; fi + script: - - make PLATFORM=$PLATFORM UNICODE=$UNICODE - - make test PLATFORM=$PLATFORM UNICODE=$UNICODE + - if [ -z "$CMAKE" ]; then make PLATFORM=$PLATFORM UNICODE=$UNICODE; fi + - if [ -z "$CMAKE" ]; then make test PLATFORM=$PLATFORM UNICODE=$UNICODE; fi + - if [ ! -z "$CMAKE" ]; then cmake --build .; fi - cd example/DllLoader - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoader.exe - WINEPREFIX=`pwd`/$WINE WINEPATH=/usr/lib/gcc/$PLATFORM-w64-mingw32/4.6/ $WINE ./DllLoaderLoader.exe diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..52aed26 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,45 @@ +project (MemoryModule) +cmake_minimum_required (VERSION 2.8.7) + +set (PLATFORM "x86_64" CACHE STRING "Platform to compile for") +message (STATUS "Compile for ${PLATFORM} platform") + +if (NOT MSVC) + set (CMAKE_SYSTEM_NAME Windows) + set (CMAKE_POSITION_INDEPENDENT_CODE False) + + set (COMPILER_PREFIX "${PLATFORM}-w64-mingw32") + set (CMAKE_C_COMPILER "${COMPILER_PREFIX}-gcc") + set (CMAKE_CXX_COMPILER "${COMPILER_PREFIX}-g++") + set (CMAKE_RC_COMPILER "${COMPILER_PREFIX}-windres") + set (CMAKE_AR "${COMPILER_PREFIX}-ar") + set (CMAKE_RANLIB "${COMPILER_PREFIX}-ranlib") + + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + + set (CMAKE_RC_COMPILE_OBJECT "${CMAKE_RC_COMPILER} -O coff -I${CMAKE_CURRENT_SOURCE_DIR} ") +endif () + +add_definitions ("-Wall") + +option(UNICODE "Compile with UNICODE support" OFF) +if (UNICODE) + message (STATUS "Compile with UNICODE support") + add_definitions ("-DUNICODE" "-D_UNICODE") +else () + message (STATUS "Compile without UNICODE support") +endif () + +add_library (MemoryModule STATIC MemoryModule.c MemoryModule.h) +if (NOT MSVC) + set_target_properties ("MemoryModule" PROPERTIES PREFIX "") +endif () + +add_subdirectory (example) + +enable_language (RC) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..dff006d --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory (DllLoader) +add_subdirectory (SampleDLL) diff --git a/example/DllLoader/CMakeLists.txt b/example/DllLoader/CMakeLists.txt new file mode 100644 index 0000000..c2be9a7 --- /dev/null +++ b/example/DllLoader/CMakeLists.txt @@ -0,0 +1,26 @@ +set (sources_dllloader + DllLoader.cpp +) + +set (sources_dllloaderloader + DllLoaderLoader.cpp +) + +if (NOT MSVC) + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-static") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-static") +endif () + +add_executable (DllLoader ${sources_dllloader}) +target_link_libraries ("DllLoader" "MemoryModule") +if (NOT MSVC) + set_target_properties ("DllLoader" PROPERTIES SUFFIX ".exe") + set_target_properties ("DllLoader" PROPERTIES LINK_FLAGS "-Wl,--image-base -Wl,0x20000000") +endif () + +add_executable (DllLoaderLoader ${sources_dllloaderloader}) +target_link_libraries ("DllLoaderLoader" "MemoryModule") +if (NOT MSVC) + set_target_properties ("DllLoaderLoader" PROPERTIES SUFFIX ".exe") + set_target_properties ("DllLoaderLoader" PROPERTIES LINK_FLAGS "-Wl,--image-base -Wl,0x10000000") +endif () diff --git a/example/SampleDLL/CMakeLists.txt b/example/SampleDLL/CMakeLists.txt new file mode 100644 index 0000000..e3a3af3 --- /dev/null +++ b/example/SampleDLL/CMakeLists.txt @@ -0,0 +1,12 @@ +set (sources + SampleDLL.cpp + SampleDLL.h + SampleDLL.rc +) + +add_definitions (-DSAMPLEDLL_EXPORTS) +add_library (SampleDLL MODULE ${sources}) +if (NOT MSVC) + set_target_properties ("SampleDLL" PROPERTIES PREFIX "") + set_target_properties ("SampleDLL" PROPERTIES SUFFIX ".dll") +endif () From a13ad18e11d5c20ab860202545659f117ddb1fc6 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:03:50 +0200 Subject: [PATCH 38/94] Added AppVeyor CI integration. --- CMakeLists.txt | 6 +++++- appveyor.yml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 52aed26..9ddd49a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,11 @@ if (NOT MSVC) set (CMAKE_RC_COMPILE_OBJECT "${CMAKE_RC_COMPILER} -O coff -I${CMAKE_CURRENT_SOURCE_DIR} ") endif () -add_definitions ("-Wall") +if (NOT MSVC) + add_definitions ("-Wall") +else () + add_definitions ("-W4") +endif () option(UNICODE "Compile with UNICODE support" OFF) if (UNICODE) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..24e01ac --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,44 @@ +version: #{build} + +os: + - Windows Server 2012 R2 + +environment: + matrix: + - GENERATOR: "Visual Studio 10 2010" + UNICODE: ON + - GENERATOR: "Visual Studio 10 2010" + UNICODE: OFF + - GENERATOR: "Visual Studio 11 2012" + UNICODE: ON + - GENERATOR: "Visual Studio 11 2012" + UNICODE: OFF + - GENERATOR: "Visual Studio 12 2013" + UNICODE: ON + - GENERATOR: "Visual Studio 12 2013" + UNICODE: OFF + +platform: + - x86 + - x64 + +configuration: + - Debug + +build: + verbosity: normal + +build_script: + - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } + - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -H. -Bbuild + - cmake --build build --config %CONFIGURATION% + +before_test: + - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoader.exe build\example\DllLoader\ + - copy /y build\example\DllLoader\%CONFIGURATION%\DllLoaderLoader.exe build\example\DllLoader\ + - copy /y build\example\SampleDLL\%CONFIGURATION%\SampleDLL.dll build\example\SampleDLL\ + +test_script: + - cd build\example\DllLoader + - DllLoader.exe + - DllLoaderLoader.exe From 422f918c3384f7fe9e8ff1fe142338d690327b3c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:17:03 +0200 Subject: [PATCH 39/94] Declare variables at start of function. --- MemoryModule.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index b4fc5cc..b4ace84 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -270,14 +270,16 @@ static BOOL ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; + PIMAGE_TLS_DIRECTORY tls; + PIMAGE_TLS_CALLBACK* callback; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS); if (directory->VirtualAddress == 0) { return TRUE; } - PIMAGE_TLS_DIRECTORY tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); - PIMAGE_TLS_CALLBACK* callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; + tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); + callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; if (callback) { while (*callback) { (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); From b4bf2f7c4aa2b98ba7c124ca8a00265c5bb0da09 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 01:28:43 +0200 Subject: [PATCH 40/94] Don't disable warnings about conversions. --- MemoryModule.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index b4ace84..35920a4 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -24,11 +24,6 @@ * */ -#ifndef __GNUC__ -// disable warnings about pointer <-> DWORD conversions -#pragma warning( disable : 4311 4312 ) -#endif - #include #include #include From 62e357e51521c0c7f33ebdb437bf596b4d4a13b2 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sat, 22 Aug 2015 23:56:52 +0200 Subject: [PATCH 41/94] Added information about build status. --- appveyor.yml | 2 ++ readme.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 24e01ac..676f268 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,5 @@ +# Status available at +# https://ci.appveyor.com/project/fancycode/memorymodule version: #{build} os: diff --git a/readme.md b/readme.md index ab35ac6..607ddba 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ MemoryModule ============ -[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule) +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's From 8d5dbf39e84db977ea2bc1bca4010ec5ef167d6d Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 23 Aug 2015 00:02:04 +0200 Subject: [PATCH 42/94] Show AppVeyor status of master branch. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 607ddba..aa9f497 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ MemoryModule ============ -[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) +[![Build Status](https://travis-ci.org/fancycode/MemoryModule.svg?branch=master)](https://travis-ci.org/fancycode/MemoryModule)[![Build status](https://ci.appveyor.com/api/projects/status/qcrfxbno0jbbl9cx/branch/master?svg=true)](https://ci.appveyor.com/project/fancycode/memorymodule) The default windows API functions to load external libraries into a program (`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's From d19707369a4410bfa45430d722bcc9b40f291e1f Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 23 Aug 2015 00:22:42 +0200 Subject: [PATCH 43/94] Avoid (re-)allocations when searching for named resources. Also add tests to load resources by name. --- MemoryModule.c | 53 +++++++++++++-------- tests/LoadDll.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++ tests/SampleDLL.rc | 24 ++++++++++ 3 files changed, 174 insertions(+), 19 deletions(-) diff --git a/MemoryModule.c b/MemoryModule.c index 35920a4..567799a 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -729,32 +729,45 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } } else { -#if !defined(UNICODE) - char *searchKey = NULL; - int searchKeyLength = 0; + LPCWSTR searchKey; + size_t searchKeyLen = _tcslen(key); +#if defined(UNICODE) + searchKey = key; +#else + // Resource names are always stored using 16bit characters, need to + // convert string we search for. +#define MAX_LOCAL_KEY_LENGTH 2048 + // In most cases resource names are short, so optimize for that by + // using a pre-allocated array. + wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1]; + LPWSTR _searchKey; + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t); + _searchKey = (LPWSTR) malloc(_searchKeySize); + if (_searchKey == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + } else { + _searchKey = &_searchKeySpace[0]; + } + + mbstowcs(_searchKey, key, searchKeyLen); + _searchKey[searchKeyLen] = 0; + searchKey = _searchKey; #endif start = 0; end = resources->NumberOfNamedEntries; while (end > start) { - // resource names are always stored using 16bit characters int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); -#if !defined(UNICODE) - if (searchKey == NULL || searchKeyLength < resourceString->Length) { - void *tmp = realloc(searchKey, resourceString->Length); - if (tmp == NULL) { - break; - } - - searchKey = (char *) tmp; + cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); + if (cmp == 0) { + // Handle partial match + cmp = searchKeyLen - resourceString->Length; } - wcstombs(searchKey, resourceString->NameString, resourceString->Length); - cmp = strncmp(key, searchKey, resourceString->Length); -#else - cmp = wcsncmp(key, resourceString->NameString, resourceString->Length); -#endif if (cmp < 0) { end = (middle != end ? middle : middle-1); } else if (cmp > 0) { @@ -765,11 +778,13 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( } } #if !defined(UNICODE) - free(searchKey); + if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { + free(_searchKey); + } +#undef MAX_LOCAL_KEY_LENGTH #endif } - return result; } diff --git a/tests/LoadDll.cpp b/tests/LoadDll.cpp index 4413f48..43cf8fd 100644 --- a/tests/LoadDll.cpp +++ b/tests/LoadDll.cpp @@ -9,6 +9,64 @@ typedef int (*addNumberProc)(int, int); +// Thanks to Tim Cooper (from http://stackoverflow.com/a/8584708) +const char *sstrstr(const char *haystack, const char *needle, size_t length) { + size_t needle_length = strlen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (strncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +const wchar_t *swcsstr(const wchar_t *haystack, const wchar_t *needle, size_t length) { + size_t needle_length = wcslen(needle); + size_t i; + + for (i = 0; i < length; i++) { + if (i + needle_length > length) { + return NULL; + } + + if (wcsncmp(&haystack[i], needle, needle_length) == 0) { + return &haystack[i]; + } + } + return NULL; +} + +BOOL CheckResourceStrings(LPVOID data, DWORD size, const char *first, const wchar_t *second) { + const char *first_pos; + const wchar_t *second_pos; + const wchar_t *src; + + if (data == NULL || size == 0) { + return FALSE; + } + + first_pos = sstrstr((const char *) data, first, size); + if (first_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't start with %s\n", first); + return FALSE; + } + + src = (const wchar_t *) (((const char *) data) + strlen(first) + 1); + second_pos = swcsstr(src, second, (size - strlen(first) - 1) / sizeof(wchar_t)); + if (second_pos == NULL) { + fprintf(stderr, "ERROR: data doesn't continue with %S\n", second); + return FALSE; + } + + return TRUE; +} + BOOL LoadFromMemory(char *filename) { FILE *fp; @@ -88,6 +146,64 @@ BOOL LoadFromMemory(char *filename) result = FALSE; } + resourceInfo = MemoryFindResource(handle, _T("stringres"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is a ANSI string", L"This is a UNICODE string")) { + result = FALSE; + } + } else { + result = FALSE; + } + + resourceInfo = MemoryFindResource(handle, _T("stringres1"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 1", L"This is UNICODE string 1")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres2"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 2", L"This is UNICODE string 2")) { + result = FALSE; + } + } else { + result = FALSE; + } + + + resourceInfo = MemoryFindResource(handle, _T("stringres3"), RT_RCDATA); + _tprintf(_T("MemoryFindResource returned 0x%p\n"), resourceInfo); + if (resourceInfo != NULL) { + resourceSize = MemorySizeofResource(handle, resourceInfo); + resourceData = MemoryLoadResource(handle, resourceInfo); + + _tprintf(_T("Memory resource data: %ld bytes at 0x%p\n"), resourceSize, resourceData); + if (!CheckResourceStrings(resourceData, resourceSize, "This is ANSI string 3", L"This is UNICODE string 3")) { + result = FALSE; + } + } else { + result = FALSE; + } + MemoryFreeLibrary(handle); exit: diff --git a/tests/SampleDLL.rc b/tests/SampleDLL.rc index 5a0da61..bbe5774 100644 --- a/tests/SampleDLL.rc +++ b/tests/SampleDLL.rc @@ -32,3 +32,27 @@ STRINGTABLE IDS_HELLO, "Hello" IDS_WORLD, "World!" } + +STRINGRES RCDATA +{ + "This is a ANSI string\0", + L"This is a UNICODE string\0", +} + +STRINGRES1 RCDATA +{ + "This is ANSI string 1\0", + L"This is UNICODE string 1\0", +} + +STRINGRES2 RCDATA +{ + "This is ANSI string 2\0", + L"This is UNICODE string 2\0", +} + +STRINGRES3 RCDATA +{ + "This is ANSI string 3\0", + L"This is UNICODE string 3\0", +} From 71643ae62bbe44cfb49baa95fd7b8da55c6d66b3 Mon Sep 17 00:00:00 2001 From: Vlatko Kosturjak Date: Sun, 18 Oct 2015 11:13:24 +0200 Subject: [PATCH 44/94] Use _wcsnicmp instead of wcsnicmp "These POSIX functions are deprecated. Use the ISO C++ conformant" https://msdn.microsoft.com/en-us/library/ms235324.aspx --- MemoryModule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemoryModule.c b/MemoryModule.c index 567799a..cb888ed 100644 --- a/MemoryModule.c +++ b/MemoryModule.c @@ -763,7 +763,7 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) (((char *) root) + (entries[middle].Name & 0x7FFFFFFF)); - cmp = wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); + cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match cmp = searchKeyLen - resourceString->Length; From 9df6e7dc93060287581f2f1add0ed84f1232d01c Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Sun, 20 Dec 2015 18:53:18 +0100 Subject: [PATCH 45/94] 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 46/94] 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 47/94] 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 48/94] 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 49/94] 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 50/94] 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 51/94] 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 52/94] 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 53/94] 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 54/94] 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 55/94] 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 56/94] 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 57/94] 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 58/94] 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 59/94] 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 60/94] 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 61/94] 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 62/94] 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 63/94] 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 64/94] 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 65/94] 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 66/94] 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 67/94] 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 68/94] 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 69/94] 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 70/94] 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 71/94] 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 72/94] 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 73/94] 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 74/94] 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 75/94] 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 76/94] 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 77/94] 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 78/94] 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 79/94] 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 80/94] 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 81/94] 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 82/94] 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 83/94] 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 84/94] 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 85/94] 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 86/94] 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 87/94] 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 88/94] 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 89/94] 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 90/94] 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 91/94] 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 92/94] 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 93/94] 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 94/94] 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