Update detours library to latest.

This commit is contained in:
Mr_Goldberg 2021-05-16 21:04:54 -04:00
parent 5495f36ed6
commit c162ca79d5
No known key found for this signature in database
GPG key ID: 8597D87419DEF278
7 changed files with 1294 additions and 864 deletions

View file

@ -29,32 +29,32 @@ const GUID DETOUR_EXE_HELPER_GUID = { /* ea0251b9-5cde-41b5-98d0-2af4a26b0fee */
//////////////////////////////////////////////////////////////////////////////
//
// Enumate through modules in the target process.
// Enumerate through modules in the target process.
//
static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess,
HMODULE hModule,
PIMAGE_NT_HEADERS32 pNtHeader)
static PVOID LoadNtHeaderFromProcess(_In_ HANDLE hProcess,
_In_ HMODULE hModule,
_Out_ PIMAGE_NT_HEADERS32 pNtHeader)
{
ZeroMemory(pNtHeader, sizeof(*pNtHeader));
PBYTE pbModule = (PBYTE)hModule;
if (pbModule == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
return NULL;
}
MEMORY_BASIC_INFORMATION mbi;
ZeroMemory(&mbi, sizeof(mbi));
if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) {
return FALSE;
return NULL;
}
IMAGE_DOS_HEADER idh;
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError()));
return FALSE;
return NULL;
}
if (idh.e_magic != IMAGE_DOS_SIGNATURE ||
@ -62,31 +62,37 @@ static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess,
(DWORD)idh.e_lfanew < sizeof(idh)) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE;
return NULL;
}
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew,
pNtHeader, sizeof(*pNtHeader), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %lu\n",
pbModule + idh.e_lfanew,
pbModule + idh.e_lfanew + sizeof(*pNtHeader),
pbModule,
GetLastError()));
return FALSE;
return NULL;
}
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE;
return NULL;
}
return TRUE;
return pbModule + idh.e_lfanew;
}
static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess,
HMODULE hModuleLast,
PIMAGE_NT_HEADERS32 pNtHeader)
static HMODULE EnumerateModulesInProcess(_In_ HANDLE hProcess,
_In_opt_ HMODULE hModuleLast,
_Out_ PIMAGE_NT_HEADERS32 pNtHeader,
_Out_opt_ PVOID *pRemoteNtHeader)
{
ZeroMemory(pNtHeader, sizeof(*pNtHeader));
if (pRemoteNtHeader) {
*pRemoteNtHeader = NULL;
}
PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
MEMORY_BASIC_INFORMATION mbi;
@ -118,13 +124,147 @@ static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess,
continue;
}
if (LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader)) {
PVOID remoteHeader
= LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader);
if (remoteHeader) {
if (pRemoteNtHeader) {
*pRemoteNtHeader = remoteHeader;
}
return (HMODULE)pbLast;
}
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
// Find payloads in target process.
//
static PVOID FindDetourSectionInRemoteModule(_In_ HANDLE hProcess,
_In_ HMODULE hModule,
_In_ const IMAGE_NT_HEADERS32 *pNtHeader,
_In_ PVOID pRemoteNtHeader)
{
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
PIMAGE_SECTION_HEADER pRemoteSectionHeaders
= (PIMAGE_SECTION_HEADER)((PBYTE)pRemoteNtHeader
+ sizeof(pNtHeader->Signature)
+ sizeof(pNtHeader->FileHeader)
+ pNtHeader->FileHeader.SizeOfOptionalHeader);
IMAGE_SECTION_HEADER header;
for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; ++n) {
if (!ReadProcessMemory(hProcess, pRemoteSectionHeaders + n, &header, sizeof(header), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
pRemoteSectionHeaders + n,
(PBYTE)(pRemoteSectionHeaders + n) + sizeof(header),
GetLastError()));
return NULL;
}
if (strcmp((PCHAR)header.Name, ".detour") == 0) {
if (header.VirtualAddress == 0 ||
header.SizeOfRawData == 0) {
break;
}
SetLastError(NO_ERROR);
return (PBYTE)hModule + header.VirtualAddress;
}
}
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
static PVOID FindPayloadInRemoteDetourSection(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData,
_In_ PVOID pvRemoteDetoursSection)
{
if (pcbData) {
*pcbData = 0;
}
PBYTE pbData = (PBYTE)pvRemoteDetoursSection;
DETOUR_SECTION_HEADER header;
if (!ReadProcessMemory(hProcess, pbData, &header, sizeof(header), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(dsh@%p..%p) failed: %lu\n",
pbData,
pbData + sizeof(header),
GetLastError()));
return NULL;
}
if (header.cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
header.nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
if (header.nDataOffset == 0) {
header.nDataOffset = header.cbHeaderSize;
}
for (PVOID pvSection = pbData + header.nDataOffset; pvSection < pbData + header.cbDataSize;) {
DETOUR_SECTION_RECORD section;
if (!ReadProcessMemory(hProcess, pvSection, &section, sizeof(section), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(dsr@%p..%p) failed: %lu\n",
pvSection,
(PBYTE)pvSection + sizeof(section),
GetLastError()));
return NULL;
}
if (DetourAreSameGuid(section.guid, rguid)) {
if (pcbData) {
*pcbData = section.cbBytes - sizeof(section);
}
SetLastError(NO_ERROR);
return (DETOUR_SECTION_RECORD *)pvSection + 1;
}
pvSection = (PBYTE)pvSection + section.cbBytes;
}
return NULL;
}
_Success_(return != NULL)
PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData)
{
if (hProcess == NULL) {
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
IMAGE_NT_HEADERS32 header;
PVOID pvRemoteHeader;
for (HMODULE hMod = NULL; (hMod = EnumerateModulesInProcess(hProcess, hMod, &header, &pvRemoteHeader)) != NULL;) {
PVOID pvData = FindDetourSectionInRemoteModule(hProcess, hMod, &header, pvRemoteHeader);
if (pvData != NULL) {
pvData = FindPayloadInRemoteDetourSection(hProcess, rguid, pcbData, pvData);
if (pvData != NULL) {
return pvData;
}
}
}
SetLastError(ERROR_MOD_NOT_FOUND);
return NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
// Find a region of memory in which we can create a replacement import table.
@ -142,7 +282,7 @@ static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBa
if (GetLastError() == ERROR_INVALID_PARAMETER) {
break;
}
DETOUR_TRACE(("VirtualQueryEx(%p) failed: %d\n",
DETOUR_TRACE(("VirtualQueryEx(%p) failed: %lu\n",
pbLast, GetLastError()));
break;
}
@ -187,7 +327,7 @@ static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBa
PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (pbAlloc == NULL) {
DETOUR_TRACE(("VirtualAllocEx(%p) failed: %d\n", pbAddress, GetLastError()));
DETOUR_TRACE(("VirtualAllocEx(%p) failed: %lu\n", pbAddress, GetLastError()));
continue;
}
#ifdef _WIN64
@ -246,7 +386,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
der.pidh = (PBYTE)hModule;
der.cbidh = sizeof(der.idh);
if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
der.pidh, der.pidh + der.cbidh, GetLastError()));
return FALSE;
}
@ -257,7 +397,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
der.pinh = der.pidh + der.idh.e_lfanew;
der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader);
if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
der.pinh, der.pinh + der.cbinh, GetLastError()));
return FALSE;
}
@ -272,7 +412,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
}
if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
der.pinh, der.pinh + der.cbinh, GetLastError()));
return FALSE;
}
@ -284,7 +424,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 &&
der.inh32.CLR_DIRECTORY.Size != 0) {
DETOUR_TRACE(("CLR32.VirtAddr=%x, CLR.Size=%x\n",
DETOUR_TRACE(("CLR32.VirtAddr=%08lx, CLR.Size=%lu\n",
der.inh32.CLR_DIRECTORY.VirtualAddress,
der.inh32.CLR_DIRECTORY.Size));
@ -295,7 +435,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 &&
der.inh64.CLR_DIRECTORY.Size != 0) {
DETOUR_TRACE(("CLR64.VirtAddr=%x, CLR.Size=%x\n",
DETOUR_TRACE(("CLR64.VirtAddr=%08lx, CLR.Size=%lu\n",
der.inh64.CLR_DIRECTORY.VirtualAddress,
der.inh64.CLR_DIRECTORY.Size));
@ -306,7 +446,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.pclr != 0) {
der.cbclr = sizeof(der.clr);
if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %lu\n",
der.pclr, der.pclr + der.cbclr, GetLastError()));
return FALSE;
}
@ -323,6 +463,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS32
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR32_MAGIC
#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG32
#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA32
#define UPDATE_IMPORTS_XX UpdateImports32
#define DETOURS_BITS_XX 32
#include "uimports.cc"
@ -339,6 +480,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS64
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR64_MAGIC
#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG64
#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA64
#define UPDATE_IMPORTS_XX UpdateImports64
#define DETOURS_BITS_XX 64
#include "uimports.cc"
@ -374,7 +516,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
//////////////////////////////////////////////////////// Read old headers.
//
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError()));
return FALSE;
}
@ -383,7 +525,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
PBYTE pnh = pbModule + idh.e_lfanew;
if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh32), GetLastError()));
return FALSE;
}
@ -398,7 +540,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
inh32.FileHeader.SizeOfOptionalHeader;
ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (!ReadProcessMemory(hProcess, psects, &sects, cb, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
psects, psects + cb, GetLastError()));
return FALSE;
}
@ -455,7 +597,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
}
if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh64), GetLastError()));
return FALSE;
}
@ -466,7 +608,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
inh64.FileHeader.SizeOfOptionalHeader;
cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (!WriteProcessMemory(hProcess, psects, &sects, cb, NULL)) {
DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %d\n",
DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %lu\n",
psects, psects + cb, GetLastError()));
return FALSE;
}
@ -478,12 +620,12 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
}
// Remove the import table.
if (der.pclr != NULL && (der.clr.Flags & 1)) {
if (der.pclr != NULL && (der.clr.Flags & COMIMAGE_FLAGS_ILONLY)) {
inh64.IMPORT_DIRECTORY.VirtualAddress = 0;
inh64.IMPORT_DIRECTORY.Size = 0;
if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh64), GetLastError()));
return FALSE;
}
@ -499,6 +641,37 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
}
#endif // DETOURS_64BIT
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
static BOOL IsWow64ProcessHelper(HANDLE hProcess,
PBOOL Wow64Process)
{
#ifdef _X86_
if (Wow64Process == NULL) {
return FALSE;
}
// IsWow64Process is not available on all supported versions of Windows.
//
HMODULE hKernel32 = LoadLibraryW(L"KERNEL32.DLL");
if (hKernel32 == NULL) {
DETOUR_TRACE(("LoadLibraryW failed: %lu\n", GetLastError()));
return FALSE;
}
LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
hKernel32, "IsWow64Process");
if (pfnIsWow64Process == NULL) {
DETOUR_TRACE(("GetProcAddress failed: %lu\n", GetLastError()));
return FALSE;
}
return pfnIsWow64Process(hProcess, Wow64Process);
#else
return IsWow64Process(hProcess, Wow64Process);
#endif
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
@ -507,18 +680,17 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
{
// Find the next memory region that contains a mapped PE image.
//
BOOL bHas64BitDll = FALSE;
BOOL bHas32BitExe = FALSE;
BOOL bIs32BitProcess;
BOOL bIs64BitOS = FALSE;
HMODULE hModule = NULL;
HMODULE hLast = NULL;
DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%d)\n", hProcess, nDlls));
DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%lu)\n", hProcess, nDlls));
for (;;) {
IMAGE_NT_HEADERS32 inh;
if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh)) == NULL) {
if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh, NULL)) == NULL) {
break;
}
@ -527,20 +699,8 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
hModule = hLast;
if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
&& inh.FileHeader.Machine != 0) {
bHas32BitExe = TRUE;
}
DETOUR_TRACE(("%p Found EXE\n", hLast));
}
else {
if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
&& inh.FileHeader.Machine != 0) {
bHas64BitDll = TRUE;
}
}
}
if (hModule == NULL) {
@ -548,19 +708,37 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
return FALSE;
}
if (!bHas32BitExe) {
bIs32BitProcess = FALSE;
// Determine if the target process is 32bit or 64bit. This is a two-stop process:
//
// 1. First, determine if we're running on a 64bit operating system.
// - If we're running 64bit code (i.e. _WIN64 is defined), this is trivially true.
// - If we're running 32bit code (i.e. _WIN64 is not defined), test if
// we're running under Wow64. If so, it implies that the operating system
// is 64bit.
//
#ifdef _WIN64
bIs64BitOS = TRUE;
#else
if (!IsWow64ProcessHelper(GetCurrentProcess(), &bIs64BitOS)) {
return FALSE;
}
else if (!bHas64BitDll) {
bIs32BitProcess = TRUE;
}
else {
if (!IsWow64Process(hProcess, &bIs32BitProcess)) {
#endif
// 2. With the operating system bitness known, we can now consider the target process:
// - If we're running on a 64bit OS, the target process is 32bit in case
// it is running under Wow64. Otherwise, it's 64bit, running natively
// (without Wow64).
// - If we're running on a 32bit OS, the target process must be 32bit, too.
//
if (bIs64BitOS) {
if (!IsWow64ProcessHelper(hProcess, &bIs32BitProcess)) {
return FALSE;
}
} else {
bIs32BitProcess = TRUE;
}
DETOUR_TRACE((" 32BitExe=%d 32BitProcess\n", bHas32BitExe, bIs32BitProcess));
DETOUR_TRACE((" 32BitProcess=%d\n", bIs32BitProcess));
return DetourUpdateProcessWithDllEx(hProcess,
hModule,
@ -579,11 +757,11 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
//
BOOL bIs32BitExe = FALSE;
DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%d)\n", hProcess, hModule, nDlls));
DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%lu)\n", hProcess, hModule, nDlls));
IMAGE_NT_HEADERS32 inh;
if (hModule == NULL || LoadNtHeaderFromProcess(hProcess, hModule, &inh) == NULL) {
if (hModule == NULL || !LoadNtHeaderFromProcess(hProcess, hModule, &inh)) {
SetLastError(ERROR_INVALID_OPERATION);
return FALSE;
}
@ -594,7 +772,7 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
bIs32BitExe = TRUE;
}
DETOUR_TRACE((" 32BitExe=%d 32BitProcess\n", bIs32BitExe, bIs32BitProcess));
DETOUR_TRACE((" 32BitExe=%d\n", bIs32BitExe));
if (hModule == NULL) {
SetLastError(ERROR_INVALID_OPERATION);
@ -613,8 +791,8 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
// Try to convert a neutral 32-bit managed binary to a 64-bit managed binary.
if (bIs32BitExe && !bIs32BitProcess) {
if (!der.pclr // Native binary
|| (der.clr.Flags & 1) == 0 // Or mixed-mode MSIL
|| (der.clr.Flags & 2) != 0) { // Or 32BIT Required MSIL
|| (der.clr.Flags & COMIMAGE_FLAGS_ILONLY) == 0 // Or mixed-mode MSIL
|| (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0) { // Or 32BIT Required MSIL
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
@ -677,30 +855,30 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
if (der.pclr != NULL) {
DETOUR_CLR_HEADER clr;
CopyMemory(&clr, &der.clr, sizeof(clr));
clr.Flags &= 0xfffffffe; // Clear the IL_ONLY flag.
clr.Flags &= ~COMIMAGE_FLAGS_ILONLY; // Clear the IL_ONLY flag.
DWORD dwProtect;
if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %d\n", GetLastError()));
DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %lu\n", GetLastError()));
return FALSE;
}
if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(clr) failed: %d\n", GetLastError()));
DETOUR_TRACE(("WriteProcessMemory(clr) failed: %lu\n", GetLastError()));
return FALSE;
}
if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %d\n", GetLastError()));
DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %lu\n", GetLastError()));
return FALSE;
}
DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));
#if DETOURS_64BIT
if (der.clr.Flags & 0x2) { // Is the 32BIT Required Flag set?
if (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) { // Is the 32BIT Required Flag set?
// X64 never gets here because the process appears as a WOW64 process.
// However, on IA64, it doesn't appear to be a WOW process.
DETOUR_TRACE(("CLR Requires 32-bit\n", der.pclr, der.pclr + der.cbclr));
DETOUR_TRACE(("CLR Requires 32-bit\n"));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
@ -710,7 +888,7 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
//////////////////////////////// Save the undo data to the target process.
//
if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError()));
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
return FALSE;
}
return TRUE;
@ -834,9 +1012,23 @@ BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) PVOID pvData,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData)
{
return DetourCopyPayloadToProcessEx(hProcess, rguid, pvData, cbData) != NULL;
}
_Success_(return != NULL)
PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData)
{
if (hProcess == NULL) {
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) +
sizeof(IMAGE_NT_HEADERS) +
sizeof(IMAGE_SECTION_HEADER) +
@ -847,10 +1039,15 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal,
MEM_COMMIT, PAGE_READWRITE);
if (pbBase == NULL) {
DETOUR_TRACE(("VirtualAllocEx(%d) failed: %d\n", cbTotal, GetLastError()));
return FALSE;
DETOUR_TRACE(("VirtualAllocEx(%lu) failed: %lu\n", cbTotal, GetLastError()));
return NULL;
}
// As you can see in the following code,
// the memory layout of the payload range "[pbBase, pbBase+cbTotal]" is a PE executable file,
// so DetourFreePayload can use "DetourGetContainingModule(Payload pointer)" to get the above "pbBase" pointer,
// pbBase: the memory block allocated by VirtualAllocEx will be released in DetourFreePayload by VirtualFree.
PBYTE pbTarget = pbBase;
IMAGE_DOS_HEADER idh;
IMAGE_NT_HEADERS inh;
@ -864,8 +1061,8 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
idh.e_lfanew = sizeof(idh);
if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) ||
cbWrote != sizeof(idh)) {
DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError()));
return FALSE;
DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
return NULL;
}
pbTarget += sizeof(idh);
@ -877,7 +1074,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) ||
cbWrote != sizeof(inh)) {
return FALSE;
return NULL;
}
pbTarget += sizeof(inh);
@ -889,7 +1086,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
cbData);
if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) ||
cbWrote != sizeof(ish)) {
return FALSE;
return NULL;
}
pbTarget += sizeof(ish);
@ -902,7 +1099,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
cbData);
if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) ||
cbWrote != sizeof(dsh)) {
return FALSE;
return NULL;
}
pbTarget += sizeof(dsh);
@ -912,19 +1109,20 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
dsr.guid = rguid;
if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) ||
cbWrote != sizeof(dsr)) {
return FALSE;
return NULL;
}
pbTarget += sizeof(dsr);
if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) ||
cbWrote != cbData) {
return FALSE;
return NULL;
}
pbTarget += cbData;
DETOUR_TRACE(("Copied %d byte payload into target process at %p\n",
cbTotal, pbTarget - cbTotal));
return TRUE;
DETOUR_TRACE(("Copied %lu byte payload into target process at %p\n",
cbData, pbTarget));
SetLastError(NO_ERROR);
return pbTarget;
}
static BOOL s_fSearchedForHelper = FALSE;
@ -949,7 +1147,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid);
if (hProcess == NULL) {
DETOUR_TRACE(("OpenProcess(pid=%d) failed: %d\n",
DETOUR_TRACE(("OpenProcess(pid=%lu) failed: %lu\n",
s_pHelper->pid, GetLastError()));
Result = 9901;
goto Cleanup;
@ -970,7 +1168,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
}
if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) {
DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%d) failed: %d\n",
DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%lu) failed: %lu\n",
s_pHelper->pid, GetLastError()));
Result = 9903;
goto Cleanup;
@ -983,6 +1181,15 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
rlpDlls = NULL;
}
// Note: s_pHelper is allocated as part of injecting the payload in DetourCopyPayloadToProcess(..),
// it's a fake section and not data allocated by the system PE loader.
// Delete the payload after execution to release the memory occupied by it
if (s_pHelper != NULL) {
DetourFreePayload(s_pHelper);
s_pHelper = NULL;
}
ExitProcess(Result);
}
@ -1146,7 +1353,7 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
HRESULT hr;
DWORD nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%d,dlls=%d)\n", dwTargetPid, nDlls));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
if (nDlls < 1 || nDlls > 4096) {
SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup;
@ -1172,8 +1379,10 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
goto Cleanup;
}
//for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
//so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand),
"rundll32.exe \"%hs\",#1", &helper->rDlls[0]);
"rundll32.exe \"%s\",#1", &helper->rDlls[0]);
if (!SUCCEEDED(hr)) {
goto Cleanup;
}
@ -1189,7 +1398,7 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
if (!DetourCopyPayloadToProcess(pi.hProcess,
DETOUR_EXE_HELPER_GUID,
helper, helper->cb)) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError()));
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
TerminateProcess(pi.hProcess, ~0u);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
@ -1206,13 +1415,13 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
CloseHandle(pi.hThread);
if (dwResult != 0) {
DETOUR_TRACE(("Rundll32.exe failed: result=%d\n", dwResult));
DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
goto Cleanup;
}
Result = TRUE;
}
else {
DETOUR_TRACE(("CreateProcess failed: %d\n", GetLastError()));
DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
goto Cleanup;
}
@ -1240,9 +1449,11 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
WCHAR szCommand[MAX_PATH];
PDETOUR_EXE_HELPER helper = NULL;
HRESULT hr;
WCHAR szDllName[MAX_PATH];
int cchWrittenWideChar;
DWORD nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%d,dlls=%d)\n", dwTargetPid, nDlls));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
if (nDlls < 1 || nDlls > 4096) {
SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup;
@ -1268,8 +1479,15 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
goto Cleanup;
}
//for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
//so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
cchWrittenWideChar = MultiByteToWideChar(CP_ACP, 0, &helper->rDlls[0], -1, szDllName, ARRAYSIZE(szDllName));
if (cchWrittenWideChar >= ARRAYSIZE(szDllName) || cchWrittenWideChar <= 0) {
goto Cleanup;
}
hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand),
L"rundll32.exe \"%hs\",#1", &helper->rDlls[0]);
L"rundll32.exe \"%s\",#1", szDllName);
if (!SUCCEEDED(hr)) {
goto Cleanup;
}
@ -1285,15 +1503,13 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
if (!DetourCopyPayloadToProcess(pi.hProcess,
DETOUR_EXE_HELPER_GUID,
helper, helper->cb)) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError()));
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
TerminateProcess(pi.hProcess, ~0u);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
goto Cleanup;
}
ResumeThread(pi.hThread);
ResumeThread(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
@ -1304,13 +1520,13 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
CloseHandle(pi.hThread);
if (dwResult != 0) {
DETOUR_TRACE(("Rundll32.exe failed: result=%d\n", dwResult));
DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
goto Cleanup;
}
Result = TRUE;
}
else {
DETOUR_TRACE(("CreateProcess failed: %d\n", GetLastError()));
DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
goto Cleanup;
}

