725 lines
22 KiB
C++
725 lines
22 KiB
C++
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Module Enumeration Functions (modules.cpp of detours.lib)
|
||
|
//
|
||
|
// Microsoft Research Detours Package, Version 2.1.
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// Module enumeration functions.
|
||
|
//
|
||
|
|
||
|
#include <windows.h>
|
||
|
#if (_MSC_VER < 1310)
|
||
|
#else
|
||
|
#include <strsafe.h>
|
||
|
#endif
|
||
|
|
||
|
//#define DETOUR_DEBUG 1
|
||
|
#define DETOURS_INTERNAL
|
||
|
#include "detours.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
#ifndef _STRSAFE_H_INCLUDED_
|
||
|
static inline HRESULT StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
size_t cchMaxPrev = cchMax;
|
||
|
|
||
|
if (cchMax > 2147483647)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
while (cchMax && (*psz != '\0'))
|
||
|
{
|
||
|
psz++;
|
||
|
cchMax--;
|
||
|
}
|
||
|
|
||
|
if (cchMax == 0)
|
||
|
{
|
||
|
// the string is longer than cchMax
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr) && pcch)
|
||
|
{
|
||
|
*pcch = cchMaxPrev - cchMax;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
static inline HRESULT StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (cchDest == 0)
|
||
|
{
|
||
|
// can not null terminate a zero-byte dest buffer
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while (cchDest && (*pszSrc != '\0'))
|
||
|
{
|
||
|
*pszDest++ = *pszSrc++;
|
||
|
cchDest--;
|
||
|
}
|
||
|
|
||
|
if (cchDest == 0)
|
||
|
{
|
||
|
// we are going to truncate pszDest
|
||
|
pszDest--;
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
*pszDest= '\0';
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
static inline HRESULT StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
size_t cchDestCurrent;
|
||
|
|
||
|
if (cchDest > 2147483647)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
hr = StringCchLengthA(pszDest, cchDest, &cchDestCurrent);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = StringCchCopyA(pszDest + cchDestCurrent,
|
||
|
cchDest - cchDestCurrent,
|
||
|
pszSrc);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
const GUID DETOUR_EXE_RESTORE_GUID = {
|
||
|
0x2ed7a3ff, 0x3339, 0x4a8d,
|
||
|
{ 0x80, 0x5c, 0xd4, 0x98, 0x15, 0x3f, 0xc2, 0x8f }};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
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 = LoadLibraryA("dbghelp.dll");
|
||
|
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(PCSTR pszModule, PCSTR pszFunction)
|
||
|
{
|
||
|
/////////////////////////////////////////////// First, try GetProcAddress.
|
||
|
//
|
||
|
HMODULE hModule = LoadLibraryA(pszModule);
|
||
|
if (hModule == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PBYTE pbCode = (PBYTE)GetProcAddress(hModule, pszFunction);
|
||
|
if (pbCode) {
|
||
|
return pbCode;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////// Then try ImageHelp.
|
||
|
//
|
||
|
DETOUR_TRACE(("DetourFindFunction(%s, %s)\n", pszModule, pszFunction));
|
||
|
PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp();
|
||
|
if (pSymInfo == NULL) {
|
||
|
DETOUR_TRACE(("DetourLoadImageHlp failed: %d\n",
|
||
|
GetLastError()));
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (pSymInfo->pfSymLoadModule64(pSymInfo->hProcess, NULL,
|
||
|
(PCHAR)pszModule, NULL,
|
||
|
(DWORD64)hModule, 0) == 0) {
|
||
|
DETOUR_TRACE(("SymLoadModule64(%p) failed: %d\n",
|
||
|
pSymInfo->hProcess, GetLastError()));
|
||
|
// We don't stop because some version of dbghelp fail secondary calls.
|
||
|
//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: %d\n",
|
||
|
pSymInfo->hProcess, hModule, GetLastError()));
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName);
|
||
|
if (FAILED(hrRet)) {
|
||
|
DETOUR_TRACE(("StringCchCopyA failed: %08x\n", hrRet));
|
||
|
return NULL;
|
||
|
}
|
||
|
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!");
|
||
|
if (FAILED(hrRet)) {
|
||
|
DETOUR_TRACE(("StringCchCatA failed: %08x\n", hrRet));
|
||
|
return NULL;
|
||
|
}
|
||
|
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction);
|
||
|
if (FAILED(hrRet)) {
|
||
|
DETOUR_TRACE(("StringCchCatA failed: %08x\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(%s) failed: %d\n", szFullName, GetLastError()));
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#ifdef 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;
|
||
|
#else
|
||
|
return (PBYTE)symbol.Address;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////// Module Image Functions.
|
||
|
//
|
||
|
HMODULE WINAPI DetourEnumerateModules(HMODULE hModuleLast)
|
||
|
{
|
||
|
PBYTE pbLast;
|
||
|
|
||
|
if (hModuleLast == NULL) {
|
||
|
pbLast = (PBYTE)0x10000;
|
||
|
}
|
||
|
else {
|
||
|
pbLast = (PBYTE)hModuleLast + 0x10000;
|
||
|
}
|
||
|
|
||
|
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((PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Skip uncommitted regions and guard pages.
|
||
|
//
|
||
|
if ((mbi.State != MEM_COMMIT) || (mbi.Protect & PAGE_GUARD)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
|
||
|
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||
|
pDosHeader->e_lfanew);
|
||
|
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
return (HMODULE)pDosHeader;
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PVOID WINAPI DetourGetEntryPoint(HMODULE hModule)
|
||
|
{
|
||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||
|
if (hModule == NULL) {
|
||
|
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
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 ((PBYTE)pDosHeader) +
|
||
|
pNtHeader->OptionalHeader.AddressOfEntryPoint;
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG WINAPI DetourGetModuleSize(HMODULE hModule)
|
||
|
{
|
||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||
|
if (hModule == NULL) {
|
||
|
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
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(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline PBYTE RvaAdjust(PIMAGE_DOS_HEADER pDosHeader, DWORD raddr)
|
||
|
{
|
||
|
if (raddr != NULL) {
|
||
|
return ((PBYTE)pDosHeader) + raddr;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL WINAPI DetourEnumerateExports(HMODULE hModule,
|
||
|
PVOID pContext,
|
||
|
PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport)
|
||
|
{
|
||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||
|
if (hModule == NULL) {
|
||
|
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
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(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static PDETOUR_LOADED_BINARY WINAPI GetPayloadSectionFromModule(HMODULE hModule)
|
||
|
{
|
||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||
|
if (hModule == NULL) {
|
||
|
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
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(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_EXE_MARKED_INVALID);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DWORD WINAPI DetourGetSizeOfPayloads(HMODULE hModule)
|
||
|
{
|
||
|
PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
|
||
|
if (pBinary == NULL) {
|
||
|
// Error set by GetPayloadSectonFromModule.
|
||
|
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(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_INVALID_HANDLE);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PVOID WINAPI DetourFindPayload(HMODULE hModule, REFGUID rguid, DWORD * pcbData)
|
||
|
{
|
||
|
PBYTE pbData = NULL;
|
||
|
if (pcbData) {
|
||
|
*pcbData = 0;
|
||
|
}
|
||
|
|
||
|
PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule);
|
||
|
if (pBinary == NULL) {
|
||
|
// Error set by GetPayloadSectonFromModule.
|
||
|
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 (pSection->guid.Data1 == rguid.Data1 &&
|
||
|
pSection->guid.Data2 == rguid.Data2 &&
|
||
|
pSection->guid.Data3 == rguid.Data3 &&
|
||
|
pSection->guid.Data4[0] == rguid.Data4[0] &&
|
||
|
pSection->guid.Data4[1] == rguid.Data4[1] &&
|
||
|
pSection->guid.Data4[2] == rguid.Data4[2] &&
|
||
|
pSection->guid.Data4[3] == rguid.Data4[3] &&
|
||
|
pSection->guid.Data4[4] == rguid.Data4[4] &&
|
||
|
pSection->guid.Data4[5] == rguid.Data4[5] &&
|
||
|
pSection->guid.Data4[6] == rguid.Data4[6] &&
|
||
|
pSection->guid.Data4[7] == rguid.Data4[7]) {
|
||
|
|
||
|
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(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(ERROR_INVALID_HANDLE);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL WINAPI DetourRestoreAfterWithEx(PVOID pvData, 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;
|
||
|
DWORD dwPermInh;
|
||
|
DWORD dwPermClr;
|
||
|
DWORD dwOld;
|
||
|
BOOL fSucceeded = FALSE;
|
||
|
|
||
|
if (!VirtualProtect(pder->pidh, sizeof(pder->idh),
|
||
|
PAGE_EXECUTE_READWRITE, &dwPermIdh)) {
|
||
|
goto end0;
|
||
|
}
|
||
|
if (!VirtualProtect(pder->pinh, sizeof(pder->inh),
|
||
|
PAGE_EXECUTE_READWRITE, &dwPermInh)) {
|
||
|
goto end1;
|
||
|
}
|
||
|
if (pder->pclrFlags != NULL) {
|
||
|
if (!VirtualProtect(pder->pclrFlags, sizeof(pder->clrFlags),
|
||
|
PAGE_EXECUTE_READWRITE, &dwPermClr)) {
|
||
|
goto end2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CopyMemory(pder->pidh, &pder->idh, sizeof(pder->idh));
|
||
|
CopyMemory(pder->pinh, &pder->inh, sizeof(pder->inh));
|
||
|
|
||
|
if (pder->pclrFlags != NULL) {
|
||
|
CopyMemory(pder->pclrFlags, &pder->clrFlags, sizeof(pder->clrFlags));
|
||
|
}
|
||
|
fSucceeded = TRUE;
|
||
|
|
||
|
if (pder->pclrFlags != NULL) {
|
||
|
VirtualProtect(pder->pclrFlags, sizeof(pder->clrFlags), dwPermIdh, &dwOld);
|
||
|
}
|
||
|
end2:
|
||
|
VirtualProtect(pder->pinh, sizeof(pder->inh), dwPermInh, &dwOld);
|
||
|
end1:
|
||
|
VirtualProtect(pder->pidh, sizeof(pder->idh), dwPermIdh, &dwOld);
|
||
|
end0:
|
||
|
return fSucceeded;
|
||
|
}
|
||
|
|
||
|
BOOL WINAPI DetourRestoreAfterWith()
|
||
|
{
|
||
|
for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
|
||
|
PVOID pvData;
|
||
|
DWORD cbData;
|
||
|
|
||
|
pvData = DetourFindPayload(hMod, DETOUR_EXE_RESTORE_GUID, &cbData);
|
||
|
|
||
|
if (pvData == NULL || cbData == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
return DetourRestoreAfterWithEx(pvData, cbData);
|
||
|
}
|
||
|
SetLastError(ERROR_MOD_NOT_FOUND);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// End of File
|