mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
add hooks for .net
This commit is contained in:
@@ -64,7 +64,8 @@ static SYSTEM_INFO sysInfo = []()->SYSTEM_INFO {
|
||||
|
||||
NTSTATUS MemoryLoadLibrary(
|
||||
_Out_ HMEMORYMODULE* MemoryModuleHandle,
|
||||
_In_ LPCVOID data) {
|
||||
_In_ LPCVOID data,
|
||||
_In_ DWORD size) {
|
||||
|
||||
PIMAGE_DOS_HEADER dos_header = nullptr;
|
||||
PIMAGE_NT_HEADERS old_header = nullptr;
|
||||
@@ -122,7 +123,7 @@ NTSTATUS MemoryLoadLibrary(
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(status)) return status;
|
||||
if (!NT_SUCCESS(status) || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)return status;
|
||||
|
||||
//
|
||||
// Reserve the address range of image
|
||||
@@ -178,9 +179,10 @@ NTSTATUS MemoryLoadLibrary(
|
||||
PMEMORYMODULE hMemoryModule = (PMEMORYMODULE)(base + old_header->OptionalHeader.SizeOfHeaders);
|
||||
RtlZeroMemory(hMemoryModule, sizeof(MEMORYMODULE));
|
||||
hMemoryModule->codeBase = base;
|
||||
hMemoryModule->pageSize = sysInfo.dwPageSize;
|
||||
hMemoryModule->dwImageFileSize = size;
|
||||
hMemoryModule->Signature = MEMORY_MODULE_SIGNATURE;
|
||||
hMemoryModule->SizeofHeaders = old_header->OptionalHeader.SizeOfHeaders;
|
||||
hMemoryModule->lpReserved = (LPVOID)data;
|
||||
|
||||
do {
|
||||
//
|
||||
|
||||
@@ -52,7 +52,7 @@ typedef struct _MEMORYMODULE {
|
||||
DWORD dwModulesCount; //number of module handles
|
||||
DWORD dwReserved;
|
||||
|
||||
DWORD pageSize; //SYSTEM_INFO::dwPageSize
|
||||
DWORD dwImageFileSize;
|
||||
DWORD headers_align; //headers_align == OptionalHeaders.BaseOfCode;
|
||||
|
||||
} MEMORYMODULE, * PMEMORYMODULE;
|
||||
@@ -66,7 +66,8 @@ extern "C" {
|
||||
|
||||
NTSTATUS MemoryLoadLibrary(
|
||||
_Out_ HMEMORYMODULE* MemoryModuleHandle,
|
||||
_In_ LPCVOID data
|
||||
_In_ LPCVOID data,
|
||||
_In_ DWORD size
|
||||
);
|
||||
|
||||
bool MemoryFreeLibrary(HMEMORYMODULE);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<ClCompile Include="..\3rdparty\Detours\modules.cpp" />
|
||||
<ClCompile Include="LoadDllMemoryApi.cpp" />
|
||||
<ClCompile Include="MemoryModule.cpp" />
|
||||
<ClCompile Include="MmpDotNet.cpp" />
|
||||
<ClCompile Include="MmpTls.cpp" />
|
||||
<ClCompile Include="Native.cpp" />
|
||||
<ClCompile Include="NativeFunctionsInternal.cpp" />
|
||||
@@ -45,6 +46,7 @@
|
||||
<ClInclude Include="..\3rdparty\Detours\detver.h" />
|
||||
<ClInclude Include="LoadDllMemoryApi.h" />
|
||||
<ClInclude Include="MemoryModule.h" />
|
||||
<ClInclude Include="MmpDotNet.h" />
|
||||
<ClInclude Include="Native.h" />
|
||||
<ClInclude Include="NativeFunctionsInternal.h" />
|
||||
<ClInclude Include="rtlinv.h" />
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
<ClCompile Include="..\3rdparty\Detours\modules.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MmpDotNet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryModule.h">
|
||||
@@ -125,6 +128,9 @@
|
||||
<ClInclude Include="..\3rdparty\Detours\detver.h">
|
||||
<Filter>Header Files\3rdparty\Detours</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MmpDotNet.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md">
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
#include "stdafx.h"
|
||||
#include <3rdparty/Detours/detours.h>
|
||||
|
||||
typedef HRESULT (WINAPI* GetFileVersion_T)(
|
||||
LPCWSTR szFilename,
|
||||
LPWSTR szBuffer,
|
||||
DWORD cchBuffer,
|
||||
DWORD* dwLength
|
||||
);
|
||||
|
||||
typedef struct _MMP_FAKE_HANDLE_LIST_ENTRY {
|
||||
LIST_ENTRY InMmpFakeHandleList;
|
||||
HANDLE hObject;
|
||||
PVOID value;
|
||||
}MMP_FAKE_HANDLE_LIST_ENTRY, * PMMP_FAKE_HANDLE_LIST_ENTRY;
|
||||
|
||||
static decltype(&CreateFileW) OriginCreateFileW = CreateFileW;
|
||||
static decltype(&GetFileInformationByHandle) OriginGetFileInformationByHandle = GetFileInformationByHandle;
|
||||
static decltype(&GetFileAttributesExW) OriginGetFileAttributesExW = GetFileAttributesExW;
|
||||
static decltype(&CreateFileMappingW) OriginCreateFileMappingW = CreateFileMappingW;
|
||||
static decltype(&MapViewOfFileEx) OriginMapViewOfFileEx = MapViewOfFileEx;
|
||||
static decltype(&UnmapViewOfFile)OriginUnmapViewOfFile = UnmapViewOfFile;
|
||||
static decltype(&CloseHandle)OriginCloseHandle = CloseHandle;
|
||||
static GetFileVersion_T OriginGetFileVersion = nullptr;
|
||||
|
||||
FILETIME AssemblyTimes;
|
||||
|
||||
CRITICAL_SECTION MmpFakeHandleListLock;
|
||||
LIST_ENTRY MmpFakeHandleListHead;
|
||||
|
||||
static BOOL Initialized = FALSE;
|
||||
|
||||
BOOL MmpIsMemoryModuleFileName(
|
||||
_In_ LPCWSTR lpFileName,
|
||||
_Out_opt_ PLDR_DATA_TABLE_ENTRY *LdrEntry) {
|
||||
|
||||
__try {
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL result = FALSE;
|
||||
|
||||
EnterCriticalSection(NtCurrentPeb()->LoaderLock);
|
||||
for (auto entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
|
||||
entry != &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
|
||||
entry = entry->Flink) {
|
||||
|
||||
PLDR_DATA_TABLE_ENTRY CurEntry = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InLoadOrderLinks);
|
||||
if (!wcsncmp(CurEntry->FullDllName.Buffer, lpFileName, CurEntry->FullDllName.Length) &&
|
||||
wcslen(lpFileName) * 2 == CurEntry->FullDllName.Length) {
|
||||
result = IsValidMemoryModuleHandle((HMODULE)CurEntry->DllBase);
|
||||
if (result) {
|
||||
if (LdrEntry) {
|
||||
__try {
|
||||
*LdrEntry = CurEntry;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
LeaveCriticalSection(NtCurrentPeb()->LoaderLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID MmpInsertHandleEntry(
|
||||
_In_ HANDLE hObject,
|
||||
_In_ PVOID value) {
|
||||
auto entry = (PMMP_FAKE_HANDLE_LIST_ENTRY)RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(MMP_FAKE_HANDLE_LIST_ENTRY));
|
||||
entry->hObject = hObject;
|
||||
entry->value = value;
|
||||
|
||||
EnterCriticalSection(&MmpFakeHandleListLock);
|
||||
InsertTailList(&MmpFakeHandleListHead, &entry->InMmpFakeHandleList);
|
||||
LeaveCriticalSection(&MmpFakeHandleListLock);
|
||||
}
|
||||
|
||||
PMMP_FAKE_HANDLE_LIST_ENTRY MmpFindHandleEntry(HANDLE hObject) {
|
||||
|
||||
PMMP_FAKE_HANDLE_LIST_ENTRY result = nullptr;
|
||||
EnterCriticalSection(&MmpFakeHandleListLock);
|
||||
|
||||
for (auto entry = MmpFakeHandleListHead.Flink; entry != &MmpFakeHandleListHead; entry = entry->Flink) {
|
||||
auto CurEntry = CONTAINING_RECORD(entry, MMP_FAKE_HANDLE_LIST_ENTRY, MMP_FAKE_HANDLE_LIST_ENTRY::InMmpFakeHandleList);
|
||||
|
||||
if (CurEntry->hObject == hObject) {
|
||||
result = CurEntry;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&MmpFakeHandleListLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID MmpFreeHandleEntry(PMMP_FAKE_HANDLE_LIST_ENTRY lpHandleEntry) {
|
||||
EnterCriticalSection(&MmpFakeHandleListLock);
|
||||
RemoveEntryList(&lpHandleEntry->InMmpFakeHandleList);
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, lpHandleEntry);
|
||||
LeaveCriticalSection(&MmpFakeHandleListLock);
|
||||
}
|
||||
|
||||
HANDLE WINAPI HookCreateFileW(
|
||||
_In_ LPCWSTR lpFileName,
|
||||
_In_ DWORD dwDesiredAccess,
|
||||
_In_ DWORD dwShareMode,
|
||||
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
_In_ DWORD dwCreationDisposition,
|
||||
_In_ DWORD dwFlagsAndAttributes,
|
||||
_In_opt_ HANDLE hTemplateFile) {
|
||||
|
||||
PLDR_DATA_TABLE_ENTRY entry;
|
||||
if (MmpIsMemoryModuleFileName(lpFileName, &entry)) {
|
||||
HANDLE hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
MmpInsertHandleEntry(hEvent, entry);
|
||||
return hEvent;
|
||||
}
|
||||
|
||||
return OriginCreateFileW(
|
||||
lpFileName,
|
||||
dwDesiredAccess,
|
||||
dwShareMode,
|
||||
lpSecurityAttributes,
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
hTemplateFile
|
||||
);
|
||||
}
|
||||
|
||||
BOOL WINAPI HookGetFileInformationByHandle(
|
||||
_In_ HANDLE hFile,
|
||||
_Out_ LPBY_HANDLE_FILE_INFORMATION lpFileInformation) {
|
||||
auto iter = MmpFindHandleEntry(hFile);
|
||||
if (iter) {
|
||||
RtlZeroMemory(lpFileInformation, sizeof(BY_HANDLE_FILE_INFORMATION));
|
||||
|
||||
auto entry = (PLDR_DATA_TABLE_ENTRY)iter->value;
|
||||
auto module = MapMemoryModuleHandle((HMEMORYMODULE)entry->DllBase);
|
||||
|
||||
lpFileInformation->ftCreationTime = lpFileInformation->ftLastAccessTime = lpFileInformation->ftLastWriteTime = AssemblyTimes;
|
||||
lpFileInformation->nFileSizeLow = module->dwImageFileSize;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return OriginGetFileInformationByHandle(
|
||||
hFile,
|
||||
lpFileInformation
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI HookGetFileAttributesExW(
|
||||
_In_ LPCWSTR lpFileName,
|
||||
_In_ GET_FILEEX_INFO_LEVELS fInfoLevelId,
|
||||
_Out_writes_bytes_(sizeof(WIN32_FILE_ATTRIBUTE_DATA)) LPVOID lpFileInformation) {
|
||||
|
||||
PLDR_DATA_TABLE_ENTRY entry;
|
||||
if (MmpIsMemoryModuleFileName(lpFileName, &entry)) {
|
||||
__try {
|
||||
RtlZeroMemory(
|
||||
lpFileInformation,
|
||||
sizeof(WIN32_FILE_ATTRIBUTE_DATA)
|
||||
);
|
||||
|
||||
LPWIN32_FILE_ATTRIBUTE_DATA data = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
|
||||
auto module = MapMemoryModuleHandle((HMEMORYMODULE)entry->DllBase);
|
||||
|
||||
data->ftCreationTime = data->ftLastAccessTime = data->ftLastWriteTime = AssemblyTimes;
|
||||
data->nFileSizeLow = module->dwImageFileSize;
|
||||
return TRUE;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return OriginGetFileAttributesExW(
|
||||
lpFileName,
|
||||
fInfoLevelId,
|
||||
lpFileInformation
|
||||
);
|
||||
}
|
||||
|
||||
HANDLE WINAPI HookCreateFileMappingW(
|
||||
_In_ HANDLE hFile,
|
||||
_In_opt_ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
|
||||
_In_ DWORD flProtect,
|
||||
_In_ DWORD dwMaximumSizeHigh,
|
||||
_In_ DWORD dwMaximumSizeLow,
|
||||
_In_opt_ LPCWSTR lpName) {
|
||||
|
||||
auto iter = MmpFindHandleEntry(hFile);
|
||||
if (iter) {
|
||||
HANDLE hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
|
||||
MmpInsertHandleEntry(hEvent, iter->value);
|
||||
return hEvent;
|
||||
}
|
||||
|
||||
return OriginCreateFileMappingW(
|
||||
hFile,
|
||||
lpFileMappingAttributes,
|
||||
flProtect,
|
||||
dwMaximumSizeHigh,
|
||||
dwMaximumSizeLow,
|
||||
lpName
|
||||
);
|
||||
}
|
||||
|
||||
LPVOID WINAPI HookMapViewOfFileEx(
|
||||
_In_ HANDLE hFileMappingObject,
|
||||
_In_ DWORD dwDesiredAccess,
|
||||
_In_ DWORD dwFileOffsetHigh,
|
||||
_In_ DWORD dwFileOffsetLow,
|
||||
_In_ SIZE_T dwNumberOfBytesToMap,
|
||||
_In_opt_ LPVOID lpBaseAddress) {
|
||||
|
||||
auto iter = MmpFindHandleEntry(hFileMappingObject);
|
||||
if (iter) {
|
||||
HMEMORYMODULE hModule = nullptr;
|
||||
auto entry = (PLDR_DATA_TABLE_ENTRY)iter->value;
|
||||
auto pModule = MapMemoryModuleHandle((HMEMORYMODULE)entry->DllBase);
|
||||
if (pModule) {
|
||||
MemoryLoadLibrary(&hModule, pModule->lpReserved, pModule->dwImageFileSize);
|
||||
|
||||
if (hModule) MmpInsertHandleEntry(hModule, hModule);
|
||||
}
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
return OriginMapViewOfFileEx(
|
||||
hFileMappingObject,
|
||||
dwDesiredAccess,
|
||||
dwFileOffsetHigh,
|
||||
dwFileOffsetLow,
|
||||
dwNumberOfBytesToMap,
|
||||
lpBaseAddress
|
||||
);
|
||||
}
|
||||
|
||||
BOOL WINAPI HookUnmapViewOfFile(_In_ LPCVOID lpBaseAddress) {
|
||||
auto iter = MmpFindHandleEntry((HANDLE)lpBaseAddress);
|
||||
if (iter) {
|
||||
MemoryFreeLibrary((HMEMORYMODULE)lpBaseAddress);
|
||||
MmpFreeHandleEntry(iter);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return OriginUnmapViewOfFile(lpBaseAddress);
|
||||
}
|
||||
|
||||
BOOL WINAPI HookCloseHandle(_In_ _Post_ptr_invalid_ HANDLE hObject) {
|
||||
auto iter = MmpFindHandleEntry(hObject);
|
||||
if (iter)MmpFreeHandleEntry(iter);
|
||||
|
||||
return OriginCloseHandle(hObject);
|
||||
}
|
||||
|
||||
HRESULT WINAPI HookGetFileVersion(
|
||||
LPCWSTR szFilename,
|
||||
LPWSTR szBuffer,
|
||||
DWORD cchBuffer,
|
||||
DWORD* dwLength) {
|
||||
|
||||
typedef struct _COR20_METADATA {
|
||||
DWORD Signature;
|
||||
WORD MajorVersion;
|
||||
WORD MinorVersion;
|
||||
DWORD Reserved;
|
||||
DWORD VersionLength;
|
||||
CHAR VersionString[ANYSIZE_ARRAY];
|
||||
}COR20_METADATA, * PCOR20_METADATA;
|
||||
|
||||
PLDR_DATA_TABLE_ENTRY entry = nullptr;
|
||||
|
||||
if (MmpIsMemoryModuleFileName(szFilename, &entry)) {
|
||||
|
||||
__try {
|
||||
PIMAGE_NT_HEADERS headers = RtlImageNtHeader(entry->DllBase);
|
||||
auto dir = headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
|
||||
if (!dir.Size || !dir.VirtualAddress)__leave;
|
||||
|
||||
PIMAGE_COR20_HEADER cor2 = PIMAGE_COR20_HEADER(LPBYTE(entry->DllBase) + dir.VirtualAddress);
|
||||
if (!cor2->MetaData.Size || !cor2->MetaData.VirtualAddress) __leave;
|
||||
|
||||
PCOR20_METADATA meta = PCOR20_METADATA(LPBYTE(entry->DllBase) + cor2->MetaData.VirtualAddress);
|
||||
if (dwLength)*dwLength = meta->VersionLength;
|
||||
if (cchBuffer < meta->VersionLength)return 0x8007007A;
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, meta->VersionString, meta->VersionLength, szBuffer, cchBuffer);
|
||||
return 0;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return OriginGetFileVersion(
|
||||
szFilename,
|
||||
szBuffer,
|
||||
cchBuffer,
|
||||
dwLength
|
||||
);
|
||||
}
|
||||
|
||||
BOOL WINAPI MmpInitializeHooksForDotNet() {
|
||||
HMODULE hModule = GetModuleHandleW(L"mscoreei.dll");
|
||||
if (!hModule) {
|
||||
RtlRaiseStatus(STATUS_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
OriginGetFileVersion = (GetFileVersion_T)GetProcAddress(hModule, "GetFileVersion");
|
||||
if (!OriginGetFileVersion) {
|
||||
RtlRaiseStatus(STATUS_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GetSystemTimeAsFileTime(&AssemblyTimes);
|
||||
|
||||
EnterCriticalSection(NtCurrentPeb()->FastPebLock);
|
||||
if (!Initialized) {
|
||||
|
||||
InitializeCriticalSection(&MmpFakeHandleListLock);
|
||||
InitializeListHead(&MmpFakeHandleListHead);
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(NtCurrentThread());
|
||||
DetourAttach((PVOID*)&OriginCreateFileW, HookCreateFileW);
|
||||
DetourAttach((PVOID*)&OriginGetFileInformationByHandle, HookGetFileInformationByHandle);
|
||||
DetourAttach((PVOID*)&OriginGetFileAttributesExW, HookGetFileAttributesExW);
|
||||
DetourAttach((PVOID*)&OriginCreateFileMappingW, HookCreateFileMappingW);
|
||||
DetourAttach((PVOID*)&OriginMapViewOfFileEx, HookMapViewOfFileEx);
|
||||
DetourAttach((PVOID*)&OriginUnmapViewOfFile, HookUnmapViewOfFile);
|
||||
DetourAttach((PVOID*)&OriginCloseHandle, HookCloseHandle);
|
||||
DetourAttach((PVOID*)&OriginGetFileVersion, HookGetFileVersion);
|
||||
DetourTransactionCommit();
|
||||
Initialized = TRUE;
|
||||
}
|
||||
LeaveCriticalSection(NtCurrentPeb()->FastPebLock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
BOOL WINAPI MmpInitializeHooksForDotNet();
|
||||
+20
-28
@@ -9,9 +9,15 @@
|
||||
// [MMP_START_TLS_INDEX, MMP_MAXIMUM_TLS_INDEX) Reserved for MemoryModule
|
||||
//
|
||||
|
||||
#define MMP_START_TLS_INDEX 0x80 //128
|
||||
#define MMP_START_TLS_INDEX 0x80 //128
|
||||
|
||||
#define MMP_MAXIMUM_TLS_INDEX 0x100 //256
|
||||
#define MMP_MAXIMUM_TLS_INDEX 0x100 //256
|
||||
|
||||
#define MMP_TLSP_INDEX_BUFFER_SIZE (MMP_MAXIMUM_TLS_INDEX / 8) //32
|
||||
|
||||
#if (((MMP_START_TLS_INDEX | MMP_MAXIMUM_TLS_INDEX) & 7) || (MMP_START_TLS_INDEX >= MMP_MAXIMUM_TLS_INDEX))
|
||||
#error "MMP_START_TLS_INDEX must be smaller than MMP_MAXIMUM_TLS_INDEX, and both are 8-bit aligned."
|
||||
#endif
|
||||
|
||||
#define MmpAllocateTlsp() (RtlAllocateHeap(\
|
||||
RtlProcessHeap(),\
|
||||
@@ -137,26 +143,18 @@ PVOID NTAPI MmpQuerySystemInformation(
|
||||
return buffer;
|
||||
}
|
||||
|
||||
PSYSTEM_PROCESS_INFORMATION NTAPI MmpGetProcessInformation() {
|
||||
DWORD NTAPI MmpGetThreadCount() {
|
||||
DWORD result = 0;
|
||||
auto pid = NtCurrentProcessId();
|
||||
|
||||
auto spi = PSYSTEM_PROCESS_INFORMATION(MmpQuerySystemInformation(SystemProcessInformation, nullptr));
|
||||
PSYSTEM_PROCESS_INFORMATION result = nullptr;
|
||||
if (spi) {
|
||||
auto p = spi;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (p->UniqueProcessId == pid) {
|
||||
result = PSYSTEM_PROCESS_INFORMATION(RtlAllocateHeap(RtlProcessHeap(), 0, p->NextEntryOffset));
|
||||
if (!result)break;
|
||||
|
||||
RtlCopyMemory(
|
||||
result,
|
||||
p,
|
||||
p->NextEntryOffset
|
||||
);
|
||||
|
||||
result = p->NumberOfThreads;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -170,18 +168,6 @@ PSYSTEM_PROCESS_INFORMATION NTAPI MmpGetProcessInformation() {
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD NTAPI MmpGetThreadCount() {
|
||||
DWORD result = 0;
|
||||
auto p = MmpGetProcessInformation();
|
||||
|
||||
if (p) {
|
||||
result = p->NumberOfThreads;
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, p);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD NTAPI MmpUserThreadStart(LPVOID lpThreadParameter) {
|
||||
|
||||
THREAD_CONTEXT Context;
|
||||
@@ -838,6 +824,12 @@ NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) {
|
||||
|
||||
BOOL NTAPI MmpInitialize() {
|
||||
|
||||
auto tls = CONTAINING_RECORD(NtCurrentTeb()->ThreadLocalStoragePointer, TLS_VECTOR, TLS_VECTOR::ModuleTlsData);
|
||||
if (tls && tls->Length > MMP_START_TLS_INDEX) {
|
||||
RtlRaiseStatus(STATUS_NOT_SUPPORTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Capture thread count
|
||||
//
|
||||
@@ -855,13 +847,13 @@ BOOL NTAPI MmpInitialize() {
|
||||
InitializeListHead(&MmpTlsList);
|
||||
RtlInitializeSRWLock(&MmpTlsListLock);
|
||||
|
||||
PULONG buffer = PULONG(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ULONG) * 8));
|
||||
PULONG buffer = PULONG(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, MMP_TLSP_INDEX_BUFFER_SIZE));
|
||||
if (!buffer) {
|
||||
RtlRaiseStatus(STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
RtlFillMemory(buffer, sizeof(ULONG) * 4, -1);
|
||||
RtlInitializeBitMap(&MmpTlsBitmap, buffer, 0x100);
|
||||
RtlFillMemory(buffer, MMP_START_TLS_INDEX / 8, -1);
|
||||
RtlInitializeBitMap(&MmpTlsBitmap, buffer, MMP_MAXIMUM_TLS_INDEX);
|
||||
|
||||
if (NtCurrentTeb()->ThreadLocalStoragePointer) {
|
||||
if (!PreHookNtSetInformationProcess()) {
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include <random>
|
||||
|
||||
#define InsertTailList(ListHead,Entry) {\
|
||||
PLIST_ENTRY _EX_Blink;\
|
||||
PLIST_ENTRY _EX_ListHead;\
|
||||
_EX_ListHead = (ListHead);\
|
||||
_EX_Blink = _EX_ListHead->Blink;\
|
||||
(Entry)->Flink = _EX_ListHead;\
|
||||
(Entry)->Blink = _EX_Blink;\
|
||||
_EX_Blink->Flink = (Entry);\
|
||||
_EX_ListHead->Blink = (Entry);\
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI* PDLL_STARTUP_ROUTINE)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
||||
|
||||
static PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex() {
|
||||
@@ -491,10 +480,15 @@ BOOLEAN __forceinline WINAPI CheckSumBufferedFile(LPVOID BaseAddress, DWORD Buff
|
||||
return HdrSum == CalcSum;
|
||||
}
|
||||
#endif
|
||||
BOOLEAN NTAPI RtlIsValidImageBuffer(PVOID Buffer) {
|
||||
BOOLEAN NTAPI RtlIsValidImageBuffer(
|
||||
_In_ PVOID Buffer,
|
||||
_Out_opt_ size_t* Size) {
|
||||
|
||||
BOOLEAN result = FALSE;
|
||||
__try {
|
||||
|
||||
if (Size)*Size = 0;
|
||||
|
||||
union {
|
||||
PIMAGE_NT_HEADERS32 nt32;
|
||||
PIMAGE_NT_HEADERS64 nt64;
|
||||
@@ -532,6 +526,7 @@ BOOLEAN NTAPI RtlIsValidImageBuffer(PVOID Buffer) {
|
||||
}
|
||||
IMAGE_FIRST_SECTION(headers.nt32);
|
||||
ProbeForRead(Buffer, SizeofImage);
|
||||
if (Size)*Size = SizeofImage;
|
||||
result = CheckSumBufferedFile(Buffer, SizeofImage);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
@@ -602,7 +597,7 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW(
|
||||
__try {
|
||||
*BaseAddress = nullptr;
|
||||
if (LdrEntry)*LdrEntry = nullptr;
|
||||
if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress))status = STATUS_INVALID_IMAGE_FORMAT;
|
||||
if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress, &BufferSize))status = STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
@@ -645,8 +640,8 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW(
|
||||
}
|
||||
}
|
||||
|
||||
status = MemoryLoadLibrary(BaseAddress, BufferAddress);
|
||||
if (!NT_SUCCESS(status))return status;
|
||||
status = MemoryLoadLibrary(BaseAddress, BufferAddress, BufferSize);
|
||||
if (!NT_SUCCESS(status) || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)return status;
|
||||
|
||||
if (!(module = MapMemoryModuleHandle(*BaseAddress))) {
|
||||
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
||||
@@ -714,6 +709,10 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW(
|
||||
LdrUnloadDllMemory(*BaseAddress);
|
||||
}
|
||||
|
||||
if (dwFlags & LOAD_FLAGS_HOOK_DOT_NET) {
|
||||
MmpInitializeHooksForDotNet();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -827,8 +826,8 @@ NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) {
|
||||
if (RtlFindLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP;
|
||||
if (RtlFindLdrpHashTable())features |= MEMORY_FEATURE_LDRP_HASH_TABLE;
|
||||
if (RtlFindLdrpInvertedFunctionTable())features |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE;
|
||||
if (NT_SUCCESS(RtlFindLdrpHandleTlsData(&pfn, &value)) && pfn)features |= MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA;
|
||||
if (NT_SUCCESS(RtlFindLdrpReleaseTlsEntry(&pfn, &value) && pfn))features |= MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY;
|
||||
features |= MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA | MEMORY_FEATURE_LDRP_RELEASE_TLS_ENTRY;
|
||||
|
||||
if (features)features |= MEMORY_FEATURE_SUPPORT_VERSION;
|
||||
*pFeatures = features;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ NTSTATUS NTAPI LdrQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures);
|
||||
//Dont call LdrpHandleTlsData routine if this flag is specified.
|
||||
#define LOAD_FLAGS_NOT_HANDLE_TLS 0x00000008
|
||||
|
||||
//Hook for dotnet dlls
|
||||
#define LOAD_FLAGS_HOOK_DOT_NET 0x00000010
|
||||
|
||||
|
||||
NTSTATUS NTAPI LdrLoadDllMemoryExW(
|
||||
OUT HMEMORYMODULE* BaseAddress, // Output module base address
|
||||
|
||||
@@ -6,265 +6,10 @@ NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry);
|
||||
// MmpTls.cpp
|
||||
NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry);
|
||||
|
||||
|
||||
static NTSTATUS NTAPI LdrpHandleTlsDataXp(PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall) {
|
||||
*_LdrpHandleTlsData = MmpHandleTlsData;
|
||||
*stdcall = true;
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
|
||||
static PVOID _LdrpHandleTlsData_ = (PVOID)~0;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
__try {
|
||||
if (_LdrpHandleTlsData_ != (PVOID)~0) {
|
||||
*_LdrpHandleTlsData = _LdrpHandleTlsData_;
|
||||
if (_LdrpHandleTlsData_ == nullptr)status = STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
else {
|
||||
*_LdrpHandleTlsData = _LdrpHandleTlsData_ = nullptr;
|
||||
if (stdcall) {
|
||||
*stdcall = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(status))return status;
|
||||
|
||||
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
|
||||
//19H2
|
||||
if (Versions[2] == 18363) {
|
||||
Feature = "\x74\x25\x8b\xc1\x8d\x4d\xbc";
|
||||
OffsetOfFunctionBegin = 0x16;
|
||||
}
|
||||
//RS6(19H1)
|
||||
else 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 = LdrpHandleTlsDataXp;
|
||||
*stdcall = true;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast<PVOID>(Feature),SearchContext.BufferLength = Size - 1 };
|
||||
if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(RtlFindNtdllLdrEntry()->DllBase), ".text", &SearchContext)))
|
||||
SearchContext.OutBufferPtr -= OffsetOfFunctionBegin;
|
||||
if (!(*_LdrpHandleTlsData = _LdrpHandleTlsData_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED;
|
||||
if (stdcall) *stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry(PVOID* _LdrpReleaseTlsEntry, bool* stdcall) {
|
||||
*_LdrpReleaseTlsEntry = MmpReleaseTlsEntry;
|
||||
*stdcall = true;
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
static PVOID _LdrpReleaseTlsEntry_ = (PVOID)~0;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
__try {
|
||||
if (_LdrpReleaseTlsEntry_ != (PVOID)~0) {
|
||||
*_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_;
|
||||
if (!_LdrpReleaseTlsEntry_)status = STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
else {
|
||||
*_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_ = nullptr;
|
||||
if (stdcall) {
|
||||
*stdcall = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
if (!NT_SUCCESS(status))return status;
|
||||
|
||||
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]) {
|
||||
status = STATUS_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
if (Versions[2] >= 18362) {
|
||||
Size = 0x10;
|
||||
OffsetOfFunctionBegin = 0x2F;
|
||||
Feature = "\x74\x26\x48\x8B\x00\x48\x39\x58\x08\x75\x5D\x48\x8B\x4B\x08";
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
status = STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast<PVOID>(Feature),SearchContext.BufferLength = Size - 1 };
|
||||
if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(HMODULE(RtlFindNtdllLdrEntry()->DllBase), ".text", &SearchContext)))
|
||||
SearchContext.OutBufferPtr -= OffsetOfFunctionBegin;
|
||||
if (!(*_LdrpReleaseTlsEntry = _LdrpReleaseTlsEntry_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED;
|
||||
if (stdcall)*stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS NTAPI RtlInvokeTlsHandler(IN PLDR_DATA_TABLE_ENTRY LdrEntry, IN BOOLEAN Release) {
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
struct _FUNCTION_SET {
|
||||
bool stdcall;
|
||||
|
||||
union {
|
||||
struct {
|
||||
NTSTATUS(__stdcall* LdrpHandleTlsData)(PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
NTSTATUS(__stdcall* LdrpReleaseTlsEntry)(PLDR_DATA_TABLE_ENTRY LdrEntry, DWORD);
|
||||
}Default;
|
||||
|
||||
struct {
|
||||
NTSTATUS(__thiscall* LdrpHandleTlsData)(PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
NTSTATUS(__thiscall* LdrpReleaseTlsEntry)(PLDR_DATA_TABLE_ENTRY LdrEntry, DWORD);
|
||||
}WinBlue;
|
||||
};
|
||||
|
||||
_FUNCTION_SET() {
|
||||
if (!NT_SUCCESS(RtlFindLdrpHandleTlsData((PVOID*)(&this->Default.LdrpHandleTlsData), &this->stdcall)) ||
|
||||
!NT_SUCCESS(RtlFindLdrpReleaseTlsEntry((PVOID*)(&this->Default.LdrpReleaseTlsEntry), nullptr))) {
|
||||
this->Default = {};
|
||||
OutputDebugString(L"Can`t find both LdrpHandleTlsData and LdrpReleaseTlsEntry.\n");
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS operator()(PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
if (!Default.LdrpHandleTlsData) {
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
return stdcall ? Default.LdrpHandleTlsData(LdrEntry) : WinBlue.LdrpHandleTlsData(LdrEntry);
|
||||
}
|
||||
|
||||
NTSTATUS operator()(PLDR_DATA_TABLE_ENTRY LdrEntry, DWORD dwFlags) {
|
||||
if (!Default.LdrpReleaseTlsEntry) {
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
return stdcall ? Default.LdrpReleaseTlsEntry(LdrEntry,dwFlags) : WinBlue.LdrpReleaseTlsEntry(LdrEntry, dwFlags);
|
||||
}
|
||||
|
||||
}static InvokeHandler;
|
||||
|
||||
return Release ? InvokeHandler(LdrEntry, 0) : InvokeHandler(LdrEntry);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
return MmpHandleTlsData(LdrEntry);
|
||||
//return RtlInvokeTlsHandler(LdrEntry, FALSE);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) {
|
||||
return MmpReleaseTlsEntry(LdrEntry);
|
||||
//return RtlInvokeTlsHandler(LdrEntry, TRUE);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall);
|
||||
|
||||
NTSTATUS NTAPI RtlFindLdrpReleaseTlsEntry(PVOID* _LdrpReleaseTlsEntry, bool* stdcall);
|
||||
|
||||
NTSTATUS NTAPI LdrpHandleTlsData(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
|
||||
NTSTATUS NTAPI LdrpReleaseTlsEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
//tls support
|
||||
#include "rtltls.h"
|
||||
|
||||
//DotNet support
|
||||
#include "MmpDotNet.h"
|
||||
|
||||
//MemoryModulePP api interface
|
||||
#include "NativeFunctionsInternal.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user