View file

@ -18,6 +18,27 @@
#define NOTHROW
//////////////////////////////////////////////////////////////////////////////
//
#ifdef _DEBUG
extern "C" IMAGE_DOS_HEADER __ImageBase;
int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg)
{
int nRet = 0;
DWORD dwLastError = GetLastError();
CHAR szModuleNameWithFunctionName[MAX_PATH * 2];
szModuleNameWithFunctionName[0] = 0;
GetModuleFileNameA((HMODULE)&__ImageBase, szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName));
StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), ",", ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), FunctionName, ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
SetLastError(dwLastError);
nRet = _CrtDbgReport(reportType, filename, linenumber, szModuleNameWithFunctionName, msg);
SetLastError(dwLastError);
return nRet;
}
#endif// _DEBUG
//////////////////////////////////////////////////////////////////////////////
//
struct _DETOUR_ALIGN
@ -186,7 +207,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
// And, within +/- 2GB of relative jmp targets.
if (pbCode[0] == 0xe9) { // jmp +imm32
@ -198,7 +219,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else {
lo = detour_2gb_below((ULONG_PTR)pbNew);
}
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
}
*ppLower = (PDETOUR_TRAMPOLINE)lo;
@ -399,7 +420,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
// And, within +/- 2GB of relative jmp vectors.
if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
@ -411,7 +432,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else {
lo = detour_2gb_below((ULONG_PTR)pbNew);
}
DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", (PVOID)lo, pbCode, (PVOID)hi));
}
// And, within +/- 2GB of relative jmp targets.
else if (pbCode[0] == 0xe9) { // jmp +imm32
@ -423,7 +444,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else {
lo = detour_2gb_below((ULONG_PTR)pbNew);
}
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
}
*ppLower = (PDETOUR_TRAMPOLINE)lo;
@ -818,7 +839,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
*ppLower = (PDETOUR_TRAMPOLINE)lo;
*ppUpper = (PDETOUR_TRAMPOLINE)hi;
@ -863,7 +884,7 @@ struct _DETOUR_TRAMPOLINE
// An ARM64 instruction is 4 bytes long.
//
// The overwrite is always composed of 3 instructions (12 bytes) which perform an indirect jump
// using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location.
// using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location.
//
// Copied instructions can expand.
//
@ -1124,7 +1145,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
*ppLower = (PDETOUR_TRAMPOLINE)lo;
*ppUpper = (PDETOUR_TRAMPOLINE)hi;
@ -1237,7 +1258,7 @@ static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
break;
}
DETOUR_TRACE((" Try %p => %p..%p %6x\n",
DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
pbTry,
mbi.BaseAddress,
(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
@ -1252,6 +1273,9 @@ static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
if (pv != NULL) {
return pv;
}
else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
return NULL;
}
pbTry += DETOUR_REGION_SIZE;
}
else {
@ -1284,7 +1308,7 @@ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
break;
}
DETOUR_TRACE((" Try %p => %p..%p %6x\n",
DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
pbTry,
mbi.BaseAddress,
(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
@ -1299,6 +1323,9 @@ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
if (pv != NULL) {
return pv;
}
else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
return NULL;
}
pbTry -= DETOUR_REGION_SIZE;
}
else {
@ -1698,7 +1725,7 @@ LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
#endif // DETOURS_ARM
}
else {
DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n",
DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%u\n",
o->pTrampoline,
o->pTrampoline->pbRemain,
o->pTrampoline->pbDetour,
@ -1990,13 +2017,13 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
}
if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId));
DETOUR_TRACE(("transaction conflict with thread id=%ld\n", s_nPendingThreadId));
return ERROR_INVALID_OPERATION;
}
// If any of the pending operations failed, then we don't need to do this.
if (s_nPendingError != NO_ERROR) {
DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError));
DETOUR_TRACE(("pending transaction error=%ld\n", s_nPendingError));
return s_nPendingError;
}
@ -2177,7 +2204,7 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
pTrampoline->rAlign[n].obTrampoline == 0) {
break;
}
DETOUR_TRACE((" %d/%d",
DETOUR_TRACE((" %u/%u",
pTrampoline->rAlign[n].obTarget,
pTrampoline->rAlign[n].obTrampoline
));
@ -2545,4 +2572,20 @@ BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
pAddress, nSize, dwNewProtect, pdwOldProtect);
}
BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right)
{
return
left.Data1 == right.Data1 &&
left.Data2 == right.Data2 &&
left.Data3 == right.Data3 &&
left.Data4[0] == right.Data4[0] &&
left.Data4[1] == right.Data4[1] &&
left.Data4[2] == right.Data4[2] &&
left.Data4[3] == right.Data4[3] &&
left.Data4[4] == right.Data4[4] &&
left.Data4[5] == right.Data4[5] &&
left.Data4[6] == right.Data4[6] &&
left.Data4[7] == right.Data4[7];
}
// End of File

