Skip to content

Commit ed550ae

Browse files
committed
1. Add Win10 forward export support
2. Fixed some bugs
1 parent ea135ac commit ed550ae

15 files changed

Lines changed: 761 additions & 172 deletions

MemoryModule/MemoryModule.cpp

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <tchar.h>
55
#include "rtltype.h"
66
#include "ntstatus.h"
7+
#include "Native.h"
78
#include <algorithm>
89

910
#if _MSC_VER
@@ -134,7 +135,7 @@ static BOOL CheckSize(size_t size, size_t expected) {
134135
return TRUE;
135136
}
136137

137-
static BOOL CopySections(const unsigned char* data, size_t size, PMEMORYMODULE module) {
138+
static BOOL CopySections(const unsigned char* data, PMEMORYMODULE module) {
138139
LPBYTE codeBase = module->codeBase;
139140
LPVOID dest;
140141
PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
@@ -145,7 +146,12 @@ static BOOL CopySections(const unsigned char* data, size_t size, PMEMORYMODULE m
145146
alloc_size = headers->OptionalHeader.SectionAlignment;
146147
cp = false;
147148
if (section->SizeOfRawData) {
148-
if (!CheckSize(size, static_cast<size_t>(section->PointerToRawData) + section->SizeOfRawData)) return FALSE;
149+
__try {
150+
ProbeForRead(data, static_cast<size_t>(section->PointerToRawData) + section->SizeOfRawData);
151+
}
152+
__except (EXCEPTION_EXECUTE_HANDLER) {
153+
return FALSE;
154+
}
149155
alloc_size = section->SizeOfRawData;
150156
cp = true;
151157
}
@@ -354,15 +360,23 @@ static BOOL BuildImportTable(PMEMORYMODULE module) {
354360
return result;
355361
}
356362

357-
HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
363+
//static BOOL PerformForwardExport(PMEMORYMODULE module) {
364+
// PIMAGE_EXPORT_DIRECTORY exports;
365+
// PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module);
366+
// PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_EXPORT);
367+
// if (!directory->Size)return TRUE;
368+
// return FALSE;
369+
//
370+
//}
371+
372+
HMEMORYMODULE MemoryLoadLibrary(const void* data) {
358373
PMEMORYMODULE hMemoryModule = nullptr;
359374
PIMAGE_DOS_HEADER dos_header, new_dos_header;
360375
PIMAGE_NT_HEADERS old_header, new_header;
361-
unsigned char* code;
376+
unsigned char* base;
362377
ptrdiff_t locationDelta;
363-
SYSTEM_INFO sysInfo;
378+
static SYSTEM_INFO sysInfo{};
364379
PIMAGE_SECTION_HEADER section;
365-
DWORD i;
366380
size_t optionalSectionSize;
367381
size_t lastSectionEnd = 0;
368382
size_t alignedImageSize;
@@ -371,40 +385,36 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
371385
POINTER_LIST* blockedMemory = nullptr;
372386
#endif
373387

374-
if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) return nullptr;
375-
dos_header = (PIMAGE_DOS_HEADER)data;
376-
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
377-
SetLastError(ERROR_BAD_EXE_FORMAT);
378-
return nullptr;
379-
}
380-
381-
if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) return nullptr;
382-
old_header = (PIMAGE_NT_HEADERS) & ((const unsigned char*)(data))[dos_header->e_lfanew];
383-
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
384-
SetLastError(ERROR_BAD_EXE_FORMAT);
385-
return nullptr;
386-
}
387-
388-
if (old_header->FileHeader.Machine != HOST_MACHINE) {
389-
SetLastError(ERROR_BAD_EXE_FORMAT);
390-
return nullptr;
391-
}
392-
393-
if (old_header->OptionalHeader.SectionAlignment & 1) {
394-
// Only support section alignments that are a multiple of 2
395-
SetLastError(ERROR_BAD_EXE_FORMAT);
396-
return nullptr;
388+
__try {
389+
ProbeForRead(data, sizeof(IMAGE_DOS_HEADER));
390+
dos_header = (PIMAGE_DOS_HEADER)data;
391+
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
392+
SetLastError(ERROR_BAD_EXE_FORMAT);
393+
return nullptr;
394+
}
395+
ProbeForRead(data, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS));
396+
old_header = (PIMAGE_NT_HEADERS)((size_t)data + dos_header->e_lfanew);
397+
if (old_header->Signature != IMAGE_NT_SIGNATURE ||
398+
!ProbeForRead(data, old_header->OptionalHeader.SizeOfHeaders) ||
399+
old_header->FileHeader.Machine != HOST_MACHINE ||
400+
old_header->OptionalHeader.SectionAlignment & 1) {
401+
SetLastError(ERROR_BAD_EXE_FORMAT);
402+
return nullptr;
403+
}
404+
//only dll image support
405+
if (!(old_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
406+
SetLastError(ERROR_NOT_SUPPORTED);
407+
return nullptr;
408+
}
397409
}
398-
399-
//only dll image support
400-
if (!(old_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) {
401-
SetLastError(ERROR_NOT_SUPPORTED);
410+
__except (EXCEPTION_EXECUTE_HANDLER) {
411+
SetLastError(ERROR_INVALID_DATA);
402412
return nullptr;
403413
}
404-
414+
405415
section = IMAGE_FIRST_SECTION(old_header);
406416
optionalSectionSize = old_header->OptionalHeader.SectionAlignment;
407-
for (i = 0; i < old_header->FileHeader.NumberOfSections; i++, section++) {
417+
for (DWORD i = 0; i < old_header->FileHeader.NumberOfSections; i++, section++) {
408418
size_t endOfSection;
409419
if (section->SizeOfRawData == 0) {
410420
// Section without data in the DLL
@@ -419,7 +429,7 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
419429
}
420430
}
421431

422-
GetNativeSystemInfo(&sysInfo);
432+
if (!sysInfo.dwPageSize)GetNativeSystemInfo(&sysInfo);
423433
alignedImageSize = AlignValueUp(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize);
424434
if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) {
425435
SetLastError(ERROR_BAD_EXE_FORMAT);
@@ -430,45 +440,45 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
430440
// reserve memory for image of library
431441
// XXX: is it correct to commit the complete memory region at once?
432442
// calling DllEntry raises an exception if we don't...
433-
if (!(code = (LPBYTE)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
443+
if (!(base = (LPBYTE)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
434444
if (!(old_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) {
435445
SetLastError(ERROR_BAD_EXE_FORMAT);
436446
return nullptr;
437447
}
438-
if (!(code = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
448+
if (!(base = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
439449
SetLastError(ERROR_OUTOFMEMORY);
440450
return nullptr;
441451
}
442452
}
443453

444454
#ifdef _WIN64
445455
// Memory block may not span 4 GB boundaries.
446-
while ((((uintptr_t)code) >> 32) < (((uintptr_t)(code + alignedImageSize)) >> 32)) {
456+
while ((((uintptr_t)base) >> 32) < (((uintptr_t)(base + alignedImageSize)) >> 32)) {
447457
POINTER_LIST* node = new POINTER_LIST;
448458
if (!node) {
449-
VirtualFree(code, 0, MEM_RELEASE);
459+
VirtualFree(base, 0, MEM_RELEASE);
450460
FreePointerList(blockedMemory);
451461
SetLastError(ERROR_OUTOFMEMORY);
452462
return nullptr;
453463
}
454464

455465
node->next = blockedMemory;
456-
node->address = code;
466+
node->address = base;
457467
blockedMemory = node;
458468

459-
if (!(code = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
469+
if (!(base = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
460470
FreePointerList(blockedMemory);
461471
SetLastError(ERROR_OUTOFMEMORY);
462472
return nullptr;
463473
}
464474
}
465475
#endif
466476

467-
new_dos_header = (PIMAGE_DOS_HEADER)code;
468-
new_header = (PIMAGE_NT_HEADERS)(code + dos_header->e_lfanew);
469-
hMemoryModule = (PMEMORYMODULE)(code + old_header->OptionalHeader.SizeOfHeaders);
477+
new_dos_header = (PIMAGE_DOS_HEADER)base;
478+
new_header = (PIMAGE_NT_HEADERS)(base + dos_header->e_lfanew);
479+
hMemoryModule = (PMEMORYMODULE)(base + old_header->OptionalHeader.SizeOfHeaders);
470480
RtlZeroMemory(hMemoryModule, sizeof(MEMORYMODULE));
471-
hMemoryModule->codeBase = code;
481+
hMemoryModule->codeBase = base;
472482
hMemoryModule->pageSize = sysInfo.dwPageSize;
473483
hMemoryModule->Signature = MEMORY_MODULE_SIGNATURE;
474484
hMemoryModule->SizeofHeaders = old_header->OptionalHeader.SizeOfHeaders;
@@ -477,18 +487,14 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
477487
hMemoryModule->blockedMemory = blockedMemory;
478488
#endif
479489

480-
if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) {
481-
goto error;
482-
}
483-
484490
// copy PE header to code
485491
memcpy(new_dos_header, dos_header, old_header->OptionalHeader.SizeOfHeaders);
486492
new_header->OptionalHeader.SizeOfImage = (DWORD)(alignedImageSize);
487-
new_header->OptionalHeader.ImageBase = (size_t)code;
493+
new_header->OptionalHeader.ImageBase = (size_t)base;
488494
new_header->OptionalHeader.BaseOfCode = headers_align;
489495

490496
// copy sections from DLL file block to new memory location
491-
if (!CopySections((LPBYTE)data, size, hMemoryModule)) goto error;
497+
if (!CopySections((LPBYTE)data, hMemoryModule)) goto error;
492498

493499
// adjust base address of imported data
494500
locationDelta = (ptrdiff_t)(hMemoryModule->codeBase - old_header->OptionalHeader.ImageBase);
@@ -509,7 +515,7 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
509515
if (new_header->OptionalHeader.AddressOfEntryPoint) {
510516
__try {
511517
// notify library about attaching to process
512-
if (!((DllEntryProc)(code + new_header->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)code, DLL_PROCESS_ATTACH, 0)) {
518+
if (!((DllEntryProc)(base + new_header->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)base, DLL_PROCESS_ATTACH, 0)) {
513519
SetLastError(ERROR_DLL_INIT_FAILED);
514520
goto error;
515521
}
@@ -521,7 +527,7 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data, size_t size) {
521527
hMemoryModule->initialized = TRUE;
522528
}
523529

524-
return code;
530+
return base;
525531
error:
526532
// cleanup
527533
MemoryFreeLibrary(hMemoryModule);

MemoryModule/MemoryModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ extern "C" {
101101
* All dependencies are resolved using default LoadLibrary/GetProcAddress
102102
* calls through the Windows API.
103103
*/
104-
HMEMORYMODULE MemoryLoadLibrary(const void*, size_t);
104+
HMEMORYMODULE MemoryLoadLibrary(const void*);
105105

106106
/**
107107
* Get address of exported method. Supports loading both by name and by

MemoryModule/Native.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,24 @@ PVOID NTAPI RtlEncodeSystemPointer(PVOID Pointer) {
364364
PVOID NTAPI RtlDecodeSystemPointer(PVOID Pointer) {
365365
return decltype(&RtlDecodeSystemPointer)(RtlGetNtProcAddress("RtlDecodeSystemPointer"))(Pointer);
366366
}
367+
368+
BOOLEAN NTAPI VirtualAccessCheck(LPCVOID pBuffer, size_t size, ACCESS_MASK protect) {
369+
MEMORY_BASIC_INFORMATION mbi{};
370+
SIZE_T len = 0;
371+
if (!NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(), const_cast<PVOID>(pBuffer), MemoryBasicInformation, &mbi, sizeof(mbi), &len)) ||
372+
!(mbi.Protect & protect)) {
373+
RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, nullptr);
374+
return FALSE;
375+
}
376+
return TRUE;
377+
}
378+
379+
NTSTATUS NTAPI LdrLockLoaderLock(size_t Flags, size_t* State, size_t* Cookie) {
380+
return (decltype(&LdrLockLoaderLock)(RtlGetNtProcAddress("LdrLockLoaderLock")))(Flags, State, Cookie);
381+
}
382+
NTSTATUS NTAPI LdrUnlockLoaderLock(size_t Flags, size_t Cookie) {
383+
return (decltype(&LdrUnlockLoaderLock)(RtlGetNtProcAddress("LdrUnlockLoaderLock")))(Flags, Cookie);
384+
}
385+
NTSTATUS NTAPI LdrUnloadDll(IN HANDLE ModuleHandle) {
386+
return (decltype(&LdrUnloadDll)(RtlGetNtProcAddress("LdrUnloadDll")))(ModuleHandle);
387+
}

MemoryModule/Native.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,60 @@ typedef enum _PROCESSINFOCLASS {
372372
ProcessLeapSecondInformation, // PROCESS_LEAP_SECOND_INFORMATION
373373
MaxProcessInfoClass
374374
} PROCESSINFOCLASS;
375+
typedef enum _THREADINFOCLASS {
376+
ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION
377+
ThreadTimes, // q: KERNEL_USER_TIMES
378+
ThreadPriority, // s: KPRIORITY
379+
ThreadBasePriority, // s: LONG
380+
ThreadAffinityMask, // s: KAFFINITY
381+
ThreadImpersonationToken, // s: HANDLE
382+
ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY)
383+
ThreadEnableAlignmentFaultFixup, // s: BOOLEAN
384+
ThreadEventPair,
385+
ThreadQuerySetWin32StartAddress, // q: PVOID
386+
ThreadZeroTlsCell, // 10
387+
ThreadPerformanceCount, // q: LARGE_INTEGER
388+
ThreadAmILastThread, // q: ULONG
389+
ThreadIdealProcessor, // s: ULONG
390+
ThreadPriorityBoost, // qs: ULONG
391+
ThreadSetTlsArrayAddress,
392+
ThreadIsIoPending, // q: ULONG
393+
ThreadHideFromDebugger, // s: void
394+
ThreadBreakOnTermination, // qs: ULONG
395+
ThreadSwitchLegacyState,
396+
ThreadIsTerminated, // q: ULONG // 20
397+
ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION
398+
ThreadIoPriority, // qs: IO_PRIORITY_HINT
399+
ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION
400+
ThreadPagePriority, // q: ULONG
401+
ThreadActualBasePriority,
402+
ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT)
403+
ThreadCSwitchMon,
404+
ThreadCSwitchPmu,
405+
ThreadWow64Context, // q: WOW64_CONTEXT
406+
ThreadGroupInformation, // q: GROUP_AFFINITY // 30
407+
ThreadUmsInformation, // q: THREAD_UMS_INFORMATION
408+
ThreadCounterProfiling,
409+
ThreadIdealProcessorEx, // q: PROCESSOR_NUMBER
410+
ThreadCpuAccountingInformation, // since WIN8
411+
ThreadSuspendCount, // since WINBLUE
412+
ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD
413+
ThreadContainerId, // q: GUID
414+
ThreadNameInformation, // qs: THREAD_NAME_INFORMATION
415+
ThreadSelectedCpuSets,
416+
ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40
417+
ThreadActualGroupAffinity, // since THRESHOLD2
418+
ThreadDynamicCodePolicyInfo,
419+
ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables
420+
ThreadWorkOnBehalfTicket,
421+
ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2
422+
ThreadDbgkWerReportActive,
423+
ThreadAttachContainer,
424+
ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3
425+
ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE
426+
ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50
427+
MaxThreadInfoClass
428+
} THREADINFOCLASS;
375429
typedef struct _SYSTEM_PROCESS {
376430
ULONG NextEntryOffset;//relative offset
377431
ULONG ThreadCount;
@@ -998,6 +1052,13 @@ typedef struct _SECURITY__LOGON_SESSION_DATA {
9981052
LARGE_INTEGER PasswordMustChange;
9991053
}SECURITY_LOGON_SESSION_DATA, *PSECURITY_LOGON_SESSION_DATA,
10001054
LOGON_SESSION_DATA, *PLOGON_SESSION_DATA;
1055+
typedef struct _INITIAL_TEB {
1056+
PVOID StackBase;
1057+
PVOID StackLimit;
1058+
PVOID StackCommit;
1059+
PVOID StackCommitMax;
1060+
PVOID StackReserved;
1061+
} INITIAL_TEB, * PINITIAL_TEB;
10011062

10021063
NTSTATUS NTAPI NtQueryObject(
10031064
IN HANDLE ObjectHandle,
@@ -1340,3 +1401,23 @@ typedef struct _UNWIND_INFO {
13401401
NTSTATUS NTAPI NtQuerySystemTime(PLARGE_INTEGER SystemTime);
13411402
PVOID NTAPI RtlEncodeSystemPointer(PVOID Pointer);
13421403
PVOID NTAPI RtlDecodeSystemPointer(PVOID Pointer);
1404+
1405+
#define NtCurrentProcess() (HANDLE)-1
1406+
#define NtCurrentThread() (HANDLE)-2
1407+
1408+
BOOLEAN NTAPI VirtualAccessCheck(LPCVOID pBuffer, size_t size, ACCESS_MASK protect);
1409+
#define ProbeForRead(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)
1410+
#define ProbeForWrite(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE)
1411+
#define ProbeForReadWrite(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_EXECUTE_READWRITE | PAGE_READWRITE)
1412+
#define ProbeForExecute(pBuffer, size) VirtualAccessCheck(pBuffer, size, PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
1413+
1414+
//Flags
1415+
#define LOCK_RAISE_EXCEPTION 1
1416+
#define LOCK_NO_WAIT_IF_BUSY 2
1417+
//State
1418+
#define LOCK_STATE_NO_ENTER 0
1419+
#define LOCK_STATE_ENTERED 1
1420+
#define LOCK_STATE_LOCK_BUSY 2
1421+
NTSTATUS NTAPI LdrLockLoaderLock(size_t Flags, size_t* State, size_t* Cookie);
1422+
NTSTATUS NTAPI LdrUnlockLoaderLock(size_t Flags, size_t Cookie);
1423+
NTSTATUS NTAPI LdrUnloadDll(IN HANDLE ModuleHandle);

0 commit comments

Comments
 (0)