int TestDetourCopyInstruction(PBYTE pbSrcInstruction, PCHAR pszFunction) { PBYTE pbSrc = pbSrcInstruction; ULONG nIns = 0; if (pszFunction) { printf("%s:\n", pszFunction); } for (; nIns < 4096; nIns++) { BYTE rbDst[128]; PVOID pbDstPool = (PVOID)(rbDst + sizeof(rbDst)); LONG lExtra = 0; PVOID pbTarget = NULL; ULONG cbStep = (ULONG)((PBYTE)DetourCopyInstruction(rbDst, &pbDstPool, pbSrc, &pbTarget, &lExtra) - pbSrc); printf(" %p:", pbSrc); DumpMemoryFragment(rbDst, cbStep, 10); printf(" "); DumpMemoryFragment(rbDst, cbStep, 10); if (pbTarget) { if (pbTarget == DETOUR_INSTRUCTION_TARGET_DYNAMIC) { printf(" Dynamic\n"); } else { printf(" %p%c\n", pbTarget, (pbTarget >= s_pbBegin && pbTarget < s_pbLimit) ? ' ' : '!'); } } else { printf("\n"); } if (pbTarget && pbTarget != DETOUR_INSTRUCTION_TARGET_DYNAMIC) { if (pbTarget > pbSrc && pbTarget >= s_pbBegin && pbTarget < s_pbLimit ) { (void) new BasicBlockLink((PBYTE)pbTarget, NULL); } } if (IsTerminate(pbSrc)) { break; } pbSrc += cbStep; } return nIns; }
static VOID Decode(PBYTE pbCode, LONG nInst) { PBYTE pbSrc = pbCode; PBYTE pbEnd; PBYTE pbTarget; for (LONG n = 0; n < nInst; n++) { pbTarget = NULL; pbEnd = (PBYTE)DetourCopyInstruction(NULL, NULL, (PVOID)pbSrc, (PVOID*)&pbTarget, NULL); //Dump(pbSrc, (int)(pbEnd - pbSrc), pbTarget); pbSrc = pbEnd; if (pbTarget != NULL) { break; } } }
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR lpszCmdLine, int nCmdShow) { (void)hprev; (void)hinst; (void)lpszCmdLine; (void)nCmdShow; #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 #if defined(DETOURS_X64) || defined(DETOURS_X86) // First we check the pre-canned TestCodes from disasm.asm // PBYTE pbBegin = (PBYTE)DetourCodeFromPointer(TestCodes, NULL); printf("%p:\n", pbBegin); for (PBYTE pbTest = pbBegin;;) { if (pbTest[0] != 0xcc) { // int 3 printf("%08x ", pbTest - pbBegin); DumpMemoryFragment(pbTest, 8, 8); printf("\n"); printf("failed on last.\n"); return 1; } pbTest++; if (pbTest[0] == 0x70 || pbTest[0] == 0x71) { printf("[%p]:\n", pbTest); } BYTE rbDst[128]; PVOID pbDstPool = (PVOID)(rbDst + sizeof(rbDst)); LONG lExtra = 0; PVOID pbTarget = NULL; PBYTE pbNext = (PBYTE)DetourCopyInstruction(rbDst, &pbDstPool, pbTest, &pbTarget, &lExtra); LONG cbTest = (LONG)(pbNext - pbTest); printf("%08x ", pbTest - pbBegin); DumpMemoryFragment(pbTest, cbTest, 12); printf("[%16p] ", pbTarget); DumpMemoryFragment(rbDst, cbTest + lExtra, 11); printf("\n"); if (pbTest[cbTest] != 0xcc) { printf("failed!\n"); return 1; } pbTest += cbTest; if (pbTest[0] == 0xcc && pbTest[1] == 0xcc) { break; } } #if 0 // Then we check all of the code we can find in user32.dll // HINSTANCE hInst = LoadLibrary("user32.dll"); printf("Loaded: user32.dll: %p\n", hInst); s_pbBegin = (PBYTE)hInst; s_pbLimit = s_pbBegin + DetourGetModuleSize(hInst); PBYTE pbEntry = DetourGetEntryPoint(hInst); (VOID) new BasicBlockLink(pbEntry, "user32.dll"); DetourEnumerateExports(hInst, NULL, ExportCallback); ULONG nIns = 0; for (BasicBlockLink *pLink = BasicBlockLink::GetListHead(); pLink; pLink = pLink->Next()) { nIns += TestDetourCopyInstruction(pLink->m_pbEntry, pLink->m_pszName); if (nIns > 100000) { break; } } printf("Disassembled %d instructions.\n", nIns); #endif #endif // DETOURS_X86 || DETOURS_X64 #ifdef DETOURS_ARM #error Feature not supported in this release. #endif // DETOURS_ARM return 0; }
LONG WINAPI DetourAttachEx(PVOID *ppPointer, PVOID pDetour, PDETOUR_TRAMPOLINE *ppRealTrampoline, PVOID *ppRealTarget, PVOID *ppRealDetour) { LONG error = NO_ERROR; if (ppRealTrampoline != NULL) { *ppRealTrampoline = NULL; } if (ppRealTarget != NULL) { *ppRealTarget = NULL; } if (ppRealDetour != NULL) { *ppRealDetour = NULL; } if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId)); return ERROR_INVALID_OPERATION; } // If any of the pending operations failed, then we don't need to do this. if (s_nPendingError != NO_ERROR) { DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError)); return s_nPendingError; } if (ppPointer == NULL) { DETOUR_TRACE(("ppPointer is null\n")); return ERROR_INVALID_HANDLE; } if (*ppPointer == NULL) { error = ERROR_INVALID_HANDLE; s_nPendingError = error; s_ppPendingError = ppPointer; DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer)); DETOUR_BREAK(); return error; } PBYTE pbTarget = (PBYTE)*ppPointer; PDETOUR_TRAMPOLINE pTrampoline = NULL; DetourOperation *o = NULL; #ifdef DETOURS_IA64 #error Feature not supported in this release. #else // DETOURS_IA64 pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); pDetour = DetourCodeFromPointer(pDetour, NULL); #endif // !DETOURS_IA64 // 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) { if (s_fIgnoreTooSmall) { goto stop; } else { DETOUR_BREAK(); goto fail; } } if (ppRealTarget != NULL) { *ppRealTarget = pbTarget; } if (ppRealDetour != NULL) { *ppRealDetour = pDetour; } o = new DetourOperation; if (o == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; fail: s_nPendingError = error; DETOUR_BREAK(); stop: if (pTrampoline != NULL) { detour_free_trampoline(pTrampoline); pTrampoline = NULL; if (ppRealTrampoline != NULL) { *ppRealTrampoline = NULL; } } if (o != NULL) { delete o; o = NULL; } s_ppPendingError = ppPointer; return error; } pTrampoline = detour_alloc_trampoline(pbTarget); if (pTrampoline == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; DETOUR_BREAK(); goto fail; } if (ppRealTrampoline != NULL) { *ppRealTrampoline = pTrampoline; } DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour)); memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign)); // Determine the number of movable target instructions. PBYTE pbSrc = pbTarget; PBYTE pbTrampoline = pTrampoline->rbCode; PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode); ULONG cbTarget = 0; ULONG cbJump = SIZE_OF_JMP; ULONG nAlign = 0; #ifdef DETOURS_ARM #error Feature not supported in this release. #endif while (cbTarget < cbJump) { PBYTE pbOp = pbSrc; LONG lExtra = 0; DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n", pbTrampoline, pbSrc)); pbSrc = (PBYTE) DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra); DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n", pbSrc, (int)(pbSrc - pbOp))); pbTrampoline += (pbSrc - pbOp) + lExtra; cbTarget = (LONG)(pbSrc - pbTarget); pTrampoline->rAlign[nAlign].obTarget = cbTarget; pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode; if (detour_does_code_end_function(pbOp)) { break; } } // Consume, but don't duplicate padding if it is needed and available. while (cbTarget < cbJump) { LONG cFiller = detour_is_code_filler(pbSrc); if (cFiller == 0) { break; } pbSrc += cFiller; cbTarget = (LONG)(pbSrc - pbTarget); } #if DETOUR_DEBUG { DETOUR_TRACE((" detours: rAlign [")); LONG n = 0; for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { if (pTrampoline->rAlign[n].obTarget == 0 && pTrampoline->rAlign[n].obTrampoline == 0) { break; } DETOUR_TRACE((" %d/%d", pTrampoline->rAlign[n].obTarget, pTrampoline->rAlign[n].obTrampoline )); } DETOUR_TRACE((" ]\n")); } #endif if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) { // Too few instructions. error = ERROR_INVALID_BLOCK; if (s_fIgnoreTooSmall) { goto stop; } else { DETOUR_BREAK(); goto fail; } } if (pbTrampoline > pbPool) { __debugbreak(); } #if 0 // [GalenH] if (cbTarget < pbTrampoline - pTrampoline->rbCode) { __debugbreak(); } #endif pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode); pTrampoline->cbRestore = (BYTE)cbTarget; CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget); #if !defined(DETOURS_IA64) if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) { // Too many instructions. error = ERROR_INVALID_HANDLE; DETOUR_BREAK(); goto fail; } #endif // !DETOURS_IA64 pTrampoline->pbRemain = pbTarget + cbTarget; pTrampoline->pbDetour = (PBYTE)pDetour; #ifdef DETOURS_IA64 #error Feature not supported in this release. #endif // DETOURS_IA64 pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode; #ifdef DETOURS_X64 #error Feature not supported in this release. #endif // DETOURS_X64 #ifdef DETOURS_X86 pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain); pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); #endif // DETOURS_X86 #ifdef DETOURS_ARM #error Feature not supported in this release. #endif // DETOURS_ARM DWORD dwOld = 0; if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) { error = GetLastError(); DETOUR_BREAK(); goto fail; } DETOUR_TRACE(("detours: pbTarget=%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x\n", pbTarget, pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3], pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7], pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11])); DETOUR_TRACE(("detours: pbTramp =%p: " "%02x %02x %02x %02x " "%02x %02x %02x %02x " "%02x %02x %02x %02x\n", pTrampoline, pTrampoline->rbCode[0], pTrampoline->rbCode[1], pTrampoline->rbCode[2], pTrampoline->rbCode[3], pTrampoline->rbCode[4], pTrampoline->rbCode[5], pTrampoline->rbCode[6], pTrampoline->rbCode[7], pTrampoline->rbCode[8], pTrampoline->rbCode[9], pTrampoline->rbCode[10], pTrampoline->rbCode[11])); o->fIsRemove = FALSE; o->ppbPointer = (PBYTE*)ppPointer; o->pTrampoline = pTrampoline; o->pbTarget = pbTarget; o->dwPerm = dwOld; o->pNext = s_pPendingOperations; s_pPendingOperations = o; return NO_ERROR; }