mirror of
https://github.com/vxcontrol/MemoryModule.git
synced 2026-07-25 08:35:44 -04:00
Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8da72d503 | |||
| 59307f0a63 | |||
| 47a9ee83db | |||
| 08a59f2922 | |||
| 5e850c0b76 | |||
| 0a984057da | |||
| fdf41455e9 | |||
| acd7da679a | |||
| fef80b544b | |||
| 5f83e41c3a | |||
| 316aa59c48 | |||
| 9f37952407 | |||
| d1a0824733 | |||
| e4c1b3566c | |||
| a15e0769b0 | |||
| e039372355 | |||
| 060f0bd736 | |||
| 403a31e7bb | |||
| e7d53b53e0 | |||
| 0acf4e7785 | |||
| 663ddca84b | |||
| 9ecfeb025d | |||
| 9e295953a8 | |||
| 55577d939c | |||
| ac78ea10e7 | |||
| 98b95eca4c | |||
| 0884dccfa7 | |||
| 00bc61e8c7 | |||
| 2bbbc205d6 | |||
| 7d0c143f92 | |||
| 2ecf5b764b | |||
| 5c6b699b36 | |||
| 184113ca09 | |||
| f5c9db8b5c | |||
| 6c4ab3589d | |||
| 8d609dc2a2 | |||
| 5ce3707c7d | |||
| d9dcc0eb8c | |||
| e2826eb956 | |||
| 49a82873f7 | |||
| 4074f1e6ab | |||
| caf917707b | |||
| 221a470ad1 | |||
| 097403a8ad | |||
| 6c2c3e2fee | |||
| 03cd7c91d9 | |||
| de5dbce770 | |||
| 89883558fe | |||
| b26476ff8d | |||
| 1d19f9f750 | |||
| d19c62ed82 | |||
| cfba548c66 | |||
| af2c521cf2 | |||
| 164b21ac07 | |||
| c4074afd3e | |||
| c174ed1177 | |||
| 4b3d2a08d5 | |||
| a1fb42d4c5 | |||
| bc38a6b01d | |||
| d46b74d00d | |||
| d88817fbf7 | |||
| d9a6bb9c8f | |||
| 905ad75e82 | |||
| 2e193f153a | |||
| cc562219af | |||
| cddc54a671 | |||
| 5bda2104b9 | |||
| 394fae8d51 | |||
| 15983313f4 | |||
| 583e1b4a93 | |||
| bc04853584 | |||
| 9df6e7dc93 | |||
| f02a8e6a38 | |||
| 71643ae62b | |||
| d19707369a | |||
| 8d5dbf39e8 | |||
| 62e357e515 | |||
| b4bf2f7c4a | |||
| 422f918c33 | |||
| a13ad18e11 | |||
| 8c3d253325 | |||
| 70c4977019 | |||
| 5a0c512885 | |||
| 78330cd2f1 | |||
| db9c2389f2 | |||
| 83899ac7f7 | |||
| 6276f4426d | |||
| e5d42852de | |||
| 48d3c5a7f6 | |||
| 82b11d57db | |||
| 0ce2454fc3 | |||
| 89e02fcd9e | |||
| dc173cad6d | |||
| d9dc0b0270 | |||
| 31cbe89bfe | |||
| 2da44d00e9 | |||
| 36574a5638 | |||
| 463447c1ed | |||
| d321abf8fa | |||
| aa6b93bab4 | |||
| 927bd2a9f0 | |||
| dd5e818dfc | |||
| 4c08d8eb92 | |||
| 625aa47035 | |||
| dacdbaba9a | |||
| 6212358a24 | |||
| 808c043faf | |||
| dcccd79158 | |||
| b889c72727 | |||
| 3422b5791c | |||
| 52b0379749 | |||
| 1d55f77753 | |||
| 5a448ce93a | |||
| 2d504b533e |
@@ -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
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
*.o
|
*.o
|
||||||
*.obj
|
*.obj
|
||||||
*.exe
|
*.exe
|
||||||
|
tests/*.dll
|
||||||
|
tests/*.res
|
||||||
|
|
||||||
|
tests/SampleExports.cpp
|
||||||
|
tests/SampleExports.h
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
sudo: true
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- env: PLATFORM=x86_64 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:amd64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-x86-64
|
||||||
|
- mingw-w64-x86-64-dev
|
||||||
|
- g++-mingw-w64-x86-64
|
||||||
|
- gcc-mingw-w64-x86-64
|
||||||
|
- env: PLATFORM=i686 UNICODE= CMAKE= WINE_PACKAGE=winehq-stable:i386
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-i686
|
||||||
|
- mingw-w64-i686-dev
|
||||||
|
- g++-mingw-w64-i686
|
||||||
|
- gcc-mingw-w64-i686
|
||||||
|
- env: PLATFORM=x86_64 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:amd64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-x86-64
|
||||||
|
- mingw-w64-x86-64-dev
|
||||||
|
- g++-mingw-w64-x86-64
|
||||||
|
- gcc-mingw-w64-x86-64
|
||||||
|
- env: PLATFORM=i686 UNICODE=1 CMAKE= WINE_PACKAGE=winehq-stable:i386
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-i686
|
||||||
|
- mingw-w64-i686-dev
|
||||||
|
- g++-mingw-w64-i686
|
||||||
|
- gcc-mingw-w64-i686
|
||||||
|
- env: PLATFORM=x86_64 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:amd64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-x86-64
|
||||||
|
- mingw-w64-x86-64-dev
|
||||||
|
- g++-mingw-w64-x86-64
|
||||||
|
- gcc-mingw-w64-x86-64
|
||||||
|
- env: PLATFORM=i686 UNICODE= CMAKE=1 WINE_PACKAGE=winehq-stable:i386
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-i686
|
||||||
|
- cmake
|
||||||
|
- mingw-w64-i686-dev
|
||||||
|
- g++-mingw-w64-i686
|
||||||
|
- gcc-mingw-w64-i686
|
||||||
|
- env: PLATFORM=x86_64 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:amd64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-x86-64
|
||||||
|
- cmake
|
||||||
|
- mingw-w64-x86-64-dev
|
||||||
|
- g++-mingw-w64-x86-64
|
||||||
|
- gcc-mingw-w64-x86-64
|
||||||
|
- env: PLATFORM=i686 UNICODE=1 CMAKE=1 WINE_PACKAGE=winehq-stable:i386
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- binutils-mingw-w64-i686
|
||||||
|
- cmake
|
||||||
|
- mingw-w64-i686-dev
|
||||||
|
- g++-mingw-w64-i686
|
||||||
|
- gcc-mingw-w64-i686
|
||||||
|
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
dist: xenial
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- apt
|
||||||
|
- 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:
|
||||||
|
- 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
|
||||||
|
- ../../tests/runwine.sh $PLATFORM ./DllLoader.exe
|
||||||
|
- ../../tests/runwine.sh $PLATFORM ./DllLoaderLoader.exe
|
||||||
|
- cd ../../tests
|
||||||
|
- ./runwine.sh $PLATFORM ./TestSuite.exe
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
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} <SOURCE> <OBJECT>")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT MSVC)
|
||||||
|
add_definitions ("-Wall")
|
||||||
|
else ()
|
||||||
|
# Show level 4 warnings.
|
||||||
|
add_definitions ("-W4")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
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 ()
|
||||||
|
|
||||||
|
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)
|
||||||
|
target_include_directories(MemoryModule PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
if (NOT MSVC)
|
||||||
|
set_target_properties ("MemoryModule" PROPERTIES PREFIX "")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_subdirectory (example)
|
||||||
|
add_subdirectory (tests)
|
||||||
|
|
||||||
|
enable_language (RC)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = example
|
SUBDIRS = example tests
|
||||||
|
|
||||||
.PHONY: subdirs $(SUBDIRS)
|
.PHONY: subdirs $(SUBDIRS)
|
||||||
|
|
||||||
@@ -13,5 +13,8 @@ clean: $(CLEANDIRS)
|
|||||||
$(CLEANDIRS):
|
$(CLEANDIRS):
|
||||||
$(MAKE) -C $(@:clean-%=%) clean
|
$(MAKE) -C $(@:clean-%=%) clean
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(MAKE) -C tests test
|
||||||
|
|
||||||
.PHONY: subdirs $(INSTALLDIRS)
|
.PHONY: subdirs $(INSTALLDIRS)
|
||||||
.PHONY: clean
|
.PHONY: clean test
|
||||||
|
|||||||
+797
-297
File diff suppressed because it is too large
Load Diff
+73
-8
@@ -2,7 +2,7 @@
|
|||||||
* Memory DLL loading code
|
* Memory DLL loading code
|
||||||
* Version 0.0.4
|
* 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
|
* http://www.joachim-bauch.de
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the Mozilla Public License Version
|
* 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.
|
* 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.
|
* Joachim Bauch. All Rights Reserved.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -39,39 +39,64 @@ typedef void *HCUSTOMMODULE;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef LPVOID (*CustomAllocFunc)(LPVOID, SIZE_T, DWORD, DWORD, void*);
|
||||||
|
typedef BOOL (*CustomFreeFunc)(LPVOID, SIZE_T, DWORD, void*);
|
||||||
typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *);
|
typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *);
|
||||||
typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
|
typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
|
||||||
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
|
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load DLL from memory location.
|
* Load EXE/DLL from memory location with the given size.
|
||||||
*
|
*
|
||||||
* All dependencies are resolved using default LoadLibrary/GetProcAddress
|
* All dependencies are resolved using default LoadLibrary/GetProcAddress
|
||||||
* calls through the Windows API.
|
* calls through the Windows API.
|
||||||
*/
|
*/
|
||||||
HMEMORYMODULE MemoryLoadLibrary(const void *);
|
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load 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.
|
* Dependencies will be resolved using passed callback methods.
|
||||||
*/
|
*/
|
||||||
HMEMORYMODULE MemoryLoadLibraryEx(const void *,
|
HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t,
|
||||||
|
CustomAllocFunc,
|
||||||
|
CustomFreeFunc,
|
||||||
CustomLoadLibraryFunc,
|
CustomLoadLibraryFunc,
|
||||||
CustomGetProcAddressFunc,
|
CustomGetProcAddressFunc,
|
||||||
CustomFreeLibraryFunc,
|
CustomFreeLibraryFunc,
|
||||||
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);
|
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free previously loaded DLL.
|
* Get the code base address of loading module to store it above.
|
||||||
|
* On load dynamic library it used as a handle of library instance.
|
||||||
|
*/
|
||||||
|
LPVOID MemoryGetCodeAddress(HMEMORYMODULE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free previously loaded EXE/DLL.
|
||||||
*/
|
*/
|
||||||
void MemoryFreeLibrary(HMEMORYMODULE);
|
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.
|
* Find the location of a resource with the specified type and name.
|
||||||
*/
|
*/
|
||||||
@@ -102,6 +127,46 @@ int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int);
|
|||||||
*/
|
*/
|
||||||
int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD);
|
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.
|
||||||
|
*
|
||||||
|
* 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Status available at
|
||||||
|
# https://ci.appveyor.com/project/fancycode/memorymodule
|
||||||
|
version: 1.0.{build}
|
||||||
|
|
||||||
|
os:
|
||||||
|
- Visual Studio 2015
|
||||||
|
|
||||||
|
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"
|
||||||
|
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
|
||||||
|
- GENERATOR: "Visual Studio 14 2015"
|
||||||
|
UNICODE: ON
|
||||||
|
- GENERATOR: "Visual Studio 14 2015"
|
||||||
|
UNICODE: OFF
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x86
|
||||||
|
- x64
|
||||||
|
|
||||||
|
configuration:
|
||||||
|
- Debug
|
||||||
|
|
||||||
|
install:
|
||||||
|
- call scripts\run-appveyor.bat
|
||||||
|
|
||||||
|
build: off
|
||||||
|
test: off
|
||||||
|
deploy: off
|
||||||
@@ -511,7 +511,7 @@ The interface is very similar to the standard methods for loading of libraries::
|
|||||||
|
|
||||||
typedef void *HMEMORYMODULE;
|
typedef void *HMEMORYMODULE;
|
||||||
|
|
||||||
HMEMORYMODULE MemoryLoadLibrary(const void *);
|
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
|
||||||
FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *);
|
FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *);
|
||||||
void MemoryFreeLibrary(HMEMORYMODULE);
|
void MemoryFreeLibrary(HMEMORYMODULE);
|
||||||
|
|
||||||
@@ -543,4 +543,4 @@ Copyright
|
|||||||
==========
|
==========
|
||||||
|
|
||||||
The MemoryModule library and this tutorial are
|
The MemoryModule library and this tutorial are
|
||||||
Copyright (c) 2004-2014 by Joachim Bauch.
|
Copyright (c) 2004-2015 by Joachim Bauch.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
add_subdirectory (DllLoader)
|
||||||
|
add_subdirectory (SampleDLL)
|
||||||
@@ -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 ()
|
||||||
+252
-17
@@ -1,5 +1,9 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -42,10 +46,47 @@ void LoadFromFile(void)
|
|||||||
FreeLibrary(handle);
|
FreeLibrary(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* ReadLibrary(size_t* pSize) {
|
||||||
|
size_t 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 = static_cast<size_t>(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 != *pSize)
|
||||||
|
{
|
||||||
|
free(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void LoadFromMemory(void)
|
void LoadFromMemory(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
void *data;
|
||||||
unsigned char *data=NULL;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
HMEMORYMODULE handle;
|
HMEMORYMODULE handle;
|
||||||
addNumberProc addNumber;
|
addNumberProc addNumber;
|
||||||
@@ -54,21 +95,13 @@ void LoadFromMemory(void)
|
|||||||
LPVOID resourceData;
|
LPVOID resourceData;
|
||||||
TCHAR buffer[100];
|
TCHAR buffer[100];
|
||||||
|
|
||||||
fp = _tfopen(DLL_FILE, _T("rb"));
|
data = ReadLibrary(&size);
|
||||||
if (fp == NULL)
|
if (data == NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("Can't open DLL file \"%s\"."), DLL_FILE);
|
return;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
handle = MemoryLoadLibrary(data, size);
|
||||||
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)
|
if (handle == NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("Can't load library from memory.\n"));
|
_tprintf(_T("Can't load library from memory.\n"));
|
||||||
@@ -94,15 +127,217 @@ void LoadFromMemory(void)
|
|||||||
MemoryFreeLibrary(handle);
|
MemoryFreeLibrary(handle);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (data)
|
free(data);
|
||||||
free(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
#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, size_t 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, size_t 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, size_t 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
|
||||||
|
LPVOID MemoryAllocHigh(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata)
|
||||||
|
{
|
||||||
|
int* counter = static_cast<int*>(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;
|
||||||
|
size_t 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);
|
||||||
|
#ifdef _WIN64
|
||||||
|
_tprintf(_T("Test allocating in high memory\n"));
|
||||||
|
TestAllocHighMemory(data, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
{
|
{
|
||||||
LoadFromFile();
|
LoadFromFile();
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
LoadFromMemory();
|
LoadFromMemory();
|
||||||
|
printf("\n\n");
|
||||||
|
TestCustomAllocAndFree();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "../../MemoryModule.h"
|
||||||
|
|
||||||
|
#define EXE_FILE TEXT("DllLoader.exe")
|
||||||
|
|
||||||
|
int RunFromMemory(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
unsigned char *data=NULL;
|
||||||
|
long size;
|
||||||
|
size_t read;
|
||||||
|
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);
|
||||||
|
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_t>(size));
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
handle = MemoryLoadLibrary(data, size);
|
||||||
|
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:
|
||||||
|
free(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return RunFromMemory();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -22,9 +22,15 @@ CFLAGS += -DUNICODE -D_UNICODE
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
OBJ = DllLoader.o ../../MemoryModule.o
|
OBJ = DllLoader.o ../../MemoryModule.o
|
||||||
|
OBJ_LOADER = DllLoaderLoader.o ../../MemoryModule.o
|
||||||
|
|
||||||
|
all: DllLoader.exe DllLoaderLoader.exe
|
||||||
|
|
||||||
DllLoader.exe: $(OBJ)
|
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
|
%.o: %.cpp
|
||||||
$(CXX) $(CFLAGS) -c $<
|
$(CXX) $(CFLAGS) -c $<
|
||||||
@@ -33,4 +39,4 @@ DllLoader.exe: $(OBJ)
|
|||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) -rf $(OBJ) DllLoader.exe
|
$(RM) -rf $(OBJ) $(OBJ_LOADER) DllLoader.exe DllLoaderLoader.exe
|
||||||
|
|||||||
@@ -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 ()
|
||||||
@@ -6,7 +6,7 @@ PLATFORM = i686
|
|||||||
endif
|
endif
|
||||||
CC = $(PLATFORM)-w64-mingw32-g++
|
CC = $(PLATFORM)-w64-mingw32-g++
|
||||||
CXX = $(PLATFORM)-w64-mingw32-g++
|
CXX = $(PLATFORM)-w64-mingw32-g++
|
||||||
LINK = $(PLATFORM)-w64-mingw32-ld
|
LINK = $(PLATFORM)-w64-mingw32-g++
|
||||||
RC = $(PLATFORM)-w64-mingw32-windres
|
RC = $(PLATFORM)-w64-mingw32-windres
|
||||||
else
|
else
|
||||||
CC = g++
|
CC = g++
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ BEGIN
|
|||||||
VALUE "FileDescription", "SampleDLL"
|
VALUE "FileDescription", "SampleDLL"
|
||||||
VALUE "FileVersion", "1.0"
|
VALUE "FileVersion", "1.0"
|
||||||
VALUE "InternalName", "SampleDLL"
|
VALUE "InternalName", "SampleDLL"
|
||||||
VALUE "LegalCopyright", "Copyright (c) 2004-2014 Joachim Bauch"
|
VALUE "LegalCopyright", "Copyright (c) 2004-2015 Joachim Bauch"
|
||||||
VALUE "OriginalFilename", "SampleDLL.dll"
|
VALUE "OriginalFilename", "SampleDLL.dll"
|
||||||
VALUE "ProductName", "MemoryModule"
|
VALUE "ProductName", "MemoryModule"
|
||||||
VALUE "ProductVersion", "0.0.4"
|
VALUE "ProductVersion", "0.0.4"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
MemoryModule
|
MemoryModule
|
||||||
============
|
============
|
||||||
|
|
||||||
|
[](https://travis-ci.org/fancycode/MemoryModule)[](https://ci.appveyor.com/project/fancycode/memorymodule)
|
||||||
|
|
||||||
The default windows API functions to load external libraries into a program
|
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.
|
therefore impossible to load a DLL from memory.
|
||||||
@@ -14,5 +16,5 @@ 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.
|
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.
|
a tutorial how they can be loaded directly.
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
@echo off
|
||||||
|
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=
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Preparing %CONFIGURATION% build environment for %GENERATOR%%CMAKE_GEN_SUFFIX% ...
|
||||||
|
cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DPLATFORM=%PLATFORM% -DUNICODE=%UNICODE% -DTESTSUITE=ON -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
|
||||||
|
copy /y build\tests\%CONFIGURATION%\TestSuite.exe build\tests\ > 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%
|
||||||
|
|
||||||
|
cd ..\..\tests
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Running TestSuite.exe ...
|
||||||
|
TestSuite.exe
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
@@ -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 ()
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "../MemoryModule.h"
|
||||||
|
|
||||||
|
typedef int (*addProc)(int);
|
||||||
|
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) {
|
||||||
|
fwprintf(stderr, L"ERROR: data doesn't continue with %s\n", second);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LoadFromMemory(char *filename)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
unsigned char *data=NULL;
|
||||||
|
long size;
|
||||||
|
size_t read;
|
||||||
|
HMEMORYMODULE handle = NULL;
|
||||||
|
addNumberProc addNumber;
|
||||||
|
addNumberProc addNumber2;
|
||||||
|
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);
|
||||||
|
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_t>(size));
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
handle = MemoryLoadLibrary(data, size);
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
_tprintf(_T("Can't load library from memory.\n"));
|
||||||
|
result = FALSE;
|
||||||
|
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<LPCSTR>(0xff));
|
||||||
|
if (addNumber != NULL) {
|
||||||
|
_tprintf(_T("MemoryGetProcAddress(0xff) returned %p\n"), addNumber);
|
||||||
|
result = FALSE;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
addNumber2 = (addNumberProc)MemoryGetProcAddress(handle, reinterpret_cast<LPCSTR>(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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
MemoryFreeLibrary(handle);
|
||||||
|
free(data);
|
||||||
|
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_t>(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) {
|
||||||
|
fprintf(stderr, "USAGE: %s <filename.dll>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strstr((const char *) argv[1], "exports")) {
|
||||||
|
if (!LoadFromMemory(argv[1])) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!LoadExportsFromMemory(argv[1])) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
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 -DTESTSUITE
|
||||||
|
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-relocate.dll \
|
||||||
|
test-exports.dll
|
||||||
|
|
||||||
|
LOADDLL_OBJ = LoadDll.o ../MemoryModule.o
|
||||||
|
TESTSUITE_OBJ = TestSuite.o ../MemoryModule.o
|
||||||
|
DLL_OBJ = SampleDLL.o SampleDLL.res
|
||||||
|
|
||||||
|
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 $<
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 $<
|
||||||
|
|
||||||
|
%.o: %.cc
|
||||||
|
$(CC) $(CFLAGS) $(CFLAGS_DLL) -c $<
|
||||||
|
|
||||||
|
%.res: %.rc
|
||||||
|
$(RC) $(RCFLAGS) -o $*.res $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -rf LoadDll.exe $(TEST_DLLS) $(LOADDLL_OBJ) $(DLL_OBJ) $(TESTSUITE_OBJ) SampleExports.o
|
||||||
|
|
||||||
|
test: all
|
||||||
|
./runwine.sh $(PLATFORM) TestSuite.exe
|
||||||
|
./runtests.sh $(PLATFORM) "$(TEST_DLLS)"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include "SampleDLL.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
SAMPLEDLL_API int addNumbers(int a, int b)
|
||||||
|
{
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
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!"
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
extern BOOL MemoryModuleTestsuite();
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(argc);
|
||||||
|
UNREFERENCED_PARAMETER(argv);
|
||||||
|
if (!MemoryModuleTestsuite()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Executable
+52
@@ -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
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PLATFORM=$1
|
||||||
|
|
||||||
|
read -a TEST_DLLS <<< $2
|
||||||
|
|
||||||
|
for filename in "${TEST_DLLS[@]}"
|
||||||
|
do
|
||||||
|
:
|
||||||
|
echo "Testing $filename"
|
||||||
|
./runwine.sh "${PLATFORM}" ./LoadDll.exe $filename
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "${#TEST_DLLS[@]} tests completed successfully"
|
||||||
Executable
+15
@@ -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.8/:/usr/${PLATFORM}-w64-mingw32/lib
|
||||||
|
|
||||||
|
exec ${WINE} $@
|
||||||
Reference in New Issue
Block a user