diff --git a/build/premake/premake.lua b/build/premake/premake.lua index 0b75f7717f..30ad181a8b 100755 --- a/build/premake/premake.lua +++ b/build/premake/premake.lua @@ -412,7 +412,7 @@ function setup_all_libs () linux = { "lib/sysdep/unix" }, -- note: RC file must be added to main_exe package. -- note: don't add "lib/sysdep/win/aken.cpp" because that must be compiled with the DDK. - windows = { "lib/sysdep/win", "lib/sysdep/win/wposix", "lib/sysdep/win/whrt" }, + windows = { "lib/sysdep/win", "lib/sysdep/win/wposix", "lib/sysdep/win/whrt", "lib/sysdep/win/detours" }, macosx = { "lib/sysdep/osx", "lib/sysdep/unix" }, } tinsert(package.files, sourcesfromdirs(source_root, sysdep_dirs[OS])); diff --git a/build/workspaces/update-workspaces.bat b/build/workspaces/update-workspaces.bat index 116cb69e1f..0ba57116ac 100644 --- a/build/workspaces/update-workspaces.bat +++ b/build/workspaces/update-workspaces.bat @@ -1,7 +1,7 @@ @echo off rem ** Create Visual Studio Workspaces on Windows ** -mkdir vc2003 +rem mkdir vc2003 mkdir vc2005 cd ..\premake @@ -9,7 +9,7 @@ cd ..\premake rem VC2002 removed because no one is using it and generating it wastes time. rem it's entirely analogous to other cmdlines - just copy+paste if needed again. -premake --target vs2003 --outpath ../workspaces/vc2003 %* -premake --target vs2005 --outpath ../workspaces/vc2005 %* +rem premake --target vs2003 --outpath ../workspaces/vc2003 %* +premake --target vs2005 --outpath ../workspaces/vc2005 --atlas %* cd ..\workspaces diff --git a/source/lib/sysdep/win/detours/detours.cpp b/source/lib/sysdep/win/detours/detours.cpp new file mode 100644 index 0000000000..a3e53f9b0f --- /dev/null +++ b/source/lib/sysdep/win/detours/detours.cpp @@ -0,0 +1,505 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.cpp of detours.lib) +// +// Microsoft Research Detours Package, Version 2.1. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#include "precompiled.h" +#include "lib/sysdep/win/win.h" + +#if (_MSC_VER < 1299) +#pragma warning(disable: 4710) +#endif + +//#define DETOUR_DEBUG 1 +#define DETOURS_INTERNAL + +#include "detours.h" + +#if !CPU_IA32 +#error "detours currently only supports x86" +#endif + +////////////////////////////////////////////////////////////////////////////// +// +static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); + __try { + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + return false; + } + + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + + pDosHeader->e_lfanew); + if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { + return false; + } + + if (pbAddress >= ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && + pbAddress < ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { + return true; + } + return false; + } + __except(EXCEPTION_EXECUTE_HANDLER) { + return false; + } +} + +///////////////////////////////////////////////////////////////////////// X86. +// +#ifdef DETOURS_X86 + +struct _DETOUR_TRAMPOLINE +{ + BYTE rbCode[23]; // target code + jmp to pbRemain + BYTE cbTarget; // size of target code moved. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +enum { + SIZE_OF_JMP = 5 +}; + +inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 5; + *pbCode++ = 0xE9; // jmp +imm32 + *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 6; + *pbCode++ = 0xff; // jmp [+imm32] + *pbCode++ = 0x25; + *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + *pbCode++ = 0xcc; // brk; + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = *(PBYTE *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + return pbNew; + } + } + else if (pbCode[0] == 0xeb) { // jmp +imm8 + // These just started appearing with CL13. + PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + if (pbNew[0] == 0xe9) { // jmp +imm32 + pbCode = pbNew; + pbNew = pbCode + *(INT32 *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + } + return pbNew; + } + return pbCode; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + if (pbCode[0] == 0xe9 || // jmp +imm32 + pbCode[0] == 0xe0 || // jmp eax + pbCode[0] == 0xc2 || // ret +imm8 + pbCode[0] == 0xc3 || // ret + pbCode[0] == 0xcc) { // brk + return TRUE; + } + else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + return TRUE; + } + else if ((pbCode[0] == 0x26 || // jmp es: + pbCode[0] == 0x2e || // jmp cs: + pbCode[0] == 0x36 || // jmp ss: + pbCode[0] == 0xe3 || // jmp ds: + pbCode[0] == 0x64 || // jmp fs: + pbCode[0] == 0x65) && // jmp gs: + pbCode[1] == 0xff && // jmp [+imm32] + pbCode[2] == 0x25) { + return TRUE; + } + return FALSE; +} +#endif // DETOURS_X86 + +//////////////////////////////////////////////// Trampoline Memory Management. +// +struct DETOUR_REGION +{ + ULONG dwSignature; + DETOUR_REGION * pNext; // Next region in list of regions. + DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region. +}; +typedef DETOUR_REGION * PDETOUR_REGION; + +const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd'; +const ULONG DETOUR_REGION_SIZE = 0x10000; +const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE + / sizeof(DETOUR_TRAMPOLINE)) - 1; +static PDETOUR_REGION s_pRegions = NULL; // List of all regions. +static PDETOUR_REGION s_pRegion = NULL; // Default region. + +static void detour_writable_trampoline_regions() +{ + // Mark all of the regions as writable. + for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { + DWORD dwOld; + VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld); + } +} + +static void detour_runnable_trampoline_regions() +{ + // Mark all of the regions as executable. + for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { + DWORD dwOld; + VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld); + } +} + +static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget) +{ + // We have to place trampolines within +/- 2GB of target. + // The allocation code assumes that + + PDETOUR_TRAMPOLINE pLo = (PDETOUR_TRAMPOLINE) + ((pbTarget > (PBYTE)0x7ff80000) + ? pbTarget - 0x7ff80000 : (PBYTE)(ULONG_PTR)DETOUR_REGION_SIZE); + PDETOUR_TRAMPOLINE pHi = (PDETOUR_TRAMPOLINE) + ((pbTarget < (PBYTE)0xffffffff80000000) + ? pbTarget + 0x7ff80000 : (PBYTE)0xfffffffffff80000); + DETOUR_TRACE(("[%p..%p..%p]\n", pLo, pbTarget, pHi)); + + PDETOUR_TRAMPOLINE pTrampoline = NULL; + + // Insure that there is a default region. + if (s_pRegion == NULL && s_pRegions != NULL) { + s_pRegion = s_pRegions; + } + + // First check the default region for an valid free block. + if (s_pRegion != NULL && s_pRegion->pFree != NULL && + s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { + + found_region: + pTrampoline = s_pRegion->pFree; + // do a last sanity check on region. + if (pTrampoline < pLo || pTrampoline > pHi) { + return NULL; + } + s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain; + memset(pTrampoline, 0xcc, sizeof(*pTrampoline)); + return pTrampoline; + } + + // Then check the existing regions for a valid free block. + for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) { + if (s_pRegion != NULL && s_pRegion->pFree != NULL && + s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { + goto found_region; + } + } + + // We need to allocate a new region. + + // Round pbTarget down to 64K block. + pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff); + + // First we search down (within the valid region) + + DETOUR_TRACE((" Looking for free region below %p:\n", pbTarget)); + + PBYTE pbTry; + for (pbTry = pbTarget; pbTry > (PBYTE)pLo;) { + MEMORY_BASIC_INFORMATION mbi; + + DETOUR_TRACE((" Try %p\n", pbTry)); + if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && + pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { + // Skip region reserved for system DLLs. + pbTry = (PBYTE)(ULONG_PTR)(0x70000000 - DETOUR_REGION_SIZE); + } + if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { + break; + } + + DETOUR_TRACE((" Try %p => %p..%p %6x\n", + pbTry, + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, + mbi.State)); + + if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { + s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, + DETOUR_REGION_SIZE, + MEM_COMMIT|MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if (s_pRegion != NULL) { + alloced_region: + s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE; + s_pRegion->pFree = NULL; + s_pRegion->pNext = s_pRegions; + s_pRegions = s_pRegion; + DETOUR_TRACE((" Allocated region %p..%p\n\n", + s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1)); + + // Put everything but the first trampoline on the free list. + PBYTE pFree = NULL; + pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1; + for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) { + pTrampoline[i].pbRemain = pFree; + pFree = (PBYTE)&pTrampoline[i]; + } + s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree; + goto found_region; + } + else { + DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); + break; + } + } + pbTry = (PBYTE)mbi.AllocationBase - DETOUR_REGION_SIZE; + } + + DETOUR_TRACE((" Looking for free region above %p:\n", pbTarget)); + + for (pbTry = pbTarget; pbTry < (PBYTE)pHi;) { + MEMORY_BASIC_INFORMATION mbi; + + if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && + pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { + // Skip region reserved for system DLLs. + pbTry = (PBYTE)(ULONG_PTR)(0x80000000 + DETOUR_REGION_SIZE); + } + if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { + break; + } + + DETOUR_TRACE((" Try %p => %p..%p %6x\n", + pbTry, + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, + mbi.State)); + + if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { + ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); + if (extra != 0) { + // WinXP64 returns free areas that aren't REGION aligned to + // 32-bit applications. + ULONG_PTR adjust = DETOUR_REGION_SIZE - extra; + mbi.RegionSize -= adjust; + ((PBYTE&)mbi.BaseAddress) += adjust; + DETOUR_TRACE(("--Try %p => %p..%p %6x\n", + pbTry, + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, + mbi.State)); + pbTry = (PBYTE)mbi.BaseAddress; + } + s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, + DETOUR_REGION_SIZE, + MEM_COMMIT|MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if (s_pRegion != NULL) { + goto alloced_region; + } + else { + DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); + } + } + + pbTry = (PBYTE)mbi.BaseAddress + mbi.RegionSize; + } + + DETOUR_TRACE(("Couldn't find available memory region!\n")); + throw std::bad_alloc(""); +} + + +///////////////////////////////////////////////////////// Transaction Structs. +// + +struct DetourOperation +{ + DetourOperation * pNext; + PBYTE * ppbPointer; + PBYTE pbTarget; + PDETOUR_TRAMPOLINE pTrampoline; + ULONG dwPerm; +}; + +static DetourOperation * s_pPendingOperations = NULL; + +////////////////////////////////////////////////////////////////////////////// +// +PVOID DetourCodeFromPointer(PVOID pPointer, PVOID *ppGlobals) +{ + return detour_skip_jmp((PBYTE)pPointer, ppGlobals); +} + +//////////////////////////////////////////////////////////// Transaction APIs. +// + +LONG DetourTransactionBegin() +{ + // Make sure only one thread can start a transaction. +/// if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) +/// return ERROR_INVALID_OPERATION; + + s_pPendingOperations = NULL; + + // Make sure the trampoline pages are writable. + detour_writable_trampoline_regions(); + + return NO_ERROR; +} + +LONG DetourTransactionCommit() +{ + // Common variables. + DetourOperation *o; + + // Insert or remove each of the detours. + for (o = s_pPendingOperations; o != NULL; o = o->pNext) + { +#ifdef DETOURS_X86 + PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour); + pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); + *o->ppbPointer = o->pTrampoline->rbCode; +#endif // DETOURS_X86 + } + + // Restore all of the page permissions and flush the icache. + HANDLE hProcess = GetCurrentProcess(); + for (o = s_pPendingOperations; o != NULL;) { + // We don't care if this fails, because the code is still accessible. + DWORD dwOld; + VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget, o->dwPerm, &dwOld); + FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbTarget); + + DetourOperation *n = o->pNext; + delete o; + o = n; + } + s_pPendingOperations = NULL; + + // Make sure the trampoline pages are no longer writable. + detour_runnable_trampoline_regions(); + + return NO_ERROR; +} + +///////////////////////////////////////////////////////////// Transacted APIs. +// + +LONG DetourAttach(PVOID *ppPointer, PVOID pDetour) +{ + LONG error = NO_ERROR; + + if (*ppPointer == NULL) { + error = ERROR_INVALID_HANDLE; + DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer)); + DETOUR_BREAK(); + return error; + } + + PBYTE pbTarget = (PBYTE)*ppPointer; + PDETOUR_TRAMPOLINE pTrampoline = NULL; + DetourOperation *o = NULL; + + pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); + pDetour = DetourCodeFromPointer(pDetour, NULL); + + // Don't follow a jump if its destination is the target function. + // This happens when the detour does nothing other than call the target. + if (pDetour == (PVOID)pbTarget) + exit(1); + + o = new DetourOperation; + pTrampoline = detour_alloc_trampoline(pbTarget); + + // Determine the number of movable target instructions. + PBYTE pbSrc = pbTarget; + LONG cbTarget = 0; + while (cbTarget < SIZE_OF_JMP) { + PBYTE pbOp = pbSrc; + LONG lExtra = 0; + + DETOUR_TRACE((" DetourCopyInstructionEx(%p,%p)\n", pTrampoline->rbCode + cbTarget, pbSrc)); + pbSrc = (PBYTE)DetourCopyInstructionEx(pTrampoline->rbCode + cbTarget, pbSrc, NULL, &lExtra); + DETOUR_TRACE((" DetourCopyInstructionEx() = %p (%d bytes)\n", pbSrc, (int)(pbSrc - pbOp))); + + if (lExtra != 0) { + break; // Abort if offset doesn't fit. + } + cbTarget = (LONG)(pbSrc - pbTarget); + + if (detour_does_code_end_function(pbOp)) { + break; + } + } + // Too few instructions. + if (cbTarget < SIZE_OF_JMP) + exit(2); + + // Too many instructions. + if (cbTarget > sizeof(pTrampoline->rbCode) - SIZE_OF_JMP) + exit(3); + + pTrampoline->pbRemain = pbTarget + cbTarget; + pTrampoline->pbDetour = (PBYTE)pDetour; + pTrampoline->cbTarget = (BYTE)cbTarget; + +#ifdef DETOURS_X86 + pbSrc = detour_gen_jmp_immediate(pTrampoline->rbCode + cbTarget, pTrampoline->pbRemain); + pbSrc = detour_gen_brk(pbSrc, + pTrampoline->rbCode + sizeof(pTrampoline->rbCode)); +#endif // DETOURS_X86 + + DWORD dwOld = 0; + if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) + exit(4); + + o->ppbPointer = (PBYTE*)ppPointer; + o->pTrampoline = pTrampoline; + o->pbTarget = pbTarget; + o->dwPerm = dwOld; + o->pNext = s_pPendingOperations; + s_pPendingOperations = o; + + return NO_ERROR; +} diff --git a/source/lib/sysdep/win/detours/detours.h b/source/lib/sysdep/win/detours/detours.h new file mode 100644 index 0000000000..43faeade45 --- /dev/null +++ b/source/lib/sysdep/win/detours/detours.h @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.h of detours.lib) +// +// Microsoft Research Detours Package, Version 2.1. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#ifndef _DETOURS_H_ +#define _DETOURS_H_ + +#define DETOURS_X86 + + +#define DETOURS_VERSION 20100 // 2.1.0 + + +#define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) +#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) + + +#define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! +typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; + + +LONG DetourTransactionBegin(); +LONG DetourTransactionCommit(); +LONG DetourAttach(PVOID *ppPointer, PVOID pDetour); + + +PVOID WINAPI DetourCopyInstructionEx(PVOID pDst, PVOID pSrc, PVOID *ppTarget, LONG *plExtra); + + +////////////////////////////////////////////////////////////////////////////// +// +#include + +#ifndef DETOUR_TRACE +#if DETOUR_DEBUG +#define DETOUR_TRACE(x) printf x +#define DETOUR_BREAK() DebugBreak() +#include +#include +#else +#define DETOUR_TRACE(x) +#define DETOUR_BREAK() +#endif +#endif + +#endif // DETOURS_INTERNAL + +#endif // _DETOURS_H_ diff --git a/source/lib/sysdep/win/detours/disasm.cpp b/source/lib/sysdep/win/detours/disasm.cpp new file mode 100644 index 0000000000..ddf67d773a --- /dev/null +++ b/source/lib/sysdep/win/detours/disasm.cpp @@ -0,0 +1,1083 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Detours Disassembler (disasm.cpp of detours.lib) +// +// Microsoft Research Detours Package, Version 2.1. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#include "precompiled.h" +#include "lib/sysdep/win/win.h" + +#include + +// #define DETOUR_DEBUG 1 +#define DETOURS_INTERNAL + +#include "detours.h" + +#if !defined(DETOURS_X86) && !defined(DETOURS_X64) && !defined(DETOURS_IA64) +#error Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA64 +#endif + +#undef ASSERT +#define ASSERT(x) + +////////////////////////////////////////////////////////////////////////////// +// +// Function: +// DetourCopyInstructionEx(PVOID pDst, +// PVOID pSrc, +// PVOID *ppTarget, +// LONG *plExtra) +// Purpose: +// Copy a single instruction from pSrc to pDst. +// +// Arguments: +// pDst: +// Destination address for the instruction. May be NULL in which +// case DetourCopyInstruction is used to measure an instruction. +// If not NULL then the source instruction is copied to the +// destination instruction and any relative arguments are adjusted. +// pSrc: +// Source address of the instruction. +// ppTarget: +// Out parameter for any target instruction address pointed to by +// the instruction. For example, a branch or a jump insruction has +// a target, but a load or store instruction doesn't. A target is +// another instruction that may be executed as a result of this +// instruction. ppTarget may be NULL. +// plExtra: +// Out parameter for the number of extra bytes needed by the +// instruction to reach the target. For example, lExtra = 3 if the +// instruction had an 8-bit relative offset, but needs a 32-bit +// relative offset. +// +// Returns: +// Returns the address of the next instruction (following in the source) +// instruction. By subtracting pSrc from the return value, the caller +// can determinte the size of the instruction copied. +// +// Comments: +// By following the pTarget, the caller can follow alternate +// instruction streams. However, it is not always possible to determine +// the target based on static analysis. For example, the destination of +// a jump relative to a register cannot be determined from just the +// instruction stream. The output value, pTarget, can have any of the +// following outputs: +// DETOUR_INSTRUCTION_TARGET_NONE: +// The instruction has no targets. +// DETOUR_INSTRUCTION_TARGET_DYNAMIC: +// The instruction has a non-deterministic (dynamic) target. +// (i.e. the jump is to an address held in a register.) +// Address: The instruction has the specified target. +// +// When copying instructions, DetourCopyInstruction insures that any +// targets remain constant. It does so by adjusting any IP relative +// offsets. +// + +PVOID WINAPI DetourCopyInstruction(PVOID pDst, PVOID pSrc, PVOID *ppTarget) +{ + return DetourCopyInstructionEx(pDst, pSrc, ppTarget, NULL); +} + +//////////////////////////////////////////////////// X86 and X64 Disassembler. +// +// Includes full support for all x86 chips prior to the Pentium III. +// +#if defined(DETOURS_X64) || defined(DETOURS_X86) + +class CDetourDis +{ + public: + CDetourDis(PBYTE *ppbTarget, LONG *plExtra); + + PBYTE CopyInstruction(PBYTE pbDst, PBYTE pbSrc); + static BOOL SanityCheckSystem(); + + public: + struct COPYENTRY; + typedef const COPYENTRY * REFCOPYENTRY; + + typedef PBYTE (CDetourDis::* COPYFUNC)(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + + enum { + DYNAMIC = 0x1u, + ADDRESS = 0x2u, + NOENLARGE = 0x4u, + RAX = 0x8u, + + SIB = 0x10u, + RIP = 0x20u, + NOTSIB = 0x0fu, + }; + struct COPYENTRY + { + ULONG nOpcode : 8; // Opcode + ULONG nFixedSize : 4; // Fixed size of opcode + ULONG nFixedSize16 : 4; // Fixed size when 16 bit operand + ULONG nModOffset : 4; // Offset to mod/rm byte (0=none) + LONG nRelOffset : 4; // Offset to relative target. + LONG nTargetBack : 4; // Offset back to absolute or rip target + ULONG nFlagBits : 4; // Flags for DYNAMIC, etc. + COPYFUNC pfCopy; // Function pointer. + }; + + protected: + // These macros define common uses of nFixedSize..pfCopy. +#define ENTRY_CopyBytes1 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes1Dynamic 1, 1, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2 2, 2, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2Jump 2, 2, 0, 1, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2CantJump 2, 2, 0, 1, 0, NOENLARGE, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2Dynamic 2, 2, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3 3, 3, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Dynamic 3, 3, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Or5 5, 3, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Or5Rax 5, 3, 0, 0, 0, RAX, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Or5Target 5, 3, 0, 1, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes5Or7Dynamic 7, 5, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Or5Address 5, 3, 0, 0, 0, ADDRESS, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes4 4, 4, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes5 5, 5, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes7 7, 7, 0, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2Mod 2, 2, 1, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2Mod1 3, 3, 1, 0, 1, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes2ModOperand 6, 4, 1, 0, 4, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytes3Mod 3, 3, 2, 0, 0, 0, &CDetourDis::CopyBytes +#define ENTRY_CopyBytesPrefix 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytesPrefix +#define ENTRY_CopyBytesRax 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytesRax +#define ENTRY_Copy0F 1, 1, 0, 0, 0, 0, &CDetourDis::Copy0F +#define ENTRY_Copy66 1, 1, 0, 0, 0, 0, &CDetourDis::Copy66 +#define ENTRY_Copy67 1, 1, 0, 0, 0, 0, &CDetourDis::Copy67 +#define ENTRY_CopyF6 0, 0, 0, 0, 0, 0, &CDetourDis::CopyF6 +#define ENTRY_CopyF7 0, 0, 0, 0, 0, 0, &CDetourDis::CopyF7 +#define ENTRY_CopyFF 0, 0, 0, 0, 0, 0, &CDetourDis::CopyFF +#define ENTRY_Invalid 1, 1, 0, 0, 0, 0, &CDetourDis::Invalid +#define ENTRY_End 0, 0, 0, 0, 0, 0, NULL + + PBYTE CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE CopyBytesRax(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + + PBYTE Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + + PBYTE AdjustTarget(PBYTE pbDst, PBYTE pbSrc, LONG cbOp, + LONG cbTargetOffset, LONG cbTargetSize); + + protected: + PBYTE Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + PBYTE CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); + + protected: + static const COPYENTRY s_rceCopyTable[257]; + static const COPYENTRY s_rceCopyTable0F[257]; + static const BYTE s_rbModRm[256]; + + protected: + BOOL m_bOperandOverride; + BOOL m_bAddressOverride; + BOOL m_bRaxOverride; + + PBYTE * m_ppbTarget; + LONG * m_plExtra; + + LONG m_lScratchExtra; + PBYTE m_pbScratchTarget; + BYTE m_rbScratchDst[64]; +}; + +PVOID WINAPI DetourCopyInstructionEx(PVOID pDst, + PVOID pSrc, + PVOID *ppTarget, + LONG *plExtra) +{ + CDetourDis oDetourDisasm((PBYTE*)ppTarget, plExtra); + return oDetourDisasm.CopyInstruction((PBYTE)pDst, (PBYTE)pSrc); +} + +/////////////////////////////////////////////////////////// Disassembler Code. +// +CDetourDis::CDetourDis(PBYTE *ppbTarget, LONG *plExtra) +{ + m_bOperandOverride = FALSE; + m_bAddressOverride = FALSE; + m_bRaxOverride = FALSE; + + m_ppbTarget = ppbTarget ? ppbTarget : &m_pbScratchTarget; + m_plExtra = plExtra ? plExtra : &m_lScratchExtra; + + *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_NONE; + *m_plExtra = 0; +} + +PBYTE CDetourDis::CopyInstruction(PBYTE pbDst, PBYTE pbSrc) +{ + // Configure scratch areas if real areas are not available. + if (NULL == pbDst) { + pbDst = m_rbScratchDst; + } + if (NULL == pbSrc) { + // We can't copy a non-existent instruction. + SetLastError(ERROR_INVALID_DATA); + return NULL; + } + + // Figure out how big the instruction is, do the appropriate copy, + // and figure out what the target of the instruction is if any. + // + REFCOPYENTRY pEntry = &s_rceCopyTable[pbSrc[0]]; + return (this->*pEntry->pfCopy)(pEntry, pbDst, pbSrc); +} + +PBYTE CDetourDis::CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ +#ifdef DETOURS_X64 +#error Feature not supported in this release. + + + + +#else + LONG nBytesFixed = (pEntry->nFlagBits & ADDRESS) + ? (m_bAddressOverride ? pEntry->nFixedSize16 : pEntry->nFixedSize) + : (m_bOperandOverride ? pEntry->nFixedSize16 : pEntry->nFixedSize); +#endif + + LONG nBytes = nBytesFixed; + LONG nRelOffset = pEntry->nRelOffset; + LONG cbTarget = nBytes - nRelOffset; + if (pEntry->nModOffset > 0) { + BYTE bModRm = pbSrc[pEntry->nModOffset]; + BYTE bFlags = s_rbModRm[bModRm]; + + nBytes += bFlags & NOTSIB; + + if (bFlags & SIB) { + BYTE bSib = pbSrc[pEntry->nModOffset + 1]; + + if ((bSib & 0x07) == 0x05) { + if ((bModRm & 0xc0) == 0x00) { + nBytes += 4; + } + else if ((bModRm & 0xc0) == 0x40) { + nBytes += 1; + } + else if ((bModRm & 0xc0) == 0x80) { + nBytes += 4; + } + } + cbTarget = nBytes - nRelOffset; + } + else if (bFlags & RIP) { +#ifdef DETOURS_X64 +#error Feature not supported in this release. + + +#endif + } + } + CopyMemory(pbDst, pbSrc, nBytes); + + if (nRelOffset) { + *m_ppbTarget = AdjustTarget(pbDst, pbSrc, nBytesFixed, nRelOffset, cbTarget); +#ifdef DETOURS_X64 +#error Feature not supported in this release. + + + +#endif + } + if (pEntry->nFlagBits & NOENLARGE) { + *m_plExtra = -*m_plExtra; + } + if (pEntry->nFlagBits & DYNAMIC) { + *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_DYNAMIC; + } + return pbSrc + nBytes; +} + +PBYTE CDetourDis::CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + CopyBytes(pEntry, pbDst, pbSrc); + + pEntry = &s_rceCopyTable[pbSrc[1]]; + return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); +} + +PBYTE CDetourDis::CopyBytesRax(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + CopyBytes(pEntry, pbDst, pbSrc); + + if (*pbSrc & 0x8) { + m_bRaxOverride = TRUE; + } + + pEntry = &s_rceCopyTable[pbSrc[1]]; + return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); +} + +PBYTE CDetourDis::AdjustTarget(PBYTE pbDst, PBYTE pbSrc, LONG cbOp, + LONG cbTargetOffset, LONG cbTargetSize) +{ + PBYTE pbTarget = NULL; + PVOID pvTargetAddr = &pbDst[cbTargetOffset]; + LONG_PTR nOldOffset = 0; + + switch (cbTargetSize) { + case 1: + nOldOffset = (LONG_PTR)*(CHAR*&)pvTargetAddr; + break; + case 2: + nOldOffset = (LONG_PTR)*(SHORT*&)pvTargetAddr; + break; + case 4: + nOldOffset = (LONG_PTR)*(LONG*&)pvTargetAddr; + break; + case 8: + nOldOffset = (LONG_PTR)*(LONG_PTR*&)pvTargetAddr; + break; + default: + ASSERT(!"cbTargetSize is invalid."); + break; + } + + pbTarget = pbSrc + cbOp + nOldOffset; + LONG_PTR nNewOffset = nOldOffset - (pbDst - pbSrc); + + switch (cbTargetSize) { + case 1: + *(CHAR*&)pvTargetAddr = (CHAR)nNewOffset; + if (nNewOffset < SCHAR_MIN || nNewOffset > SCHAR_MAX) { + *m_plExtra = sizeof(ULONG_PTR) - 1; + } + break; + case 2: + *(SHORT*&)pvTargetAddr = (SHORT)nNewOffset; + if (nNewOffset < SHRT_MIN || nNewOffset > SHRT_MAX) { + *m_plExtra = sizeof(ULONG_PTR) - 2; + } + break; + case 4: + *(LONG*&)pvTargetAddr = (LONG)nNewOffset; + if (nNewOffset < LONG_MIN || nNewOffset > LONG_MAX) { + *m_plExtra = sizeof(ULONG_PTR) - 4; + } + break; + case 8: + *(LONG_PTR*&)pvTargetAddr = (LONG_PTR)nNewOffset; + break; + } + ASSERT(pbDst + cbOp + nNewOffset == pbTarget); + return pbTarget; +} + +PBYTE CDetourDis::Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + (void)pbDst; + (void)pEntry; + ASSERT(!"Invalid Instruction"); + return pbSrc + 1; +} + +////////////////////////////////////////////////////// Individual Bytes Codes. +// +PBYTE CDetourDis::Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + CopyBytes(pEntry, pbDst, pbSrc); + + pEntry = &s_rceCopyTable0F[pbSrc[1]]; + return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); +} + +PBYTE CDetourDis::Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ // Operand-size override prefix + m_bOperandOverride = TRUE; + return CopyBytesPrefix(pEntry, pbDst, pbSrc); +} + +PBYTE CDetourDis::Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ // Address size override prefix + m_bAddressOverride = TRUE; + return CopyBytesPrefix(pEntry, pbDst, pbSrc); +} + +PBYTE CDetourDis::CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + (void)pEntry; + + // TEST BYTE /0 + if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0 + const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod1 }; + return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); + } + // DIV /6 + // IDIV /7 + // IMUL /5 + // MUL /4 + // NEG /3 + // NOT /2 + + const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod }; + return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); +} + +PBYTE CDetourDis::CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ + (void)pEntry; + + // TEST WORD /0 + if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0 + const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2ModOperand }; + return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); + } + + // DIV /6 + // IDIV /7 + // IMUL /5 + // MUL /4 + // NEG /3 + // NOT /2 + const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2Mod }; + return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); +} + +PBYTE CDetourDis::CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) +{ // CALL /2 + // CALL /3 + // INC /0 + // JMP /4 + // JMP /5 + // PUSH /6 + (void)pEntry; + + if (0x15 == pbSrc[1] || 0x25 == pbSrc[1]) { // CALL [], JMP [] +#ifdef DETOURS_X64 +#error Feature not supported in this release. + + +#else + PBYTE *ppbTarget = *(PBYTE**)&pbSrc[2]; + *m_ppbTarget = *ppbTarget; +#endif + } + else if (0x10 == (0x38 & pbSrc[1]) || // CALL /2 --> reg(bits 543) of ModR/M == 010 + 0x18 == (0x38 & pbSrc[1]) || // CALL /3 --> reg(bits 543) of ModR/M == 011 + 0x20 == (0x38 & pbSrc[1]) || // JMP /4 --> reg(bits 543) of ModR/M == 100 + 0x28 == (0x38 & pbSrc[1]) // JMP /5 --> reg(bits 543) of ModR/M == 101 + ) { + *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_DYNAMIC; + } + const COPYENTRY ce = { 0xff, ENTRY_CopyBytes2Mod }; + return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); +} + +///////////////////////////////////////////////////////// Disassembler Tables. +// +const BYTE CDetourDis::s_rbModRm[256] = { + 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 0x + 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 1x + 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 2x + 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 3x + 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 4x + 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 5x + 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 6x + 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 7x + 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 8x + 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 9x + 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Ax + 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Bx + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Cx + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Dx + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Ex + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 // Fx +}; + +const CDetourDis::COPYENTRY CDetourDis::s_rceCopyTable[257] = +{ + { 0x00, ENTRY_CopyBytes2Mod }, // ADD /r + { 0x01, ENTRY_CopyBytes2Mod }, // ADD /r + { 0x02, ENTRY_CopyBytes2Mod }, // ADD /r + { 0x03, ENTRY_CopyBytes2Mod }, // ADD /r + { 0x04, ENTRY_CopyBytes2 }, // ADD ib + { 0x05, ENTRY_CopyBytes3Or5 }, // ADD iw + { 0x06, ENTRY_CopyBytes1 }, // PUSH + { 0x07, ENTRY_CopyBytes1 }, // POP + { 0x08, ENTRY_CopyBytes2Mod }, // OR /r + { 0x09, ENTRY_CopyBytes2Mod }, // OR /r + { 0x0A, ENTRY_CopyBytes2Mod }, // OR /r + { 0x0B, ENTRY_CopyBytes2Mod }, // OR /r + { 0x0C, ENTRY_CopyBytes2 }, // OR ib + { 0x0D, ENTRY_CopyBytes3Or5 }, // OR iw + { 0x0E, ENTRY_CopyBytes1 }, // PUSH + { 0x0F, ENTRY_Copy0F }, // Extension Ops + { 0x10, ENTRY_CopyBytes2Mod }, // ADC /r + { 0x11, ENTRY_CopyBytes2Mod }, // ADC /r + { 0x12, ENTRY_CopyBytes2Mod }, // ADC /r + { 0x13, ENTRY_CopyBytes2Mod }, // ADC /r + { 0x14, ENTRY_CopyBytes2 }, // ADC ib + { 0x15, ENTRY_CopyBytes3Or5 }, // ADC id + { 0x16, ENTRY_CopyBytes1 }, // PUSH + { 0x17, ENTRY_CopyBytes1 }, // POP + { 0x18, ENTRY_CopyBytes2Mod }, // SBB /r + { 0x19, ENTRY_CopyBytes2Mod }, // SBB /r + { 0x1A, ENTRY_CopyBytes2Mod }, // SBB /r + { 0x1B, ENTRY_CopyBytes2Mod }, // SBB /r + { 0x1C, ENTRY_CopyBytes2 }, // SBB ib + { 0x1D, ENTRY_CopyBytes3Or5 }, // SBB id + { 0x1E, ENTRY_CopyBytes1 }, // PUSH + { 0x1F, ENTRY_CopyBytes1 }, // POP + { 0x20, ENTRY_CopyBytes2Mod }, // AND /r + { 0x21, ENTRY_CopyBytes2Mod }, // AND /r + { 0x22, ENTRY_CopyBytes2Mod }, // AND /r + { 0x23, ENTRY_CopyBytes2Mod }, // AND /r + { 0x24, ENTRY_CopyBytes2 }, // AND ib + { 0x25, ENTRY_CopyBytes3Or5 }, // AND id + { 0x26, ENTRY_CopyBytesPrefix }, // ES prefix + { 0x27, ENTRY_CopyBytes1 }, // DAA + { 0x28, ENTRY_CopyBytes2Mod }, // SUB /r + { 0x29, ENTRY_CopyBytes2Mod }, // SUB /r + { 0x2A, ENTRY_CopyBytes2Mod }, // SUB /r + { 0x2B, ENTRY_CopyBytes2Mod }, // SUB /r + { 0x2C, ENTRY_CopyBytes2 }, // SUB ib + { 0x2D, ENTRY_CopyBytes3Or5 }, // SUB id + { 0x2E, ENTRY_CopyBytesPrefix }, // CS prefix + { 0x2F, ENTRY_CopyBytes1 }, // DAS + { 0x30, ENTRY_CopyBytes2Mod }, // XOR /r + { 0x31, ENTRY_CopyBytes2Mod }, // XOR /r + { 0x32, ENTRY_CopyBytes2Mod }, // XOR /r + { 0x33, ENTRY_CopyBytes2Mod }, // XOR /r + { 0x34, ENTRY_CopyBytes2 }, // XOR ib + { 0x35, ENTRY_CopyBytes3Or5 }, // XOR id + { 0x36, ENTRY_CopyBytesPrefix }, // SS prefix + { 0x37, ENTRY_CopyBytes1 }, // AAA + { 0x38, ENTRY_CopyBytes2Mod }, // CMP /r + { 0x39, ENTRY_CopyBytes2Mod }, // CMP /r + { 0x3A, ENTRY_CopyBytes2Mod }, // CMP /r + { 0x3B, ENTRY_CopyBytes2Mod }, // CMP /r + { 0x3C, ENTRY_CopyBytes2 }, // CMP ib + { 0x3D, ENTRY_CopyBytes3Or5 }, // CMP id + { 0x3E, ENTRY_CopyBytesPrefix }, // DS prefix + { 0x3F, ENTRY_CopyBytes1 }, // AAS +#ifdef DETOURS_X64 // For Rax Prefix +#error Feature not supported in this release. + + + + + + + + + + + + + + + +#else + { 0x40, ENTRY_CopyBytes1 }, // INC + { 0x41, ENTRY_CopyBytes1 }, // INC + { 0x42, ENTRY_CopyBytes1 }, // INC + { 0x43, ENTRY_CopyBytes1 }, // INC + { 0x44, ENTRY_CopyBytes1 }, // INC + { 0x45, ENTRY_CopyBytes1 }, // INC + { 0x46, ENTRY_CopyBytes1 }, // INC + { 0x47, ENTRY_CopyBytes1 }, // INC + { 0x48, ENTRY_CopyBytes1 }, // DEC + { 0x49, ENTRY_CopyBytes1 }, // DEC + { 0x4A, ENTRY_CopyBytes1 }, // DEC + { 0x4B, ENTRY_CopyBytes1 }, // DEC + { 0x4C, ENTRY_CopyBytes1 }, // DEC + { 0x4D, ENTRY_CopyBytes1 }, // DEC + { 0x4E, ENTRY_CopyBytes1 }, // DEC + { 0x4F, ENTRY_CopyBytes1 }, // DEC +#endif + { 0x50, ENTRY_CopyBytes1 }, // PUSH + { 0x51, ENTRY_CopyBytes1 }, // PUSH + { 0x52, ENTRY_CopyBytes1 }, // PUSH + { 0x53, ENTRY_CopyBytes1 }, // PUSH + { 0x54, ENTRY_CopyBytes1 }, // PUSH + { 0x55, ENTRY_CopyBytes1 }, // PUSH + { 0x56, ENTRY_CopyBytes1 }, // PUSH + { 0x57, ENTRY_CopyBytes1 }, // PUSH + { 0x58, ENTRY_CopyBytes1 }, // POP + { 0x59, ENTRY_CopyBytes1 }, // POP + { 0x5A, ENTRY_CopyBytes1 }, // POP + { 0x5B, ENTRY_CopyBytes1 }, // POP + { 0x5C, ENTRY_CopyBytes1 }, // POP + { 0x5D, ENTRY_CopyBytes1 }, // POP + { 0x5E, ENTRY_CopyBytes1 }, // POP + { 0x5F, ENTRY_CopyBytes1 }, // POP + { 0x60, ENTRY_CopyBytes1 }, // PUSHAD + { 0x61, ENTRY_CopyBytes1 }, // POPAD + { 0x62, ENTRY_CopyBytes2Mod }, // BOUND /r + { 0x63, ENTRY_CopyBytes2Mod }, // ARPL /r + { 0x64, ENTRY_CopyBytesPrefix }, // FS prefix + { 0x65, ENTRY_CopyBytesPrefix }, // GS prefix + { 0x66, ENTRY_Copy66 }, // Operand Prefix + { 0x67, ENTRY_Copy67 }, // Address Prefix + { 0x68, ENTRY_CopyBytes3Or5 }, // PUSH + { 0x69, ENTRY_CopyBytes2ModOperand }, // + { 0x6A, ENTRY_CopyBytes2 }, // PUSH + { 0x6B, ENTRY_CopyBytes2Mod1 }, // IMUL /r ib + { 0x6C, ENTRY_CopyBytes1 }, // INS + { 0x6D, ENTRY_CopyBytes1 }, // INS + { 0x6E, ENTRY_CopyBytes1 }, // OUTS/OUTSB + { 0x6F, ENTRY_CopyBytes1 }, // OUTS/OUTSW + { 0x70, ENTRY_CopyBytes2Jump }, // JO + { 0x71, ENTRY_CopyBytes2Jump }, // JNO + { 0x72, ENTRY_CopyBytes2Jump }, // JB/JC/JNAE + { 0x73, ENTRY_CopyBytes2Jump }, // JAE/JNB/JNC + { 0x74, ENTRY_CopyBytes2Jump }, // JE/JZ + { 0x75, ENTRY_CopyBytes2Jump }, // JNE/JNZ + { 0x76, ENTRY_CopyBytes2Jump }, // JBE/JNA + { 0x77, ENTRY_CopyBytes2Jump }, // JA/JNBE + { 0x78, ENTRY_CopyBytes2Jump }, // JS + { 0x79, ENTRY_CopyBytes2Jump }, // JNS + { 0x7A, ENTRY_CopyBytes2Jump }, // JP/JPE + { 0x7B, ENTRY_CopyBytes2Jump }, // JNP/JPO + { 0x7C, ENTRY_CopyBytes2Jump }, // JL/JNGE + { 0x7D, ENTRY_CopyBytes2Jump }, // JGE/JNL + { 0x7E, ENTRY_CopyBytes2Jump }, // JLE/JNG + { 0x7F, ENTRY_CopyBytes2Jump }, // JG/JNLE + { 0x80, ENTRY_CopyBytes2Mod1 }, // ADC/2 ib, etc.s + { 0x81, ENTRY_CopyBytes2ModOperand }, // + { 0x82, ENTRY_CopyBytes2 }, // MOV al,x + { 0x83, ENTRY_CopyBytes2Mod1 }, // ADC/2 ib, etc. + { 0x84, ENTRY_CopyBytes2Mod }, // TEST /r + { 0x85, ENTRY_CopyBytes2Mod }, // TEST /r + { 0x86, ENTRY_CopyBytes2Mod }, // XCHG /r @todo + { 0x87, ENTRY_CopyBytes2Mod }, // XCHG /r @todo + { 0x88, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x89, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x8A, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x8B, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x8C, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x8D, ENTRY_CopyBytes2Mod }, // LEA /r + { 0x8E, ENTRY_CopyBytes2Mod }, // MOV /r + { 0x8F, ENTRY_CopyBytes2Mod }, // POP /0 + { 0x90, ENTRY_CopyBytes1 }, // NOP + { 0x91, ENTRY_CopyBytes1 }, // XCHG + { 0x92, ENTRY_CopyBytes1 }, // XCHG + { 0x93, ENTRY_CopyBytes1 }, // XCHG + { 0x94, ENTRY_CopyBytes1 }, // XCHG + { 0x95, ENTRY_CopyBytes1 }, // XCHG + { 0x96, ENTRY_CopyBytes1 }, // XCHG + { 0x97, ENTRY_CopyBytes1 }, // XCHG + { 0x98, ENTRY_CopyBytes1 }, // CWDE + { 0x99, ENTRY_CopyBytes1 }, // CDQ + { 0x9A, ENTRY_CopyBytes5Or7Dynamic }, // CALL cp + { 0x9B, ENTRY_CopyBytes1 }, // WAIT/FWAIT + { 0x9C, ENTRY_CopyBytes1 }, // PUSHFD + { 0x9D, ENTRY_CopyBytes1 }, // POPFD + { 0x9E, ENTRY_CopyBytes1 }, // SAHF + { 0x9F, ENTRY_CopyBytes1 }, // LAHF + { 0xA0, ENTRY_CopyBytes3Or5Address }, // MOV + { 0xA1, ENTRY_CopyBytes3Or5Address }, // MOV + { 0xA2, ENTRY_CopyBytes3Or5Address }, // MOV + { 0xA3, ENTRY_CopyBytes3Or5Address }, // MOV + { 0xA4, ENTRY_CopyBytes1 }, // MOVS + { 0xA5, ENTRY_CopyBytes1 }, // MOVS/MOVSD + { 0xA6, ENTRY_CopyBytes1 }, // CMPS/CMPSB + { 0xA7, ENTRY_CopyBytes1 }, // CMPS/CMPSW + { 0xA8, ENTRY_CopyBytes2 }, // TEST + { 0xA9, ENTRY_CopyBytes3Or5 }, // TEST + { 0xAA, ENTRY_CopyBytes1 }, // STOS/STOSB + { 0xAB, ENTRY_CopyBytes1 }, // STOS/STOSW + { 0xAC, ENTRY_CopyBytes1 }, // LODS/LODSB + { 0xAD, ENTRY_CopyBytes1 }, // LODS/LODSW + { 0xAE, ENTRY_CopyBytes1 }, // SCAS/SCASB + { 0xAF, ENTRY_CopyBytes1 }, // SCAS/SCASD + { 0xB0, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB1, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB2, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB3, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB4, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB5, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB6, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB7, ENTRY_CopyBytes2 }, // MOV B0+rb + { 0xB8, ENTRY_CopyBytes3Or5Rax }, // MOV B8+rb + { 0xB9, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBA, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBB, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBC, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBD, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBE, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xBF, ENTRY_CopyBytes3Or5 }, // MOV B8+rb + { 0xC0, ENTRY_CopyBytes2Mod1 }, // RCL/2 ib, etc. + { 0xC1, ENTRY_CopyBytes2Mod1 }, // RCL/2 ib, etc. + { 0xC2, ENTRY_CopyBytes3 }, // RET + { 0xC3, ENTRY_CopyBytes1 }, // RET + { 0xC4, ENTRY_CopyBytes2Mod }, // LES + { 0xC5, ENTRY_CopyBytes2Mod }, // LDS + { 0xC6, ENTRY_CopyBytes2Mod1 }, // MOV + { 0xC7, ENTRY_CopyBytes2ModOperand }, // MOV + { 0xC8, ENTRY_CopyBytes4 }, // ENTER + { 0xC9, ENTRY_CopyBytes1 }, // LEAVE + { 0xCA, ENTRY_CopyBytes3Dynamic }, // RET + { 0xCB, ENTRY_CopyBytes1Dynamic }, // RET + { 0xCC, ENTRY_CopyBytes1Dynamic }, // INT 3 + { 0xCD, ENTRY_CopyBytes2Dynamic }, // INT ib + { 0xCE, ENTRY_CopyBytes1Dynamic }, // INTO + { 0xCF, ENTRY_CopyBytes1Dynamic }, // IRET + { 0xD0, ENTRY_CopyBytes2Mod }, // RCL/2, etc. + { 0xD1, ENTRY_CopyBytes2Mod }, // RCL/2, etc. + { 0xD2, ENTRY_CopyBytes2Mod }, // RCL/2, etc. + { 0xD3, ENTRY_CopyBytes2Mod }, // RCL/2, etc. + { 0xD4, ENTRY_CopyBytes2 }, // AAM + { 0xD5, ENTRY_CopyBytes2 }, // AAD + { 0xD6, ENTRY_Invalid }, // + { 0xD7, ENTRY_CopyBytes1 }, // XLAT/XLATB + { 0xD8, ENTRY_CopyBytes2Mod }, // FADD, etc. + { 0xD9, ENTRY_CopyBytes2Mod }, // F2XM1, etc. + { 0xDA, ENTRY_CopyBytes2Mod }, // FLADD, etc. + { 0xDB, ENTRY_CopyBytes2Mod }, // FCLEX, etc. + { 0xDC, ENTRY_CopyBytes2Mod }, // FADD/0, etc. + { 0xDD, ENTRY_CopyBytes2Mod }, // FFREE, etc. + { 0xDE, ENTRY_CopyBytes2Mod }, // FADDP, etc. + { 0xDF, ENTRY_CopyBytes2Mod }, // FBLD/4, etc. + { 0xE0, ENTRY_CopyBytes2CantJump }, // LOOPNE cb + { 0xE1, ENTRY_CopyBytes2CantJump }, // LOOPE cb + { 0xE2, ENTRY_CopyBytes2CantJump }, // LOOP cb + { 0xE3, ENTRY_CopyBytes2Jump }, // JCXZ/JECXZ + { 0xE4, ENTRY_CopyBytes2 }, // IN ib + { 0xE5, ENTRY_CopyBytes2 }, // IN id + { 0xE6, ENTRY_CopyBytes2 }, // OUT ib + { 0xE7, ENTRY_CopyBytes2 }, // OUT ib + { 0xE8, ENTRY_CopyBytes3Or5Target }, // CALL cd + { 0xE9, ENTRY_CopyBytes3Or5Target }, // JMP cd + { 0xEA, ENTRY_CopyBytes5Or7Dynamic }, // JMP cp + { 0xEB, ENTRY_CopyBytes2Jump }, // JMP cb + { 0xEC, ENTRY_CopyBytes1 }, // IN ib + { 0xED, ENTRY_CopyBytes1 }, // IN id + { 0xEE, ENTRY_CopyBytes1 }, // OUT + { 0xEF, ENTRY_CopyBytes1 }, // OUT + { 0xF0, ENTRY_CopyBytesPrefix }, // LOCK prefix + { 0xF1, ENTRY_Invalid }, // + { 0xF2, ENTRY_CopyBytesPrefix }, // REPNE prefix + { 0xF3, ENTRY_CopyBytesPrefix }, // REPE prefix + { 0xF4, ENTRY_CopyBytes1 }, // HLT + { 0xF5, ENTRY_CopyBytes1 }, // CMC + { 0xF6, ENTRY_CopyF6 }, // TEST/0, DIV/6 + { 0xF7, ENTRY_CopyF7 }, // TEST/0, DIV/6 + { 0xF8, ENTRY_CopyBytes1 }, // CLC + { 0xF9, ENTRY_CopyBytes1 }, // STC + { 0xFA, ENTRY_CopyBytes1 }, // CLI + { 0xFB, ENTRY_CopyBytes1 }, // STI + { 0xFC, ENTRY_CopyBytes1 }, // CLD + { 0xFD, ENTRY_CopyBytes1 }, // STD + { 0xFE, ENTRY_CopyBytes2Mod }, // DEC/1,INC/0 + { 0xFF, ENTRY_CopyFF }, // CALL/2 + { 0, ENTRY_End }, +}; + +const CDetourDis::COPYENTRY CDetourDis::s_rceCopyTable0F[257] = +{ + { 0x00, ENTRY_CopyBytes2Mod }, // LLDT/2, etc. + { 0x01, ENTRY_CopyBytes2Mod }, // INVLPG/7, etc. + { 0x02, ENTRY_CopyBytes2Mod }, // LAR/r + { 0x03, ENTRY_CopyBytes2Mod }, // LSL/r + { 0x04, ENTRY_Invalid }, // _04 + { 0x05, ENTRY_Invalid }, // _05 + { 0x06, ENTRY_CopyBytes2 }, // CLTS + { 0x07, ENTRY_Invalid }, // _07 + { 0x08, ENTRY_CopyBytes2 }, // INVD + { 0x09, ENTRY_CopyBytes2 }, // WBINVD + { 0x0A, ENTRY_Invalid }, // _0A + { 0x0B, ENTRY_CopyBytes2 }, // UD2 + { 0x0C, ENTRY_Invalid }, // _0C + { 0x0D, ENTRY_CopyBytes2Mod }, // PREFETCH + { 0x0E, ENTRY_CopyBytes2 }, // FEMMS + { 0x0F, ENTRY_CopyBytes3Mod }, // 3DNow Opcodes + { 0x10, ENTRY_CopyBytes2Mod }, // MOVSS MOVUPD MOVSD + { 0x11, ENTRY_CopyBytes2Mod }, // MOVSS MOVUPD MOVSD + { 0x12, ENTRY_CopyBytes2Mod }, // MOVLPD + { 0x13, ENTRY_CopyBytes2Mod }, // MOVLPD + { 0x14, ENTRY_CopyBytes2Mod }, // UNPCKLPD + { 0x15, ENTRY_CopyBytes2Mod }, // UNPCKHPD + { 0x16, ENTRY_CopyBytes2Mod }, // MOVHPD + { 0x17, ENTRY_CopyBytes2Mod }, // MOVHPD + { 0x18, ENTRY_CopyBytes2Mod }, // PREFETCHINTA... + { 0x19, ENTRY_Invalid }, // _19 + { 0x1A, ENTRY_Invalid }, // _1A + { 0x1B, ENTRY_Invalid }, // _1B + { 0x1C, ENTRY_Invalid }, // _1C + { 0x1D, ENTRY_Invalid }, // _1D + { 0x1E, ENTRY_Invalid }, // _1E + { 0x1F, ENTRY_Invalid }, // _1F + { 0x20, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x21, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x22, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x23, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x24, ENTRY_Invalid }, // _24 + { 0x25, ENTRY_Invalid }, // _25 + { 0x26, ENTRY_Invalid }, // _26 + { 0x27, ENTRY_Invalid }, // _27 + { 0x28, ENTRY_CopyBytes2Mod }, // MOVAPS MOVAPD + { 0x29, ENTRY_CopyBytes2Mod }, // MOVAPS MOVAPD + { 0x2A, ENTRY_CopyBytes2Mod }, // CVPI2PS & + { 0x2B, ENTRY_CopyBytes2Mod }, // MOVNTPS MOVNTPD + { 0x2C, ENTRY_CopyBytes2Mod }, // CVTTPS2PI & + { 0x2D, ENTRY_CopyBytes2Mod }, // CVTPS2PI & + { 0x2E, ENTRY_CopyBytes2Mod }, // UCOMISS UCOMISD + { 0x2F, ENTRY_CopyBytes2Mod }, // COMISS COMISD + { 0x30, ENTRY_CopyBytes2 }, // WRMSR + { 0x31, ENTRY_CopyBytes2 }, // RDTSC + { 0x32, ENTRY_CopyBytes2 }, // RDMSR + { 0x33, ENTRY_CopyBytes2 }, // RDPMC + { 0x34, ENTRY_CopyBytes2 }, // SYSENTER + { 0x35, ENTRY_CopyBytes2 }, // SYSEXIT + { 0x36, ENTRY_Invalid }, // _36 + { 0x37, ENTRY_Invalid }, // _37 + { 0x38, ENTRY_Invalid }, // _38 + { 0x39, ENTRY_Invalid }, // _39 + { 0x3A, ENTRY_Invalid }, // _3A + { 0x3B, ENTRY_Invalid }, // _3B + { 0x3C, ENTRY_Invalid }, // _3C + { 0x3D, ENTRY_Invalid }, // _3D + { 0x3E, ENTRY_Invalid }, // _3E + { 0x3F, ENTRY_Invalid }, // _3F + { 0x40, ENTRY_CopyBytes2Mod }, // CMOVO (0F 40) + { 0x41, ENTRY_CopyBytes2Mod }, // CMOVNO (0F 41) + { 0x42, ENTRY_CopyBytes2Mod }, // CMOVB & CMOVNE (0F 42) + { 0x43, ENTRY_CopyBytes2Mod }, // CMOVAE & CMOVNB (0F 43) + { 0x44, ENTRY_CopyBytes2Mod }, // CMOVE & CMOVZ (0F 44) + { 0x45, ENTRY_CopyBytes2Mod }, // CMOVNE & CMOVNZ (0F 45) + { 0x46, ENTRY_CopyBytes2Mod }, // CMOVBE & CMOVNA (0F 46) + { 0x47, ENTRY_CopyBytes2Mod }, // CMOVA & CMOVNBE (0F 47) + { 0x48, ENTRY_CopyBytes2Mod }, // CMOVS (0F 48) + { 0x49, ENTRY_CopyBytes2Mod }, // CMOVNS (0F 49) + { 0x4A, ENTRY_CopyBytes2Mod }, // CMOVP & CMOVPE (0F 4A) + { 0x4B, ENTRY_CopyBytes2Mod }, // CMOVNP & CMOVPO (0F 4B) + { 0x4C, ENTRY_CopyBytes2Mod }, // CMOVL & CMOVNGE (0F 4C) + { 0x4D, ENTRY_CopyBytes2Mod }, // CMOVGE & CMOVNL (0F 4D) + { 0x4E, ENTRY_CopyBytes2Mod }, // CMOVLE & CMOVNG (0F 4E) + { 0x4F, ENTRY_CopyBytes2Mod }, // CMOVG & CMOVNLE (0F 4F) + { 0x50, ENTRY_CopyBytes2Mod }, // MOVMSKPD MOVMSKPD + { 0x51, ENTRY_CopyBytes2Mod }, // SQRTPS & + { 0x52, ENTRY_CopyBytes2Mod }, // RSQRTTS RSQRTPS + { 0x53, ENTRY_CopyBytes2Mod }, // RCPPS RCPSS + { 0x54, ENTRY_CopyBytes2Mod }, // ANDPS ANDPD + { 0x55, ENTRY_CopyBytes2Mod }, // ANDNPS ANDNPD + { 0x56, ENTRY_CopyBytes2Mod }, // ORPS ORPD + { 0x57, ENTRY_CopyBytes2Mod }, // XORPS XORPD + { 0x58, ENTRY_CopyBytes2Mod }, // ADDPS & + { 0x59, ENTRY_CopyBytes2Mod }, // MULPS & + { 0x5A, ENTRY_CopyBytes2Mod }, // CVTPS2PD & + { 0x5B, ENTRY_CopyBytes2Mod }, // CVTDQ2PS & + { 0x5C, ENTRY_CopyBytes2Mod }, // SUBPS & + { 0x5D, ENTRY_CopyBytes2Mod }, // MINPS & + { 0x5E, ENTRY_CopyBytes2Mod }, // DIVPS & + { 0x5F, ENTRY_CopyBytes2Mod }, // MASPS & + { 0x60, ENTRY_CopyBytes2Mod }, // PUNPCKLBW/r + { 0x61, ENTRY_CopyBytes2Mod }, // PUNPCKLWD/r + { 0x62, ENTRY_CopyBytes2Mod }, // PUNPCKLWD/r + { 0x63, ENTRY_CopyBytes2Mod }, // PACKSSWB/r + { 0x64, ENTRY_CopyBytes2Mod }, // PCMPGTB/r + { 0x65, ENTRY_CopyBytes2Mod }, // PCMPGTW/r + { 0x66, ENTRY_CopyBytes2Mod }, // PCMPGTD/r + { 0x67, ENTRY_CopyBytes2Mod }, // PACKUSWB/r + { 0x68, ENTRY_CopyBytes2Mod }, // PUNPCKHBW/r + { 0x69, ENTRY_CopyBytes2Mod }, // PUNPCKHWD/r + { 0x6A, ENTRY_CopyBytes2Mod }, // PUNPCKHDQ/r + { 0x6B, ENTRY_CopyBytes2Mod }, // PACKSSDW/r + { 0x6C, ENTRY_CopyBytes2Mod }, // PUNPCKLQDQ + { 0x6D, ENTRY_CopyBytes2Mod }, // PUNPCKHQDQ + { 0x6E, ENTRY_CopyBytes2Mod }, // MOVD/r + { 0x6F, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x70, ENTRY_CopyBytes2Mod1 }, // PSHUFW/r ib + { 0x71, ENTRY_CopyBytes2Mod1 }, // PSLLW/6 ib,PSRAW/4 ib,PSRLW/2 ib + { 0x72, ENTRY_CopyBytes2Mod1 }, // PSLLD/6 ib,PSRAD/4 ib,PSRLD/2 ib + { 0x73, ENTRY_CopyBytes2Mod1 }, // PSLLQ/6 ib,PSRLQ/2 ib + { 0x74, ENTRY_CopyBytes2Mod }, // PCMPEQB/r + { 0x75, ENTRY_CopyBytes2Mod }, // PCMPEQW/r + { 0x76, ENTRY_CopyBytes2Mod }, // PCMPEQD/r + { 0x77, ENTRY_CopyBytes2 }, // EMMS + { 0x78, ENTRY_Invalid }, // _78 + { 0x79, ENTRY_Invalid }, // _79 + { 0x7A, ENTRY_Invalid }, // _7A + { 0x7B, ENTRY_Invalid }, // _7B + { 0x7C, ENTRY_Invalid }, // _7C + { 0x7D, ENTRY_Invalid }, // _7D + { 0x7E, ENTRY_CopyBytes2Mod }, // MOVD/r + { 0x7F, ENTRY_CopyBytes2Mod }, // MOV/r + { 0x80, ENTRY_CopyBytes3Or5Target }, // JO + { 0x81, ENTRY_CopyBytes3Or5Target }, // JNO + { 0x82, ENTRY_CopyBytes3Or5Target }, // JB,JC,JNAE + { 0x83, ENTRY_CopyBytes3Or5Target }, // JAE,JNB,JNC + { 0x84, ENTRY_CopyBytes3Or5Target }, // JE,JZ,JZ + { 0x85, ENTRY_CopyBytes3Or5Target }, // JNE,JNZ + { 0x86, ENTRY_CopyBytes3Or5Target }, // JBE,JNA + { 0x87, ENTRY_CopyBytes3Or5Target }, // JA,JNBE + { 0x88, ENTRY_CopyBytes3Or5Target }, // JS + { 0x89, ENTRY_CopyBytes3Or5Target }, // JNS + { 0x8A, ENTRY_CopyBytes3Or5Target }, // JP,JPE + { 0x8B, ENTRY_CopyBytes3Or5Target }, // JNP,JPO + { 0x8C, ENTRY_CopyBytes3Or5Target }, // JL,NGE + { 0x8D, ENTRY_CopyBytes3Or5Target }, // JGE,JNL + { 0x8E, ENTRY_CopyBytes3Or5Target }, // JLE,JNG + { 0x8F, ENTRY_CopyBytes3Or5Target }, // JG,JNLE + { 0x90, ENTRY_CopyBytes2Mod }, // CMOVO (0F 40) + { 0x91, ENTRY_CopyBytes2Mod }, // CMOVNO (0F 41) + { 0x92, ENTRY_CopyBytes2Mod }, // CMOVB & CMOVC & CMOVNAE (0F 42) + { 0x93, ENTRY_CopyBytes2Mod }, // CMOVAE & CMOVNB & CMOVNC (0F 43) + { 0x94, ENTRY_CopyBytes2Mod }, // CMOVE & CMOVZ (0F 44) + { 0x95, ENTRY_CopyBytes2Mod }, // CMOVNE & CMOVNZ (0F 45) + { 0x96, ENTRY_CopyBytes2Mod }, // CMOVBE & CMOVNA (0F 46) + { 0x97, ENTRY_CopyBytes2Mod }, // CMOVA & CMOVNBE (0F 47) + { 0x98, ENTRY_CopyBytes2Mod }, // CMOVS (0F 48) + { 0x99, ENTRY_CopyBytes2Mod }, // CMOVNS (0F 49) + { 0x9A, ENTRY_CopyBytes2Mod }, // CMOVP & CMOVPE (0F 4A) + { 0x9B, ENTRY_CopyBytes2Mod }, // CMOVNP & CMOVPO (0F 4B) + { 0x9C, ENTRY_CopyBytes2Mod }, // CMOVL & CMOVNGE (0F 4C) + { 0x9D, ENTRY_CopyBytes2Mod }, // CMOVGE & CMOVNL (0F 4D) + { 0x9E, ENTRY_CopyBytes2Mod }, // CMOVLE & CMOVNG (0F 4E) + { 0x9F, ENTRY_CopyBytes2Mod }, // CMOVG & CMOVNLE (0F 4F) + { 0xA0, ENTRY_CopyBytes2 }, // PUSH + { 0xA1, ENTRY_CopyBytes2 }, // POP + { 0xA2, ENTRY_CopyBytes2 }, // CPUID + { 0xA3, ENTRY_CopyBytes2Mod }, // BT (0F A3) + { 0xA4, ENTRY_CopyBytes2Mod1 }, // SHLD + { 0xA5, ENTRY_CopyBytes2Mod }, // SHLD + { 0xA6, ENTRY_Invalid }, // _A6 + { 0xA7, ENTRY_Invalid }, // _A7 + { 0xA8, ENTRY_CopyBytes2 }, // PUSH + { 0xA9, ENTRY_CopyBytes2 }, // POP + { 0xAA, ENTRY_CopyBytes2 }, // RSM + { 0xAB, ENTRY_CopyBytes2Mod }, // BTS (0F AB) + { 0xAC, ENTRY_CopyBytes2Mod1 }, // SHRD + { 0xAD, ENTRY_CopyBytes2Mod }, // SHRD + { 0xAE, ENTRY_CopyBytes2Mod }, // FXRSTOR/1,FXSAVE/0 + { 0xAF, ENTRY_CopyBytes2Mod }, // IMUL (0F AF) + { 0xB0, ENTRY_CopyBytes2Mod }, // CMPXCHG (0F B0) + { 0xB1, ENTRY_CopyBytes2Mod }, // CMPXCHG (0F B1) + { 0xB2, ENTRY_CopyBytes2Mod }, // LSS/r + { 0xB3, ENTRY_CopyBytes2Mod }, // BTR (0F B3) + { 0xB4, ENTRY_CopyBytes2Mod }, // LFS/r + { 0xB5, ENTRY_CopyBytes2Mod }, // LGS/r + { 0xB6, ENTRY_CopyBytes2Mod }, // MOVZX/r + { 0xB7, ENTRY_CopyBytes2Mod }, // MOVZX/r + { 0xB8, ENTRY_Invalid }, // _B8 + { 0xB9, ENTRY_Invalid }, // _B9 + { 0xBA, ENTRY_CopyBytes2Mod1 }, // BT & BTC & BTR & BTS (0F BA) + { 0xBB, ENTRY_CopyBytes2Mod }, // BTC (0F BB) + { 0xBC, ENTRY_CopyBytes2Mod }, // BSF (0F BC) + { 0xBD, ENTRY_CopyBytes2Mod }, // BSR (0F BD) + { 0xBE, ENTRY_CopyBytes2Mod }, // MOVSX/r + { 0xBF, ENTRY_CopyBytes2Mod }, // MOVSX/r + { 0xC0, ENTRY_CopyBytes2Mod }, // XADD/r + { 0xC1, ENTRY_CopyBytes2Mod }, // XADD/r + { 0xC2, ENTRY_CopyBytes2Mod }, // CMPPS & + { 0xC3, ENTRY_CopyBytes2Mod }, // MOVNTI + { 0xC4, ENTRY_CopyBytes2Mod1 }, // PINSRW /r ib + { 0xC5, ENTRY_CopyBytes2Mod1 }, // PEXTRW /r ib + { 0xC6, ENTRY_CopyBytes2Mod1 }, // SHUFPS & SHUFPD + { 0xC7, ENTRY_CopyBytes2Mod }, // CMPXCHG8B (0F C7) + { 0xC8, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xC9, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xCA, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xCB, ENTRY_CopyBytes2 }, //CVTPD2PI BSWAP 0F C8 + rd + { 0xCC, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xCD, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xCE, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xCF, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd + { 0xD0, ENTRY_Invalid }, // _D0 + { 0xD1, ENTRY_CopyBytes2Mod }, // PSRLW/r + { 0xD2, ENTRY_CopyBytes2Mod }, // PSRLD/r + { 0xD3, ENTRY_CopyBytes2Mod }, // PSRLQ/r + { 0xD4, ENTRY_CopyBytes2Mod }, // PADDQ + { 0xD5, ENTRY_CopyBytes2Mod }, // PMULLW/r + { 0xD6, ENTRY_CopyBytes2Mod }, // MOVDQ2Q / MOVQ2DQ + { 0xD7, ENTRY_CopyBytes2Mod }, // PMOVMSKB/r + { 0xD8, ENTRY_CopyBytes2Mod }, // PSUBUSB/r + { 0xD9, ENTRY_CopyBytes2Mod }, // PSUBUSW/r + { 0xDA, ENTRY_CopyBytes2Mod }, // PMINUB/r + { 0xDB, ENTRY_CopyBytes2Mod }, // PAND/r + { 0xDC, ENTRY_CopyBytes2Mod }, // PADDUSB/r + { 0xDD, ENTRY_CopyBytes2Mod }, // PADDUSW/r + { 0xDE, ENTRY_CopyBytes2Mod }, // PMAXUB/r + { 0xDF, ENTRY_CopyBytes2Mod }, // PANDN/r + { 0xE0, ENTRY_CopyBytes2Mod }, // PAVGB + { 0xE1, ENTRY_CopyBytes2Mod }, // PSRAW/r + { 0xE2, ENTRY_CopyBytes2Mod }, // PSRAD/r + { 0xE3, ENTRY_CopyBytes2Mod }, // PAVGW + { 0xE4, ENTRY_CopyBytes2Mod }, // PMULHUW/r + { 0xE5, ENTRY_CopyBytes2Mod }, // PMULHW/r + { 0xE6, ENTRY_CopyBytes2Mod }, // CTDQ2PD & + { 0xE7, ENTRY_CopyBytes2Mod }, // MOVNTQ + { 0xE8, ENTRY_CopyBytes2Mod }, // PSUBB/r + { 0xE9, ENTRY_CopyBytes2Mod }, // PSUBW/r + { 0xEA, ENTRY_CopyBytes2Mod }, // PMINSW/r + { 0xEB, ENTRY_CopyBytes2Mod }, // POR/r + { 0xEC, ENTRY_CopyBytes2Mod }, // PADDSB/r + { 0xED, ENTRY_CopyBytes2Mod }, // PADDSW/r + { 0xEE, ENTRY_CopyBytes2Mod }, // PMAXSW /r + { 0xEF, ENTRY_CopyBytes2Mod }, // PXOR/r + { 0xF0, ENTRY_Invalid }, // _F0 + { 0xF1, ENTRY_CopyBytes2Mod }, // PSLLW/r + { 0xF2, ENTRY_CopyBytes2Mod }, // PSLLD/r + { 0xF3, ENTRY_CopyBytes2Mod }, // PSLLQ/r + { 0xF4, ENTRY_CopyBytes2Mod }, // PMULUDQ/r + { 0xF5, ENTRY_CopyBytes2Mod }, // PMADDWD/r + { 0xF6, ENTRY_CopyBytes2Mod }, // PSADBW/r + { 0xF7, ENTRY_CopyBytes2Mod }, // MASKMOVQ + { 0xF8, ENTRY_CopyBytes2Mod }, // PSUBB/r + { 0xF9, ENTRY_CopyBytes2Mod }, // PSUBW/r + { 0xFA, ENTRY_CopyBytes2Mod }, // PSUBD/r + { 0xFB, ENTRY_CopyBytes2Mod }, // FSUBQ/r + { 0xFC, ENTRY_CopyBytes2Mod }, // PADDB/r + { 0xFD, ENTRY_CopyBytes2Mod }, // PADDW/r + { 0xFE, ENTRY_CopyBytes2Mod }, // PADDD/r + { 0xFF, ENTRY_Invalid }, // _FF + { 0, ENTRY_End }, +}; + +BOOL CDetourDis::SanityCheckSystem() +{ + ULONG n = 0; + for (; n < 256; n++) { + REFCOPYENTRY pEntry = &s_rceCopyTable[n]; + + if (n != pEntry->nOpcode) { + ASSERT(n == pEntry->nOpcode); + return FALSE; + } + } + if (s_rceCopyTable[256].pfCopy != NULL) { + ASSERT(!"Missing end marker."); + return FALSE; + } + + for (n = 0; n < 256; n++) { + REFCOPYENTRY pEntry = &s_rceCopyTable0F[n]; + + if (n != pEntry->nOpcode) { + ASSERT(n == pEntry->nOpcode); + return FALSE; + } + } + if (s_rceCopyTable0F[256].pfCopy != NULL) { + ASSERT(!"Missing end marker."); + return FALSE; + } + + return TRUE; +} +#endif // defined(DETOURS_X64) || defined(DETOURS_X86) + +/////////////////////////////////////////////////////////// IA64 Disassembler. +// +#ifdef DETOURS_IA64 +#error Feature not supported in this release. +#endif // DETOURS_IA64 + +// +///////////////////////////////////////////////////////////////// End of File. diff --git a/source/lib/sysdep/win/wstartup.cpp b/source/lib/sysdep/win/wstartup.cpp index e539064832..78d27aba12 100644 --- a/source/lib/sysdep/win/wstartup.cpp +++ b/source/lib/sysdep/win/wstartup.cpp @@ -23,18 +23,12 @@ #include "win.h" #include // __security_init_cookie -#include +#include "lib/sysdep/win/detours/detours.h" #include "winit.h" #include "wdbg.h" // wdbg_exception_filter -#if MSC_VERSION -#pragma comment(lib, "detours.lib") -#pragma comment(lib, "detoured.lib") -#endif - - //----------------------------------------------------------------------------- // do shutdown at exit @@ -60,7 +54,6 @@ static void InstallExitHook() RealExitProcess = ExitProcess; DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)RealExitProcess, HookedExitProcess); DetourTransactionCommit(); } @@ -126,11 +119,11 @@ typedef int(*PfnIntVoid)(void); static int RunWithinTryBlock(PfnIntVoid func) { int ret; - __try + //__try { ret = func(); } - __except(wdbg_exception_filter(GetExceptionInformation())) + //__except(wdbg_exception_filter(GetExceptionInformation())) { ret = -1; }