mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
update
This commit is contained in:
@@ -52,6 +52,7 @@ int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int);
|
||||
*/
|
||||
int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD);
|
||||
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemory(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
IN LPVOID BufferAddress,
|
||||
@@ -59,7 +60,7 @@ NTSTATUS NTAPI NtLoadDllMemory(
|
||||
);
|
||||
|
||||
/*
|
||||
NtLoadDllMemoryEx dwFlags
|
||||
NtLoadDllMemoryEx dwFlags
|
||||
*/
|
||||
|
||||
//If this flag is specified, all subsequent flags will be ignored.
|
||||
@@ -77,12 +78,15 @@ NTSTATUS NTAPI NtLoadDllMemory(
|
||||
//If this flag is specified, DllName and DllFullName cannot be nullptr,
|
||||
// they can be arbitrary strings without having to be correct file names and paths.
|
||||
//Otherwise, DllName and DllFullName will use random names if they are nullptr.
|
||||
//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in .dll
|
||||
//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in ".dll"
|
||||
#define LOAD_FLAGS_USE_DLL_NAME 0x00000004
|
||||
|
||||
//Dont call LdrpHandleTlsData routine if this flag is specified.
|
||||
#define LOAD_FLAGS_NOT_HANDLE_TLS 0x00000008
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL,
|
||||
OUT PVOID* LdrEntry OPTIONAL,
|
||||
IN DWORD dwFlags,
|
||||
IN LPVOID BufferAddress,
|
||||
IN size_t BufferSize,
|
||||
@@ -91,7 +95,7 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
);
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExA(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL,
|
||||
OUT PVOID* LdrEntry OPTIONAL,
|
||||
IN DWORD dwFlags,
|
||||
IN LPVOID BufferAddress,
|
||||
IN size_t BufferSize,
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<ClInclude Include="NativeFunctionsInternal.h" />
|
||||
<ClInclude Include="rtltype.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{5B1F46DB-036E-4A50-AF5F-F5D6584D42C6}</ProjectGuid>
|
||||
|
||||
@@ -42,4 +42,9 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -274,15 +274,15 @@ static NTSTATUS NTAPI NtRemoveModuleBaseAddressIndexNode(IN PLDR_DATA_TABLE_ENTR
|
||||
|
||||
static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
OUT PLDR_DATA_TABLE_ENTRY LdrEntry,
|
||||
IN DWORD dwFlags,
|
||||
IN PVOID BaseAddress,
|
||||
IN ULONG SizeofImage,
|
||||
IN DWORD TimeDateStamp,
|
||||
IN UNICODE_STRING &DllBaseName,
|
||||
IN UNICODE_STRING &DllFullName,
|
||||
IN PVOID EntryPoint) {
|
||||
|
||||
IN UNICODE_STRING &DllFullName) {
|
||||
UNREFERENCED_PARAMETER(dwFlags);
|
||||
RtlZeroMemory(LdrEntry, NtLdrDataTableEntrySize());
|
||||
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(BaseAddress);
|
||||
if (!headers)return false;
|
||||
bool FlagsProcessed = false;
|
||||
|
||||
switch (NtWindowsVersion()) {
|
||||
case win10:
|
||||
@@ -300,11 +300,16 @@ static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
entry->LoadReason = LoadReasonDynamicLoad;
|
||||
if (!NT_SUCCESS(NtInsertModuleBaseAddressIndexNode(LdrEntry, BaseAddress)))return false;
|
||||
if (!(entry->DdagNode = (decltype(entry->DdagNode))NtAllocateLdrpHeap(sizeof(_LDR_DDAG_NODE))))return false;
|
||||
NtInitializeListEntry(&entry->NodeModuleLink);
|
||||
NtInitializeListEntry(&entry->DdagNode->Modules);
|
||||
NtInitializeSingleEntry(&entry->DdagNode->CondenseLink);
|
||||
//NtInitializeListEntry(&entry->NodeModuleLink);
|
||||
//NtInitializeListEntry(&entry->DdagNode->Modules);
|
||||
entry->NodeModuleLink.Flink = &entry->DdagNode->Modules;
|
||||
entry->NodeModuleLink.Blink = &entry->DdagNode->Modules;
|
||||
entry->DdagNode->Modules.Flink = &entry->NodeModuleLink;
|
||||
entry->DdagNode->Modules.Blink = &entry->NodeModuleLink;
|
||||
entry->DdagNode->State = LdrModulesReadyToRun;
|
||||
entry->DdagNode->LoadCount = 0;
|
||||
|
||||
NtInitializeSingleEntry(&entry->DdagNode->CondenseLink);
|
||||
}
|
||||
|
||||
case win7: {
|
||||
@@ -325,12 +330,13 @@ static bool NTAPI NtInitializeLdrDataTableEntry(
|
||||
}
|
||||
case xp: {
|
||||
LdrEntry->DllBase = BaseAddress;
|
||||
LdrEntry->SizeOfImage = SizeofImage;
|
||||
LdrEntry->TimeDateStamp = TimeDateStamp;
|
||||
LdrEntry->SizeOfImage = headers->OptionalHeader.SizeOfImage;
|
||||
LdrEntry->TimeDateStamp = headers->FileHeader.TimeDateStamp;
|
||||
LdrEntry->BaseDllName = DllBaseName;
|
||||
LdrEntry->FullDllName = DllFullName;
|
||||
LdrEntry->EntryPoint = EntryPoint;
|
||||
if (headers->OptionalHeader.DllCharacteristics & IMAGE_FILE_DLL)LdrEntry->Flags |= LDRP_IMAGE_DLL;
|
||||
LdrEntry->EntryPoint = (PVOID)((size_t)BaseAddress + headers->OptionalHeader.AddressOfEntryPoint);
|
||||
if (!FlagsProcessed) LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_INSERTED | LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED;
|
||||
NtInitializeListEntry(&LdrEntry->HashLinks);
|
||||
return true;
|
||||
}
|
||||
default:return false;
|
||||
@@ -355,6 +361,7 @@ static bool NTAPI NtFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
NtFreeLdrpHeap(LdrEntry->FullDllName.Buffer);
|
||||
RemoveEntryList(&LdrEntry->InLoadOrderLinks);
|
||||
RemoveEntryList(&LdrEntry->InMemoryOrderLinks);
|
||||
RemoveEntryList(&LdrEntry->InInitializationOrderLinks);
|
||||
RemoveEntryList(&LdrEntry->HashLinks);
|
||||
NtFreeLdrpHeap(LdrEntry);
|
||||
return true;
|
||||
@@ -508,9 +515,10 @@ static VOID NTAPI NtInsertMemoryTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
/* Insert into other lists */
|
||||
InsertTailList(&PebData->InLoadOrderModuleList, &LdrEntry->InLoadOrderLinks);
|
||||
InsertTailList(&PebData->InMemoryOrderModuleList, &LdrEntry->InMemoryOrderLinks);
|
||||
InsertTailList(&PebData->InInitializationOrderModuleList, &LdrEntry->InInitializationOrderLinks);
|
||||
}
|
||||
|
||||
static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN PCWSTR DllName OPTIONAL,
|
||||
static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags, IN PCWSTR DllName OPTIONAL,
|
||||
IN PCWSTR lpFullDllName OPTIONAL, OUT PLDR_DATA_TABLE_ENTRY* DataTableEntry OPTIONAL) {
|
||||
|
||||
UNICODE_STRING FullDllName, BaseDllName;
|
||||
@@ -526,11 +534,7 @@ static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN PCWSTR DllNam
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!NtInitializeLdrDataTableEntry(LdrEntry, ViewBase,
|
||||
NtHeaders->OptionalHeader.SizeOfImage,
|
||||
NtHeaders->FileHeader.TimeDateStamp,
|
||||
BaseDllName, FullDllName,
|
||||
(PVOID)(NtHeaders->OptionalHeader.AddressOfEntryPoint + NtHeaders->OptionalHeader.ImageBase))) {
|
||||
if (!NtInitializeLdrDataTableEntry(LdrEntry, dwFlags, ViewBase, BaseDllName, FullDllName)) {
|
||||
NtFreeLdrpHeap(LdrEntry);
|
||||
NtFreeLdrpHeap(BaseDllName.Buffer);
|
||||
NtFreeLdrpHeap(FullDllName.Buffer);
|
||||
@@ -548,16 +552,25 @@ NTSTATUS NTAPI NtLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferA
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL,
|
||||
OUT PVOID* LdrEntry OPTIONAL,
|
||||
IN DWORD dwFlags,
|
||||
IN LPVOID BufferAddress,
|
||||
IN size_t BufferSize,
|
||||
IN LPCWSTR DllName OPTIONAL,
|
||||
IN LPCWSTR DllFullName OPTIONAL) {
|
||||
if (IsBadReadPtr(BufferAddress, BufferSize) || IsBadWritePtr(BaseAddress, sizeof(HMEMORYMODULE)))return STATUS_ACCESS_VIOLATION;
|
||||
*BaseAddress = nullptr;
|
||||
PMEMORYMODULE module = nullptr;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr;
|
||||
|
||||
__try {
|
||||
if (IsBadReadPtr(BufferAddress, BufferSize))status = STATUS_ACCESS_VIOLATION;
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(status))return status;
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) {
|
||||
dwFlags &= LOAD_FLAGS_NOT_MAP_DLL;
|
||||
@@ -612,28 +625,44 @@ NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
}
|
||||
module->loadFromNtLoadDllMemory = true;
|
||||
if (dwFlags & LOAD_FLAGS_NOT_MAP_DLL) return STATUS_SUCCESS;
|
||||
status = NtMapDllMemory(*BaseAddress, DllName, DllFullName, LdrEntry);
|
||||
|
||||
status = NtMapDllMemory(*BaseAddress, dwFlags, DllName, DllFullName, &ModuleEntry);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
return status;
|
||||
}
|
||||
module->MappedDll = true;
|
||||
|
||||
if (LdrEntry)*LdrEntry = ModuleEntry;
|
||||
|
||||
if (!(dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT))module->UseReferenceCount = true;
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION)return STATUS_SUCCESS;
|
||||
status = RtlInsertInvertedFunctionTable((PVOID)module->codeBase, RtlImageNtHeader(*BaseAddress)->OptionalHeader.SizeOfImage);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
}
|
||||
module->InsertInvertedFunctionTableEntry = true;
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_NOT_HANDLE_TLS)return STATUS_SUCCESS;
|
||||
status = LdrpHandleTlsData(ModuleEntry);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NtUnloadDllMemory(*BaseAddress);
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
return status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS NtLoadDllMemoryExA(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL,
|
||||
OUT PVOID* LdrEntry OPTIONAL,
|
||||
IN DWORD dwFlags,
|
||||
IN LPVOID BufferAddress,
|
||||
IN size_t BufferSize,
|
||||
@@ -907,7 +936,7 @@ static NTSTATUS NTAPI RtlProtectMrdata(IN SIZE_T Protect) {
|
||||
NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize) {
|
||||
static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable());
|
||||
if (!table)return STATUS_NOT_SUPPORTED;
|
||||
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(10, 0, 0);
|
||||
bool need_virtual_protect = RtlIsWindowsVersionOrGreater(8, 3, 0);
|
||||
NTSTATUS status;
|
||||
|
||||
if (need_virtual_protect) {
|
||||
@@ -940,3 +969,144 @@ NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase) {
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS NTAPI LdrpHandleTlsDataXp(PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
typedef NTSTATUS(__thiscall* _PTR_WIN8_1)(PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
typedef NTSTATUS(__stdcall* _PTR_WIN)(PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
union _FUNCTION_SET {
|
||||
_PTR_WIN8_1 Win8_1_OrGreater;
|
||||
_PTR_WIN Default;
|
||||
_FUNCTION_SET() {
|
||||
this->Default = nullptr;
|
||||
}
|
||||
operator bool() {
|
||||
return this->Default != nullptr;
|
||||
}
|
||||
};
|
||||
static _FUNCTION_SET _LdrpHandleTlsData{};
|
||||
static bool stdcall = false;
|
||||
if (_LdrpHandleTlsData)
|
||||
return stdcall ? _LdrpHandleTlsData.Default(LdrEntry) : _LdrpHandleTlsData.Win8_1_OrGreater(LdrEntry);
|
||||
|
||||
DWORD Versions[3]{};
|
||||
LPCVOID Feature = nullptr;
|
||||
BYTE Size = 0;
|
||||
WORD OffsetOfFunctionBegin = 0;
|
||||
RtlGetNtVersionNumbers(Versions, Versions + 1, Versions + 2);
|
||||
switch (Versions[0]) {
|
||||
case 10: {
|
||||
if (Versions[1])return STATUS_NOT_SUPPORTED;
|
||||
|
||||
//RS3
|
||||
if (Versions[2] >= 16299) {
|
||||
Size = 7;
|
||||
//19H2
|
||||
if (Versions[2] >= 18363)Feature = "\x74\x33\x44\x8D\x43\x09";
|
||||
//RS5
|
||||
else if (Versions[2] >= 17763) Feature = "\x8b\xc1\x8d\x4d\xbc\x51";
|
||||
//RS4
|
||||
else if (Versions[2] >= 17134) Feature = "\x33\xf6\x85\xc0\x79\x03";
|
||||
//RS3
|
||||
else Feature = "\x8b\xc1\x8d\x4d\xac\x51";
|
||||
#ifdef _WIN64
|
||||
//RS6(19H1)
|
||||
if (Versions[2] >= 18362) OffsetOfFunctionBegin = 0x46;
|
||||
//RS4
|
||||
else if (Versions[2] >= 17134) OffsetOfFunctionBegin = 0x44;
|
||||
//RS3
|
||||
else OffsetOfFunctionBegin = 0x43;
|
||||
#else
|
||||
//RS6(19H1)
|
||||
if (Versions[2] >= 18362) OffsetOfFunctionBegin = 0x2E;
|
||||
//RS5
|
||||
else if (Versions[2] >= 17763) OffsetOfFunctionBegin = 0x2C;
|
||||
//RS3,4
|
||||
else OffsetOfFunctionBegin = 0x18;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
//RS2
|
||||
else if (Versions[2] >= 15063) {
|
||||
Size = 7;
|
||||
#ifdef _WIN64
|
||||
OffsetOfFunctionBegin = 0x43;
|
||||
Feature = "\x74\x33\x44\x8d\x43\x09";
|
||||
#else
|
||||
OffsetOfFunctionBegin = 0x18;
|
||||
Feature = "\x8b\xc1\x8d\x4d\xbc\x51";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
// NO BREAK
|
||||
}
|
||||
case 6: {
|
||||
switch (Versions[1]) {
|
||||
//8.1
|
||||
case 3: {
|
||||
#ifdef _WIN64
|
||||
Size = 10;
|
||||
OffsetOfFunctionBegin = 0x43;
|
||||
Feature = "\x44\x8d\x43\x09\x4c\x8d\x4c\x24\x38";
|
||||
#else
|
||||
Size = 8;
|
||||
OffsetOfFunctionBegin = 0x1B;
|
||||
Feature = "\x50\x6a\x09\x6a\x01\x8b\xc1";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
//8
|
||||
case 2: {
|
||||
#ifdef _WIN64
|
||||
Size = 9;
|
||||
OffsetOfFunctionBegin = 0x49;
|
||||
Feature = "\x48\x8b\x79\x30\x45\x8d\x66\x01";
|
||||
#else
|
||||
Size = 7;
|
||||
OffsetOfFunctionBegin = 0xC;
|
||||
Feature = "\x8b\x45\x08\x89\x45\xa0";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
//7
|
||||
case 1: {
|
||||
#ifdef _WIN64
|
||||
Size = 12;
|
||||
OffsetOfFunctionBegin = 0x27;
|
||||
Feature = "\x41\xb8\x09\x00\x00\x00\x48\x8d\x44\x24\x38";
|
||||
#else
|
||||
Size = 9;
|
||||
OffsetOfFunctionBegin = 0x14;
|
||||
Feature = "\x74\x20\x8d\x45\xd4\x50\x6a\x09";
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
_LdrpHandleTlsData.Default = LdrpHandleTlsDataXp;
|
||||
stdcall = true;
|
||||
return LdrpHandleTlsDataXp(LdrEntry);
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
|
||||
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(ntdll);
|
||||
if (!Feature || !headers)return STATUS_NOT_SUPPORTED;
|
||||
Size--;
|
||||
for (size_t i = 0; i < headers->OptionalHeader.SizeOfCode - Size; ++i) {
|
||||
if (RtlCompareMemory((PBYTE)ntdll + i, Feature, Size) == Size) {
|
||||
_LdrpHandleTlsData.Default = (_PTR_WIN)((PBYTE)ntdll + i - OffsetOfFunctionBegin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_LdrpHandleTlsData)return STATUS_NOT_SUPPORTED;
|
||||
stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0);
|
||||
return stdcall ? _LdrpHandleTlsData.Default(LdrEntry) : _LdrpHandleTlsData.Win8_1_OrGreater(LdrEntry);
|
||||
}
|
||||
|
||||
@@ -393,6 +393,7 @@ NTSTATUS NTAPI NtLoadDllMemory(
|
||||
/*
|
||||
NtLoadDllMemoryEx dwFlags
|
||||
*/
|
||||
|
||||
//If this flag is specified, all subsequent flags will be ignored.
|
||||
//Also, will be incompatible with Win32 API.
|
||||
#define LOAD_FLAGS_NOT_MAP_DLL 0x10000000
|
||||
@@ -408,13 +409,16 @@ NTSTATUS NTAPI NtLoadDllMemory(
|
||||
//If this flag is specified, DllName and DllFullName cannot be nullptr,
|
||||
// they can be arbitrary strings without having to be correct file names and paths.
|
||||
//Otherwise, DllName and DllFullName will use random names if they are nullptr.
|
||||
//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in .dll
|
||||
//For compatibility with GetModuleHandle, DllName and DllFullName should be guaranteed to always end in ".dll"
|
||||
#define LOAD_FLAGS_USE_DLL_NAME 0x00000004
|
||||
|
||||
//Dont call LdrpHandleTlsData routine if this flag is specified.
|
||||
#define LOAD_FLAGS_NOT_HANDLE_TLS 0x00000008
|
||||
|
||||
|
||||
NTSTATUS NTAPI NtLoadDllMemoryExW(
|
||||
OUT HMEMORYMODULE* BaseAddress,
|
||||
OUT PLDR_DATA_TABLE_ENTRY* LdrEntry OPTIONAL,
|
||||
OUT PVOID* LdrEntry OPTIONAL,
|
||||
IN DWORD dwFlags,
|
||||
IN LPVOID BufferAddress,
|
||||
IN size_t BufferSize,
|
||||
@@ -449,3 +453,4 @@ typedef struct _RTL_INVERTED_FUNCTION_TABLE {
|
||||
|
||||
NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize);
|
||||
NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase);
|
||||
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
|
||||
@@ -8,6 +8,11 @@ MemoryModulePP, used to load a DLL from memory. MemoryModulePP is compatible wit
|
||||
|
||||
**This repository is under development.**
|
||||
|
||||
# NewFeatures
|
||||
- Compatible with Win32 API: LoadStringA/W
|
||||
- Support for TLS(Thread Local Storage)
|
||||
- DllMain can receive four types of notifications
|
||||
|
||||
# Features
|
||||
- Compatible with Win32 API (GetModuleHandleA/W/Ex GetModuleFileNameA/W/Ex GetProcAddress)
|
||||
- Support for C ++ exceptions and SEH
|
||||
|
||||
+536
-33
@@ -1,35 +1,538 @@
|
||||
struct FuncInfoHeader
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t isCatch : 1; // 1 if this represents a catch funclet, 0 otherwise
|
||||
uint8_t isSeparated : 1; // 1 if this function has separated code segments, 0 otherwise
|
||||
uint8_t BBT : 1; // Flags set by Basic Block Transformations
|
||||
uint8_t UnwindMap : 1; // Existence of Unwind Map RVA
|
||||
uint8_t TryBlockMap : 1; // Existence of Try Block Map RVA
|
||||
uint8_t EHs : 1; // EHs flag set
|
||||
uint8_t NoExcept : 1; // NoExcept flag set
|
||||
uint8_t reserved : 1;
|
||||
};
|
||||
uint8_t value;
|
||||
};
|
||||
};
|
||||
struct FuncInfo4
|
||||
{
|
||||
FuncInfoHeader header;
|
||||
uint32_t bbtFlags; // flags that may be set by BBT processing
|
||||
#include <Windows.h>
|
||||
#include "../MemoryModule/NativeFunctionsInternal.h"
|
||||
|
||||
int32_t dispUnwindMap; // Image relative offset of the unwind map
|
||||
int32_t dispTryBlockMap; // Image relative offset of the handler map
|
||||
int32_t dispIPtoStateMap; // Image relative offset of the IP to state map
|
||||
uint32_t dispFrame; // displacement of address of function frame wrt establisher frame, only used for catch funclets
|
||||
typedef struct _THREAD_TLS_INFORMATION {
|
||||
ULONG Flags;
|
||||
union {
|
||||
PVOID* TlsVector;
|
||||
PVOID TlsModulePointer;
|
||||
};
|
||||
HANDLE ThreadId;
|
||||
} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION;
|
||||
|
||||
typedef enum _PROCESS_TLS_INFORMATION_TYPE {
|
||||
ProcessTlsReplaceIndex,
|
||||
ProcessTlsReplaceVector,
|
||||
MaxProcessTlsOperation
|
||||
} PROCESS_TLS_INFORMATION_TYPE, * PPROCESS_TLS_INFORMATION_TYPE;
|
||||
|
||||
typedef struct _PROCESS_TLS_INFORMATION {
|
||||
ULONG Reserved; // Reserved bitmask
|
||||
ULONG OperationType;
|
||||
ULONG ThreadDataCount;
|
||||
union {
|
||||
ULONG TlsIndex;
|
||||
ULONG TlsVectorLength;
|
||||
};
|
||||
THREAD_TLS_INFORMATION ThreadData[ANYSIZE_ARRAY];
|
||||
} PROCESS_TLS_INFORMATION, * PPROCESS_TLS_INFORMATION;
|
||||
|
||||
// Need struct name
|
||||
typedef struct _TLS_VECTOR {
|
||||
union {
|
||||
ULONG Length;
|
||||
HANDLE ThreadId;
|
||||
};
|
||||
|
||||
struct _TLS_VECTOR* PreviousDeferredTlsVector;
|
||||
PVOID ModuleTlsData[ANYSIZE_ARRAY];
|
||||
} TLS_VECTOR, * PTLS_VECTOR;
|
||||
|
||||
// Need struct name
|
||||
typedef struct _TLS_RECLAIM_TABLE_ENTRY {
|
||||
PTLS_VECTOR TlsVector;
|
||||
RTL_SRWLOCK Lock;
|
||||
} TLS_RECLAIM_TABLE_ENTRY, * PTLS_RECLAIM_TABLE_ENTRY;
|
||||
|
||||
// Need struct name
|
||||
typedef struct _TLS_ENTRY {
|
||||
LIST_ENTRY TlsEntryLinks;
|
||||
IMAGE_TLS_DIRECTORY TlsDirectory;
|
||||
PLDR_DATA_TABLE_ENTRY ModuleEntry;
|
||||
} TLS_ENTRY, * PTLS_ENTRY;
|
||||
|
||||
//0x10 bytes (sizeof)
|
||||
typedef struct _RTL_BITMAP {
|
||||
ULONG SizeOfBitMap; //0x0
|
||||
ULONG* Buffer; //0x8
|
||||
}RTL_BITMAP, * PRTL_BITMAP;
|
||||
|
||||
VOID RtlClearBit(
|
||||
PRTL_BITMAP BitMapHeader,
|
||||
ULONG BitNumber
|
||||
);
|
||||
|
||||
VOID RtlInitializeBitMap(
|
||||
PRTL_BITMAP BitMapHeader,
|
||||
PULONG BitMapBuffer,
|
||||
ULONG SizeOfBitMap
|
||||
);
|
||||
|
||||
ULONG RtlFindClearBitsAndSet(
|
||||
PRTL_BITMAP BitMapHeader,
|
||||
ULONG NumberToFind,
|
||||
ULONG HintIndex
|
||||
);
|
||||
|
||||
VOID RtlClearBits(
|
||||
PRTL_BITMAP BitMapHeader,
|
||||
ULONG StartingIndex,
|
||||
ULONG NumberToClear
|
||||
);
|
||||
|
||||
VOID RtlSetBit(
|
||||
PRTL_BITMAP BitMapHeader,
|
||||
ULONG BitNumber
|
||||
);
|
||||
|
||||
BOOLEAN RemoveEntryList(
|
||||
PLIST_ENTRY Entry
|
||||
);
|
||||
|
||||
VOID NTAPI RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock);
|
||||
VOID NTAPI RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock);
|
||||
|
||||
NTSTATUS NTAPI NtSetInformationProcess(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN ULONG ProcessInformationClass,
|
||||
IN PVOID ProcessInformation,
|
||||
IN ULONG ProcessInformationLength);
|
||||
|
||||
#define ProcessTlsInformation ProcessResourceManagement
|
||||
|
||||
PUCHAR NtdllBaseTag = 0;
|
||||
ULONG LdrpActiveThreadCount = 0;
|
||||
ULONG LdrpPotentialTlsLeaks = 0;
|
||||
RTL_BITMAP LdrpTlsBitmap;
|
||||
LIST_ENTRY LdrpTlsList;
|
||||
|
||||
TLS_RECLAIM_TABLE_ENTRY LdrpDelayedTlsReclaimTable[16];
|
||||
|
||||
ULONG LdrpStaticTlsBitmapVector[4];
|
||||
ULONG LdrpActualBitmapSize = 0;
|
||||
|
||||
|
||||
VOID LdrpInit() {
|
||||
RtlCopyMemory(&LdrpTlsBitmap, NtCurrentPeb()->TlsBitmap, sizeof(RTL_BITMAP));
|
||||
PROCESS_TLS_INFORMATION pti;
|
||||
|
||||
}
|
||||
|
||||
VOID LdrpReleaseTlsIndex(ULONG TlsIndex) {
|
||||
RtlClearBit(&LdrpTlsBitmap, TlsIndex);
|
||||
}
|
||||
|
||||
#define LDRP_BITMAP_INCREMENT (0x27 - sizeof( PVOID ))
|
||||
|
||||
NTSTATUS LdrpAcquireTlsIndex(PULONG TlsIndex, PBOOLEAN AllocatedBitmap) {
|
||||
ULONG Length;
|
||||
ULONG Index;
|
||||
PULONG NewBitmapBuffer;
|
||||
|
||||
Length = LdrpTlsBitmap.SizeOfBitMap;
|
||||
|
||||
if (Length == 0) {
|
||||
//
|
||||
// If we're the first caller, then we shall need to be initializing the
|
||||
// bitmap.
|
||||
//
|
||||
// This implies that we don't need to expand as by definition, there
|
||||
// shall exist space for ourselves at the start of the bitmap now.
|
||||
//
|
||||
RtlInitializeBitMap(&LdrpTlsBitmap, LdrpStaticTlsBitmapVector, 4);
|
||||
LdrpActualBitmapSize = 1;
|
||||
}
|
||||
else {
|
||||
Index = RtlFindClearBitsAndSet(&LdrpTlsBitmap, 1, 0);
|
||||
|
||||
//
|
||||
// If we found space in the existing bitmap then there is no reason to
|
||||
// expand buffers, so we'll just return with the existing data.
|
||||
//
|
||||
if (Index != 0xFFFFFFFF) {
|
||||
*TlsIndex = Index;
|
||||
*AllocatedBitmap = FALSE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if we need to grow the bitmap itself or if the bitmap still
|
||||
// has space.
|
||||
//
|
||||
if (((LdrpTlsBitmap.SizeOfBitMap + LDRP_BITMAP_INCREMENT) >> 5) > LdrpActualBitmapSize) {
|
||||
//
|
||||
// We'll need to grow it. Let's go do so now.
|
||||
//
|
||||
|
||||
//
|
||||
// BUG: We set the new size before checking the allocation. If we
|
||||
// fail, then we leave the TLS variables in an inconsistant state.
|
||||
//
|
||||
LdrpActualBitmapSize = (Length + LDRP_BITMAP_INCREMENT) >> 5;
|
||||
NewBitmapBuffer = (PULONG)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), LdrpActualBitmapSize);
|
||||
if (!NewBitmapBuffer) return STATUS_NO_MEMORY;
|
||||
|
||||
//
|
||||
// Copy the contents of the previous buffer into the new one.
|
||||
//
|
||||
RtlCopyMemory(NewBitmapBuffer, LdrpTlsBitmap.Buffer, Length + 7);
|
||||
|
||||
//
|
||||
// Free the old buffer if it wasn't the initial static buffer.
|
||||
//
|
||||
if (LdrpTlsBitmap.Buffer != LdrpStaticTlsBitmapVector) {
|
||||
RtlFreeHeap(GetProcessHeap(), 0, LdrpTlsBitmap.Buffer);
|
||||
}
|
||||
|
||||
//
|
||||
// Reinitialize the bitmap as we've changed the buffer pointer.
|
||||
//
|
||||
RtlInitializeBitMap(&LdrpTlsBitmap, NewBitmapBuffer, Length + 4);
|
||||
}
|
||||
else {
|
||||
LdrpTlsBitmap.SizeOfBitMap += 4;
|
||||
}
|
||||
}
|
||||
|
||||
RtlClearBits(&LdrpTlsBitmap, Length + 1, 3);
|
||||
RtlSetBit(&LdrpTlsBitmap, Length);
|
||||
|
||||
*TlsIndex = Index;
|
||||
*AllocatedBitmap = TRUE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS LdrpAllocateTlsEntry(PIMAGE_TLS_DIRECTORY TlsDirectory, PLDR_DATA_TABLE_ENTRY ModuleEntry, PULONG TlsIndex, PBOOLEAN AllocatedBitmap, PTLS_ENTRY* TlsEntry) {
|
||||
|
||||
PTLS_ENTRY Entry = nullptr;
|
||||
NTSTATUS Status;
|
||||
|
||||
__try {
|
||||
Entry = (PTLS_ENTRY)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), sizeof(TLS_ENTRY));
|
||||
if (!Entry) return STATUS_NO_MEMORY;
|
||||
Status = STATUS_SUCCESS;
|
||||
RtlCopyMemory(&Entry->TlsDirectory, TlsDirectory, sizeof(IMAGE_TLS_DIRECTORY));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
//
|
||||
// Also print string and complain.
|
||||
//
|
||||
Status = GetExceptionCode();
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
RtlFreeHeap(GetProcessHeap(), 0, Entry);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate that the TLS directory entry is sane.
|
||||
//
|
||||
if (Entry->TlsDirectory.StartAddressOfRawData < Entry->TlsDirectory.EndAddressOfRawData) {
|
||||
RtlFreeHeap(GetProcessHeap(), 0, Entry);
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
Entry->ModuleEntry = ModuleEntry;
|
||||
|
||||
//
|
||||
// Insert the entry into our list.
|
||||
//
|
||||
|
||||
InsertTailList(&LdrpTlsList, &Entry->TlsEntryLinks);
|
||||
if (AllocatedBitmap) {
|
||||
Status = LdrpAcquireTlsIndex(TlsIndex, AllocatedBitmap);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
//
|
||||
// BUG: We don't remove the entry from LdrpTlsList
|
||||
//
|
||||
RtlFreeHeap(GetProcessHeap(), 0, Entry);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*TlsIndex += 1;
|
||||
}
|
||||
|
||||
//
|
||||
// We reuse the 'Characteristics' field for the real TLS index.
|
||||
//
|
||||
Entry->TlsDirectory.Characteristics = *TlsIndex;
|
||||
__try {
|
||||
*(PULONG)Entry->TlsDirectory.AddressOfIndex = *TlsIndex;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
Status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
if (AllocatedBitmap) {
|
||||
LdrpReleaseTlsIndex(*TlsIndex);
|
||||
if (*AllocatedBitmap) LdrpTlsBitmap.SizeOfBitMap -= 4;
|
||||
}
|
||||
|
||||
//
|
||||
// BUG: We don't remove the entry from LdrpTlsList
|
||||
//
|
||||
RtlFreeHeap(GetProcessHeap(), 0, Entry);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (TlsEntry) *TlsEntry = Entry;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
PTLS_ENTRY __fastcall LdrpFindTlsEntry(PLDR_DATA_TABLE_ENTRY ModuleEntry) {
|
||||
PTLS_ENTRY TlsEntry;
|
||||
PLIST_ENTRY ListHead;
|
||||
|
||||
ListHead = &LdrpTlsList;
|
||||
|
||||
for (TlsEntry = CONTAINING_RECORD(LdrpTlsList.Flink, TLS_ENTRY, TlsEntryLinks);
|
||||
&TlsEntry->TlsEntryLinks != ListHead;
|
||||
TlsEntry = CONTAINING_RECORD(TlsEntry->TlsEntryLinks.Flink, TLS_ENTRY, TlsEntryLinks)) {
|
||||
|
||||
if (TlsEntry->ModuleEntry == ModuleEntry) return TlsEntry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NTSTATUS LdrpReleaseTlsEntry(PLDR_DATA_TABLE_ENTRY ModuleEntry) {
|
||||
PTLS_ENTRY TlsEntry;
|
||||
|
||||
//
|
||||
// Find the corresponding TLS_ENTRY for this module entry.
|
||||
//
|
||||
TlsEntry = LdrpFindTlsEntry(ModuleEntry);
|
||||
if (!TlsEntry) return STATUS_NOT_FOUND;
|
||||
|
||||
//
|
||||
// Remove it from the global list of outstanding TLS entries.
|
||||
//
|
||||
RemoveEntryList(&TlsEntry->TlsEntryLinks);
|
||||
|
||||
//
|
||||
// Deallocate the TLS index.
|
||||
//
|
||||
LdrpReleaseTlsIndex(TlsEntry->TlsDirectory.Characteristics);
|
||||
|
||||
//
|
||||
// Deallocate the TLS_ENTRY object itself.
|
||||
//
|
||||
RtlFreeHeap(GetProcessHeap(), 0, TlsEntry);
|
||||
|
||||
//
|
||||
// We're done.
|
||||
//
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
PVOID* __fastcall LdrpGetNewTlsVector(ULONG TlsBitmapLength) {
|
||||
PTLS_VECTOR TlsVector;
|
||||
|
||||
TlsVector = (PTLS_VECTOR)RtlAllocateHeap(GetProcessHeap(), (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000),
|
||||
sizeof(TLS_VECTOR) + (sizeof(PVOID) * TlsBitmapLength) - sizeof(PVOID));
|
||||
if (!TlsVector) return 0;
|
||||
TlsVector->Length = TlsBitmapLength;
|
||||
RtlZeroMemory(TlsVector->ModuleTlsData, TlsBitmapLength * sizeof(PVOID));
|
||||
return TlsVector->ModuleTlsData;
|
||||
}
|
||||
|
||||
VOID LdrpQueueDeferredTlsData(PVOID TlsVector, PVOID ThreadId) {
|
||||
PTLS_VECTOR RealTlsVector;
|
||||
PTLS_RECLAIM_TABLE_ENTRY ReclaimEntry;
|
||||
|
||||
RealTlsVector = CONTAINING_RECORD(TlsVector, TLS_VECTOR, ModuleTlsData);
|
||||
|
||||
RealTlsVector->ThreadId = ThreadId;
|
||||
|
||||
ReclaimEntry = &LdrpDelayedTlsReclaimTable[((ULONG_PTR)(ThreadId) >> 2) & 0xF];
|
||||
|
||||
RtlAcquireSRWLockExclusive(&ReclaimEntry->Lock);
|
||||
|
||||
RealTlsVector->PreviousDeferredTlsVector = ReclaimEntry->TlsVector;
|
||||
ReclaimEntry->TlsVector = RealTlsVector;
|
||||
|
||||
RtlReleaseSRWLockExclusive(&ReclaimEntry->Lock);
|
||||
}
|
||||
|
||||
#define SIZEOF_TLS_INFO(_ThreadCount_) (_ThreadCount_==0)?sizeof(PROCESS_TLS_INFORMATION)-sizeof(THREAD_TLS_INFORMATION):(_ThreadCount_-1)*sizeof(THREAD_TLS_INFORMATION)+sizeof(PROCESS_TLS_INFORMATION)
|
||||
NTSTATUS LdrpHandleTlsData(PLDR_DATA_TABLE_ENTRY ModuleEntry) {
|
||||
PIMAGE_TLS_DIRECTORY TlsDirectory;
|
||||
ULONG DirectorySize;
|
||||
ULONG TlsIndex;
|
||||
HANDLE Heap;
|
||||
PPROCESS_TLS_INFORMATION TlsInfo;
|
||||
PROCESS_TLS_INFORMATION OneThreadTlsInfo;
|
||||
NTSTATUS Status;
|
||||
BOOLEAN AllocatedBitmap;
|
||||
PTLS_ENTRY TlsEntry;
|
||||
ULONG TlsBitmapLength;
|
||||
SIZE_T TlsRawDataLength;
|
||||
ULONG ThreadIndex;
|
||||
PVOID TlsData = nullptr;
|
||||
PVOID* TlsVector;
|
||||
PTHREAD_TLS_INFORMATION ThreadTlsData;
|
||||
ULONG ThreadsCleanedUp;
|
||||
|
||||
if (LdrpActiveThreadCount == 0) return STATUS_SUCCESS;
|
||||
TlsDirectory = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(ModuleEntry->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &DirectorySize);
|
||||
if (!TlsDirectory) return STATUS_SUCCESS;
|
||||
Heap = NtCurrentPeb()->ProcessHeap;
|
||||
|
||||
TlsInfo = LdrpActiveThreadCount == 1 ? &OneThreadTlsInfo :
|
||||
(decltype(TlsInfo))RtlAllocateHeap(Heap, (ULONG)NtdllBaseTag + 0x000C0000, SIZEOF_TLS_INFO(LdrpActiveThreadCount));
|
||||
if (!TlsInfo) return STATUS_NO_MEMORY;
|
||||
|
||||
do {
|
||||
TlsBitmapLength = LdrpTlsBitmap.SizeOfBitMap;
|
||||
Status = LdrpAllocateTlsEntry(TlsDirectory, ModuleEntry, &TlsIndex, &AllocatedBitmap, &TlsEntry);
|
||||
if (!NT_SUCCESS(Status)) break;
|
||||
TlsInfo->ThreadDataCount = LdrpActiveThreadCount;
|
||||
if (AllocatedBitmap) {
|
||||
TlsInfo->OperationType = ProcessTlsReplaceVector;
|
||||
TlsInfo->TlsVectorLength = TlsBitmapLength;
|
||||
TlsBitmapLength = LdrpTlsBitmap.SizeOfBitMap;
|
||||
}
|
||||
else {
|
||||
TlsInfo->OperationType = ProcessTlsReplaceIndex;
|
||||
TlsInfo->TlsIndex = TlsIndex;
|
||||
}
|
||||
Status = STATUS_SUCCESS;
|
||||
ThreadsCleanedUp = 0;
|
||||
|
||||
//
|
||||
// Calculate the size of the raw TLS data for this module.
|
||||
//
|
||||
TlsRawDataLength = TlsEntry->TlsDirectory.EndAddressOfRawData - TlsEntry->TlsDirectory.StartAddressOfRawData;
|
||||
|
||||
//
|
||||
// Prepare data for each running thread.
|
||||
//
|
||||
for (ThreadIndex = 0; ThreadIndex < TlsInfo->ThreadDataCount; ++ThreadIndex) {
|
||||
TlsData = RtlAllocateHeap(Heap, (ULONG_PTR)((PUCHAR)NtdllBaseTag + 0x000C0000), TlsRawDataLength);
|
||||
if (!TlsData) {
|
||||
Status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
__try {
|
||||
RtlCopyMemory(TlsData, (PVOID)TlsEntry->TlsDirectory.StartAddressOfRawData, TlsRawDataLength);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
Status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
RtlFreeHeap(Heap, 0, TlsData);
|
||||
break;
|
||||
}
|
||||
|
||||
if (AllocatedBitmap) {
|
||||
TlsVector = LdrpGetNewTlsVector(TlsBitmapLength);
|
||||
if (!TlsVector) {
|
||||
RtlFreeHeap(Heap, 0, TlsData);
|
||||
break;
|
||||
}
|
||||
TlsVector[TlsIndex] = TlsData;
|
||||
TlsInfo->ThreadData[ThreadIndex].TlsVector = TlsVector;
|
||||
}
|
||||
else {
|
||||
TlsInfo->ThreadData[ThreadIndex].TlsModulePointer = TlsData;
|
||||
}
|
||||
|
||||
TlsInfo->ThreadData[ThreadIndex].Flags = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// This is awkward; all the 'break' above really are either goto or
|
||||
// __leave, but we aren't using those. This is really supposed to
|
||||
// just happen on normal for loop exit.
|
||||
//
|
||||
if (ThreadIndex == TlsInfo->ThreadDataCount) {
|
||||
TlsInfo->Reserved = 0;
|
||||
Status = NtSetInformationProcess(GetCurrentProcess(), ProcessTlsInformation, TlsInfo,
|
||||
TlsInfo->ThreadDataCount * sizeof(THREAD_TLS_INFORMATION) + sizeof(PROCESS_TLS_INFORMATION) - sizeof(THREAD_TLS_INFORMATION));
|
||||
}
|
||||
|
||||
//
|
||||
// Let's handle each thread that we replaced, as the
|
||||
// ProcessTlsInformation call fills our buffer with the old data
|
||||
// after performing a swap.
|
||||
//
|
||||
for (ThreadTlsData = &TlsInfo->ThreadData[ThreadIndex]; ThreadIndex > 0;) {
|
||||
ThreadIndex -= 1;
|
||||
ThreadTlsData -= 1;
|
||||
|
||||
if (ThreadTlsData->Flags & 0x2) {
|
||||
if (!ThreadTlsData->TlsVector) continue;
|
||||
|
||||
if (!AllocatedBitmap) {
|
||||
RtlFreeHeap(Heap, 0, ThreadTlsData->TlsVector);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
LdrpQueueDeferredTlsData(ThreadTlsData->TlsVector, ThreadTlsData->ThreadId);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ThreadTlsData->Flags & 0x1) {
|
||||
++LdrpPotentialTlsLeaks;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
++ThreadsCleanedUp;
|
||||
if (AllocatedBitmap) {
|
||||
TlsData = ThreadTlsData->TlsVector[TlsIndex];
|
||||
RtlFreeHeap(Heap, 0, CONTAINING_RECORD(ThreadTlsData->TlsVector, TLS_VECTOR, ModuleTlsData));
|
||||
}
|
||||
RtlFreeHeap(Heap, 0, TlsData);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
LdrpReleaseTlsEntry(ModuleEntry);
|
||||
if (AllocatedBitmap) LdrpTlsBitmap.SizeOfBitMap -= 4;
|
||||
}
|
||||
else if (ThreadsCleanedUp > 0) {
|
||||
LdrpActiveThreadCount -= ThreadsCleanedUp;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (TlsInfo != &OneThreadTlsInfo) RtlFreeHeap(Heap, 0, TlsInfo);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
ModuleEntry->TlsIndex = 0xFFFF;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//struct UNKNOWN {
|
||||
// PVOID unknown1; //+0x0
|
||||
// PVOID unknown2; //+0x8
|
||||
// PVOID unknown3; //+0x10
|
||||
// struct {
|
||||
// DWORD dwFlags; //+0x14
|
||||
// DWORD unknown4; //+0x18
|
||||
// };
|
||||
// PWSTR DllName; //+0x20
|
||||
// PVOID unknown[11];
|
||||
//};
|
||||
//
|
||||
////#include "../MemoryModule/Native.h"
|
||||
//
|
||||
////size = 0xC0 + DllName->Length + sizeof(wchar_t)
|
||||
//typedef struct _ALLOCATE_ENTRY_PARAMETER {
|
||||
// UNICODE_STRING DllName; //+0x0
|
||||
// UNKNOWN* unknown_structure; //+0x10
|
||||
// PVOID reserved1; //+0x18
|
||||
// struct {
|
||||
// DWORD ProcessStatus; //+0x20
|
||||
// DWORD reserved2; //+0x24
|
||||
// };
|
||||
// PVOID reserved3; //+0x28
|
||||
// PVOID reserved4; //+0x30
|
||||
// PVOID LdrEntry; //+0x38
|
||||
// PVOID reserved[16]; //+0x40
|
||||
// BYTE UnicodeStringBuffer[1]; //+0xC0
|
||||
//}ALLOCATE_ENTRY_PARAMETER, * PALLOCATE_ENTRY_PARAMETER;
|
||||
|
||||
};
|
||||
struct EHRegistrationNode {
|
||||
/* void * stackPtr */ // Stack ptr at entry to try (below address point)
|
||||
EHRegistrationNode* pNext; // Next node in the chain
|
||||
void* frameHandler; // The handler function for this frame
|
||||
int state; // The current state of this function
|
||||
};
|
||||
|
||||
+96
-22
@@ -1,10 +1,16 @@
|
||||
#include "../MemoryModule/NativeFunctionsInternal.h"
|
||||
//#include "../MemoryModule/LoadDllMemoryApi.h"
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
#endif
|
||||
#include <cstdio>
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
int main() {
|
||||
//GetProcAddress(LoadLibraryA("a.dll"), "thread")();
|
||||
LPVOID buffer;
|
||||
size_t size;
|
||||
FILE* f = fopen("d.dll", "rb");
|
||||
FILE* f = fopen("a.dll", "rb");
|
||||
if (!f)return 0;
|
||||
_fseeki64(f, 0, SEEK_END);
|
||||
if (!(size = _ftelli64(f))) {
|
||||
@@ -23,37 +29,105 @@ int main() {
|
||||
_exception exception = nullptr;
|
||||
|
||||
if (!NT_SUCCESS(NtLoadDllMemoryExW(&m1, nullptr, 0, buffer, size, L"kernel64", nullptr))) goto end;
|
||||
if (!NT_SUCCESS(NtLoadDllMemoryExW(&_m1, nullptr, 0, buffer, size, L"kernel64.dll", nullptr))) goto end;
|
||||
if (!NT_SUCCESS(NtLoadDllMemoryExW(&m2, nullptr, 0, buffer, size, L"kernel128.dll", L"\\?\\kernel512.dll"))) goto end;
|
||||
//if (!NT_SUCCESS(NtLoadDllMemoryExW(&_m1, nullptr, 0, buffer, size, L"kernel64.dll", nullptr))) goto end;
|
||||
//if (!NT_SUCCESS(NtLoadDllMemoryExW(&m2, nullptr, 0, buffer, size, L"kernel128.dll", L"\\?\\kernel512.dll"))) goto end;
|
||||
|
||||
char t[100];
|
||||
LoadStringA((HINSTANCE)m1, 101, t, 100);
|
||||
printf("%s\n", t);
|
||||
|
||||
hModule = GetModuleHandleA("kernel64.dll");
|
||||
GetModuleFileNameA(hModule, name, MAX_PATH);
|
||||
if (hModule)test = GetProcAddress(hModule, "test");
|
||||
if (hModule)test = GetProcAddress(hModule, "thread");
|
||||
printf("m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m1, hModule, name, test);
|
||||
if (test)test();
|
||||
if (test) test();
|
||||
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)test, &hModule);
|
||||
GetModuleFileNameA(hModule, name, MAX_PATH);
|
||||
test = GetProcAddress(hModule, "test");
|
||||
printf("_m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", _m1, hModule, name, test);
|
||||
if (test)test();
|
||||
//GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR)test, &hModule);
|
||||
//GetModuleFileNameA(hModule, name, MAX_PATH);
|
||||
//test = GetProcAddress(hModule, "test");
|
||||
//printf("_m1:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", _m1, hModule, name, test);
|
||||
//if (test)test();
|
||||
|
||||
hModule = GetModuleHandleA("kernel128");
|
||||
GetModuleFileNameA(hModule, name, MAX_PATH);
|
||||
if (hModule)exception = (_exception)GetProcAddress(hModule, "exception");
|
||||
printf("m2:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m2, hModule, name, test);
|
||||
if (exception) {
|
||||
exception(0);
|
||||
exception(1);
|
||||
exception(2);
|
||||
exception(3);
|
||||
}
|
||||
//hModule = GetModuleHandleA("kernel128");
|
||||
//GetModuleFileNameA(hModule, name, MAX_PATH);
|
||||
//if (hModule)exception = (_exception)GetProcAddress(hModule, "exception");
|
||||
//printf("m2:\n\tHMEMORYMODULE\t= 0x%p\n\tHMODULE\t\t= 0x%p\n\tModuleFileName\t= %s\n\ttest\t\t= 0x%p\n\n", m2, hModule, name, test);
|
||||
//if (exception) {
|
||||
// exception(0);
|
||||
// exception(1);
|
||||
// exception(2);
|
||||
// exception(3);
|
||||
//}
|
||||
|
||||
end:
|
||||
delete[]buffer;
|
||||
if (m1)NtUnloadDllMemory(m1);
|
||||
if (_m1)NtUnloadDllMemory(_m1);
|
||||
if (m2)NtUnloadDllMemory(m2);
|
||||
//if (_m1)NtUnloadDllMemory(_m1);
|
||||
//if (m2)NtUnloadDllMemory(m2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//#include <cstdio>
|
||||
//#include "../MemoryModule/NativeFunctionsInternal.h"
|
||||
//
|
||||
//bool c;
|
||||
//static thread_local int x = -1;
|
||||
//
|
||||
//DWORD WINAPI Thread(PVOID) {
|
||||
// printf("[1] x = %d\n", x);
|
||||
// x = 0;
|
||||
// c = true;
|
||||
// while (c)Sleep(100);
|
||||
// return x;
|
||||
//}
|
||||
//
|
||||
//int main() {
|
||||
// x = 1;
|
||||
// c = false;
|
||||
// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr);
|
||||
// DWORD ex = 0;
|
||||
// if (hThread) {
|
||||
// while (!c)Sleep(100);
|
||||
// printf("[0] x = %d\n", x);
|
||||
// c = false;
|
||||
// WaitForSingleObject(hThread, 0xffffffff);
|
||||
// GetExitCodeThread(hThread, &ex);
|
||||
// CloseHandle(hThread);
|
||||
// printf("[0] Exit = %d\n", ex);
|
||||
// }
|
||||
//
|
||||
// PLIST_ENTRY entry = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
// PLDR_DATA_TABLE_ENTRY_WIN7 data = nullptr;
|
||||
//
|
||||
// while (entry != entry->Flink) {
|
||||
// entry = entry->Flink;
|
||||
// data = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY_WIN7, InLoadOrderLinks);
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
//#include "../MemoryModule/Native.h"
|
||||
//#include <cstdio>
|
||||
//
|
||||
//static thread_local int x = 0xffccffdd;
|
||||
//
|
||||
//DWORD WINAPI Thread(PVOID) {
|
||||
// printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
// return x == 0xffccffdd ? 0 : 1;
|
||||
//}
|
||||
//
|
||||
//int main() {
|
||||
// x = 2;
|
||||
// printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr);
|
||||
// DWORD ret = -1;
|
||||
// if (hThread) {
|
||||
// WaitForSingleObject(hThread, 0xffffffff);
|
||||
// GetExitCodeThread(hThread, &ret);
|
||||
// CloseHandle(hThread);
|
||||
// return ret;
|
||||
// }
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user