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
|
||||
*.obj
|
||||
*.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)
|
||||
|
||||
@@ -13,5 +13,8 @@ clean: $(CLEANDIRS)
|
||||
$(CLEANDIRS):
|
||||
$(MAKE) -C $(@:clean-%=%) clean
|
||||
|
||||
test:
|
||||
$(MAKE) -C tests test
|
||||
|
||||
.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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
@@ -39,39 +39,64 @@ 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 *);
|
||||
|
||||
/**
|
||||
* Load 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 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,
|
||||
CustomAllocFunc,
|
||||
CustomFreeFunc,
|
||||
CustomLoadLibraryFunc,
|
||||
CustomGetProcAddressFunc,
|
||||
CustomFreeLibraryFunc,
|
||||
void *);
|
||||
|
||||
/**
|
||||
* Get address of exported method.
|
||||
* Get address of exported method. Supports loading both by name and by
|
||||
* ordinal value.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -102,6 +127,46 @@ 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.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
HMEMORYMODULE MemoryLoadLibrary(const void *);
|
||||
HMEMORYMODULE MemoryLoadLibrary(const void *, size_t);
|
||||
FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *);
|
||||
void MemoryFreeLibrary(HMEMORYMODULE);
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
@@ -42,10 +46,47 @@ void LoadFromFile(void)
|
||||
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)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char *data=NULL;
|
||||
void *data;
|
||||
size_t size;
|
||||
HMEMORYMODULE handle;
|
||||
addNumberProc addNumber;
|
||||
@@ -54,21 +95,13 @@ 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);
|
||||
data = (unsigned char *)malloc(size);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fread(data, 1, size, fp);
|
||||
fclose(fp);
|
||||
|
||||
handle = MemoryLoadLibrary(data);
|
||||
handle = MemoryLoadLibrary(data, size);
|
||||
if (handle == NULL)
|
||||
{
|
||||
_tprintf(_T("Can't load library from memory.\n"));
|
||||
@@ -94,15 +127,217 @@ void LoadFromMemory(void)
|
||||
MemoryFreeLibrary(handle);
|
||||
|
||||
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();
|
||||
printf("\n\n");
|
||||
LoadFromMemory();
|
||||
printf("\n\n");
|
||||
TestCustomAllocAndFree();
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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++
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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
|
||||
(`LoadLibrary`, `LoadLibraryEx`) only work with files on the filesystem. It's
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -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