View file

@ -28,6 +28,15 @@
#pragma warning(disable:4091) // empty typedef
#endif
// Suppress declspec(dllimport) for the sake of Detours
// users that provide kernel32 functionality themselves.
// This is ok in the mainstream case, it will just cost
// an extra instruction calling some functions, which
// LTCG optimizes away.
//
#define _KERNEL32_ 1
#define _USER32_ 1
#include <windows.h>
#if (_MSC_VER < 1310)
#else
@ -36,8 +45,28 @@
#pragma warning(disable:6102 6103) // /analyze warnings
#endif
#include <strsafe.h>
#include <intsafe.h>
#pragma warning(pop)
#endif
#include <crtdbg.h>
// Allow Detours to cleanly compile with the MingW toolchain.
//
#ifdef __GNUC__
#define __try
#define __except(x) if (0)
#include <strsafe.h>
#endif
// From winerror.h, as this error isn't found in some SDKs:
//
// MessageId: ERROR_DYNAMIC_CODE_BLOCKED
//
// MessageText:
//
// The operation was blocked as the process prohibits dynamic code generation.
//
#define ERROR_DYNAMIC_CODE_BLOCKED 1655L
#endif // DETOURS_INTERNAL
@ -99,7 +128,7 @@
//////////////////////////////////////////////////////////////////////////////
//
#if (_MSC_VER < 1299)
#if (_MSC_VER < 1299) && !defined(__MINGW32__)
typedef LONG LONG_PTR;
typedef ULONG ULONG_PTR;
#endif
@ -120,6 +149,7 @@ typedef ULONG ULONG_PTR;
#undef _In_
#undef _In_bytecount_
#undef _In_count_
#undef __in_ecount
#undef _In_opt_
#undef _In_opt_bytecount_
#undef _In_opt_count_
@ -176,6 +206,10 @@ typedef ULONG ULONG_PTR;
#define _In_count_(x)
#endif
#ifndef __in_ecount
#define __in_ecount(x)
#endif
#ifndef _In_opt_
#define _In_opt_
#endif
@ -581,16 +615,17 @@ _Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
_In_ REFGUID rguid,
_Out_ DWORD *pcbData);
_Out_opt_ DWORD *pcbData);
_Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
_Out_ DWORD * pcbData);
_Out_opt_ DWORD *pcbData);
DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule);
BOOL WINAPI DetourFreePayload(_In_ PVOID pvData);
///////////////////////////////////////////////// Persistent Binary Functions.
//
@ -629,6 +664,11 @@ BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary);
/////////////////////////////////////////////////// Create Process & Load Dll.
//
_Success_(return != NULL)
PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData);
typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)(
_In_opt_ LPCSTR lpApplicationName,
_Inout_opt_ LPSTR lpCommandLine,
@ -795,8 +835,14 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) PVOID pvData,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData);
_Success_(return != NULL)
PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData);
BOOL WINAPI DetourRestoreAfterWith(VOID);
BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
_In_ DWORD cbData);
@ -812,6 +858,60 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
}
#endif // __cplusplus
/////////////////////////////////////////////////// Type-safe overloads for C++
//
#if __cplusplus >= 201103L || _MSVC_LANG >= 201103L
#include <type_traits>
template<typename T>
struct DetoursIsFunctionPointer : std::false_type {};
template<typename T>
struct DetoursIsFunctionPointer<T*> : std::is_function<typename std::remove_pointer<T>::type> {};
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourAttach(_Inout_ T *ppPointer,
_In_ T pDetour) noexcept
{
return DetourAttach(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour));
}
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourAttachEx(_Inout_ T *ppPointer,
_In_ T pDetour,
_Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
_Out_opt_ T *ppRealTarget,
_Out_opt_ T *ppRealDetour) noexcept
{
return DetourAttachEx(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour),
ppRealTrampoline,
reinterpret_cast<void**>(ppRealTarget),
reinterpret_cast<void**>(ppRealDetour));
}
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourDetach(_Inout_ T *ppPointer,
_In_ T pDetour) noexcept
{
return DetourDetach(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour));
}
#endif // __cplusplus >= 201103L || _MSVC_LANG >= 201103L
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// Detours Internal Definitions.
//
#ifdef __cplusplus
@ -822,7 +922,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
//////////////////////////////////////////////////////////////////////////////
//
#if (_MSC_VER < 1299)
#if (_MSC_VER < 1299) && !defined(__GNUC__)
#include <imagehlp.h>
typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64;
typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64;
@ -884,6 +984,21 @@ PDETOUR_SYM_INFO DetourLoadImageHlp(VOID);
#endif
#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1
#ifdef _DEBUG
int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg);
#define DETOUR_ASSERT_EXPR_WITH_FUNCTION(expr, msg) \
(void) ((expr) || \
(1 != Detour_AssertExprWithFunctionName(_CRT_ASSERT, __FILE__, __LINE__,__FUNCTION__, msg)) || \
(_CrtDbgBreak(), 0))
#define DETOUR_ASSERT(expr) DETOUR_ASSERT_EXPR_WITH_FUNCTION((expr), #expr)
#else// _DEBUG
#define DETOUR_ASSERT(expr)
#endif// _DEBUG
#ifndef DETOUR_TRACE
#if DETOUR_DEBUG
#define DETOUR_TRACE(x) printf x
@ -1090,6 +1205,9 @@ BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
_In_ SIZE_T nSize,
_In_ DWORD dwNewProtect,
_Out_ PDWORD pdwOldProtect);
// Detours must depend only on kernel32.lib, so we cannot use IsEqualGUID
BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right);
#ifdef __cplusplus
}
#endif // __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -146,6 +146,8 @@ protected:
DWORD m_cbAlloc;
};
class CImageImportName;
class CImageImportFile
{
friend class CImage;
@ -534,18 +536,7 @@ PBYTE CImageData::Find(REFGUID rguid, DWORD *pcbData)
continue;
}
if (pRecord->guid.Data1 == rguid.Data1 &&
pRecord->guid.Data2 == rguid.Data2 &&
pRecord->guid.Data3 == rguid.Data3 &&
pRecord->guid.Data4[0] == rguid.Data4[0] &&
pRecord->guid.Data4[1] == rguid.Data4[1] &&
pRecord->guid.Data4[2] == rguid.Data4[2] &&
pRecord->guid.Data4[3] == rguid.Data4[3] &&
pRecord->guid.Data4[4] == rguid.Data4[4] &&
pRecord->guid.Data4[5] == rguid.Data4[5] &&
pRecord->guid.Data4[6] == rguid.Data4[6] &&
pRecord->guid.Data4[7] == rguid.Data4[7]) {
if (DetourAreSameGuid(pRecord->guid, rguid)) {
*pcbData = cbBytes - sizeof(DETOUR_SECTION_RECORD);
return (PBYTE)(pRecord + 1);
}

View file

@ -23,8 +23,8 @@
//////////////////////////////////////////////////////////////////////////////
//
const GUID DETOUR_EXE_RESTORE_GUID = {
0x2ed7a3ff, 0x3339, 0x4a8d,
{ 0x80, 0x5c, 0xd4, 0x98, 0x15, 0x3f, 0xc2, 0x8f }};
0xbda26f34, 0xbc82, 0x4829,
{ 0x9e, 0x64, 0x74, 0x2c, 0x4, 0xc8, 0x4f, 0xa0 } };
//////////////////////////////////////////////////////////////////////////////
//
@ -142,6 +142,11 @@ PDETOUR_SYM_INFO DetourLoadImageHlp(VOID)
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.")
@ -160,7 +165,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction));
PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp();
if (pSymInfo == NULL) {
DETOUR_TRACE(("DetourLoadImageHlp failed: %d\n",
DETOUR_TRACE(("DetourLoadImageHlp failed: %lu\n",
GetLastError()));
return NULL;
}
@ -169,7 +174,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
(PCHAR)pszModule, NULL,
(DWORD64)hModule, 0) == 0) {
if (ERROR_SUCCESS != GetLastError()) {
DETOUR_TRACE(("SymLoadModule64(%p) failed: %d\n",
DETOUR_TRACE(("SymLoadModule64(%p) failed: %lu\n",
pSymInfo->hProcess, GetLastError()));
return NULL;
}
@ -181,24 +186,24 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
ZeroMemory(&modinfo, sizeof(modinfo));
modinfo.SizeOfStruct = sizeof(modinfo);
if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) {
DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %d\n",
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: %08x\n", hrRet));
DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
return NULL;
}
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!");
if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCatA failed: %08x\n", 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: %08x\n", hrRet));
DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet));
return NULL;
}
@ -215,7 +220,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
#endif
if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) {
DETOUR_TRACE(("SymFromName(%hs) failed: %d\n", szFullName, GetLastError()));
DETOUR_TRACE(("SymFromName(%hs) failed: %lu\n", szFullName, GetLastError()));
return NULL;
}
@ -277,6 +282,7 @@ HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast)
continue;
}
SetLastError(NO_ERROR);
return (HMODULE)pDosHeader;
}
#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
@ -340,7 +346,7 @@ PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule)
}
SetLastError(NO_ERROR);
return GetProcAddress(hClr, "_CorExeMain");
return (PVOID)GetProcAddress(hClr, "_CorExeMain");
}
SetLastError(NO_ERROR);
@ -456,6 +462,11 @@ 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);
@ -658,6 +669,11 @@ BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
_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,
@ -761,7 +777,7 @@ _Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
_In_ REFGUID rguid,
_Out_ DWORD *pcbData)
_Out_opt_ DWORD *pcbData)
{
PBYTE pbData = NULL;
if (pcbData) {
@ -789,23 +805,12 @@ PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
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 (DetourAreSameGuid(pSection->guid, rguid)) {
if (pcbData) {
*pcbData = pSection->cbBytes - sizeof(*pSection);
SetLastError(NO_ERROR);
return (PBYTE)(pSection + 1);
}
SetLastError(NO_ERROR);
return (PBYTE)(pSection + 1);
}
pbData = (PBYTE)pSection + pSection->cbBytes;
@ -824,7 +829,7 @@ _Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData)
_Success_(return != NULL)
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
_Out_ DWORD * pcbData)
_Out_opt_ DWORD *pcbData)
{
for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
PVOID pvData;
@ -838,6 +843,24 @@ PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
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)
{
@ -884,6 +907,11 @@ BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
}
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;
}

