BOOL CDetoursor::UndoHook() { if (FALSE == s_bIsHooked) { return FALSE; } std::map<StringT, ADRRESSE_PAIR>::const_iterator it; if (NO_ERROR != DetourTransactionBegin()) { return FALSE; } if (NO_ERROR != DetourUpdateThread(GetCurrentThread())) { DetourTransactionAbort(); return FALSE; } for (it = s_mapFunctionTable.begin(); it != s_mapFunctionTable.end(); it++) { if (NO_ERROR != DetourDetach(it->second.TrueAddr, it->second.FakeAddr)) { DetourTransactionAbort(); return FALSE; } } if (NO_ERROR != DetourTransactionCommit()) { DetourTransactionAbort(); return FALSE; } s_bIsHooked = FALSE; return TRUE; }
LONG WINAPI DetourTransactionCommitEx(PVOID **pppFailedPointer) { if (pppFailedPointer != NULL) { // Used to get the last error. *pppFailedPointer = s_ppPendingError; } if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { return ERROR_INVALID_OPERATION; } // If any of the pending operations failed, then we abort the whole transaction. if (s_nPendingError != NO_ERROR) { DETOUR_BREAK(); DetourTransactionAbort(); return s_nPendingError; } // Common variables. DetourOperation *o; DetourThread *t; // Insert or remove each of the detours. for (o = s_pPendingOperations; o != NULL; o = o->pNext) { if (o->fIsRemove) { PBYTE pbSrc = o->pTrampoline->rbCode; LONG cbCopy = 0; for (; cbCopy < o->pTrampoline->cbTarget;) { LONG lExtra = 0; pbSrc = (PBYTE)DetourCopyInstructionEx(o->pbTarget + cbCopy, pbSrc, NULL, &lExtra); if (lExtra != 0) { break; // Abort if offset doesn't fit. } cbCopy = (LONG)(pbSrc - o->pTrampoline->rbCode); } if (cbCopy != o->pTrampoline->cbTarget) { // Count came out different! // This is a drastic error as the backward copy should never fail. s_nPendingError = ERROR_INVALID_DATA; s_ppPendingError = (PVOID*)o->ppbPointer; DETOUR_BREAK(); } #ifdef DETOURS_IA64 #error Feature not supported in this release. #else // DETOURS_IA64 *o->ppbPointer = o->pbTarget; #endif } else { DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbTarget=%d\n", o->pTrampoline, o->pTrampoline->pbRemain, o->pTrampoline->pbDetour, o->pTrampoline->cbTarget)); DETOUR_TRACE(("detours: pbTarget=%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x [before]\n", o->pbTarget, o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #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 DETOUR_TRACE(("detours: pbTarget=%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x [after]\n", o->pbTarget, o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); DETOUR_TRACE(("detours: pbTramp =%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x\n", o->pTrampoline, o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1], o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3], o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5], o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7], o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9], o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11])); #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 } } // Update any suspended threads. for (t = s_pPendingThreads; t != NULL; t = t->pNext) { CONTEXT cxt; cxt.ContextFlags = CONTEXT_CONTROL; #undef DETOURS_EIP #undef DETOURS_EIP_TYPE #ifdef DETOURS_X86 #define DETOURS_EIP Eip #define DETOURS_EIP_TYPE DWORD #endif // DETOURS_X86 #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 if (GetThreadContext(t->hThread, &cxt)) { for (DetourOperation *o = s_pPendingOperations; o != NULL; o = o->pNext) { if (o->fIsRemove) { if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline && cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline + sizeof(o->pTrampoline)) { cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline; cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget; SetThreadContext(t->hThread, &cxt); } } else { if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget && cxt.DETOURS_EIP < ((DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget + o->pTrampoline->cbTarget)) { cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget; cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline; SetThreadContext(t->hThread, &cxt); } } } } #undef DETOURS_EIP } // 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); if (o->fIsRemove && o->pTrampoline) { detour_free_trampoline(o->pTrampoline); o->pTrampoline = NULL; } DetourOperation *n = o->pNext; delete o; o = n; } s_pPendingOperations = NULL; // Make sure the trampoline pages are no longer writable. detour_runnable_trampoline_regions(); // Resume any suspended threads. for (t = s_pPendingThreads; t != NULL;) { // There is nothing we can do if this fails. ResumeThread(t->hThread); DetourThread *n = t->pNext; delete t; t = n; } s_pPendingThreads = NULL; s_nPendingThreadId = 0; if (pppFailedPointer != NULL) { *pppFailedPointer = s_ppPendingError; } return s_nPendingError; }
LONG WINAPI DetourTransactionCommitEx(PVOID **pppFailedPointer) { if (pppFailedPointer != NULL) { // Used to get the last error. *pppFailedPointer = s_ppPendingError; } if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { return ERROR_INVALID_OPERATION; } // If any of the pending operations failed, then we abort the whole transaction. if (s_nPendingError != NO_ERROR) { DETOUR_BREAK(); DetourTransactionAbort(); return s_nPendingError; } // Common variables. DetourOperation *o; DetourThread *t; BOOL freed = FALSE; // Insert or remove each of the detours. for (o = s_pPendingOperations; o != NULL; o = o->pNext) { if (o->fIsRemove) { CopyMemory(o->pbTarget, o->pTrampoline->rbRestore, o->pTrampoline->cbRestore); #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 #ifdef DETOURS_X86 *o->ppbPointer = o->pbTarget; #endif // DETOURS_X86 #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #ifdef DETOURS_ARM #error Feature not supported in this release. #endif // DETOURS_ARM } else { DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n", o->pTrampoline, o->pTrampoline->pbRemain, o->pTrampoline->pbDetour, o->pTrampoline->cbRestore)); DETOUR_TRACE(("detours: pbTarget=%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x [before]\n", o->pbTarget, o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #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 #ifdef DETOURS_ARM #error Feature not supported in this release. #endif // DETOURS_ARM DETOUR_TRACE(("detours: pbTarget=%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x [after]\n", o->pbTarget, o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); DETOUR_TRACE(("detours: pbTramp =%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x\n", o->pTrampoline, o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1], o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3], o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5], o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7], o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9], o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11])); #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 } } // Update any suspended threads. for (t = s_pPendingThreads; t != NULL; t = t->pNext) { CONTEXT cxt; cxt.ContextFlags = CONTEXT_CONTROL; #undef DETOURS_EIP #undef DETOURS_EIP_TYPE #ifdef DETOURS_X86 #define DETOURS_EIP Eip #define DETOURS_EIP_TYPE DWORD #endif // DETOURS_X86 #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 #ifdef DETOURS_ARM #error Feature not supported in this release. #endif // DETOURS_ARM if (GetThreadContext(t->hThread, &cxt)) { for (DetourOperation *o = s_pPendingOperations; o != NULL; o = o->pNext) { if (o->fIsRemove) { if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline && cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline + sizeof(o->pTrampoline)) ) { cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) ((ULONG_PTR)o->pbTarget + detour_align_from_trampoline(o->pTrampoline, (BYTE)(cxt.DETOURS_EIP - (DETOURS_EIP_TYPE)(ULONG_PTR) o->pTrampoline))); SetThreadContext(t->hThread, &cxt); } } else { if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget && cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget + o->pTrampoline->cbRestore) ) { cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) ((ULONG_PTR)o->pTrampoline + detour_align_from_target(o->pTrampoline, (BYTE)(cxt.DETOURS_EIP - (DETOURS_EIP_TYPE)(ULONG_PTR) o->pbTarget))); SetThreadContext(t->hThread, &cxt); } } } } #undef DETOURS_EIP } // 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->cbRestore, o->dwPerm, &dwOld); FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore); if (o->fIsRemove && o->pTrampoline) { detour_free_trampoline(o->pTrampoline); o->pTrampoline = NULL; freed = true; } DetourOperation *n = o->pNext; delete o; o = n; } s_pPendingOperations = NULL; // Free any trampoline regions that are now unused. if (freed && !s_fRetainRegions) { detour_free_unused_trampoline_regions(); } // Make sure the trampoline pages are no longer writable. detour_runnable_trampoline_regions(); // Resume any suspended threads. for (t = s_pPendingThreads; t != NULL;) { // There is nothing we can do if this fails. ResumeThread(t->hThread); DetourThread *n = t->pNext; delete t; t = n; } s_pPendingThreads = NULL; s_nPendingThreadId = 0; if (pppFailedPointer != NULL) { *pppFailedPointer = s_ppPendingError; } return s_nPendingError; }