Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/byakugan/detours/detours.cpp
Views: 11777
//////////////////////////////////////////////////////////////////////////////1//2// Core Detours Functionality (detours.cpp of detours.lib)3//4// Microsoft Research Detours Package, Version 2.1.5//6// Copyright (c) Microsoft Corporation. All rights reserved.7//8#include <windows.h>910#if (_MSC_VER < 1299)11#pragma warning(disable: 4710)12#endif1314//#define DETOUR_DEBUG 115#define DETOURS_INTERNAL1617#include "detours.h"18#include "detoured.h"1920#if !defined(DETOURS_X86) && !defined(DETOURS_X64) && !defined(DETOURS_IA64)21#error Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA6422#endif2324//////////////////////////////////////////////////////////////////////////////25//26static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)27{28MEMORY_BASIC_INFORMATION mbi;29VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));30__try {31PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;32if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {33return false;34}3536PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +37pDosHeader->e_lfanew);38if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {39return false;40}4142if (pbAddress >= ((PBYTE)pDosHeader +43pNtHeader->OptionalHeader44.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&45pbAddress < ((PBYTE)pDosHeader +46pNtHeader->OptionalHeader47.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +48pNtHeader->OptionalHeader49.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {50return true;51}52return false;53}54__except(EXCEPTION_EXECUTE_HANDLER) {55return false;56}57}5859///////////////////////////////////////////////////////////////////////// X86.60//61#ifdef DETOURS_X866263struct _DETOUR_TRAMPOLINE64{65BYTE rbCode[23]; // target code + jmp to pbRemain66BYTE cbTarget; // size of target code moved.67PBYTE pbRemain; // first instruction after moved code. [free list]68PBYTE pbDetour; // first instruction of detour function.69};7071enum {72SIZE_OF_JMP = 573};7475inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)76{77PBYTE pbJmpSrc = pbCode + 5;78*pbCode++ = 0xE9; // jmp +imm3279*((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);80return pbCode;81}8283inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)84{85PBYTE pbJmpSrc = pbCode + 6;86*pbCode++ = 0xff; // jmp [+imm32]87*pbCode++ = 0x25;88*((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);89return pbCode;90}9192inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)93{94while (pbCode < pbLimit) {95*pbCode++ = 0xcc; // brk;96}97return pbCode;98}99100inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)101{102if (pbCode == NULL) {103return NULL;104}105if (ppGlobals != NULL) {106*ppGlobals = NULL;107}108if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]109// Looks like an import alias jump, then get the code it points to.110PBYTE pbTarget = *(PBYTE *)&pbCode[2];111if (detour_is_imported(pbCode, pbTarget)) {112PBYTE pbNew = *(PBYTE *)pbTarget;113DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));114return pbNew;115}116}117else if (pbCode[0] == 0xeb) { // jmp +imm8118// These just started appearing with CL13.119PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];120DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));121if (pbNew[0] == 0xe9) { // jmp +imm32122pbCode = pbNew;123pbNew = pbCode + *(INT32 *)&pbCode[1];124DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));125}126return pbNew;127}128return pbCode;129}130131inline BOOL detour_does_code_end_function(PBYTE pbCode)132{133if (pbCode[0] == 0xe9 || // jmp +imm32134pbCode[0] == 0xe0 || // jmp eax135pbCode[0] == 0xc2 || // ret +imm8136pbCode[0] == 0xc3 || // ret137pbCode[0] == 0xcc) { // brk138return TRUE;139}140else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]141return TRUE;142}143else if ((pbCode[0] == 0x26 || // jmp es:144pbCode[0] == 0x2e || // jmp cs:145pbCode[0] == 0x36 || // jmp ss:146pbCode[0] == 0xe3 || // jmp ds:147pbCode[0] == 0x64 || // jmp fs:148pbCode[0] == 0x65) && // jmp gs:149pbCode[1] == 0xff && // jmp [+imm32]150pbCode[2] == 0x25) {151return TRUE;152}153return FALSE;154}155#endif // DETOURS_X86156157///////////////////////////////////////////////////////////////////////// X64.158//159#ifdef DETOURS_X64160#error Feature not supported in this release.161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257#endif // DETOURS_X64258259//////////////////////////////////////////////////////////////////////// IA64.260//261#ifdef DETOURS_IA64262#error Feature not supported in this release.263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404#endif405406//////////////////////////////////////////////// Trampoline Memory Management.407//408struct DETOUR_REGION409{410ULONG dwSignature;411DETOUR_REGION * pNext; // Next region in list of regions.412DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region.413};414typedef DETOUR_REGION * PDETOUR_REGION;415416const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd';417const ULONG DETOUR_REGION_SIZE = 0x10000;418const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE419/ sizeof(DETOUR_TRAMPOLINE)) - 1;420static PDETOUR_REGION s_pRegions = NULL; // List of all regions.421static PDETOUR_REGION s_pRegion = NULL; // Default region.422423static void detour_writable_trampoline_regions()424{425// Mark all of the regions as writable.426for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {427DWORD dwOld;428VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld);429}430}431432static void detour_runnable_trampoline_regions()433{434// Mark all of the regions as executable.435for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {436DWORD dwOld;437VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld);438}439}440441static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)442{443// We have to place trampolines within +/- 2GB of target.444// The allocation code assumes that445446PDETOUR_TRAMPOLINE pLo = (PDETOUR_TRAMPOLINE)447((pbTarget > (PBYTE)0x7ff80000)448? pbTarget - 0x7ff80000 : (PBYTE)(ULONG_PTR)DETOUR_REGION_SIZE);449PDETOUR_TRAMPOLINE pHi = (PDETOUR_TRAMPOLINE)450((pbTarget < (PBYTE)0xffffffff80000000)451? pbTarget + 0x7ff80000 : (PBYTE)0xfffffffffff80000);452DETOUR_TRACE(("[%p..%p..%p]\n", pLo, pbTarget, pHi));453454PDETOUR_TRAMPOLINE pTrampoline = NULL;455456// Insure that there is a default region.457if (s_pRegion == NULL && s_pRegions != NULL) {458s_pRegion = s_pRegions;459}460461// First check the default region for an valid free block.462if (s_pRegion != NULL && s_pRegion->pFree != NULL &&463s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {464465found_region:466pTrampoline = s_pRegion->pFree;467// do a last sanity check on region.468if (pTrampoline < pLo || pTrampoline > pHi) {469return NULL;470}471s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain;472memset(pTrampoline, 0xcc, sizeof(*pTrampoline));473return pTrampoline;474}475476// Then check the existing regions for a valid free block.477for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) {478if (s_pRegion != NULL && s_pRegion->pFree != NULL &&479s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {480goto found_region;481}482}483484// We need to allocate a new region.485486// Round pbTarget down to 64K block.487pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff);488489// First we search down (within the valid region)490491DETOUR_TRACE((" Looking for free region below %p:\n", pbTarget));492493PBYTE pbTry;494for (pbTry = pbTarget; pbTry > (PBYTE)pLo;) {495MEMORY_BASIC_INFORMATION mbi;496497DETOUR_TRACE((" Try %p\n", pbTry));498if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 &&499pbTry <= (PBYTE)(ULONG_PTR)0x80000000) {500// Skip region reserved for system DLLs.501pbTry = (PBYTE)(ULONG_PTR)(0x70000000 - DETOUR_REGION_SIZE);502}503if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {504break;505}506507DETOUR_TRACE((" Try %p => %p..%p %6x\n",508pbTry,509mbi.BaseAddress,510(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,511mbi.State));512513if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {514s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry,515DETOUR_REGION_SIZE,516MEM_COMMIT|MEM_RESERVE,517PAGE_EXECUTE_READWRITE);518if (s_pRegion != NULL) {519alloced_region:520s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;521s_pRegion->pFree = NULL;522s_pRegion->pNext = s_pRegions;523s_pRegions = s_pRegion;524DETOUR_TRACE((" Allocated region %p..%p\n\n",525s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1));526527// Put everything but the first trampoline on the free list.528PBYTE pFree = NULL;529pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1;530for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) {531pTrampoline[i].pbRemain = pFree;532pFree = (PBYTE)&pTrampoline[i];533}534s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree;535goto found_region;536}537else {538DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError()));539break;540}541}542pbTry = (PBYTE)mbi.AllocationBase - DETOUR_REGION_SIZE;543}544545DETOUR_TRACE((" Looking for free region above %p:\n", pbTarget));546547for (pbTry = pbTarget; pbTry < (PBYTE)pHi;) {548MEMORY_BASIC_INFORMATION mbi;549550if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 &&551pbTry <= (PBYTE)(ULONG_PTR)0x80000000) {552// Skip region reserved for system DLLs.553pbTry = (PBYTE)(ULONG_PTR)(0x80000000 + DETOUR_REGION_SIZE);554}555if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {556break;557}558559DETOUR_TRACE((" Try %p => %p..%p %6x\n",560pbTry,561mbi.BaseAddress,562(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,563mbi.State));564565if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {566ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);567if (extra != 0) {568// WinXP64 returns free areas that aren't REGION aligned to569// 32-bit applications.570ULONG_PTR adjust = DETOUR_REGION_SIZE - extra;571mbi.RegionSize -= adjust;572((PBYTE&)mbi.BaseAddress) += adjust;573DETOUR_TRACE(("--Try %p => %p..%p %6x\n",574pbTry,575mbi.BaseAddress,576(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,577mbi.State));578pbTry = (PBYTE)mbi.BaseAddress;579}580s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry,581DETOUR_REGION_SIZE,582MEM_COMMIT|MEM_RESERVE,583PAGE_EXECUTE_READWRITE);584if (s_pRegion != NULL) {585goto alloced_region;586}587else {588DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError()));589}590}591592pbTry = (PBYTE)mbi.BaseAddress + mbi.RegionSize;593}594595DETOUR_TRACE(("Couldn't find available memory region!\n"));596return NULL;597}598599static VOID detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)600{601PDETOUR_REGION pRegion = (PDETOUR_REGION)602((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff);603604memset(pTrampoline, 0, sizeof(*pTrampoline));605pTrampoline->pbRemain = (PBYTE)pRegion->pFree;606pRegion->pFree = pTrampoline;607}608609//////////////////////////////////////////////////////////////////////////////610//611static PIMAGE_DOS_HEADER detour_find_header(PBYTE pbTarget)612{613MEMORY_BASIC_INFORMATION mbi;614615if (!VirtualQuery(pbTarget, &mbi, sizeof(mbi))) {616return NULL;617}618619PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;620__try {621if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {622return NULL;623}624625PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +626pDosHeader->e_lfanew);627if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {628return NULL;629}630if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {631return NULL;632}633return pDosHeader;634} __except(EXCEPTION_EXECUTE_HANDLER) {635return NULL;636}637}638639///////////////////////////////////////////////////////// Transaction Structs.640//641struct DetourThread642{643DetourThread * pNext;644HANDLE hThread;645};646647struct DetourOperation648{649DetourOperation * pNext;650BOOL fIsRemove;651PBYTE * ppbPointer;652PBYTE pbTarget;653PDETOUR_TRAMPOLINE pTrampoline;654ULONG dwPerm;655};656657static BOOL s_fIgnoreTooSmall = FALSE;658659static LONG s_nPendingThreadId = 0; // Thread owning pending transaction.660static LONG s_nPendingError = NO_ERROR;661static PVOID * s_ppPendingError = NULL;662static DetourThread * s_pPendingThreads = NULL;663static DetourOperation * s_pPendingOperations = NULL;664665//////////////////////////////////////////////////////////////////////////////666//667PVOID WINAPI DetourCodeFromPointer(PVOID pPointer, PVOID *ppGlobals)668{669return detour_skip_jmp((PBYTE)pPointer, ppGlobals);670}671672//////////////////////////////////////////////////////////// Transaction APIs.673//674VOID WINAPI DetourSetIgnoreTooSmall(BOOL fIgnore)675{676s_fIgnoreTooSmall = fIgnore;677}678679LONG WINAPI DetourTransactionBegin()680{681// Only one transaction is allowed at a time.682if (s_nPendingThreadId != 0) {683return ERROR_INVALID_OPERATION;684}685// Make sure only one thread can start a transaction.686if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) {687return ERROR_INVALID_OPERATION;688}689690s_fIgnoreTooSmall = FALSE;691s_pPendingOperations = NULL;692s_pPendingThreads = NULL;693s_nPendingError = NO_ERROR;694s_ppPendingError = NULL;695696// Make sure the trampoline pages are writable.697detour_writable_trampoline_regions();698699return NO_ERROR;700}701702LONG WINAPI DetourTransactionAbort()703{704if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {705return ERROR_INVALID_OPERATION;706}707708// Restore all of the page permissions.709for (DetourOperation *o = s_pPendingOperations; o != NULL;) {710// We don't care if this fails, because the code is still accessible.711DWORD dwOld;712VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget,713o->dwPerm, &dwOld);714715if (!o->fIsRemove) {716if (o->pTrampoline) {717detour_free_trampoline(o->pTrampoline);718o->pTrampoline = NULL;719}720}721722DetourOperation *n = o->pNext;723delete o;724o = n;725}726s_pPendingOperations = NULL;727728// Make sure the trampoline pages are no longer writable.729detour_runnable_trampoline_regions();730731// Resume any suspended threads.732for (DetourThread *t = s_pPendingThreads; t != NULL;) {733// There is nothing we can do if this fails.734ResumeThread(t->hThread);735736DetourThread *n = t->pNext;737delete t;738t = n;739}740s_pPendingThreads = NULL;741s_nPendingThreadId = 0;742743return NO_ERROR;744}745746LONG WINAPI DetourTransactionCommit()747{748return DetourTransactionCommitEx(NULL);749}750751LONG WINAPI DetourTransactionCommitEx(PVOID **pppFailedPointer)752{753if (pppFailedPointer != NULL) {754// Used to get the last error.755*pppFailedPointer = s_ppPendingError;756}757if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {758return ERROR_INVALID_OPERATION;759}760761// If any of the pending operations failed, then we abort the whole transaction.762if (s_nPendingError != NO_ERROR) {763DETOUR_BREAK();764DetourTransactionAbort();765return s_nPendingError;766}767768// Common variables.769DetourOperation *o;770DetourThread *t;771772// Insert or remove each of the detours.773for (o = s_pPendingOperations; o != NULL; o = o->pNext) {774if (o->fIsRemove) {775PBYTE pbSrc = o->pTrampoline->rbCode;776LONG cbCopy = 0;777for (; cbCopy < o->pTrampoline->cbTarget;) {778LONG lExtra = 0;779pbSrc = (PBYTE)DetourCopyInstructionEx(o->pbTarget + cbCopy,780pbSrc, NULL, &lExtra);781if (lExtra != 0) {782break; // Abort if offset doesn't fit.783}784cbCopy = (LONG)(pbSrc - o->pTrampoline->rbCode);785}786if (cbCopy != o->pTrampoline->cbTarget) { // Count came out different!787// This is a drastic error as the backward copy should never fail.788s_nPendingError = ERROR_INVALID_DATA;789s_ppPendingError = (PVOID*)o->ppbPointer;790DETOUR_BREAK();791}792#ifdef DETOURS_IA64793#error Feature not supported in this release.794#else // DETOURS_IA64795*o->ppbPointer = o->pbTarget;796#endif797}798else {799DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbTarget=%d\n",800o->pTrampoline,801o->pTrampoline->pbRemain,802o->pTrampoline->pbDetour,803o->pTrampoline->cbTarget));804805DETOUR_TRACE(("detours: pbTarget=%p: "806"%02x %02x %02x %02x "807"%02x %02x %02x %02x "808"%02x %02x %02x %02x [before]\n",809o->pbTarget,810o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],811o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],812o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));813814#ifdef DETOURS_IA64815#error Feature not supported in this release.816817818#endif // DETOURS_IA64819820#ifdef DETOURS_X64821#error Feature not supported in this release.822823824825#endif // DETOURS_X64826827#ifdef DETOURS_X86828PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour);829pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);830*o->ppbPointer = o->pTrampoline->rbCode;831#endif // DETOURS_X86832833DETOUR_TRACE(("detours: pbTarget=%p: "834"%02x %02x %02x %02x "835"%02x %02x %02x %02x "836"%02x %02x %02x %02x [after]\n",837o->pbTarget,838o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],839o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],840o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));841842DETOUR_TRACE(("detours: pbTramp =%p: "843"%02x %02x %02x %02x "844"%02x %02x %02x %02x "845"%02x %02x %02x %02x\n",846o->pTrampoline,847o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1],848o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3],849o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5],850o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7],851o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9],852o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11]));853854#ifdef DETOURS_IA64855#error Feature not supported in this release.856857858859860861862863864865866867868869870871872873874875876877878879880881882883884#endif // DETOURS_IA64885}886}887888// Update any suspended threads.889for (t = s_pPendingThreads; t != NULL; t = t->pNext) {890CONTEXT cxt;891cxt.ContextFlags = CONTEXT_CONTROL;892893#undef DETOURS_EIP894#undef DETOURS_EIP_TYPE895896#ifdef DETOURS_X86897#define DETOURS_EIP Eip898#define DETOURS_EIP_TYPE DWORD899#endif // DETOURS_X86900901#ifdef DETOURS_X64902#error Feature not supported in this release.903904#endif // DETOURS_X64905906#ifdef DETOURS_IA64907#error Feature not supported in this release.908909#endif // DETOURS_IA64910911if (GetThreadContext(t->hThread, &cxt)) {912for (DetourOperation *o = s_pPendingOperations; o != NULL; o = o->pNext) {913if (o->fIsRemove) {914if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline &&915cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline + sizeof(o->pTrampoline)) {916917cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline;918cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget;919920SetThreadContext(t->hThread, &cxt);921}922}923else {924if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget &&925cxt.DETOURS_EIP < ((DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget +926o->pTrampoline->cbTarget)) {927928cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget;929cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline;930931SetThreadContext(t->hThread, &cxt);932}933}934}935}936#undef DETOURS_EIP937}938939// Restore all of the page permissions and flush the icache.940HANDLE hProcess = GetCurrentProcess();941for (o = s_pPendingOperations; o != NULL;) {942// We don't care if this fails, because the code is still accessible.943DWORD dwOld;944VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget, o->dwPerm, &dwOld);945FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbTarget);946947if (o->fIsRemove && o->pTrampoline) {948detour_free_trampoline(o->pTrampoline);949o->pTrampoline = NULL;950}951952DetourOperation *n = o->pNext;953delete o;954o = n;955}956s_pPendingOperations = NULL;957958// Make sure the trampoline pages are no longer writable.959detour_runnable_trampoline_regions();960961// Resume any suspended threads.962for (t = s_pPendingThreads; t != NULL;) {963// There is nothing we can do if this fails.964ResumeThread(t->hThread);965966DetourThread *n = t->pNext;967delete t;968t = n;969}970s_pPendingThreads = NULL;971s_nPendingThreadId = 0;972973if (pppFailedPointer != NULL) {974*pppFailedPointer = s_ppPendingError;975}976977return s_nPendingError;978}979980LONG WINAPI DetourUpdateThread(HANDLE hThread)981{982LONG error;983984// If any of the pending operations failed, then we don't need to do this.985if (s_nPendingError != NO_ERROR) {986return s_nPendingError;987}988989// Silently (and safely) drop any attempt to suspend our own thread.990if (hThread == GetCurrentThread()) {991return NO_ERROR;992}993994DetourThread *t = new DetourThread;995if (t == NULL) {996error = ERROR_NOT_ENOUGH_MEMORY;997fail:998if (t != NULL) {999delete t;1000t = NULL;1001}1002s_nPendingError = error;1003s_ppPendingError = NULL;1004DETOUR_BREAK();1005return error;1006}10071008if (SuspendThread(hThread) == (DWORD)-1) {1009error = GetLastError();1010DETOUR_BREAK();1011goto fail;1012}10131014t->hThread = hThread;1015t->pNext = s_pPendingThreads;1016s_pPendingThreads = t;10171018return NO_ERROR;1019}10201021///////////////////////////////////////////////////////////// Transacted APIs.1022//1023LONG WINAPI DetourAttach(PVOID *ppPointer,1024PVOID pDetour)1025{1026return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL);1027}10281029LONG WINAPI DetourAttachEx(PVOID *ppPointer,1030PVOID pDetour,1031PDETOUR_TRAMPOLINE *ppRealTrampoline,1032PVOID *ppRealTarget,1033PVOID *ppRealDetour)1034{1035LONG error = NO_ERROR;10361037if (ppRealTrampoline != NULL) {1038*ppRealTrampoline = NULL;1039}1040if (ppRealTarget != NULL) {1041*ppRealTarget = NULL;1042}1043if (ppRealDetour != NULL) {1044*ppRealDetour = NULL;1045}10461047if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {1048DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId));1049return ERROR_INVALID_OPERATION;1050}10511052// If any of the pending operations failed, then we don't need to do this.1053if (s_nPendingError != NO_ERROR) {1054DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError));1055return s_nPendingError;1056}10571058if (ppPointer == NULL) {1059DETOUR_TRACE(("ppPointer is null\n"));1060return ERROR_INVALID_HANDLE;1061}1062if (*ppPointer == NULL) {1063error = ERROR_INVALID_HANDLE;1064s_nPendingError = error;1065s_ppPendingError = ppPointer;1066DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer));1067DETOUR_BREAK();1068return error;1069}10701071PBYTE pbTarget = (PBYTE)*ppPointer;1072PDETOUR_TRAMPOLINE pTrampoline = NULL;1073DetourOperation *o = NULL;10741075#ifdef DETOURS_IA641076#error Feature not supported in this release.10771078107910801081108210831084108510861087#else1088pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL);1089pDetour = DetourCodeFromPointer(pDetour, NULL);1090#endif10911092// Don't follow a jump if its destination is the target function.1093// This happens when the detour does nothing other than call the target.1094if (pDetour == (PVOID)pbTarget) {1095if (s_fIgnoreTooSmall) {1096goto stop;1097}1098else {1099DETOUR_BREAK();1100goto fail;1101}1102}11031104if (ppRealTarget != NULL) {1105*ppRealTarget = pbTarget;1106}1107if (ppRealDetour != NULL) {1108*ppRealDetour = pDetour;1109}11101111o = new DetourOperation;1112if (o == NULL) {1113error = ERROR_NOT_ENOUGH_MEMORY;1114fail:1115s_nPendingError = error;1116DETOUR_BREAK();1117stop:1118if (pTrampoline != NULL) {1119detour_free_trampoline(pTrampoline);1120pTrampoline = NULL;1121}1122if (o != NULL) {1123delete o;1124o = NULL;1125}1126s_ppPendingError = ppPointer;1127return error;1128}11291130// Mark process as having detoured code.1131#ifdef DETOURS_INTERNAL_USAGE1132#error Feature not supported in this release.11331134#else1135Detoured();1136#endif11371138pTrampoline = detour_alloc_trampoline(pbTarget);1139if (pTrampoline == NULL) {1140error = ERROR_NOT_ENOUGH_MEMORY;1141DETOUR_BREAK();1142goto fail;1143}11441145if (ppRealTrampoline != NULL) {1146*ppRealTrampoline = pTrampoline;1147}11481149DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour));11501151// Determine the number of movable target instructions.1152PBYTE pbSrc = pbTarget;1153LONG cbTarget = 0;1154while (cbTarget < SIZE_OF_JMP) {1155PBYTE pbOp = pbSrc;1156LONG lExtra = 0;11571158DETOUR_TRACE((" DetourCopyInstructionEx(%p,%p)\n",1159pTrampoline->rbCode + cbTarget, pbSrc));1160pbSrc = (PBYTE)DetourCopyInstructionEx(pTrampoline->rbCode + cbTarget,1161pbSrc, NULL, &lExtra);1162DETOUR_TRACE((" DetourCopyInstructionEx() = %p (%d bytes)\n",1163pbSrc, (int)(pbSrc - pbOp)));11641165if (lExtra != 0) {1166break; // Abort if offset doesn't fit.1167}1168cbTarget = (LONG)(pbSrc - pbTarget);11691170if (detour_does_code_end_function(pbOp)) {1171break;1172}1173}1174if (cbTarget < SIZE_OF_JMP) {1175// Too few instructions.11761177error = ERROR_INVALID_BLOCK;1178if (s_fIgnoreTooSmall) {1179goto stop;1180}1181else {1182DETOUR_BREAK();1183goto fail;1184}1185}11861187#if !defined(DETOURS_IA64)1188if (cbTarget > sizeof(pTrampoline->rbCode) - SIZE_OF_JMP) {1189// Too many instructions.1190error = ERROR_INVALID_HANDLE;1191DETOUR_BREAK();1192goto fail;1193}1194#endif11951196pTrampoline->pbRemain = pbTarget + cbTarget;1197pTrampoline->pbDetour = (PBYTE)pDetour;1198pTrampoline->cbTarget = (BYTE)cbTarget;11991200#ifdef DETOURS_IA641201#error Feature not supported in this release.1202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238#endif // DETOURS_IA6412391240#ifdef DETOURS_X641241#error Feature not supported in this release.124212431244#endif // DETOURS_X6412451246#ifdef DETOURS_X861247pbSrc = detour_gen_jmp_immediate(pTrampoline->rbCode + cbTarget, pTrampoline->pbRemain);1248pbSrc = detour_gen_brk(pbSrc,1249pTrampoline->rbCode + sizeof(pTrampoline->rbCode));1250#endif // DETOURS_X8612511252DWORD dwOld = 0;1253if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) {1254error = GetLastError();1255DETOUR_BREAK();1256goto fail;1257}12581259DETOUR_TRACE(("detours: pbTarget=%p: "1260"%02x %02x %02x %02x "1261"%02x %02x %02x %02x "1262"%02x %02x %02x %02x\n",1263pbTarget,1264pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3],1265pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7],1266pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11]));1267DETOUR_TRACE(("detours: pbTramp =%p: "1268"%02x %02x %02x %02x "1269"%02x %02x %02x %02x "1270"%02x %02x %02x %02x\n",1271pTrampoline,1272pTrampoline->rbCode[0], pTrampoline->rbCode[1],1273pTrampoline->rbCode[2], pTrampoline->rbCode[3],1274pTrampoline->rbCode[4], pTrampoline->rbCode[5],1275pTrampoline->rbCode[6], pTrampoline->rbCode[7],1276pTrampoline->rbCode[8], pTrampoline->rbCode[9],1277pTrampoline->rbCode[10], pTrampoline->rbCode[11]));12781279/////////////////////////////////////////// Mark binary as being detoured.1280//1281PIMAGE_DOS_HEADER pDosHeader = detour_find_header(pbTarget);1282if (pDosHeader != NULL && pDosHeader->e_res[0] != 'eD') {1283DWORD dwDos = 0;1284if (!VirtualProtect(pDosHeader, sizeof(*pDosHeader), PAGE_EXECUTE_READWRITE, &dwDos)) {1285error = GetLastError();1286DETOUR_BREAK();1287goto fail;1288}1289pDosHeader->e_res[0] = 'eD';1290pDosHeader->e_res[1] = 'ot';1291pDosHeader->e_res[2] = 'ru';1292pDosHeader->e_res[3] = '!s';1293}12941295o->fIsRemove = FALSE;1296o->ppbPointer = (PBYTE*)ppPointer;1297o->pTrampoline = pTrampoline;1298o->pbTarget = pbTarget;1299o->dwPerm = dwOld;1300o->pNext = s_pPendingOperations;1301s_pPendingOperations = o;13021303return NO_ERROR;1304}13051306LONG WINAPI DetourDetach(PVOID *ppPointer,1307PVOID pDetour)1308{1309LONG error = NO_ERROR;13101311if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {1312return ERROR_INVALID_OPERATION;1313}13141315// If any of the pending operations failed, then we don't need to do this.1316if (s_nPendingError != NO_ERROR) {1317return s_nPendingError;1318}13191320if (ppPointer == NULL) {1321return ERROR_INVALID_HANDLE;1322}1323if (*ppPointer == NULL) {1324error = ERROR_INVALID_HANDLE;1325s_nPendingError = error;1326s_ppPendingError = ppPointer;1327DETOUR_BREAK();1328return error;1329}13301331DetourOperation *o = new DetourOperation;1332if (o == NULL) {1333error = ERROR_NOT_ENOUGH_MEMORY;1334fail:1335s_nPendingError = error;1336DETOUR_BREAK();1337stop:1338if (o != NULL) {1339delete o;1340o = NULL;1341}1342s_ppPendingError = ppPointer;1343return error;1344}13451346PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE)*ppPointer;1347pDetour = DetourCodeFromPointer(pDetour, NULL);13481349////////////////////////////////////// Verify that Trampoline is in place.1350//1351PBYTE pbTarget = pTrampoline->pbRemain - pTrampoline->cbTarget;1352LONG cbTarget = pTrampoline->cbTarget;1353if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) {1354error = ERROR_INVALID_BLOCK;1355if (s_fIgnoreTooSmall) {1356goto stop;1357}1358else {1359DETOUR_BREAK();1360goto fail;1361}1362}13631364if (pTrampoline->pbDetour != pDetour) {1365error = ERROR_INVALID_BLOCK;1366if (s_fIgnoreTooSmall) {1367goto stop;1368}1369else {1370DETOUR_BREAK();1371goto fail;1372}1373}13741375DWORD dwOld = 0;1376if (!VirtualProtect(pbTarget, cbTarget,1377PAGE_EXECUTE_READWRITE, &dwOld)) {1378error = GetLastError();1379DETOUR_BREAK();1380goto fail;1381}13821383o->fIsRemove = TRUE;1384o->ppbPointer = (PBYTE*)ppPointer;1385o->pTrampoline = pTrampoline;1386o->pbTarget = pbTarget;1387o->dwPerm = dwOld;1388o->pNext = s_pPendingOperations;1389s_pPendingOperations = o;13901391return NO_ERROR;1392}13931394HMODULE WINAPI DetourGetDetouredMarker()1395{1396#ifdef DETOURS_INTERNAL_USAGE1397#error Feature not supported in this release.139813991400#else1401return Detoured();1402#endif1403}14041405// End of File140614071408