View file

@ -35,7 +35,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead)
|| cbRead < sizeof(idh)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError()));
finish:
@ -51,7 +51,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead)
|| cbRead < sizeof(inh)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n",
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
pbModule + idh.e_lfanew,
pbModule + idh.e_lfanew + sizeof(inh),
GetLastError()));
@ -82,16 +82,21 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
sizeof(ish), &cbRead)
|| cbRead < sizeof(ish)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %d\n",
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[%d] : va=%08x sr=%d\n", i, ish.VirtualAddress, ish.SizeOfRawData));
DETOUR_TRACE(("ish[%lu] : va=%08lx sr=%lu\n", i, ish.VirtualAddress, ish.SizeOfRawData));
// If the file didn't have an IAT_DIRECTORY, we assign it...
// 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) {
@ -101,25 +106,78 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
}
}
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",
(DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
(DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
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 = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls;
DWORD obOld = obRem + sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls;
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);
DWORD obDll = obTab + sizeof(DWORD_XX) * 4 * nDlls;
// 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++) {
cbNew += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
if (DWordAdd(cbNew, PadToDword((DWORD)strlen(plpDlls[n]) + 1), &cbNew) != S_OK) {
DETOUR_TRACE(("Overflow adding string table entry\n"));
goto finish;
}
}
_Analysis_assume_(cbNew >
sizeof(IMAGE_IMPORT_DESCRIPTOR) * (nDlls + nOldDlls)
+ sizeof(DWORD_XX) * 4 * nDlls);
pbNew = new BYTE [cbNew];
if (pbNew == NULL) {
DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
@ -145,14 +203,14 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
}
PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
DWORD_XX *pt;
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=%x\n", dwProtect));
DETOUR_TRACE(("IMPORT_DIRECTORY perms=%lx\n", dwProtect));
if (!ReadProcessMemory(hProcess,
pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
@ -160,7 +218,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead)
|| cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
DETOUR_TRACE(("ReadProcessMemory(imports) failed: %d\n", GetLastError()));
DETOUR_TRACE(("ReadProcessMemory(imports) failed: %lu\n", GetLastError()));
goto finish;
}
}
@ -168,7 +226,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
for (n = 0; n < nDlls; n++) {
HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCopyA failed: %d\n", GetLastError()));
DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
goto finish;
}
@ -177,21 +235,24 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
cbNew - obStr,
DETOURS_STRINGIFY(DETOURS_BITS_XX));
if (FAILED(hrRet)) {
DETOUR_TRACE(("ReplaceOptionalSizeA failed: %d\n", GetLastError()));
DETOUR_TRACE(("ReplaceOptionalSizeA failed: %08lx\n", hrRet));
goto finish;
}
DWORD nOffset = obTab + (sizeof(DWORD_XX) * (4 * n));
DWORD nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * (4 * n));
piid[n].OriginalFirstThunk = obBase + nOffset;
pt = ((DWORD_XX*)(pbNew + nOffset));
pt[0] = IMAGE_ORDINAL_FLAG_XX + 1;
pt[1] = 0;
nOffset = obTab + (sizeof(DWORD_XX) * ((4 * n) + 2));
// 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 = ((DWORD_XX*)(pbNew + nOffset));
pt[0] = IMAGE_ORDINAL_FLAG_XX + 1;
pt[1] = 0;
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;
@ -216,16 +277,19 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
#endif
if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
DETOUR_TRACE(("WriteProcessMemory(iid) failed: %d\n", GetLastError()));
DETOUR_TRACE(("WriteProcessMemory(iid) failed: %lu\n", GetLastError()));
goto finish;
}
DETOUR_TRACE(("obBaseBef = %08x..%08x\n",
DETOUR_TRACE(("obBaseBef = %08lx..%08lx\n",
inh.IMPORT_DIRECTORY.VirtualAddress,
inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
DETOUR_TRACE(("obBaseAft = %08x..%08x\n", obBase, obBase + obStr));
DETOUR_TRACE(("obBaseAft = %08lx..%08lx\n", obBase, obBase + obStr));
// If the file doesn't have an IAT_DIRECTORY, we create it...
// 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;
@ -238,20 +302,20 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
//
if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
PAGE_EXECUTE_READWRITE, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %d\n", GetLastError()));
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: %d\n", GetLastError()));
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: %d\n", GetLastError()));
DETOUR_TRACE(("WriteProcessMemory(inh) failed: %lu\n", GetLastError()));
goto finish;
}
DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n",
@ -260,7 +324,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
dwProtect, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %d\n", GetLastError()));
DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %lu\n", GetLastError()));
goto finish;
}