mirror of
https://github.com/fancycode/MemoryModule
synced 2026-06-06 15:44:28 +00:00
Add some checks to prevent overruns on broken input.
This commit is contained in:
+71
-18
@@ -68,6 +68,7 @@ typedef struct {
|
|||||||
|
|
||||||
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
|
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
|
||||||
#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1))
|
#define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1))
|
||||||
|
#define ALIGN_VALUE_UP(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1))
|
||||||
|
|
||||||
#ifdef DEBUG_OUTPUT
|
#ifdef DEBUG_OUTPUT
|
||||||
static void
|
static void
|
||||||
@@ -86,9 +87,19 @@ OutputLastError(const char *msg)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
|
CheckSize(size_t size, size_t expected) {
|
||||||
|
if (size < expected) {
|
||||||
|
SetLastError(ERROR_INVALID_DATA);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
|
||||||
{
|
{
|
||||||
int i, size;
|
int i, section_size;
|
||||||
unsigned char *codeBase = module->codeBase;
|
unsigned char *codeBase = module->codeBase;
|
||||||
unsigned char *dest;
|
unsigned char *dest;
|
||||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
||||||
@@ -96,10 +107,10 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO
|
|||||||
if (section->SizeOfRawData == 0) {
|
if (section->SizeOfRawData == 0) {
|
||||||
// section doesn't contain data in the dll itself, but may define
|
// section doesn't contain data in the dll itself, but may define
|
||||||
// uninitialized data
|
// uninitialized data
|
||||||
size = old_headers->OptionalHeader.SectionAlignment;
|
section_size = old_headers->OptionalHeader.SectionAlignment;
|
||||||
if (size > 0) {
|
if (section_size > 0) {
|
||||||
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
|
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
|
||||||
size,
|
section_size,
|
||||||
MEM_COMMIT,
|
MEM_COMMIT,
|
||||||
PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
if (dest == NULL) {
|
if (dest == NULL) {
|
||||||
@@ -110,13 +121,17 @@ CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMO
|
|||||||
// than page size.
|
// than page size.
|
||||||
dest = codeBase + section->VirtualAddress;
|
dest = codeBase + section->VirtualAddress;
|
||||||
section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest;
|
section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest;
|
||||||
memset(dest, 0, size);
|
memset(dest, 0, section_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// section is empty
|
// section is empty
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// commit memory block and copy data from dll
|
// commit memory block and copy data from dll
|
||||||
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
|
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
|
||||||
section->SizeOfRawData,
|
section->SizeOfRawData,
|
||||||
@@ -285,7 +300,7 @@ ExecuteTLS(PMEMORYMODULE module)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
|
PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta)
|
||||||
{
|
{
|
||||||
unsigned char *codeBase = module->codeBase;
|
unsigned char *codeBase = module->codeBase;
|
||||||
PIMAGE_BASE_RELOCATION relocation;
|
PIMAGE_BASE_RELOCATION relocation;
|
||||||
@@ -428,30 +443,43 @@ static void _FreeLibrary(HCUSTOMMODULE module, void *userdata)
|
|||||||
FreeLibrary((HMODULE) module);
|
FreeLibrary((HMODULE) module);
|
||||||
}
|
}
|
||||||
|
|
||||||
HMEMORYMODULE MemoryLoadLibrary(const void *data)
|
HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size)
|
||||||
{
|
{
|
||||||
return MemoryLoadLibraryEx(data, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL);
|
return MemoryLoadLibraryEx(data, size, _LoadLibrary, _GetProcAddress, _FreeLibrary, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
|
#include <stdio.h>
|
||||||
|
|
||||||
|
HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
|
||||||
CustomLoadLibraryFunc loadLibrary,
|
CustomLoadLibraryFunc loadLibrary,
|
||||||
CustomGetProcAddressFunc getProcAddress,
|
CustomGetProcAddressFunc getProcAddress,
|
||||||
CustomFreeLibraryFunc freeLibrary,
|
CustomFreeLibraryFunc freeLibrary,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
PMEMORYMODULE result;
|
PMEMORYMODULE result = NULL;
|
||||||
PIMAGE_DOS_HEADER dos_header;
|
PIMAGE_DOS_HEADER dos_header;
|
||||||
PIMAGE_NT_HEADERS old_header;
|
PIMAGE_NT_HEADERS old_header;
|
||||||
unsigned char *code, *headers;
|
unsigned char *code, *headers;
|
||||||
SIZE_T locationDelta;
|
ptrdiff_t locationDelta;
|
||||||
SYSTEM_INFO sysInfo;
|
SYSTEM_INFO sysInfo;
|
||||||
|
PIMAGE_SECTION_HEADER section;
|
||||||
|
DWORD i;
|
||||||
|
size_t optionalSectionSize;
|
||||||
|
size_t lastSectionEnd = 0;
|
||||||
|
size_t alignedImageSize;
|
||||||
|
|
||||||
|
if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
dos_header = (PIMAGE_DOS_HEADER)data;
|
dos_header = (PIMAGE_DOS_HEADER)data;
|
||||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew];
|
old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew];
|
||||||
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
|
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
|
||||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||||
@@ -473,18 +501,41 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section = IMAGE_FIRST_SECTION(old_header);
|
||||||
|
optionalSectionSize = old_header->OptionalHeader.SectionAlignment;
|
||||||
|
for (i=0; i<old_header->FileHeader.NumberOfSections; i++, section++) {
|
||||||
|
size_t endOfSection;
|
||||||
|
if (section->SizeOfRawData == 0) {
|
||||||
|
// Section without data in the DLL
|
||||||
|
endOfSection = section->VirtualAddress + optionalSectionSize;
|
||||||
|
} else {
|
||||||
|
endOfSection = section->VirtualAddress + section->SizeOfRawData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endOfSection > lastSectionEnd) {
|
||||||
|
lastSectionEnd = endOfSection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetNativeSystemInfo(&sysInfo);
|
||||||
|
alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize);
|
||||||
|
if (alignedImageSize != ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) {
|
||||||
|
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// reserve memory for image of library
|
// reserve memory for image of library
|
||||||
// XXX: is it correct to commit the complete memory region at once?
|
// XXX: is it correct to commit the complete memory region at once?
|
||||||
// calling DllEntry raises an exception if we don't...
|
// calling DllEntry raises an exception if we don't...
|
||||||
code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase),
|
code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase),
|
||||||
old_header->OptionalHeader.SizeOfImage,
|
alignedImageSize,
|
||||||
MEM_RESERVE | MEM_COMMIT,
|
MEM_RESERVE | MEM_COMMIT,
|
||||||
PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
|
|
||||||
if (code == NULL) {
|
if (code == NULL) {
|
||||||
// try to allocate memory at arbitrary position
|
// try to allocate memory at arbitrary position
|
||||||
code = (unsigned char *)VirtualAlloc(NULL,
|
code = (unsigned char *)VirtualAlloc(NULL,
|
||||||
old_header->OptionalHeader.SizeOfImage,
|
alignedImageSize,
|
||||||
MEM_RESERVE | MEM_COMMIT,
|
MEM_RESERVE | MEM_COMMIT,
|
||||||
PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
if (code == NULL) {
|
if (code == NULL) {
|
||||||
@@ -506,10 +557,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
|
|||||||
result->getProcAddress = getProcAddress;
|
result->getProcAddress = getProcAddress;
|
||||||
result->freeLibrary = freeLibrary;
|
result->freeLibrary = freeLibrary;
|
||||||
result->userdata = userdata;
|
result->userdata = userdata;
|
||||||
|
|
||||||
GetNativeSystemInfo(&sysInfo);
|
|
||||||
result->pageSize = sysInfo.dwPageSize;
|
result->pageSize = sysInfo.dwPageSize;
|
||||||
|
|
||||||
|
if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
// commit memory for headers
|
// commit memory for headers
|
||||||
headers = (unsigned char *)VirtualAlloc(code,
|
headers = (unsigned char *)VirtualAlloc(code,
|
||||||
old_header->OptionalHeader.SizeOfHeaders,
|
old_header->OptionalHeader.SizeOfHeaders,
|
||||||
@@ -524,12 +577,12 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data,
|
|||||||
result->headers->OptionalHeader.ImageBase = (uintptr_t)code;
|
result->headers->OptionalHeader.ImageBase = (uintptr_t)code;
|
||||||
|
|
||||||
// copy sections from DLL file block to new memory location
|
// copy sections from DLL file block to new memory location
|
||||||
if (!CopySections((const unsigned char *) data, old_header, result)) {
|
if (!CopySections((const unsigned char *) data, size, old_header, result)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust base address of imported data
|
// adjust base address of imported data
|
||||||
locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase);
|
locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase);
|
||||||
if (locationDelta != 0) {
|
if (locationDelta != 0) {
|
||||||
result->isRelocated = PerformBaseRelocation(result, locationDelta);
|
result->isRelocated = PerformBaseRelocation(result, locationDelta);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+5
-4
@@ -44,19 +44,20 @@ typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *);
|
|||||||
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
|
typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load EXE/DLL from memory location.
|
* Load EXE/DLL from memory location with the given size.
|
||||||
*
|
*
|
||||||
* All dependencies are resolved using default LoadLibrary/GetProcAddress
|
* 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 EXE/DLL from memory location using custom dependency resolvers.
|
* Load EXE/DLL from memory location with the given size using custom dependency
|
||||||
|
* resolvers.
|
||||||
*
|
*
|
||||||
* Dependencies will be resolved using passed callback methods.
|
* Dependencies will be resolved using passed callback methods.
|
||||||
*/
|
*/
|
||||||
HMEMORYMODULE MemoryLoadLibraryEx(const void *,
|
HMEMORYMODULE MemoryLoadLibraryEx(const void *, size_t,
|
||||||
CustomLoadLibraryFunc,
|
CustomLoadLibraryFunc,
|
||||||
CustomGetProcAddressFunc,
|
CustomGetProcAddressFunc,
|
||||||
CustomFreeLibraryFunc,
|
CustomFreeLibraryFunc,
|
||||||
|
|||||||
+1
-1
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ void LoadFromMemory(void)
|
|||||||
assert(read == static_cast<size_t>(size));
|
assert(read == static_cast<size_t>(size));
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
handle = MemoryLoadLibrary(data);
|
handle = MemoryLoadLibrary(data, size);
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("Can't load library from memory.\n"));
|
_tprintf(_T("Can't load library from memory.\n"));
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ int RunFromMemory(void)
|
|||||||
assert(read == static_cast<size_t>(size));
|
assert(read == static_cast<size_t>(size));
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
handle = MemoryLoadLibrary(data);
|
handle = MemoryLoadLibrary(data, size);
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("Can't load library from memory.\n"));
|
_tprintf(_T("Can't load library from memory.\n"));
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ BOOL LoadFromMemory(char *filename)
|
|||||||
assert(read == static_cast<size_t>(size));
|
assert(read == static_cast<size_t>(size));
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
handle = MemoryLoadLibrary(data);
|
handle = MemoryLoadLibrary(data, size);
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("Can't load library from memory.\n"));
|
_tprintf(_T("Can't load library from memory.\n"));
|
||||||
|
|||||||
Reference in New Issue
Block a user