mirror of
https://github.com/bb107/MemoryModulePP
synced 2026-06-08 13:15:33 +00:00
add MmpTls.cpp
This commit is contained in:
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
# Detours Contributor Credits
|
||||
|
||||
The following individuals have helped identify specific bugs and improvements
|
||||
in Detours. The entire Detours community has benefited from their help.
|
||||
|
||||
* Jay Krell: Identified error in DetourFindPayload that caused a
|
||||
incorrect failure when pcbData is NULL. (Build_342)
|
||||
|
||||
* Jay Krell: Identified issue with VirtualSize == 0 files created in
|
||||
NT 3.1 images. (Build_339)
|
||||
|
||||
* Igor Odnovorov: Identified an issue with the placement of the trampoline
|
||||
region when a function is detoured twice and the second
|
||||
trampoline region is outside of the +/- 2GB range of
|
||||
the target. (Build_337)
|
||||
|
||||
* Jay Krell: Identified need for some programs to enumerate the
|
||||
address of IAT entries. (Build_336)
|
||||
|
||||
* Calvin Hsia: Identified need for some program to change the excluded
|
||||
system region. (Build_336)
|
||||
|
||||
* Adam Smith: Identified error in failure handling when VirtualProect
|
||||
cannot make pages executable because the Prohibit
|
||||
Dynamic Code Generation mitigation policy has been
|
||||
applied to a process. (Build_335)
|
||||
|
||||
* Ben Faull: Identified fix to detour_alloc_region_from_lo and
|
||||
detour_alloc_region_from_hi that preserves ASLR entropy.
|
||||
(Build_334)
|
||||
|
||||
* Shaoxiang Su: Reported errors building with Visual Studio 2015.
|
||||
(Build_332)
|
||||
|
||||
* Jay Krell: Identified and resolved significant gaps in the X86, X64
|
||||
and IA64 disassemblers for instruction found in code,
|
||||
but seldom found in function prologues. (Build_331)
|
||||
|
||||
* Allan Murphy: Identify error in rep and jmp ds: encodings. (Build_331)
|
||||
|
||||
* Philip Bacon: Identified incorrect entry point return for pure
|
||||
resource-only binaries. (Build_330)
|
||||
|
||||
* Jay Krell: Identified failure in DetourAttachEx to update nAlign.
|
||||
(Build_330)
|
||||
|
||||
* Sumit Sarin: Helped debug error with packed binaries.
|
||||
(Build_329)
|
||||
|
||||
* Nitya Kumar Sharma: Reported bug in DetourAfterWithDll for 32/64 agnostic
|
||||
EXEs.
|
||||
(Build_327)
|
||||
|
||||
* Richard Black: Identified a large number of typos in documentation.
|
||||
(Build_326)
|
||||
|
||||
* Michael Bilodeau: Identified bug in DetourUpdateProcessWithDll when the
|
||||
target process contains a Detours payload *after* all
|
||||
valid PE binaries.
|
||||
(Build_324)
|
||||
|
||||
* Meera Jindal: Reported bug in identification of target address in
|
||||
DetourCopyInstruction for jmp[] and call[] on x86 & x64,
|
||||
the ff15 and ff25 opcodes.
|
||||
(Build_323)
|
||||
|
||||
* Ken Johnson: Assistance with SAL 2.0 annotations.
|
||||
(Build_319)
|
||||
|
||||
* Nick Wood: Identified bug in DetourFindFunction on ARM.
|
||||
(Build_314)
|
||||
|
||||
* Mark Russinovich: Helped debug DetourCreateProcessWithDllEx.
|
||||
(Build_314)
|
||||
|
||||
* John Lin: Implementation idea for DetoursCreateProcessWithDllEx.
|
||||
(Build_314)
|
||||
|
||||
* Andrew Zawadowskiy Reported an improper memory page permissions
|
||||
vulnerability in Detours 2.1. (Vulnerability does not
|
||||
exist in versions later than Detours 2.1.)
|
||||
(Build_223)
|
||||
|
||||
* Nightxie: Identified bug in detour_alloc_round_up_to_region.
|
||||
(Build_310)
|
||||
|
||||
* Diana Milirud: Identified bug in B* instructions on ARM.
|
||||
(Build_309)
|
||||
|
||||
* Juan Carlos Identified correct MSIL entry point for unsigned MSIL.
|
||||
Luciani: (Build_308)
|
||||
|
||||
* Lee Hunt Suggested improvements in algorithm for allocation of
|
||||
Lawrence Landauer trampoline regions on x64 to avoid collisions with
|
||||
Joe Laughlin: system DLLs.
|
||||
(Build_307)
|
||||
|
||||
* Tyler Sims Identified bug in handling of "anycpu" MSIL binaries
|
||||
Darren Kennedy: on x64.
|
||||
(Build_307)
|
||||
|
||||
* Andre Vachon: Help with optimized binaries.
|
||||
(Build 301)
|
||||
|
||||
* Chris Mann: Identified fix not forward ported from 2.2 to 3.0.
|
||||
(Build_301)
|
||||
|
||||
* Mark Irving: Identified bug with EXEs missing second import table.
|
||||
(Build_300)
|
||||
|
||||
* Ben Schwarz: Identified bug in handling of multi-byte NOPs.
|
||||
(Build_300)
|
||||
|
||||
* Aaron Giles Coded initial ARM/Thumb2 disassembler.
|
||||
Jared Henderson: (Build_300)
|
||||
|
||||
* Doug Brubacher: Coded initial x86 disassembler.
|
||||
(Build_100)
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) Microsoft Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
# MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
# Microsoft Research Detours Package
|
||||
|
||||
Detours is a software package for monitoring and instrumenting API calls on Windows. Detours
|
||||
has been used by many ISVs and is also used by product teams at Microsoft. Detours is now available under
|
||||
a standard open source license ([MIT](https://github.com/microsoft/Detours/blob/master/LICENSE.md)). This simplifies licensing for programmers using Detours
|
||||
and allows the community to support Detours using open source tools and processes.
|
||||
|
||||
Detours is compatible with the Windows NT family of
|
||||
operating systems: Windows NT, Windows XP, Windows Server 2003, Windows 7,
|
||||
Windows 8, and Windows 10. It cannot be used by Windows Store apps
|
||||
because Detours requires APIs not available to those applications.
|
||||
This repo contains the source code for version 4.0.1 of Detours.
|
||||
|
||||
For technical documentation on Detours, see the [Detours Wiki](https://github.com/microsoft/Detours/wiki).
|
||||
For directions on how to build and run samples, see the
|
||||
samples [README.txt](https://github.com/Microsoft/Detours/blob/master/samples/README.TXT) file.
|
||||
|
||||
## Contributing
|
||||
|
||||
The [`Detours`](https://github.com/microsoft/detours) repository is where development is done.
|
||||
Here are some ways you can participate in the project:
|
||||
|
||||
* [Answer questions](https://github.com/microsoft/detours/issues) about using Detours.
|
||||
* [Improve the Wiki](https://github.com/microsoft/detours/wiki).
|
||||
* [Submit bugs](https://github.com/microsoft/detours/issues) and help us verify fixes and changes as they are checked in.
|
||||
* Review [source code changes](https://github.com/microsoft/detours/pulls).
|
||||
|
||||
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that
|
||||
you have the right to, and actually do, grant us the rights to use your contribution.
|
||||
For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Issues, questions, and feedback
|
||||
|
||||
* Open an issue on [GitHub Issues](https://github.com/Microsoft/detours/issues).
|
||||
|
||||
## Mailing list for announcements
|
||||
|
||||
The detours-announce mailing list is a low-traffic email list for important announcements
|
||||
about the project, such as the availability of new versions of Detours. To join it, send
|
||||
an email to listserv@lists.research.microsoft.com with a
|
||||
message body containing only the text SUBSCRIBE DETOURS-ANNOUNCE.
|
||||
To leave it, send an email to listserv@lists.research.microsoft.com with a
|
||||
message body containing only the text UNSUBSCRIBE DETOURS-ANNOUNCE.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [MIT](LICENSE.md) License.
|
||||
Vendored
+1783
File diff suppressed because it is too large
Load Diff
Vendored
+2591
File diff suppressed because it is too large
Load Diff
Vendored
+1226
File diff suppressed because it is too large
Load Diff
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Common version parameters.
|
||||
//
|
||||
// Microsoft Research Detours Package, Version 4.0.1
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
#define _USING_V110_SDK71_ 1
|
||||
#include "winver.h"
|
||||
#if 0
|
||||
#include <windows.h>
|
||||
#include <detours.h>
|
||||
#else
|
||||
#ifndef DETOURS_STRINGIFY
|
||||
#define DETOURS_STRINGIFY_(x) #x
|
||||
#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
|
||||
#endif
|
||||
|
||||
#define VER_FILEFLAGSMASK 0x3fL
|
||||
#define VER_FILEFLAGS 0x0L
|
||||
#define VER_FILEOS 0x00040004L
|
||||
#define VER_FILETYPE 0x00000002L
|
||||
#define VER_FILESUBTYPE 0x00000000L
|
||||
#endif
|
||||
#define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS)
|
||||
Vendored
+4301
File diff suppressed because it is too large
Load Diff
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define DETOURS_ARM_OFFLINE_LIBRARY
|
||||
#include "disasm.cpp"
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define DETOURS_ARM64_OFFLINE_LIBRARY
|
||||
#include "disasm.cpp"
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define DETOURS_IA64_OFFLINE_LIBRARY
|
||||
#include "disasm.cpp"
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define DETOURS_X64_OFFLINE_LIBRARY
|
||||
#include "disasm.cpp"
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
#define DETOURS_X86_OFFLINE_LIBRARY
|
||||
#include "disasm.cpp"
|
||||
Vendored
+2217
File diff suppressed because it is too large
Load Diff
Vendored
+932
@@ -0,0 +1,932 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Module Enumeration Functions (modules.cpp of detours.lib)
|
||||
//
|
||||
// Microsoft Research Detours Package, Version 4.0.1
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Module enumeration functions.
|
||||
//
|
||||
|
||||
// #define DETOUR_DEBUG 1
|
||||
#define DETOURS_INTERNAL
|
||||
#include "detours.h"
|
||||
|
||||
#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
|
||||
#error detours.h version mismatch
|
||||
#endif
|
||||
|
||||
#define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
|
||||
#define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
const GUID DETOUR_EXE_RESTORE_GUID = {
|
||||
0xbda26f34, 0xbc82, 0x4829,
|
||||
{ 0x9e, 0x64, 0x74, 0x2c, 0x4, 0xc8, 0x4f, 0xa0 } };
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
PDETOUR_SYM_INFO DetourLoadImageHlp(VOID)
|
||||
{
|
||||
static DETOUR_SYM_INFO symInfo;
|
||||
static PDETOUR_SYM_INFO pSymInfo = NULL;
|
||||
static BOOL failed = false;
|
||||
|
||||
if (failed) {
|
||||
return NULL;
|
||||
}
|
||||
if (pSymInfo != NULL) {
|
||||
return pSymInfo;
|
||||
}
|
||||
|
||||
ZeroMemory(&symInfo, sizeof(symInfo));
|
||||
// Create a real handle to the process.
|
||||
#if 0
|
||||
DuplicateHandle(GetCurrentProcess(),
|
||||
GetCurrentProcess(),
|
||||
GetCurrentProcess(),
|
||||
&symInfo.hProcess,
|
||||
0,
|
||||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS);
|
||||
#else
|
||||
symInfo.hProcess = GetCurrentProcess();
|
||||
#endif
|
||||
|
||||
symInfo.hDbgHelp = LoadLibraryExW(L"dbghelp.dll", NULL, 0);
|
||||
if (symInfo.hDbgHelp == NULL) {
|
||||
abort:
|
||||
failed = true;
|
||||
if (symInfo.hDbgHelp != NULL) {
|
||||
FreeLibrary(symInfo.hDbgHelp);
|
||||
}
|
||||
symInfo.pfImagehlpApiVersionEx = NULL;
|
||||
symInfo.pfSymInitialize = NULL;
|
||||
symInfo.pfSymSetOptions = NULL;
|
||||
symInfo.pfSymGetOptions = NULL;
|
||||
symInfo.pfSymLoadModule64 = NULL;
|
||||
symInfo.pfSymGetModuleInfo64 = NULL;
|
||||
symInfo.pfSymFromName = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
symInfo.pfImagehlpApiVersionEx
|
||||
= (PF_ImagehlpApiVersionEx)GetProcAddress(symInfo.hDbgHelp,
|
||||
"ImagehlpApiVersionEx");
|
||||
symInfo.pfSymInitialize
|
||||
= (PF_SymInitialize)GetProcAddress(symInfo.hDbgHelp, "SymInitialize");
|
||||
symInfo.pfSymSetOptions
|
||||
= (PF_SymSetOptions)GetProcAddress(symInfo.hDbgHelp, "SymSetOptions");
|
||||
symInfo.pfSymGetOptions
|
||||
= (PF_SymGetOptions)GetProcAddress(symInfo.hDbgHelp, "SymGetOptions");
|
||||
symInfo.pfSymLoadModule64
|
||||
= (PF_SymLoadModule64)GetProcAddress(symInfo.hDbgHelp, "SymLoadModule64");
|
||||
symInfo.pfSymGetModuleInfo64
|
||||
= (PF_SymGetModuleInfo64)GetProcAddress(symInfo.hDbgHelp, "SymGetModuleInfo64");
|
||||
symInfo.pfSymFromName
|
||||
= (PF_SymFromName)GetProcAddress(symInfo.hDbgHelp, "SymFromName");
|
||||
|
||||
API_VERSION av;
|
||||
ZeroMemory(&av, sizeof(av));
|
||||
av.MajorVersion = API_VERSION_NUMBER;
|
||||
|
||||
if (symInfo.pfImagehlpApiVersionEx == NULL ||
|
||||
symInfo.pfSymInitialize == NULL ||
|
||||
symInfo.pfSymLoadModule64 == NULL ||
|
||||
symInfo.pfSymGetModuleInfo64 == NULL ||
|
||||
symInfo.pfSymFromName == NULL) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
symInfo.pfImagehlpApiVersionEx(&av);
|
||||
if (av.MajorVersion < API_VERSION_NUMBER) {
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!symInfo.pfSymInitialize(symInfo.hProcess, NULL, FALSE)) {
|
||||
// We won't retry the initialize if it fails.
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (symInfo.pfSymGetOptions != NULL && symInfo.pfSymSetOptions != NULL) {
|
||||
DWORD dw = symInfo.pfSymGetOptions();
|
||||
|
||||
dw &= ~(SYMOPT_CASE_INSENSITIVE |
|
||||
SYMOPT_UNDNAME |
|
||||
SYMOPT_DEFERRED_LOADS |
|
||||
0);
|
||||
dw |= (
|
||||
#if defined(SYMOPT_EXACT_SYMBOLS)
|
||||
SYMOPT_EXACT_SYMBOLS |
|
||||
#endif
|
||||
#if defined(SYMOPT_NO_UNQUALIFIED_LOADS)
|
||||
SYMOPT_NO_UNQUALIFIED_LOADS |
|
||||
#endif
|
||||
SYMOPT_DEFERRED_LOADS |
|
||||
#if defined(SYMOPT_FAIL_CRITICAL_ERRORS)
|
||||
SYMOPT_FAIL_CRITICAL_ERRORS |
|
||||
#endif
|
||||
#if defined(SYMOPT_INCLUDE_32BIT_MODULES)
|
||||
SYMOPT_INCLUDE_32BIT_MODULES |
|
||||
#endif
|
||||
0);
|
||||
symInfo.pfSymSetOptions(dw);
|
||||
}
|
||||
|
||||
pSymInfo = &symInfo;
|
||||
return pSymInfo;
|
||||
}
|
||||
|
||||
PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
|
||||
_In_ LPCSTR pszFunction)
|
||||
{
|
||||
if (pszFunction == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////// First, try GetProcAddress.
|
||||
//
|
||||
#pragma prefast(suppress:28752, "We don't do the unicode conversion for LoadLibraryExA.")
|
||||
HMODULE hModule = LoadLibraryExA(pszModule, NULL, 0);
|
||||
if (hModule == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PBYTE pbCode = (PBYTE)GetProcAddress(hModule, pszFunction);
|
||||
if (pbCode) {
|
||||
return pbCode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////// Then try ImageHelp.
|
||||
//
|
||||
DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction));
|
||||
PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp();
|
||||
if (pSymInfo == NULL) {
|
||||
DETOUR_TRACE(("DetourLoadImageHlp failed: %lu\n",
|
||||
GetLastError()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pSymInfo->pfSymLoadModule64(pSymInfo->hProcess, NULL,
|
||||
(PCHAR)pszModule, NULL,
|
||||
(DWORD64)hModule, 0) == 0) {
|
||||
if (ERROR_SUCCESS != GetLastError()) {
|
||||
DETOUR_TRACE(("SymLoadModule64(%p) failed: %lu\n",
|
||||
pSymInfo->hProcess, GetLastError()));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hrRet;
|
||||
CHAR szFullName[512];
|
||||
IMAGEHLP_MODULE64 modinfo;
|
||||
ZeroMemory(&modinfo, sizeof(modinfo));
|
||||
modinfo.SizeOfStruct = sizeof(modinfo);
|
||||
if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) {
|
||||
DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %lu\n",
|
||||
pSymInfo->hProcess, hModule, GetLastError()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName);
|
||||
if (FAILED(hrRet)) {
|
||||
DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
|
||||
return NULL;
|
||||
}
|
||||
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!");
|
||||
if (FAILED(hrRet)) {
|
||||
DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet));
|
||||
return NULL;
|
||||
}
|
||||
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction);
|
||||
if (FAILED(hrRet)) {
|
||||
DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CFullSymbol : SYMBOL_INFO {
|
||||
CHAR szRestOfName[512];
|
||||
} symbol;
|
||||
ZeroMemory(&symbol, sizeof(symbol));
|
||||
//symbol.ModBase = (ULONG64)hModule;
|
||||
symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
#ifdef DBHLPAPI
|
||||
symbol.MaxNameLen = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]);
|
||||
#else
|
||||
symbol.MaxNameLength = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]);
|
||||
#endif
|
||||
|
||||
if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) {
|
||||
DETOUR_TRACE(("SymFromName(%hs) failed: %lu\n", szFullName, GetLastError()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(DETOURS_IA64)
|
||||
// On the IA64, we get a raw code pointer from the symbol engine
|
||||
// and have to convert it to a wrapped [code pointer, global pointer].
|
||||
//
|
||||
PPLABEL_DESCRIPTOR pldEntry = (PPLABEL_DESCRIPTOR)DetourGetEntryPoint(hModule);
|
||||
PPLABEL_DESCRIPTOR pldSymbol = new PLABEL_DESCRIPTOR;
|
||||
|
||||
pldSymbol->EntryPoint = symbol.Address;
|
||||
pldSymbol->GlobalPointer = pldEntry->GlobalPointer;
|
||||
return (PBYTE)pldSymbol;
|
||||
#elif defined(DETOURS_ARM)
|
||||
// On the ARM, we get a raw code pointer, which we must convert into a
|
||||
// valied Thumb2 function pointer.
|
||||
return DETOURS_PBYTE_TO_PFUNC(symbol.Address);
|
||||
#else
|
||||
return (PBYTE)symbol.Address;
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////// Module Image Functions.
|
||||
//
|
||||
|
||||
HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast)
|
||||
{
|
||||
PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
ZeroMemory(&mbi, sizeof(mbi));
|
||||
|
||||
// Find the next memory region that contains a mapped PE image.
|
||||
//
|
||||
for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
|
||||
if (VirtualQuery(pbLast, &mbi, sizeof(mbi)) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip uncommitted regions and guard pages.
|
||||
//
|
||||
if ((mbi.State != MEM_COMMIT) ||
|
||||
((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
|
||||
(mbi.Protect & PAGE_GUARD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
__try {
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
|
||||
(DWORD)pDosHeader->e_lfanew > mbi.RegionSize ||
|
||||
(DWORD)pDosHeader->e_lfanew < sizeof(*pDosHeader)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SetLastError(NO_ERROR);
|
||||
return (HMODULE)pDosHeader;
|
||||
}
|
||||
#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
if (hModule == NULL) {
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
__try {
|
||||
#pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PDETOUR_CLR_HEADER pClrHeader = NULL;
|
||||
if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
if (((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 &&
|
||||
((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.Size != 0) {
|
||||
pClrHeader = (PDETOUR_CLR_HEADER)
|
||||
(((PBYTE)pDosHeader)
|
||||
+ ((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress);
|
||||
}
|
||||
}
|
||||
else if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
if (((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 &&
|
||||
((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.Size != 0) {
|
||||
pClrHeader = (PDETOUR_CLR_HEADER)
|
||||
(((PBYTE)pDosHeader)
|
||||
+ ((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress);
|
||||
}
|
||||
}
|
||||
|
||||
if (pClrHeader != NULL) {
|
||||
// For MSIL assemblies, we want to use the _Cor entry points.
|
||||
|
||||
HMODULE hClr = GetModuleHandleW(L"MSCOREE.DLL");
|
||||
if (hClr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SetLastError(NO_ERROR);
|
||||
return (PVOID)GetProcAddress(hClr, "_CorExeMain");
|
||||
}
|
||||
|
||||
SetLastError(NO_ERROR);
|
||||
|
||||
// Pure resource DLLs have neither an entry point nor CLR information
|
||||
// so handle them by returning NULL (LastError is NO_ERROR)
|
||||
if (pNtHeader->OptionalHeader.AddressOfEntryPoint == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((PBYTE)pDosHeader) +
|
||||
pNtHeader->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
if (hModule == NULL) {
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
__try {
|
||||
#pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
|
||||
return (pNtHeader->OptionalHeader.SizeOfImage);
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
ZeroMemory(&mbi, sizeof(mbi));
|
||||
|
||||
__try {
|
||||
if (VirtualQuery(pvAddr, &mbi, sizeof(mbi)) <= 0) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Skip uncommitted regions and guard pages.
|
||||
//
|
||||
if ((mbi.State != MEM_COMMIT) ||
|
||||
((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
|
||||
(mbi.Protect & PAGE_GUARD)) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
|
||||
return (HMODULE)pDosHeader;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline PBYTE RvaAdjust(_Pre_notnull_ PIMAGE_DOS_HEADER pDosHeader, _In_ DWORD raddr)
|
||||
{
|
||||
if (raddr != NULL) {
|
||||
return ((PBYTE)pDosHeader) + raddr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule,
|
||||
_In_opt_ PVOID pContext,
|
||||
_In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport)
|
||||
{
|
||||
if (pfExport == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
if (hModule == NULL) {
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
__try {
|
||||
#pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return FALSE;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_EXPORT_DIRECTORY pExportDir
|
||||
= (PIMAGE_EXPORT_DIRECTORY)
|
||||
RvaAdjust(pDosHeader,
|
||||
pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
if (pExportDir == NULL) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PBYTE pExportDirEnd = (PBYTE)pExportDir + pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
||||
PDWORD pdwFunctions = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfFunctions);
|
||||
PDWORD pdwNames = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNames);
|
||||
PWORD pwOrdinals = (PWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNameOrdinals);
|
||||
|
||||
for (DWORD nFunc = 0; nFunc < pExportDir->NumberOfFunctions; nFunc++) {
|
||||
PBYTE pbCode = (pdwFunctions != NULL)
|
||||
? (PBYTE)RvaAdjust(pDosHeader, pdwFunctions[nFunc]) : NULL;
|
||||
PCHAR pszName = NULL;
|
||||
|
||||
// if the pointer is in the export region, then it is a forwarder.
|
||||
if (pbCode > (PBYTE)pExportDir && pbCode < pExportDirEnd) {
|
||||
pbCode = NULL;
|
||||
}
|
||||
|
||||
for (DWORD n = 0; n < pExportDir->NumberOfNames; n++) {
|
||||
if (pwOrdinals[n] == nFunc) {
|
||||
pszName = (pdwNames != NULL)
|
||||
? (PCHAR)RvaAdjust(pDosHeader, pdwNames[n]) : NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ULONG nOrdinal = pExportDir->Base + nFunc;
|
||||
|
||||
if (!pfExport(pContext, nOrdinal, pszName, pbCode)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
return TRUE;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule,
|
||||
_In_opt_ PVOID pContext,
|
||||
_In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
|
||||
_In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFunc)
|
||||
{
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
if (hModule == NULL) {
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
__try {
|
||||
#pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return FALSE;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR iidp
|
||||
= (PIMAGE_IMPORT_DESCRIPTOR)
|
||||
RvaAdjust(pDosHeader,
|
||||
pNtHeader->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
if (iidp == NULL) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (; iidp->OriginalFirstThunk != 0; iidp++) {
|
||||
|
||||
PCSTR pszName = (PCHAR)RvaAdjust(pDosHeader, iidp->Name);
|
||||
if (pszName == NULL) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_THUNK_DATA pThunks = (PIMAGE_THUNK_DATA)
|
||||
RvaAdjust(pDosHeader, iidp->OriginalFirstThunk);
|
||||
PVOID * pAddrs = (PVOID *)
|
||||
RvaAdjust(pDosHeader, iidp->FirstThunk);
|
||||
|
||||
HMODULE hFile = DetourGetContainingModule(pAddrs[0]);
|
||||
|
||||
if (pfImportFile != NULL) {
|
||||
if (!pfImportFile(pContext, hFile, pszName)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD nNames = 0;
|
||||
if (pThunks) {
|
||||
for (; pThunks[nNames].u1.Ordinal; nNames++) {
|
||||
DWORD nOrdinal = 0;
|
||||
PCSTR pszFunc = NULL;
|
||||
|
||||
if (IMAGE_SNAP_BY_ORDINAL(pThunks[nNames].u1.Ordinal)) {
|
||||
nOrdinal = (DWORD)IMAGE_ORDINAL(pThunks[nNames].u1.Ordinal);
|
||||
}
|
||||
else {
|
||||
pszFunc = (PCSTR)RvaAdjust(pDosHeader,
|
||||
(DWORD)pThunks[nNames].u1.AddressOfData + 2);
|
||||
}
|
||||
|
||||
if (pfImportFunc != NULL) {
|
||||
if (!pfImportFunc(pContext,
|
||||
nOrdinal,
|
||||
pszFunc,
|
||||
&pAddrs[nNames])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pfImportFunc != NULL) {
|
||||
pfImportFunc(pContext, 0, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pfImportFile != NULL) {
|
||||
pfImportFile(pContext, NULL, NULL);
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
return TRUE;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Context for DetourEnumerateImportsThunk, which adapts "regular" callbacks for use with "Ex".
|
||||
struct _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT
|
||||
{
|
||||
PVOID pContext;
|
||||
PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc;
|
||||
};
|
||||
|
||||
// Callback for DetourEnumerateImportsEx that adapts DetourEnumerateImportsEx
|
||||
// for use with a DetourEnumerateImports callback -- derefence the IAT and pass the value on.
|
||||
|
||||
static
|
||||
BOOL
|
||||
CALLBACK
|
||||
DetourEnumerateImportsThunk(_In_ PVOID VoidContext,
|
||||
_In_ DWORD nOrdinal,
|
||||
_In_opt_ PCSTR pszFunc,
|
||||
_In_opt_ PVOID* ppvFunc)
|
||||
{
|
||||
_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const * const
|
||||
pContext = (_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT*)VoidContext;
|
||||
return pContext->pfImportFunc(pContext->pContext, nOrdinal, pszFunc, ppvFunc ? *ppvFunc : NULL);
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
|
||||
_In_opt_ PVOID pContext,
|
||||
_In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
|
||||
_In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc)
|
||||
{
|
||||
if (pfImportFile == NULL || pfImportFunc == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const context = { pContext, pfImportFunc };
|
||||
|
||||
return DetourEnumerateImportsEx(hModule,
|
||||
(PVOID)&context,
|
||||
pfImportFile,
|
||||
&DetourEnumerateImportsThunk);
|
||||
}
|
||||
|
||||
static PDETOUR_LOADED_BINARY WINAPI GetPayloadSectionFromModule(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
if (hModule == NULL) {
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
__try {
|
||||
#pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL.
|
||||
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||
pDosHeader->e_lfanew);
|
||||
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER pSectionHeaders
|
||||
= (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader
|
||||
+ sizeof(pNtHeader->Signature)
|
||||
+ sizeof(pNtHeader->FileHeader)
|
||||
+ pNtHeader->FileHeader.SizeOfOptionalHeader);
|
||||
|
||||
for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; n++) {
|
||||
if (strcmp((PCHAR)pSectionHeaders[n].Name, ".detour") == 0) {
|
||||
if (pSectionHeaders[n].VirtualAddress == 0 ||
|
||||
pSectionHeaders[n].SizeOfRawData == 0) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
PBYTE pbData = (PBYTE)pDosHeader + pSectionHeaders[n].VirtualAddress;
|
||||
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pbData;
|
||||
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
|
||||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHeader->nDataOffset == 0) {
|
||||
pHeader->nDataOffset = pHeader->cbHeaderSize;
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
return (PBYTE)pHeader;
|
||||
}
|
||||
}
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule)
|
||||
{
|
||||
PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
|
||||
if (pBinary == NULL) {
|
||||
// Error set by GetPayloadSectionFromModule.
|
||||
return 0;
|
||||
}
|
||||
|
||||
__try {
|
||||
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
|
||||
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
|
||||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
|
||||
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return 0;
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
return pHeader->cbDataSize;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_Writable_bytes_(*pcbData)
|
||||
_Readable_bytes_(*pcbData)
|
||||
_Success_(return != NULL)
|
||||
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
|
||||
_In_ REFGUID rguid,
|
||||
_Out_opt_ DWORD *pcbData)
|
||||
{
|
||||
PBYTE pbData = NULL;
|
||||
if (pcbData) {
|
||||
*pcbData = 0;
|
||||
}
|
||||
|
||||
PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
|
||||
if (pBinary == NULL) {
|
||||
// Error set by GetPayloadSectionFromModule.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__try {
|
||||
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
|
||||
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
|
||||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
|
||||
|
||||
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PBYTE pbBeg = ((PBYTE)pHeader) + pHeader->nDataOffset;
|
||||
PBYTE pbEnd = ((PBYTE)pHeader) + pHeader->cbDataSize;
|
||||
|
||||
for (pbData = pbBeg; pbData < pbEnd;) {
|
||||
DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData;
|
||||
|
||||
if (DetourAreSameGuid(pSection->guid, rguid)) {
|
||||
if (pcbData) {
|
||||
*pcbData = pSection->cbBytes - sizeof(*pSection);
|
||||
}
|
||||
SetLastError(NO_ERROR);
|
||||
return (PBYTE)(pSection + 1);
|
||||
}
|
||||
|
||||
pbData = (PBYTE)pSection + pSection->cbBytes;
|
||||
}
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return NULL;
|
||||
}
|
||||
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_Writable_bytes_(*pcbData)
|
||||
_Readable_bytes_(*pcbData)
|
||||
_Success_(return != NULL)
|
||||
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
|
||||
_Out_opt_ DWORD *pcbData)
|
||||
{
|
||||
for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
|
||||
PVOID pvData;
|
||||
|
||||
pvData = DetourFindPayload(hMod, rguid, pcbData);
|
||||
if (pvData != NULL) {
|
||||
return pvData;
|
||||
}
|
||||
}
|
||||
SetLastError(ERROR_MOD_NOT_FOUND);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourFreePayload(_In_ PVOID pvData)
|
||||
{
|
||||
BOOL fSucceeded = FALSE;
|
||||
|
||||
// If you have any doubts about the following code, please refer to the comments in DetourCopyPayloadToProcess.
|
||||
HMODULE hModule = DetourGetContainingModule(pvData);
|
||||
DETOUR_ASSERT(hModule != NULL);
|
||||
if (hModule != NULL) {
|
||||
fSucceeded = VirtualFree(hModule, 0, MEM_RELEASE);
|
||||
DETOUR_ASSERT(fSucceeded);
|
||||
if (fSucceeded) {
|
||||
hModule = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return fSucceeded;
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
|
||||
_In_ DWORD cbData)
|
||||
{
|
||||
PDETOUR_EXE_RESTORE pder = (PDETOUR_EXE_RESTORE)pvData;
|
||||
|
||||
if (pder->cb != sizeof(*pder) || pder->cb > cbData) {
|
||||
SetLastError(ERROR_BAD_EXE_FORMAT);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD dwPermIdh = ~0u;
|
||||
DWORD dwPermInh = ~0u;
|
||||
DWORD dwPermClr = ~0u;
|
||||
DWORD dwIgnore;
|
||||
BOOL fSucceeded = FALSE;
|
||||
BOOL fUpdated32To64 = FALSE;
|
||||
|
||||
if (pder->pclr != NULL && pder->clr.Flags != ((PDETOUR_CLR_HEADER)pder->pclr)->Flags) {
|
||||
// If we had to promote the 32/64-bit agnostic IL to 64-bit, we can't restore
|
||||
// that.
|
||||
fUpdated32To64 = TRUE;
|
||||
}
|
||||
|
||||
if (DetourVirtualProtectSameExecute(pder->pidh, pder->cbidh,
|
||||
PAGE_EXECUTE_READWRITE, &dwPermIdh)) {
|
||||
if (DetourVirtualProtectSameExecute(pder->pinh, pder->cbinh,
|
||||
PAGE_EXECUTE_READWRITE, &dwPermInh)) {
|
||||
|
||||
CopyMemory(pder->pidh, &pder->idh, pder->cbidh);
|
||||
CopyMemory(pder->pinh, &pder->inh, pder->cbinh);
|
||||
|
||||
if (pder->pclr != NULL && !fUpdated32To64) {
|
||||
if (DetourVirtualProtectSameExecute(pder->pclr, pder->cbclr,
|
||||
PAGE_EXECUTE_READWRITE, &dwPermClr)) {
|
||||
CopyMemory(pder->pclr, &pder->clr, pder->cbclr);
|
||||
VirtualProtect(pder->pclr, pder->cbclr, dwPermClr, &dwIgnore);
|
||||
fSucceeded = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fSucceeded = TRUE;
|
||||
}
|
||||
VirtualProtect(pder->pinh, pder->cbinh, dwPermInh, &dwIgnore);
|
||||
}
|
||||
VirtualProtect(pder->pidh, pder->cbidh, dwPermIdh, &dwIgnore);
|
||||
}
|
||||
// Delete the payload after successful recovery to prevent repeated restore
|
||||
if (fSucceeded) {
|
||||
DetourFreePayload(pder);
|
||||
pder = NULL;
|
||||
}
|
||||
return fSucceeded;
|
||||
}
|
||||
|
||||
BOOL WINAPI DetourRestoreAfterWith()
|
||||
{
|
||||
PVOID pvData;
|
||||
DWORD cbData;
|
||||
|
||||
pvData = DetourFindPayloadEx(DETOUR_EXE_RESTORE_GUID, &cbData);
|
||||
|
||||
if (pvData != NULL && cbData != 0) {
|
||||
return DetourRestoreAfterWithEx(pvData, cbData);
|
||||
}
|
||||
SetLastError(ERROR_MOD_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// End of File
|
||||
Vendored
+333
@@ -0,0 +1,333 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Add DLLs to a module import table (uimports.cpp of detours.lib)
|
||||
//
|
||||
// Microsoft Research Detours Package, Version 4.0.1
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Note that this file is included into creatwth.cpp one or more times
|
||||
// (once for each supported module format).
|
||||
//
|
||||
|
||||
#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
|
||||
#error detours.h version mismatch
|
||||
#endif
|
||||
|
||||
// UpdateImports32 aka UpdateImports64
|
||||
static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
|
||||
HMODULE hModule,
|
||||
__in_ecount(nDlls) LPCSTR *plpDlls,
|
||||
DWORD nDlls)
|
||||
{
|
||||
BOOL fSucceeded = FALSE;
|
||||
DWORD cbNew = 0;
|
||||
|
||||
BYTE * pbNew = NULL;
|
||||
DWORD i;
|
||||
SIZE_T cbRead;
|
||||
DWORD n;
|
||||
|
||||
PBYTE pbModule = (PBYTE)hModule;
|
||||
|
||||
IMAGE_DOS_HEADER idh;
|
||||
ZeroMemory(&idh, sizeof(idh));
|
||||
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead)
|
||||
|| cbRead < sizeof(idh)) {
|
||||
|
||||
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
|
||||
pbModule, pbModule + sizeof(idh), GetLastError()));
|
||||
|
||||
finish:
|
||||
if (pbNew != NULL) {
|
||||
delete[] pbNew;
|
||||
pbNew = NULL;
|
||||
}
|
||||
return fSucceeded;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS_XX inh;
|
||||
ZeroMemory(&inh, sizeof(inh));
|
||||
|
||||
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead)
|
||||
|| cbRead < sizeof(inh)) {
|
||||
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
|
||||
pbModule + idh.e_lfanew,
|
||||
pbModule + idh.e_lfanew + sizeof(inh),
|
||||
GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (inh.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC_XX) {
|
||||
DETOUR_TRACE(("Wrong size image (%04x != %04x).\n",
|
||||
inh.OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC_XX));
|
||||
SetLastError(ERROR_INVALID_BLOCK);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// Zero out the bound table so loader doesn't use it instead of our new table.
|
||||
inh.BOUND_DIRECTORY.VirtualAddress = 0;
|
||||
inh.BOUND_DIRECTORY.Size = 0;
|
||||
|
||||
// Find the size of the mapped file.
|
||||
DWORD dwSec = idh.e_lfanew +
|
||||
FIELD_OFFSET(IMAGE_NT_HEADERS_XX, OptionalHeader) +
|
||||
inh.FileHeader.SizeOfOptionalHeader;
|
||||
|
||||
for (i = 0; i < inh.FileHeader.NumberOfSections; i++) {
|
||||
IMAGE_SECTION_HEADER ish;
|
||||
ZeroMemory(&ish, sizeof(ish));
|
||||
|
||||
if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish,
|
||||
sizeof(ish), &cbRead)
|
||||
|| cbRead < sizeof(ish)) {
|
||||
|
||||
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
|
||||
pbModule + dwSec + sizeof(ish) * i,
|
||||
pbModule + dwSec + sizeof(ish) * (i + 1),
|
||||
GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
DETOUR_TRACE(("ish[%lu] : va=%08lx sr=%lu\n", i, ish.VirtualAddress, ish.SizeOfRawData));
|
||||
|
||||
// If the linker didn't suggest an IAT in the data directories, the
|
||||
// loader will look for the section of the import directory to be used
|
||||
// for this instead. Since we put out new IMPORT_DIRECTORY outside any
|
||||
// section boundary, the loader will not find it. So we provide one
|
||||
// explicitly to avoid the search.
|
||||
//
|
||||
if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
|
||||
inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress &&
|
||||
inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) {
|
||||
|
||||
inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress;
|
||||
inh.IAT_DIRECTORY.Size = ish.SizeOfRawData;
|
||||
}
|
||||
}
|
||||
|
||||
if (inh.IMPORT_DIRECTORY.VirtualAddress != 0 && inh.IMPORT_DIRECTORY.Size == 0) {
|
||||
|
||||
// Don't worry about changing the PE file,
|
||||
// because the load information of the original PE header has been saved and will be restored.
|
||||
// The change here is just for the following code to work normally
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + inh.IMPORT_DIRECTORY.VirtualAddress);
|
||||
|
||||
do {
|
||||
IMAGE_IMPORT_DESCRIPTOR ImageImport;
|
||||
if (!ReadProcessMemory(hProcess, pImageImport, &ImageImport, sizeof(ImageImport), NULL)) {
|
||||
DETOUR_TRACE(("ReadProcessMemory failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
inh.IMPORT_DIRECTORY.Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
if (!ImageImport.Name) {
|
||||
break;
|
||||
}
|
||||
++pImageImport;
|
||||
} while (TRUE);
|
||||
|
||||
DWORD dwLastError = GetLastError();
|
||||
OutputDebugString(TEXT("[This PE file has an import table, but the import table size is marked as 0. This is an error.")
|
||||
TEXT("If it is not repaired, the launched program will not work properly, Detours has automatically repaired its import table size for you! ! !]\r\n"));
|
||||
if (GetLastError() != dwLastError) {
|
||||
SetLastError(dwLastError);
|
||||
}
|
||||
}
|
||||
|
||||
DETOUR_TRACE((" Imports: %p..%p\n",
|
||||
pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
|
||||
pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
|
||||
inh.IMPORT_DIRECTORY.Size));
|
||||
|
||||
// Calculate new import directory size. Note that since inh is from another
|
||||
// process, inh could have been corrupted. We need to protect against
|
||||
// integer overflow in allocation calculations.
|
||||
DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
DWORD obRem;
|
||||
if (DWordMult(sizeof(IMAGE_IMPORT_DESCRIPTOR), nDlls, &obRem) != S_OK) {
|
||||
DETOUR_TRACE(("too many new DLLs.\n"));
|
||||
goto finish;
|
||||
}
|
||||
DWORD obOld;
|
||||
if (DWordAdd(obRem, sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls, &obOld) != S_OK) {
|
||||
DETOUR_TRACE(("DLL entries overflow.\n"));
|
||||
goto finish;
|
||||
}
|
||||
DWORD obTab = PadToDwordPtr(obOld);
|
||||
// Check for integer overflow.
|
||||
if (obTab < obOld) {
|
||||
DETOUR_TRACE(("DLL entries padding overflow.\n"));
|
||||
goto finish;
|
||||
}
|
||||
DWORD stSize;
|
||||
if (DWordMult(sizeof(DWORD_XX) * 4, nDlls, &stSize) != S_OK) {
|
||||
DETOUR_TRACE(("String table overflow.\n"));
|
||||
goto finish;
|
||||
}
|
||||
DWORD obDll;
|
||||
if (DWordAdd(obTab, stSize, &obDll) != S_OK) {
|
||||
DETOUR_TRACE(("Import table size overflow\n"));
|
||||
goto finish;
|
||||
}
|
||||
DWORD obStr = obDll;
|
||||
cbNew = obStr;
|
||||
for (n = 0; n < nDlls; n++) {
|
||||
if (DWordAdd(cbNew, PadToDword((DWORD)strlen(plpDlls[n]) + 1), &cbNew) != S_OK) {
|
||||
DETOUR_TRACE(("Overflow adding string table entry\n"));
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
pbNew = new BYTE [cbNew];
|
||||
if (pbNew == NULL) {
|
||||
DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
|
||||
goto finish;
|
||||
}
|
||||
ZeroMemory(pbNew, cbNew);
|
||||
|
||||
PBYTE pbBase = pbModule;
|
||||
PBYTE pbNext = pbBase
|
||||
+ inh.OptionalHeader.BaseOfCode
|
||||
+ inh.OptionalHeader.SizeOfCode
|
||||
+ inh.OptionalHeader.SizeOfInitializedData
|
||||
+ inh.OptionalHeader.SizeOfUninitializedData;
|
||||
if (pbBase < pbNext) {
|
||||
pbBase = pbNext;
|
||||
}
|
||||
DETOUR_TRACE(("pbBase = %p\n", pbBase));
|
||||
|
||||
PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbModule, pbBase, cbNew);
|
||||
if (pbNewIid == NULL) {
|
||||
DETOUR_TRACE(("FindAndAllocateNearBase failed.\n"));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
|
||||
IMAGE_THUNK_DATAXX *pt = NULL;
|
||||
|
||||
DWORD obBase = (DWORD)(pbNewIid - pbModule);
|
||||
DWORD dwProtect = 0;
|
||||
|
||||
if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) {
|
||||
// Read the old import directory if it exists.
|
||||
DETOUR_TRACE(("IMPORT_DIRECTORY perms=%lx\n", dwProtect));
|
||||
|
||||
if (!ReadProcessMemory(hProcess,
|
||||
pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
|
||||
&piid[nDlls],
|
||||
nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead)
|
||||
|| cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
|
||||
|
||||
DETOUR_TRACE(("ReadProcessMemory(imports) failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < nDlls; n++) {
|
||||
HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
|
||||
if (FAILED(hrRet)) {
|
||||
DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// After copying the string, we patch up the size "??" bits if any.
|
||||
hrRet = ReplaceOptionalSizeA((char*)pbNew + obStr,
|
||||
cbNew - obStr,
|
||||
DETOURS_STRINGIFY(DETOURS_BITS_XX));
|
||||
if (FAILED(hrRet)) {
|
||||
DETOUR_TRACE(("ReplaceOptionalSizeA failed: %08lx\n", hrRet));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
DWORD nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * (4 * n));
|
||||
piid[n].OriginalFirstThunk = obBase + nOffset;
|
||||
|
||||
// We need 2 thunks for the import table and 2 thunks for the IAT.
|
||||
// One for an ordinal import and one to mark the end of the list.
|
||||
pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
|
||||
pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
|
||||
pt[1].u1.Ordinal = 0;
|
||||
|
||||
nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * ((4 * n) + 2));
|
||||
piid[n].FirstThunk = obBase + nOffset;
|
||||
pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
|
||||
pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
|
||||
pt[1].u1.Ordinal = 0;
|
||||
piid[n].TimeDateStamp = 0;
|
||||
piid[n].ForwarderChain = 0;
|
||||
piid[n].Name = obBase + obStr;
|
||||
|
||||
obStr += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
|
||||
}
|
||||
_Analysis_assume_(obStr <= cbNew);
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < nDlls + nOldDlls; i++) {
|
||||
DETOUR_TRACE(("%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x\n",
|
||||
i,
|
||||
piid[i].OriginalFirstThunk,
|
||||
piid[i].TimeDateStamp,
|
||||
piid[i].ForwarderChain,
|
||||
piid[i].Name,
|
||||
piid[i].FirstThunk));
|
||||
if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
|
||||
DETOUR_TRACE(("WriteProcessMemory(iid) failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
DETOUR_TRACE(("obBaseBef = %08lx..%08lx\n",
|
||||
inh.IMPORT_DIRECTORY.VirtualAddress,
|
||||
inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
|
||||
DETOUR_TRACE(("obBaseAft = %08lx..%08lx\n", obBase, obBase + obStr));
|
||||
|
||||
// In this case the file didn't have an import directory in first place,
|
||||
// so we couldn't fix the missing IAT above. We still need to explicitly
|
||||
// provide an IAT to prevent to loader from looking for one.
|
||||
//
|
||||
if (inh.IAT_DIRECTORY.VirtualAddress == 0) {
|
||||
inh.IAT_DIRECTORY.VirtualAddress = obBase;
|
||||
inh.IAT_DIRECTORY.Size = cbNew;
|
||||
}
|
||||
|
||||
inh.IMPORT_DIRECTORY.VirtualAddress = obBase;
|
||||
inh.IMPORT_DIRECTORY.Size = cbNew;
|
||||
|
||||
/////////////////////// Update the NT header for the new import directory.
|
||||
//
|
||||
if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
|
||||
PAGE_EXECUTE_READWRITE, &dwProtect)) {
|
||||
DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
inh.OptionalHeader.CheckSum = 0;
|
||||
|
||||
if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
|
||||
DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh)));
|
||||
|
||||
if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
|
||||
DETOUR_TRACE(("WriteProcessMemory(inh) failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n",
|
||||
pbModule + idh.e_lfanew,
|
||||
pbModule + idh.e_lfanew + sizeof(inh)));
|
||||
|
||||
if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
|
||||
dwProtect, &dwProtect)) {
|
||||
DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %lu\n", GetLastError()));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fSucceeded = TRUE;
|
||||
goto finish;
|
||||
}
|
||||
@@ -19,8 +19,19 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\3rdparty\Detours\creatwth.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\detours.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disasm.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disolarm.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disolarm64.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disolia64.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disolx64.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\disolx86.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\image.cpp" />
|
||||
<ClCompile Include="..\3rdparty\Detours\modules.cpp" />
|
||||
<ClCompile Include="LoadDllMemoryApi.cpp" />
|
||||
<ClCompile Include="MemoryModule.cpp" />
|
||||
<ClCompile Include="MmpTls.cpp" />
|
||||
<ClCompile Include="Native.cpp" />
|
||||
<ClCompile Include="NativeFunctionsInternal.cpp" />
|
||||
<ClCompile Include="rtlinv.cpp" />
|
||||
@@ -30,6 +41,8 @@
|
||||
<ClCompile Include="rtlver.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\3rdparty\Detours\detours.h" />
|
||||
<ClInclude Include="..\3rdparty\Detours\detver.h" />
|
||||
<ClInclude Include="LoadDllMemoryApi.h" />
|
||||
<ClInclude Include="MemoryModule.h" />
|
||||
<ClInclude Include="Native.h" />
|
||||
@@ -101,15 +114,19 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
|
||||
@@ -13,6 +13,18 @@
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\3rdparty">
|
||||
<UniqueIdentifier>{8baeecde-ca9b-43da-b847-c24b02413572}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\3rdparty\Detours">
|
||||
<UniqueIdentifier>{21335c89-8359-427a-a6c6-d621b31be2ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\3rdparty">
|
||||
<UniqueIdentifier>{22e60119-4e33-49c4-81c4-b95ea98501e3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\3rdparty\Detours">
|
||||
<UniqueIdentifier>{10bf9b0e-09d4-473b-a4bb-d7c4cecc65b4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="MemoryModule.cpp">
|
||||
@@ -42,6 +54,39 @@
|
||||
<ClCompile Include="rtlsearch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MmpTls.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\creatwth.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\detours.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disasm.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disolarm.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disolarm64.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disolia64.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disolx64.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\disolx86.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\image.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\3rdparty\Detours\modules.cpp">
|
||||
<Filter>Source Files\3rdparty\Detours</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MemoryModule.h">
|
||||
@@ -74,6 +119,12 @@
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\3rdparty\Detours\detours.h">
|
||||
<Filter>Header Files\3rdparty\Detours</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\3rdparty\Detours\detver.h">
|
||||
<Filter>Header Files\3rdparty\Detours</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.md">
|
||||
|
||||
@@ -0,0 +1,868 @@
|
||||
#include "stdafx.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <3rdparty/Detours/detours.h>
|
||||
|
||||
//
|
||||
// ThreadLocalStoragePointer Tls indexs
|
||||
// [0, MMP_START_TLS_INDEX) Reserved for ntdll loader
|
||||
// [MMP_START_TLS_INDEX, MMP_MAXIMUM_TLS_INDEX) Reserved for MemoryModule
|
||||
//
|
||||
|
||||
#define MMP_START_TLS_INDEX 0x50
|
||||
|
||||
#define MMP_MAXIMUM_TLS_INDEX 0x100
|
||||
|
||||
#define MmpAllocateTlsp() (RtlAllocateHeap(\
|
||||
RtlProcessHeap(),\
|
||||
HEAP_ZERO_MEMORY,\
|
||||
sizeof(PVOID)* MMP_MAXIMUM_TLS_INDEX\
|
||||
))
|
||||
|
||||
typedef struct _TLS_VECTOR {
|
||||
union
|
||||
{
|
||||
ULONG Length;
|
||||
HANDLE ThreadId;
|
||||
};
|
||||
|
||||
struct _TLS_VECTOR* PreviousDeferredTlsVector;
|
||||
PVOID ModuleTlsData[ANYSIZE_ARRAY];
|
||||
} TLS_VECTOR, * PTLS_VECTOR;
|
||||
|
||||
typedef struct _TLS_ENTRY {
|
||||
LIST_ENTRY TlsEntryLinks;
|
||||
IMAGE_TLS_DIRECTORY TlsDirectory;
|
||||
PLDR_DATA_TABLE_ENTRY ModuleEntry;
|
||||
} TLS_ENTRY, * PTLS_ENTRY;
|
||||
|
||||
LIST_ENTRY MmpTlsList;
|
||||
RTL_BITMAP MmpTlsBitmap;
|
||||
SRWLOCK MmpTlsListLock;
|
||||
|
||||
|
||||
typedef struct _MMP_TLSP_RECORD {
|
||||
|
||||
LIST_ENTRY InMmpThreadLocalStoragePointer;
|
||||
|
||||
HANDLE UniqueThread;
|
||||
|
||||
// PEB->ThreadLocalStoragePointer allocated by ntdll!Ldr
|
||||
PVOID* TlspLdrBlock;
|
||||
|
||||
// PEB->ThreadLocalStoragePointer allocated by MemoryModulePP
|
||||
PVOID* TlspMmpBlock;
|
||||
}MMP_TLSP_RECORD, * PMMP_TLSP_RECORD;
|
||||
|
||||
CRITICAL_SECTION MmpTlspLock;
|
||||
LIST_ENTRY MmpThreadLocalStoragePointer;
|
||||
|
||||
|
||||
decltype(&NtCreateThread) OriginNtCreateThread = NtCreateThread;
|
||||
decltype(&NtCreateThreadEx) OriginNtCreateThreadEx = NtCreateThreadEx;
|
||||
decltype(&NtSetInformationProcess) OriginNtSetInformationProcess = NtSetInformationProcess;
|
||||
decltype(&LdrShutdownThread) OriginLdrShutdownThread = LdrShutdownThread;
|
||||
|
||||
|
||||
typedef struct _THREAD_TLS_INFORMATION {
|
||||
ULONG Flags;
|
||||
|
||||
union {
|
||||
PVOID* TlsVector;
|
||||
PVOID TlsModulePointer;
|
||||
};
|
||||
|
||||
HANDLE ThreadId;
|
||||
} THREAD_TLS_INFORMATION, * PTHREAD_TLS_INFORMATION;
|
||||
|
||||
typedef struct _PROCESS_TLS_INFORMATION {
|
||||
ULONG Reserved;
|
||||
PROCESS_TLS_INFORMATION_TYPE OperationType;
|
||||
ULONG ThreadDataCount;
|
||||
|
||||
union {
|
||||
ULONG TlsIndex;
|
||||
ULONG TlsVectorLength;
|
||||
};
|
||||
|
||||
THREAD_TLS_INFORMATION ThreadData[ANYSIZE_ARRAY];
|
||||
} PROCESS_TLS_INFORMATION, * PPROCESS_TLS_INFORMATION;
|
||||
|
||||
typedef struct _THREAD_CONTEXT {
|
||||
PTHREAD_START_ROUTINE ThreadStartRoutine;
|
||||
LPVOID ThreadParameter;
|
||||
}THREAD_CONTEXT, * PTHREAD_CONTEXT;
|
||||
|
||||
PVOID NTAPI MmpQuerySystemInformation(
|
||||
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
_Out_opt_ LPDWORD ReturnLength) {
|
||||
|
||||
if (ReturnLength)*ReturnLength = 0;
|
||||
|
||||
NTSTATUS status;
|
||||
PVOID buffer = nullptr;
|
||||
ULONG len = 0;
|
||||
|
||||
|
||||
do {
|
||||
|
||||
RtlFreeHeap(
|
||||
RtlProcessHeap(),
|
||||
0,
|
||||
buffer
|
||||
);
|
||||
buffer = nullptr;
|
||||
|
||||
if (len) {
|
||||
len *= 2;
|
||||
buffer = RtlAllocateHeap(
|
||||
RtlProcessHeap(),
|
||||
0,
|
||||
len
|
||||
);
|
||||
if (!buffer)return nullptr;
|
||||
}
|
||||
|
||||
status = NtQuerySystemInformation(
|
||||
SystemInformationClass,
|
||||
buffer,
|
||||
len,
|
||||
&len
|
||||
);
|
||||
if (NT_SUCCESS(status))break;
|
||||
} while (status == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
if (ReturnLength)*ReturnLength = len;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
PSYSTEM_PROCESS_INFORMATION NTAPI MmpGetProcessInformation() {
|
||||
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
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p->NextEntryOffset)break;
|
||||
p = PSYSTEM_PROCESS_INFORMATION(LPSTR(p) + p->NextEntryOffset);
|
||||
}
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, spi);
|
||||
}
|
||||
|
||||
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;
|
||||
bool success = false;
|
||||
|
||||
__try {
|
||||
RtlCopyMemory(
|
||||
&Context,
|
||||
lpThreadParameter,
|
||||
sizeof(Context)
|
||||
);
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, lpThreadParameter);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Allocate and replace ThreadLocalStoragePointer for new thread
|
||||
//
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
|
||||
auto record = PMMP_TLSP_RECORD(RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(MMP_TLSP_RECORD)));
|
||||
if (record) {
|
||||
record->TlspLdrBlock = (PVOID*)NtCurrentTeb()->ThreadLocalStoragePointer;
|
||||
record->TlspMmpBlock = (PVOID*)MmpAllocateTlsp();
|
||||
record->UniqueThread = NtCurrentThreadId();
|
||||
if (record->TlspMmpBlock) {
|
||||
|
||||
auto size = CONTAINING_RECORD(record->TlspLdrBlock, TLS_VECTOR, ModuleTlsData)->Length;
|
||||
RtlCopyMemory(
|
||||
record->TlspMmpBlock,
|
||||
record->TlspLdrBlock,
|
||||
size
|
||||
);
|
||||
|
||||
NtCurrentTeb()->ThreadLocalStoragePointer = record->TlspMmpBlock;
|
||||
|
||||
InsertTailList(&MmpThreadLocalStoragePointer, &record->InMmpThreadLocalStoragePointer);
|
||||
success = true;
|
||||
}
|
||||
else {
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, record);
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
|
||||
//
|
||||
// Handle MemoryModule Tls data
|
||||
//
|
||||
if (success) {
|
||||
RtlAcquireSRWLockShared(&MmpTlsListLock);
|
||||
|
||||
auto ThreadLocalStoragePointer = (PVOID*)NtCurrentTeb()->ThreadLocalStoragePointer;
|
||||
PLIST_ENTRY entry = MmpTlsList.Flink;
|
||||
while (entry != &MmpTlsList) {
|
||||
|
||||
PTLS_ENTRY tls = CONTAINING_RECORD(entry, TLS_ENTRY, TlsEntryLinks);
|
||||
auto len = tls->TlsDirectory.EndAddressOfRawData - tls->TlsDirectory.StartAddressOfRawData;
|
||||
PVOID data = RtlAllocateHeap(RtlProcessHeap(), 0, len);
|
||||
if (!len) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
data,
|
||||
PVOID(tls->TlsDirectory.StartAddressOfRawData),
|
||||
len
|
||||
);
|
||||
|
||||
|
||||
ThreadLocalStoragePointer[tls->TlsDirectory.Characteristics] = data;
|
||||
|
||||
entry = entry->Flink;
|
||||
}
|
||||
|
||||
RtlReleaseSRWLockShared(&MmpTlsListLock);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
return Context.ThreadStartRoutine(Context.ThreadParameter);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI HookNtCreateThread(
|
||||
_Out_ PHANDLE ThreadHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_Out_ PCLIENT_ID ClientId,
|
||||
_In_ PCONTEXT ThreadContext,
|
||||
_In_ PINITIAL_TEB InitialTeb,
|
||||
_In_ BOOLEAN CreateSuspended) {
|
||||
CONTEXT Context = *ThreadContext;
|
||||
PTHREAD_CONTEXT _Context = PTHREAD_CONTEXT(RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(_Context)));
|
||||
NTSTATUS status;
|
||||
|
||||
if (!_Context)return STATUS_NO_MEMORY;
|
||||
|
||||
#ifndef _WIN64
|
||||
_Context->ThreadStartRoutine = PTHREAD_START_ROUTINE(Context.Eax);
|
||||
_Context->ThreadParameter = LPVOID(Context.Ebx);
|
||||
|
||||
Context.Eax = DWORD(MmpUserThreadStart);
|
||||
Context.Ebx = DWORD(_Context);
|
||||
|
||||
#else
|
||||
_Context->ThreadStartRoutine = PTHREAD_START_ROUTINE(Context.Rcx);
|
||||
_Context->ThreadParameter = LPVOID(Context.Rdx);
|
||||
|
||||
Context.Rcx = ULONG64(MmpUserThreadStart);
|
||||
Context.Rdx = ULONG64(_Context);
|
||||
#endif
|
||||
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
|
||||
status = OriginNtCreateThread(
|
||||
ThreadHandle,
|
||||
DesiredAccess,
|
||||
ObjectAttributes,
|
||||
ProcessHandle,
|
||||
ClientId,
|
||||
&Context,
|
||||
InitialTeb,
|
||||
CreateSuspended
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, _Context);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI HookNtCreateThreadEx(
|
||||
_Out_ PHANDLE ThreadHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ PVOID StartRoutine,
|
||||
_In_opt_ PVOID Argument,
|
||||
_In_ ULONG CreateFlags,
|
||||
_In_ SIZE_T ZeroBits,
|
||||
_In_ SIZE_T StackSize,
|
||||
_In_ SIZE_T MaximumStackSize,
|
||||
_In_opt_ PVOID AttributeList) {
|
||||
PTHREAD_CONTEXT Context = PTHREAD_CONTEXT(RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(Context)));
|
||||
if (!Context) {
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Context->ThreadStartRoutine = PTHREAD_START_ROUTINE(StartRoutine);
|
||||
Context->ThreadParameter = Argument;
|
||||
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
|
||||
NTSTATUS status = OriginNtCreateThreadEx(
|
||||
ThreadHandle,
|
||||
DesiredAccess,
|
||||
ObjectAttributes,
|
||||
ProcessHandle,
|
||||
MmpUserThreadStart,
|
||||
Context,
|
||||
CreateFlags,
|
||||
ZeroBits,
|
||||
StackSize,
|
||||
MaximumStackSize,
|
||||
AttributeList
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, Context);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID NTAPI HookLdrShutdownThread(VOID) {
|
||||
|
||||
PLIST_ENTRY entry;
|
||||
PMMP_TLSP_RECORD record = nullptr;
|
||||
|
||||
//
|
||||
// Find our tlsp record
|
||||
//
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
|
||||
entry = MmpThreadLocalStoragePointer.Flink;
|
||||
while (entry != &MmpThreadLocalStoragePointer) {
|
||||
|
||||
auto p = CONTAINING_RECORD(entry, MMP_TLSP_RECORD, InMmpThreadLocalStoragePointer);
|
||||
if (p->UniqueThread == NtCurrentThreadId()) {
|
||||
assert(p->TlspMmpBlock == NtCurrentTeb()->ThreadLocalStoragePointer);
|
||||
|
||||
//
|
||||
// Restore tlsp
|
||||
//
|
||||
NtCurrentTeb()->ThreadLocalStoragePointer = p->TlspLdrBlock;
|
||||
|
||||
RemoveEntryList(&p->InMmpThreadLocalStoragePointer);
|
||||
record = p;
|
||||
break;
|
||||
}
|
||||
|
||||
entry = entry->Flink;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
|
||||
//
|
||||
// Free MemoryModule Tls data
|
||||
//
|
||||
RtlAcquireSRWLockExclusive(&MmpTlsListLock);
|
||||
|
||||
if (record) {
|
||||
auto TlspMmpBlock = (PVOID*)record->TlspMmpBlock;
|
||||
entry = MmpTlsList.Flink;
|
||||
while (entry != &MmpTlsList) {
|
||||
|
||||
auto p = CONTAINING_RECORD(entry, TLS_ENTRY, TlsEntryLinks);
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, TlspMmpBlock[p->TlsDirectory.Characteristics]);
|
||||
|
||||
entry = entry->Flink;
|
||||
}
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, TlspMmpBlock);
|
||||
}
|
||||
else {
|
||||
if (MmpTlsList.Flink != &MmpTlsList) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
RtlReleaseSRWLockExclusive(&MmpTlsListLock);
|
||||
|
||||
//
|
||||
// Call the original function
|
||||
//
|
||||
OriginLdrShutdownThread();
|
||||
}
|
||||
|
||||
BOOL NTAPI PreHookNtSetInformationProcess() {
|
||||
DWORD CurrentTlsPointerSize = CONTAINING_RECORD(NtCurrentTeb()->ThreadLocalStoragePointer, TLS_VECTOR, ModuleTlsData)->Length;
|
||||
DWORD CurrentThreadCount = MmpGetThreadCount();
|
||||
DWORD ProcessTlsInformationLength = sizeof(PROCESS_TLS_INFORMATION) + (CurrentThreadCount - 1) * sizeof(THREAD_TLS_INFORMATION);
|
||||
BOOL success = TRUE;
|
||||
NTSTATUS status;
|
||||
|
||||
auto ProcessTlsInformation = PPROCESS_TLS_INFORMATION(RtlAllocateHeap(
|
||||
RtlProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
ProcessTlsInformationLength * 2
|
||||
));
|
||||
if (ProcessTlsInformation) {
|
||||
|
||||
ProcessTlsInformation->OperationType = ProcessTlsReplaceVector;
|
||||
ProcessTlsInformation->Reserved = 0;
|
||||
ProcessTlsInformation->TlsVectorLength = CurrentTlsPointerSize;
|
||||
ProcessTlsInformation->ThreadDataCount = CurrentThreadCount;
|
||||
|
||||
for (DWORD i = 0; i < CurrentThreadCount; ++i) {
|
||||
auto& current = ProcessTlsInformation->ThreadData[i];
|
||||
current.TlsVector = (PVOID*)MmpAllocateTlsp();
|
||||
if (!current.TlsVector) {
|
||||
for (DWORD j = 0; j < i; ++j) {
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, ProcessTlsInformation->ThreadData[j].TlsVector);
|
||||
}
|
||||
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
auto tmpTlsInformation = PPROCESS_TLS_INFORMATION(LPBYTE(ProcessTlsInformation) + ProcessTlsInformationLength);
|
||||
RtlCopyMemory(
|
||||
tmpTlsInformation,
|
||||
ProcessTlsInformation,
|
||||
ProcessTlsInformationLength
|
||||
);
|
||||
|
||||
status = NtSetInformationProcess(
|
||||
NtCurrentProcess(),
|
||||
ProcessResourceManagement,
|
||||
ProcessTlsInformation,
|
||||
ProcessTlsInformationLength
|
||||
);
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
for (DWORD i = 0; i < CurrentThreadCount; ++i) {
|
||||
auto const& LdrTls = ProcessTlsInformation->ThreadData[i];
|
||||
auto const& MmpTls = tmpTlsInformation->ThreadData[i];
|
||||
auto record = PMMP_TLSP_RECORD(RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(MMP_TLSP_RECORD)));
|
||||
assert(record);
|
||||
|
||||
record->TlspLdrBlock = LdrTls.TlsVector;
|
||||
record->TlspMmpBlock = MmpTls.TlsVector;
|
||||
record->UniqueThread = LdrTls.ThreadId;
|
||||
InsertTailList(&MmpThreadLocalStoragePointer, &record->InMmpThreadLocalStoragePointer);
|
||||
}
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, ProcessTlsInformation);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI HookNtSetInformationProcess(
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ PROCESSINFOCLASS ProcessInformationClass,
|
||||
_In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
|
||||
_In_ ULONG ProcessInformationLength) {
|
||||
|
||||
if (ProcessInformationClass != ProcessResourceManagement) {
|
||||
return OriginNtSetInformationProcess(
|
||||
ProcessHandle,
|
||||
ProcessInformationClass,
|
||||
ProcessInformation,
|
||||
ProcessInformationLength
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
auto ProcessTlsInformation = PPROCESS_TLS_INFORMATION(ProcessInformation);
|
||||
auto hProcess = ProcessHandle ? ProcessHandle : NtCurrentProcess();
|
||||
auto TlsLength = ProcessInformationLength;
|
||||
PPROCESS_TLS_INFORMATION Tls = nullptr;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
do {
|
||||
if (ProcessTlsInformation->OperationType >= MaxProcessTlsOperation) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate new buffer to change it
|
||||
//
|
||||
Tls = PPROCESS_TLS_INFORMATION(RtlAllocateHeap(RtlProcessHeap(), 0, ProcessInformationLength));
|
||||
if (Tls) {
|
||||
RtlCopyMemory(
|
||||
Tls,
|
||||
ProcessInformation,
|
||||
ProcessInformationLength
|
||||
);
|
||||
}
|
||||
else {
|
||||
status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert ReplaceVector to ReplaceIndex
|
||||
//
|
||||
if (ProcessTlsInformation->OperationType == ProcessTlsReplaceVector) {
|
||||
|
||||
// from MemoryModulePP
|
||||
if (!ProcessHandle) {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
// reserved 0x50 PVOID for ntdll loader
|
||||
if (ProcessTlsInformation->TlsVectorLength >= MMP_START_TLS_INDEX) {
|
||||
status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
Tls->OperationType = ProcessTlsReplaceIndex;
|
||||
for (auto i = 0; i < Tls->ThreadDataCount; ++i) {
|
||||
Tls->ThreadData[i].TlsModulePointer = Tls->ThreadData[i].TlsVector[ProcessTlsInformation->TlsVectorLength];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ProcessHandle) {
|
||||
if (ProcessTlsInformation->TlsIndex >= MMP_START_TLS_INDEX) {
|
||||
status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ProcessTlsInformation->TlsIndex < MMP_START_TLS_INDEX || ProcessTlsInformation->TlsIndex >= MMP_MAXIMUM_TLS_INDEX) {
|
||||
status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = OriginNtSetInformationProcess(
|
||||
hProcess,
|
||||
ProcessInformationClass,
|
||||
Tls,
|
||||
TlsLength
|
||||
);
|
||||
|
||||
//
|
||||
// Modify our mapping
|
||||
//
|
||||
EnterCriticalSection(&MmpTlspLock);
|
||||
for (auto i = 0; i < Tls->ThreadDataCount; ++i) {
|
||||
|
||||
bool found = false;
|
||||
PLIST_ENTRY entry = MmpThreadLocalStoragePointer.Flink;
|
||||
|
||||
// Find thread-spec tlsp
|
||||
while (entry != &MmpThreadLocalStoragePointer) {
|
||||
|
||||
PMMP_TLSP_RECORD j = CONTAINING_RECORD(entry, MMP_TLSP_RECORD, InMmpThreadLocalStoragePointer);
|
||||
|
||||
if (ProcessTlsInformation->OperationType == ProcessTlsReplaceVector) {
|
||||
if (j->TlspMmpBlock[ProcessTlsInformation->TlsVectorLength] == ProcessTlsInformation->ThreadData->TlsVector[ProcessTlsInformation->TlsVectorLength]) {
|
||||
found = true;
|
||||
|
||||
// Copy old data to new pointer
|
||||
RtlCopyMemory(
|
||||
ProcessTlsInformation->ThreadData[i].TlsVector,
|
||||
j->TlspMmpBlock,
|
||||
sizeof(PVOID) * ProcessTlsInformation->TlsVectorLength
|
||||
);
|
||||
|
||||
// Swap the tlsp
|
||||
std::swap(
|
||||
j->TlspLdrBlock,
|
||||
ProcessTlsInformation->ThreadData[i].TlsVector
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (j->TlspMmpBlock[ProcessTlsInformation->TlsIndex] == ProcessTlsInformation->ThreadData[i].TlsModulePointer) {
|
||||
found = true;
|
||||
|
||||
j->TlspLdrBlock[ProcessTlsInformation->TlsIndex] = ProcessTlsInformation->ThreadData[i].TlsModulePointer;
|
||||
ProcessTlsInformation->ThreadData[i].TlsModulePointer = Tls->ThreadData[i].TlsModulePointer;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)break;
|
||||
entry = entry->Flink;
|
||||
}
|
||||
|
||||
assert(found);
|
||||
ProcessTlsInformation->ThreadData[i].Flags = Tls->ThreadData[i].Flags;
|
||||
ProcessTlsInformation->ThreadData[i].ThreadId = Tls->ThreadData[i].ThreadId;
|
||||
}
|
||||
LeaveCriticalSection(&MmpTlspLock);
|
||||
|
||||
} while (false);
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, Tls);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI MmpAcquireTlsIndex(_Out_ PULONG TlsIndex) {
|
||||
|
||||
*TlsIndex = -1;
|
||||
|
||||
ULONG Index = RtlFindClearBitsAndSet(&MmpTlsBitmap, 1, 0);
|
||||
if (Index != -1) {
|
||||
*TlsIndex = Index;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI MmpAllocateTlsEntry(
|
||||
_In_ PIMAGE_TLS_DIRECTORY lpTlsDirectory,
|
||||
_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry,
|
||||
_Out_ PULONG lpTlsIndex,
|
||||
_Out_ PTLS_ENTRY* lpTlsEntry) {
|
||||
PTLS_ENTRY Entry = nullptr;
|
||||
IMAGE_TLS_DIRECTORY TlsDirectory;
|
||||
ULONG Length = 0;
|
||||
NTSTATUS status;
|
||||
DWORD TlsIndex;
|
||||
|
||||
__try {
|
||||
RtlCopyMemory(
|
||||
&TlsDirectory,
|
||||
lpTlsDirectory,
|
||||
sizeof(IMAGE_TLS_DIRECTORY)
|
||||
);
|
||||
|
||||
*PULONG(TlsDirectory.AddressOfIndex) = 0;
|
||||
|
||||
*lpTlsIndex = 0;
|
||||
*lpTlsEntry = nullptr;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
Entry = (PTLS_ENTRY)RtlAllocateHeap(
|
||||
NtCurrentPeb()->ProcessHeap,
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(TLS_ENTRY)
|
||||
);
|
||||
if (!Entry) {
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = MmpAcquireTlsIndex(&TlsIndex);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, Entry);
|
||||
return status;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
&Entry->TlsDirectory,
|
||||
&TlsDirectory,
|
||||
sizeof(IMAGE_TLS_DIRECTORY)
|
||||
);
|
||||
|
||||
Entry->ModuleEntry = lpModuleEntry;
|
||||
Entry->TlsDirectory.Characteristics =
|
||||
*PULONG(Entry->TlsDirectory.AddressOfIndex) = TlsIndex;
|
||||
|
||||
InsertTailList(&MmpTlsList, &Entry->TlsEntryLinks);
|
||||
|
||||
*lpTlsEntry = Entry;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) {
|
||||
|
||||
NTSTATUS status = STATUS_NOT_FOUND;
|
||||
|
||||
RtlAcquireSRWLockExclusive(&MmpTlsListLock);
|
||||
|
||||
for (auto entry = MmpTlsList.Flink; entry != &MmpTlsList; entry = entry->Flink) {
|
||||
auto p = CONTAINING_RECORD(entry, TLS_ENTRY, TlsEntryLinks);
|
||||
if (p->ModuleEntry == lpModuleEntry) {
|
||||
RemoveEntryList(&p->TlsEntryLinks);
|
||||
RtlClearBit(&MmpTlsBitmap, p->TlsDirectory.Characteristics);
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, p);
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RtlReleaseSRWLockExclusive(&MmpTlsListLock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) {
|
||||
PIMAGE_TLS_DIRECTORY lpTlsDirectory;
|
||||
ULONG DirectorySize;
|
||||
NTSTATUS status;
|
||||
ULONG TlsIndex;
|
||||
PTLS_ENTRY TlsEntry;
|
||||
|
||||
lpTlsDirectory = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(
|
||||
lpModuleEntry->DllBase,
|
||||
TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_TLS,
|
||||
&DirectorySize
|
||||
);
|
||||
|
||||
if (!lpTlsDirectory || !DirectorySize) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = MmpAllocateTlsEntry(
|
||||
lpTlsDirectory,
|
||||
lpModuleEntry,
|
||||
&TlsIndex,
|
||||
&TlsEntry
|
||||
);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlAcquireSRWLockExclusive(&MmpTlsListLock);
|
||||
InsertTailList(&MmpTlsList, &TlsEntry->TlsEntryLinks);
|
||||
RtlReleaseSRWLockExclusive(&MmpTlsListLock);
|
||||
|
||||
auto ThreadCount = MmpGetThreadCount();
|
||||
auto success = true;
|
||||
auto Length = sizeof(PROCESS_TLS_INFORMATION) + (ThreadCount - 1) * sizeof(THREAD_TLS_INFORMATION);
|
||||
auto ProcessTlsInformation = PPROCESS_TLS_INFORMATION(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, Length));
|
||||
if (!ProcessTlsInformation) {
|
||||
MmpReleaseTlsEntry(lpModuleEntry);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ProcessTlsInformation->OperationType = ProcessTlsReplaceIndex;
|
||||
ProcessTlsInformation->Reserved = 0;
|
||||
ProcessTlsInformation->TlsIndex = TlsIndex;
|
||||
ProcessTlsInformation->ThreadDataCount = ThreadCount;
|
||||
|
||||
for (DWORD i = 0; i < ThreadCount; ++i) {
|
||||
auto& current = ProcessTlsInformation->ThreadData[i];
|
||||
current.TlsModulePointer = RtlAllocateHeap(
|
||||
RtlProcessHeap(),
|
||||
0,
|
||||
lpTlsDirectory->EndAddressOfRawData - lpTlsDirectory->StartAddressOfRawData
|
||||
);
|
||||
if (!current.TlsModulePointer) {
|
||||
for (DWORD j = 0; j < i; ++j) {
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, ProcessTlsInformation->ThreadData[j].TlsModulePointer);
|
||||
}
|
||||
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
current.TlsModulePointer,
|
||||
PVOID(lpTlsDirectory->StartAddressOfRawData),
|
||||
lpTlsDirectory->EndAddressOfRawData - lpTlsDirectory->StartAddressOfRawData
|
||||
);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
MmpReleaseTlsEntry(lpModuleEntry);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = NtSetInformationProcess(
|
||||
nullptr, // hack
|
||||
ProcessResourceManagement,
|
||||
ProcessTlsInformation,
|
||||
Length
|
||||
);
|
||||
|
||||
RtlFreeHeap(RtlProcessHeap(), 0, ProcessTlsInformation);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
VOID NTAPI MmpInitialize() {
|
||||
|
||||
//
|
||||
// Initialize tlsp
|
||||
//
|
||||
InitializeCriticalSection(&MmpTlspLock);
|
||||
InitializeListHead(&MmpThreadLocalStoragePointer);
|
||||
|
||||
//
|
||||
// Initialize tls list
|
||||
//
|
||||
InitializeListHead(&MmpTlsList);
|
||||
RtlInitializeSRWLock(&MmpTlsListLock);
|
||||
|
||||
PULONG buffer = PULONG(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ULONG) * 8));
|
||||
if (!buffer) {
|
||||
RtlRaiseStatus(STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
RtlFillMemory(buffer, sizeof(ULONG) * 4, -1);
|
||||
RtlInitializeBitMap(&MmpTlsBitmap, buffer, 0x100);
|
||||
|
||||
if (NtCurrentTeb()->ThreadLocalStoragePointer) {
|
||||
if (!PreHookNtSetInformationProcess()) {
|
||||
RtlRaiseStatus(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Hook functions
|
||||
//
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(NtCurrentThread());
|
||||
DetourAttach((PVOID*)&OriginNtCreateThread, HookNtCreateThread);
|
||||
DetourAttach((PVOID*)&OriginNtCreateThreadEx, HookNtCreateThreadEx);
|
||||
DetourAttach((PVOID*)&OriginLdrShutdownThread, HookLdrShutdownThread);
|
||||
DetourAttach((PVOID*)&OriginNtSetInformationProcess, HookNtSetInformationProcess);
|
||||
DetourTransactionCommit();
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#pragma warning(disable:6387)
|
||||
#pragma warning(disable:26812)
|
||||
#pragma comment(lib,"Secur32.lib")
|
||||
#pragma comment(lib,"ntdll.lib")
|
||||
|
||||
FARPROC NTAPI RtlGetNtProcAddress(LPCSTR func_name) {
|
||||
return GetProcAddress(GetModuleHandleA("ntdll.dll"), func_name);
|
||||
|
||||
+184
-5
@@ -81,10 +81,10 @@ typedef struct _STRING {
|
||||
WORD MaximumLength;
|
||||
CHAR * Buffer;
|
||||
} STRING, *PSTRING;
|
||||
struct CLIENT_ID {
|
||||
HANDLE UniqueProcess;//Process ID
|
||||
HANDLE UniqueThread;//Thread ID
|
||||
};
|
||||
typedef struct _CLIENT_ID {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, * PCLIENT_ID;
|
||||
typedef struct _SYSTEM_THREAD {
|
||||
LARGE_INTEGER KernelTime;
|
||||
LARGE_INTEGER UserTime;
|
||||
@@ -1422,6 +1422,185 @@ NTSTATUS NTAPI LdrLockLoaderLock(size_t Flags, size_t* State, size_t* Cookie);
|
||||
NTSTATUS NTAPI LdrUnlockLoaderLock(size_t Flags, size_t Cookie);
|
||||
NTSTATUS NTAPI LdrUnloadDll(IN HANDLE ModuleHandle);
|
||||
|
||||
#define RtlRaiseStatus(_Status_) ((VOID(NTAPI*)(NTSTATUS Status))(RtlGetNtProcAddress("RtlRaiseStatus")))(_Status_)
|
||||
extern "C"
|
||||
NTSYSAPI
|
||||
DECLSPEC_NORETURN
|
||||
VOID
|
||||
NTAPI
|
||||
RtlRaiseStatus(
|
||||
_In_ NTSTATUS Status
|
||||
);
|
||||
|
||||
DECLSPEC_NORETURN VOID NTAPI RtlExitUserThread(IN NTSTATUS ExitStatus);
|
||||
|
||||
#define RtlProcessHeap() (NtCurrentPeb()->ProcessHeap)
|
||||
|
||||
#define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess)
|
||||
#define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread)
|
||||
|
||||
typedef enum _PROCESS_TLS_INFORMATION_TYPE {
|
||||
ProcessTlsReplaceIndex,
|
||||
ProcessTlsReplaceVector,
|
||||
MaxProcessTlsOperation
|
||||
} PROCESS_TLS_INFORMATION_TYPE, * PPROCESS_TLS_INFORMATION_TYPE;
|
||||
|
||||
typedef struct _RTL_BITMAP {
|
||||
ULONG SizeOfBitMap;
|
||||
PULONG Buffer;
|
||||
} RTL_BITMAP, * PRTL_BITMAP;
|
||||
|
||||
FORCEINLINE VOID InitializeListHead(
|
||||
_Out_ PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
ListHead->Flink = ListHead->Blink = ListHead;
|
||||
}
|
||||
|
||||
FORCEINLINE BOOLEAN RemoveEntryList(
|
||||
_In_ PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
PLIST_ENTRY Flink;
|
||||
|
||||
Flink = Entry->Flink;
|
||||
Blink = Entry->Blink;
|
||||
Blink->Flink = Flink;
|
||||
Flink->Blink = Blink;
|
||||
|
||||
return Flink == Blink;
|
||||
}
|
||||
|
||||
FORCEINLINE VOID InsertTailList(
|
||||
_Inout_ PLIST_ENTRY ListHead,
|
||||
_Inout_ PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
|
||||
Blink = ListHead->Blink;
|
||||
Entry->Flink = ListHead;
|
||||
Entry->Blink = Blink;
|
||||
Blink->Flink = Entry;
|
||||
ListHead->Blink = Entry;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSetInformationProcess(
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ PROCESSINFOCLASS ProcessInformationClass,
|
||||
_In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
|
||||
_In_ ULONG ProcessInformationLength
|
||||
);
|
||||
|
||||
extern "C"
|
||||
NTSYSAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LdrShutdownThread(
|
||||
VOID
|
||||
);
|
||||
|
||||
extern "C"
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCreateThread(
|
||||
_Out_ PHANDLE ThreadHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_Out_ PCLIENT_ID ClientId,
|
||||
_In_ PCONTEXT ThreadContext,
|
||||
_In_ PINITIAL_TEB InitialTeb,
|
||||
_In_ BOOLEAN CreateSuspended
|
||||
);
|
||||
|
||||
extern "C"
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCreateThreadEx(
|
||||
_Out_ PHANDLE ThreadHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ PVOID StartRoutine,
|
||||
_In_opt_ PVOID Argument,
|
||||
_In_ ULONG CreateFlags,
|
||||
_In_ SIZE_T ZeroBits,
|
||||
_In_ SIZE_T StackSize,
|
||||
_In_ SIZE_T MaximumStackSize,
|
||||
_In_opt_ PVOID AttributeList
|
||||
);
|
||||
|
||||
extern "C" {
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlInitializeSRWLock(
|
||||
_Out_ PRTL_SRWLOCK SRWLock
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlAcquireSRWLockExclusive(
|
||||
_Inout_ PRTL_SRWLOCK SRWLock
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlAcquireSRWLockShared(
|
||||
_Inout_ PRTL_SRWLOCK SRWLock
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlReleaseSRWLockExclusive(
|
||||
_Inout_ PRTL_SRWLOCK SRWLock
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlReleaseSRWLockShared(
|
||||
_Inout_ PRTL_SRWLOCK SRWLock
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlClearBits(
|
||||
_In_ PRTL_BITMAP BitMapHeader,
|
||||
_In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex,
|
||||
_In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
RtlInitializeBitMap(
|
||||
_Out_ PRTL_BITMAP BitMapHeader,
|
||||
_In_ PULONG BitMapBuffer,
|
||||
_In_ ULONG SizeOfBitMap
|
||||
);
|
||||
|
||||
_Success_(return != -1)
|
||||
NTSYSAPI
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlFindClearBitsAndSet(
|
||||
_In_ PRTL_BITMAP BitMapHeader,
|
||||
_In_ ULONG NumberToFind,
|
||||
_In_ ULONG HintIndex
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#define RtlClearBit(BitMapHeader,BitNumber) RtlClearBits((BitMapHeader),(BitNumber),1)
|
||||
|
||||
@@ -412,16 +412,4 @@ BOOL NTAPI RtlFreeLdrpHeap(IN PVOID buffer);
|
||||
#define RtlInitializeListEntry(entry) ((entry)->Blink = (entry)->Flink = (entry))
|
||||
#define RtlInitializeSingleEntry(entry) ((entry->Next = (entry)))
|
||||
|
||||
FORCEINLINE BOOLEAN NTAPI RemoveEntryList(IN PLIST_ENTRY Entry) {
|
||||
PLIST_ENTRY OldFlink;
|
||||
PLIST_ENTRY OldBlink;
|
||||
|
||||
OldFlink = Entry->Flink;
|
||||
OldBlink = Entry->Blink;
|
||||
|
||||
OldFlink->Blink = OldBlink;
|
||||
OldBlink->Flink = OldFlink;
|
||||
return (BOOLEAN)(OldFlink == OldBlink);
|
||||
}
|
||||
|
||||
size_t NTAPI LdrpDataTableEntrySize();
|
||||
|
||||
+14
-101
@@ -18,114 +18,27 @@ static PVOID ReadDllFile(LPCSTR FileName) {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int test_default() {
|
||||
LPVOID buffer = ReadDllFile("a.dll");
|
||||
VOID NTAPI MmpInitialize();
|
||||
|
||||
DWORD NTAPI Thread(PVOID) {
|
||||
|
||||
HMEMORYMODULE m1 = nullptr, m2 = m1;
|
||||
HMODULE hModule = nullptr;
|
||||
FARPROC pfn = nullptr;
|
||||
DWORD MemoryModuleFeatures = 0;
|
||||
|
||||
typedef int(* _exception)(int code);
|
||||
_exception exception = nullptr;
|
||||
HRSRC hRsrc;
|
||||
DWORD SizeofRes;
|
||||
HGLOBAL gRes;
|
||||
char str[10];
|
||||
|
||||
LdrQuerySystemMemoryModuleFeatures(&MemoryModuleFeatures);
|
||||
if (MemoryModuleFeatures != MEMORY_FEATURE_ALL) {
|
||||
printf("not support all features on this version of windows.\n");
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(LdrLoadDllMemoryExW(&m1, nullptr, 0, buffer, 0, L"kernel64", nullptr))) goto end;
|
||||
LoadLibraryW(L"wininet.dll");
|
||||
if (!NT_SUCCESS(LdrLoadDllMemoryExW(&m2, nullptr, 0, buffer, 0, L"kernel128", nullptr))) goto end;
|
||||
|
||||
//forward export
|
||||
hModule = (HMODULE)m1;
|
||||
pfn = (decltype(pfn))(GetProcAddress(hModule, "Socket")); //ws2_32.WSASocketW
|
||||
pfn = (decltype(pfn))(GetProcAddress(hModule, "VerifyTruse")); //wintrust.WinVerifyTrust
|
||||
hModule = (HMODULE)m2;
|
||||
pfn = (decltype(pfn))(GetProcAddress(hModule, "Socket"));
|
||||
pfn = (decltype(pfn))(GetProcAddress(hModule, "VerifyTruse"));
|
||||
|
||||
//exception
|
||||
hModule = (HMODULE)m1;
|
||||
exception = (_exception)GetProcAddress(hModule, "exception");
|
||||
if (exception) {
|
||||
for (int i = 0; i < 4; ++i)exception(i);
|
||||
}
|
||||
|
||||
//tls
|
||||
pfn = GetProcAddress(hModule, "thread");
|
||||
if (pfn && pfn()) {
|
||||
printf("thread test failed.\n");
|
||||
}
|
||||
|
||||
//resource
|
||||
if (!LoadStringA(hModule, 101, str, 10)) {
|
||||
printf("load string failed.\n");
|
||||
}
|
||||
else {
|
||||
printf("%s\n", str);
|
||||
}
|
||||
if (!(hRsrc = FindResourceA(hModule, MAKEINTRESOURCEA(102), "BINARY"))) {
|
||||
printf("find binary resource failed.\n");
|
||||
}
|
||||
else {
|
||||
if ((SizeofRes = SizeofResource(hModule, hRsrc)) != 0x10) {
|
||||
printf("invalid res size.\n");
|
||||
}
|
||||
else {
|
||||
if (!(gRes = LoadResource(hModule, hRsrc))) {
|
||||
printf("load res failed.\n");
|
||||
}
|
||||
else {
|
||||
if (!LockResource(gRes))printf("lock res failed.\n");
|
||||
else {
|
||||
printf("resource test success.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
delete[]buffer;
|
||||
if (m1)LdrUnloadDllMemory(m1);
|
||||
FreeLibrary(LoadLibraryW(L"wininet.dll"));
|
||||
FreeLibrary(GetModuleHandleW(L"wininet.dll"));
|
||||
if (m2)LdrUnloadDllMemory(m2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//test_default();
|
||||
//test_ws2_32();
|
||||
DWORD dwFeatures = 0;
|
||||
LdrQuerySystemMemoryModuleFeatures(&dwFeatures);
|
||||
if ((dwFeatures & MEMORY_FEATURE_ALL) != MEMORY_FEATURE_ALL) {
|
||||
printf("\n");
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
auto pOle32 = ReadDllFile("C:\\Windows\\System32\\ole32.dll");
|
||||
HMEMORYMODULE hModule;
|
||||
NTSTATUS status = LdrLoadDllMemoryExW(
|
||||
&hModule,
|
||||
nullptr,
|
||||
0,
|
||||
pOle32,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
delete[]pOle32;
|
||||
MmpInitialize();
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
LdrUnloadDllMemory(hModule);
|
||||
HMODULE hModule = LoadLibrary(L"a.dll");
|
||||
if (hModule) {
|
||||
|
||||
HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr);
|
||||
if (hThread) {
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user