////////////////////////////////////////////////////////////////////////////// // // Detours Disassembler (disasm.cpp of detours.lib) // // Microsoft Research Detours Package, Version 3.0 Build_302. // // Copyright (c) Microsoft Corporation. All rights reserved. // #include #include // #define DETOUR_DEBUG 1 #define DETOURS_INTERNAL #include "detours.h" #if defined(DETOURS_X86) #elif defined(DETOURS_X64) #elif defined(DETOURS_IA64) #elif defined(DETOURS_ARM) #else #error Must define one of DETOURS_X86, DETOURS_X64, DETOURS_IA64, or DETOURS_ARM #endif #undef ASSERT #define ASSERT(x) ////////////////////////////////////////////////////////////////////////////// // // Function: // DetourCopyInstruction(PVOID pDst, // PVOID *ppDstPool // 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. // ppDstPool: // Destination address for the end of the constant pool. The // constant pool works backwards toward pDst. All memory between // pDst and *ppDstPool must be available for use by this function. // ppDstPool may be NULL if pDst is NULL. // 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. // //////////////////////////////////////////////////// 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::CopyBytesJump #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 CopyBytesJump(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 DetourCopyInstruction(PVOID pDst, PVOID *ppDstPool, PVOID pSrc, PVOID *ppTarget, LONG *plExtra) { (void)ppDstPool; // x86 & x64 don't use a constant pool. 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 LONG nBytesFixed = (pEntry->nFlagBits & ADDRESS) ? (m_bAddressOverride ? 5 : 9) // For move A0-A3 : ((pEntry->nFlagBits & RAX) ? (m_bRaxOverride ? 9 : 5) // For move B8 : (m_bOperandOverride ? pEntry->nFixedSize16 : pEntry->nFixedSize)); #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 nBytesFixed = nBytes; nRelOffset = nBytes - (4 + pEntry->nTargetBack); cbTarget = 4; #endif } } CopyMemory(pbDst, pbSrc, nBytes); if (nRelOffset) { *m_ppbTarget = AdjustTarget(pbDst, pbSrc, nBytesFixed, nRelOffset, cbTarget); #ifdef DETOURS_X64 if (pEntry->nRelOffset == 0) { // This is a data target, not a code target, so we shoulnd't return it. *m_ppbTarget = NULL; } #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::CopyBytesJump(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) { (void)pEntry; PVOID pvSrcAddr = &pbSrc[1]; PVOID pvDstAddr = NULL; LONG_PTR nOldOffset = (LONG_PTR)*(CHAR*&)pvSrcAddr; LONG_PTR nNewOffset = 0; *m_ppbTarget = pbSrc + 2 + nOldOffset; if (pbSrc[0] == 0xeb) { pbDst[0] = 0xe9; pvDstAddr = &pbDst[1]; nNewOffset = nOldOffset - ((pbDst - pbSrc) + 3); *(LONG*&)pvDstAddr = (LONG)nNewOffset; *m_plExtra = 3; return pbSrc + 2; } ASSERT(pbSrc[0] >= 0x70 && pbSrc[0] <= 0x7f); pbDst[0] = 0x0f; pbDst[1] = 0x80 | (pbSrc[0] & 0xf); pvDstAddr = &pbDst[2]; nNewOffset = nOldOffset - ((pbDst - pbSrc) + 4); *(LONG*&)pvDstAddr = (LONG)nNewOffset; *m_plExtra = 4; return pbSrc + 2; } 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) - 1; } break; case 2: *(SHORT*&)pvTargetAddr = (SHORT)nNewOffset; if (nNewOffset < SHRT_MIN || nNewOffset > SHRT_MAX) { *m_plExtra = sizeof(ULONG) - 2; } break; case 4: *(LONG*&)pvTargetAddr = (LONG)nNewOffset; if (nNewOffset < LONG_MIN || nNewOffset > LONG_MAX) { *m_plExtra = sizeof(ULONG) - 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 INT32 offset = *(INT32 *)&pbSrc[2]; PBYTE *ppbTarget = (PBYTE *)(pbSrc + 6 + offset); *m_ppbTarget = *ppbTarget; #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 { 0x40, ENTRY_CopyBytesRax }, // Rax { 0x41, ENTRY_CopyBytesRax }, // Rax { 0x42, ENTRY_CopyBytesRax }, // Rax { 0x43, ENTRY_CopyBytesRax }, // Rax { 0x44, ENTRY_CopyBytesRax }, // Rax { 0x45, ENTRY_CopyBytesRax }, // Rax { 0x46, ENTRY_CopyBytesRax }, // Rax { 0x47, ENTRY_CopyBytesRax }, // Rax { 0x48, ENTRY_CopyBytesRax }, // Rax { 0x49, ENTRY_CopyBytesRax }, // Rax { 0x4A, ENTRY_CopyBytesRax }, // Rax { 0x4B, ENTRY_CopyBytesRax }, // Rax { 0x4C, ENTRY_CopyBytesRax }, // Rax { 0x4D, ENTRY_CopyBytesRax }, // Rax { 0x4E, ENTRY_CopyBytesRax }, // Rax { 0x4F, ENTRY_CopyBytesRax }, // Rax #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 // 0f80 { 0x71, ENTRY_CopyBytes2Jump }, // JNO // 0f81 { 0x72, ENTRY_CopyBytes2Jump }, // JB/JC/JNAE // 0f82 { 0x73, ENTRY_CopyBytes2Jump }, // JAE/JNB/JNC // 0f83 { 0x74, ENTRY_CopyBytes2Jump }, // JE/JZ // 0f84 { 0x75, ENTRY_CopyBytes2Jump }, // JNE/JNZ // 0f85 { 0x76, ENTRY_CopyBytes2Jump }, // JBE/JNA // 0f86 { 0x77, ENTRY_CopyBytes2Jump }, // JA/JNBE // 0f87 { 0x78, ENTRY_CopyBytes2Jump }, // JS // 0f88 { 0x79, ENTRY_CopyBytes2Jump }, // JNS // 0f89 { 0x7A, ENTRY_CopyBytes2Jump }, // JP/JPE // 0f8a { 0x7B, ENTRY_CopyBytes2Jump }, // JNP/JPO // 0f8b { 0x7C, ENTRY_CopyBytes2Jump }, // JL/JNGE // 0f8c { 0x7D, ENTRY_CopyBytes2Jump }, // JGE/JNL // 0f8d { 0x7E, ENTRY_CopyBytes2Jump }, // JLE/JNG // 0f8e { 0x7F, ENTRY_CopyBytes2Jump }, // JG/JNLE // 0f8f { 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_CopyBytes2Mod }, // NOP/r { 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 const DETOUR_IA64_BUNDLE::DETOUR_IA64_METADATA DETOUR_IA64_BUNDLE::s_rceCopyTable[33] = { { 0x00, M_UNIT, I_UNIT, I_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x01, M_UNIT, I_UNIT, I_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x02, M_UNIT, I_UNIT|STOP, I_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x03, M_UNIT, I_UNIT|STOP, I_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x04, M_UNIT, L_UNIT, X_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesMLX }, { 0x05, M_UNIT, L_UNIT, X_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesMLX }, { 0x06, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x07, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x08, M_UNIT, M_UNIT, I_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x09, M_UNIT, M_UNIT, I_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0a, M_UNIT|STOP, M_UNIT, I_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0b, M_UNIT|STOP, M_UNIT, I_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0c, M_UNIT, F_UNIT, I_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0d, M_UNIT, F_UNIT, I_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0e, M_UNIT, M_UNIT, F_UNIT, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x0f, M_UNIT, M_UNIT, F_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x10, M_UNIT, I_UNIT, B_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x11, M_UNIT, I_UNIT, B_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x12, M_UNIT, B_UNIT, B_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesMBB }, { 0x13, M_UNIT, B_UNIT, B_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesMBB }, { 0x14, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x15, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x16, B_UNIT, B_UNIT, B_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesBBB }, { 0x17, B_UNIT, B_UNIT, B_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesBBB }, { 0x18, M_UNIT, M_UNIT, B_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x19, M_UNIT, M_UNIT, B_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x1a, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x1b, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x1c, M_UNIT, F_UNIT, B_UNIT, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x1d, M_UNIT, F_UNIT, B_UNIT|STOP, &DETOUR_IA64_BUNDLE::CopyBytesMMB }, { 0x1e, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x1f, 0, 0, 0, &DETOUR_IA64_BUNDLE::CopyBytes }, { 0x00, 0, 0, 0, NULL }, }; // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. // 00 // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] BYTE DETOUR_IA64_BUNDLE::GetTemplate() const { return (data[0] & 0x1f); } BYTE DETOUR_IA64_BUNDLE::GetInst0() const { return ((data[5] & 0x3c) >> 2); } BYTE DETOUR_IA64_BUNDLE::GetInst1() const { return ((data[10] & 0x78) >> 3); } BYTE DETOUR_IA64_BUNDLE::GetInst2() const { return ((data[15] & 0xf0) >> 4); } BYTE DETOUR_IA64_BUNDLE::GetUnit0() const { return s_rceCopyTable[data[0] & 0x1f].nUnit0; } BYTE DETOUR_IA64_BUNDLE::GetUnit1() const { return s_rceCopyTable[data[0] & 0x1f].nUnit1; } BYTE DETOUR_IA64_BUNDLE::GetUnit2() const { return s_rceCopyTable[data[0] & 0x1f].nUnit2; } UINT64 DETOUR_IA64_BUNDLE::GetData0() const { return (((wide[0] & 0x000003ffffffffe0) >> 5)); } UINT64 DETOUR_IA64_BUNDLE::GetData1() const { return (((wide[0] & 0xffffc00000000000) >> 46) | ((wide[1] & 0x000000000007ffff) << 18)); } UINT64 DETOUR_IA64_BUNDLE::GetData2() const { return (((wide[1] & 0x0fffffffff800000) >> 23)); } VOID DETOUR_IA64_BUNDLE::SetInst0(BYTE nInst) { data[5] = (data[5] & ~0x3c) | ((nInst << 2) & 0x3c); } VOID DETOUR_IA64_BUNDLE::SetInst1(BYTE nInst) { data[10] = (data[10] & ~0x78) | ((nInst << 3) & 0x78); } VOID DETOUR_IA64_BUNDLE::SetInst2(BYTE nInst) { data[15] = (data[15] & ~0xf0) | ((nInst << 4) & 0xf0); } VOID DETOUR_IA64_BUNDLE::SetData0(UINT64 nData) { wide[0] = (wide[0] & ~0x000003ffffffffe0) | (( nData << 5) & 0x000003ffffffffe0); } VOID DETOUR_IA64_BUNDLE::SetData1(UINT64 nData) { wide[0] = (wide[0] & ~0xffffc00000000000) | ((nData << 46) & 0xffffc00000000000); wide[1] = (wide[1] & ~0x000000000007ffff) | ((nData >> 18) & 0x000000000007ffff); } VOID DETOUR_IA64_BUNDLE::SetData2(UINT64 nData) { wide[1] = (wide[1] & ~0x0fffffffff800000) | ((nData << 23) & 0x0fffffffff800000); } BOOL DETOUR_IA64_BUNDLE::IsBrl() const { // f.e. d.c. b.a. 9.8. 7.6. 5. 4. 3. 2. 1. 0. // c000 0070 0000 0000 0000 00 01 00 00 00 05 : brl.sptk.few // c8ff fff0 007f fff0 ffff 00 01 00 00 00 05 : brl.sptk.few // c000 0048 0000 0000 0001 00 00 00 00 00 05 : brl.sptk.many return ((wide[0] & 0x000000000000001e) == 0x0000000000000004 && // 4 or 5. (wide[1] & 0xe000000000000000) == 0xc000000000000000); // c or d. } VOID DETOUR_IA64_BUNDLE::SetBrl() { wide[0] = 0x0000000100000005; // few //wide[0] = 0x0000000180000005; // many wide[1] = 0xc000000800000000; } UINT64 DETOUR_IA64_BUNDLE::GetBrlImm() const { return ( // 0x0000000000fffff0 ((wide[1] & 0x00fffff000000000) >> 32) | // all 20 bits of imm20b. // 0x000000ffff000000 ((wide[0] & 0xffff000000000000) >> 24) | // bottom 16 bits of imm39. // 0x7fffff0000000000 ((wide[1] & 0x00000000007fffff) << 40) | // top 23 bits of imm39. // 0x8000000000000000 ((wide[1] & 0x0800000000000000) << 4) // single bit of i. ); } VOID DETOUR_IA64_BUNDLE::SetBrlImm(UINT64 imm) { wide[0] = ((wide[0] & ~0xffff000000000000) | // 0xffff000000000000 ((imm & 0x000000ffff000000) << 24) // bottom 16 bits of imm39. ); wide[1] = ((wide[1] & ~0x08fffff0007fffff) | // 0x00fffff000000000 ((imm & 0x0000000000fffff0) << 32) | // all 20 bits of imm20b. // 0x00000000007fffff ((imm & 0x7fffff0000000000) >> 40) | // top 23 bits of imm39. // 0x0800000000000000 ((imm & 0x8000000000000000) >> 4) // single bit of i. ); } UINT64 DETOUR_IA64_BUNDLE::GetBrlTarget() const { return (UINT64)this + GetBrlImm(); } VOID DETOUR_IA64_BUNDLE::SetBrl(UINT64 target) { UINT64 imm = target - (UINT64)this; SetBrl(); SetBrlImm(imm); } VOID DETOUR_IA64_BUNDLE::SetBrlTarget(UINT64 target) { UINT64 imm = target - (UINT64)this; SetBrlImm(imm); } BOOL DETOUR_IA64_BUNDLE::IsMovlGp() const { // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. // 6fff f7f0 207f ffff ffff c001 0000 0004 // 6000 0000 2000 0000 0000 0001 0000 0004 return ((wide[0] & 0x00003ffffffffffe) == 0x0000000100000004 && (wide[1] & 0xf000080fff800000) == 0x6000000020000000); } UINT64 DETOUR_IA64_BUNDLE::GetMovlGp() const { UINT64 raw = ( // 0x0000000000000070 ((wide[1] & 0x000007f000000000) >> 36) | // 0x000000000000ff80 ((wide[1] & 0x07fc000000000000) >> 43) | // 0x00000000001f0000 ((wide[1] & 0x0003e00000000000) >> 29) | // 0x0000000000200000 ((wide[1] & 0x0000100000000000) >> 23) | // 0x000000ffffc00000 ((wide[0] & 0xffffc00000000000) >> 24) | // 0x7fffff0000000000 ((wide[1] & 0x00000000007fffff) << 40) | // 0x8000000000000000 ((wide[1] & 0x0800000000000000) << 4) ); return (INT64)raw; } VOID DETOUR_IA64_BUNDLE::SetMovlGp(UINT64 gp) { UINT64 raw = (UINT64)gp; wide[0] = (0x0000000100000005 | // 0xffffc00000000000 ((raw & 0x000000ffffc00000) << 24) ); wide[1] = ( 0x6000000020000000 | // 0x0000070000000000 ((raw & 0x0000000000000070) << 36) | // 0x07fc000000000000 ((raw & 0x000000000000ff80) << 43) | // 0x0003e00000000000 ((raw & 0x00000000001f0000) << 29) | // 0x0000100000000000 ((raw & 0x0000000000200000) << 23) | // 0x00000000007fffff ((raw & 0x7fffff0000000000) >> 40) | // 0x0800000000000000 ((raw & 0x8000000000000000) >> 4) ); } BOOL DETOUR_IA64_BUNDLE::CopyBytes(const DETOUR_IA64_METADATA *pMeta, DETOUR_IA64_BUNDLE *pDst) const { (void)pMeta; pDst->wide[0] = wide[0]; pDst->wide[1] = wide[1]; return true; } BOOL DETOUR_IA64_BUNDLE::CopyBytesMMB(const DETOUR_IA64_METADATA *pMeta, DETOUR_IA64_BUNDLE *pDst) const { (void)pMeta; pDst->wide[0] = wide[0]; pDst->wide[1] = wide[1]; BYTE nInst2 = GetInst2(); if ((nInst2 == 0x0 || nInst2 == 0x1 || nInst2 == 0x2)) { return true; } return false; } BOOL DETOUR_IA64_BUNDLE::CopyBytesMBB(const DETOUR_IA64_METADATA *pMeta, DETOUR_IA64_BUNDLE *pDst) const { (void)pMeta; pDst->wide[0] = wide[0]; pDst->wide[1] = wide[1]; BYTE nInst1 = GetInst1(); BYTE nInst2 = GetInst2(); if ((nInst1 == 0x0 || nInst1 == 0x1 || nInst1 == 0x2) && (nInst2 == 0x0 || nInst2 == 0x1 || nInst2 == 0x2)) { return true; } return false; } BOOL DETOUR_IA64_BUNDLE::CopyBytesBBB(const DETOUR_IA64_METADATA *pMeta, DETOUR_IA64_BUNDLE *pDst) const { (void)pMeta; pDst->wide[0] = wide[0]; pDst->wide[1] = wide[1]; BYTE nInst0 = GetInst0(); BYTE nInst1 = GetInst1(); BYTE nInst2 = GetInst2(); if ((nInst0 == 0x0 || nInst0 == 0x1 || nInst0 == 0x2) && (nInst1 == 0x0 || nInst1 == 0x1 || nInst1 == 0x2) && (nInst2 == 0x0 || nInst2 == 0x1 || nInst2 == 0x2)) { return true; } return false; } BOOL DETOUR_IA64_BUNDLE::CopyBytesMLX(const DETOUR_IA64_METADATA *pMeta, DETOUR_IA64_BUNDLE *pDst) const { (void)pMeta; pDst->wide[0] = wide[0]; pDst->wide[1] = wide[1]; #if DETOUR_DEBUG { const char szUnitNames[17] = "?aimbflx?AIMBFLX"; BYTE nTemplate = GetTemplate(); BYTE nInst0 = GetInst0(); BYTE nInst1 = GetInst1(); BYTE nInst2 = GetInst2(); BYTE nUnit0 = GetUnit0(); BYTE nUnit1 = GetUnit1(); BYTE nUnit2 = GetUnit2(); if (nUnit1 == L_UNIT) { // MLX instruction UINT64 d2 = ( // 0x0000000000fffff0 ((wide[1] & 0x00fffff000000000) >> 32) | // 0x000000ffff000000 ((wide[0] & 0xffff000000000000) >> 24) | // 0x7fffff0000000000 ((wide[1] & 0x00000000007fffff) << 40) | // 0x8000000000000000 ((wide[1] & 0x0800000000000000) << 4) ); printf("%p: %02x %c%01x %010I64lx %c%01x %016I64lx\n", this, nTemplate, szUnitNames[nUnit0], nInst0, GetData0(), szUnitNames[nUnit2], nInst2, d2); } else { printf("%p: %02x %c%01x %010I64lx %c%01x %010I64lx %c%01x %010I64lx\n", this, nTemplate, szUnitNames[nUnit0], nInst0, GetData0(), szUnitNames[nUnit1], nInst1, GetData1(), szUnitNames[nUnit2], nInst2, GetData2()); } } #endif if (IsBrl()) { pDst->SetBrlTarget(GetBrlTarget()); return true; } BYTE nInst2 = GetInst2(); if (nInst2 == 0x06 && nInst2 == 0x0d) { return false; } return true; } BOOL DETOUR_IA64_BUNDLE::Copy(DETOUR_IA64_BUNDLE *pDst) const { const DETOUR_IA64_METADATA *pce = &s_rceCopyTable[GetTemplate()]; return (this->*pce->pfCopy)(pce, pDst); } BOOL DETOUR_IA64_BUNDLE::SetNop0() { const DETOUR_IA64_METADATA *pce = &s_rceCopyTable[GetTemplate()]; switch (pce->nUnit0 & UNIT_MASK) { case I_UNIT: case M_UNIT: case F_UNIT: SetInst0(0); SetData0(0x8000000); return true; case B_UNIT: SetInst0(2); SetData0(0); return true; } DebugBreak(); return false; } BOOL DETOUR_IA64_BUNDLE::SetNop1() { const DETOUR_IA64_METADATA *pce = &s_rceCopyTable[GetTemplate()]; switch (pce->nUnit1 & UNIT_MASK) { case I_UNIT: case M_UNIT: case F_UNIT: SetInst1(0); SetData1(0x8000000); return true; case B_UNIT: SetInst1(2); SetData1(0); return true; } DebugBreak(); return false; } BOOL DETOUR_IA64_BUNDLE::SetNop2() { const DETOUR_IA64_METADATA *pce = &s_rceCopyTable[GetTemplate()]; switch (pce->nUnit2 & UNIT_MASK) { case I_UNIT: case M_UNIT: case F_UNIT: SetInst2(0); SetData2(0x8000000); return true; case B_UNIT: SetInst2(2); SetData2(0); return true; } DebugBreak(); return false; } BOOL DETOUR_IA64_BUNDLE::SetStop() { data[0] |= 0x01; return true; } PVOID WINAPI DetourCopyInstruction(PVOID pDst, PVOID *ppDstPool, PVOID pSrc, PVOID *ppTarget, LONG *plExtra) { (void)ppDstPool; // IA64 doesn't use a constant pool. DETOUR_IA64_BUNDLE bExtra; DETOUR_IA64_BUNDLE *pbSrc = (DETOUR_IA64_BUNDLE *)pSrc; DETOUR_IA64_BUNDLE *pbDst = pDst ? (DETOUR_IA64_BUNDLE *)pDst : &bExtra; if (ppTarget != NULL) { if (pbSrc->IsBrl()) { *ppTarget = (PVOID)pbSrc->GetBrlTarget(); } else { *ppTarget = DETOUR_INSTRUCTION_TARGET_NONE; } } if (pbSrc->Copy(pbDst)) { if (plExtra != NULL) { *plExtra = 0; } } else { if (plExtra != NULL) { *plExtra = sizeof(DETOUR_IA64_BUNDLE); } } return pbSrc + 1; } #endif // DETOURS_IA64 #ifdef DETOURS_ARM #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) #define c_PCAdjust 4 // The PC value of an instruction is the PC address plus 4. #define c_PC 15 // The register number for the Program Counter #define c_LR 14 // The register number for the Link Register #define c_SP 13 // The register number for the Stack Pointer #define c_NOP 0xbf00 // A nop instruction #define c_BREAK 0xdefe // A nop instruction class CDetourDis { public: CDetourDis(); PBYTE CopyInstruction(PBYTE pDst, PBYTE *ppDstPool, PBYTE pSrc, PBYTE *ppTarget, LONG *plExtra); public: typedef BYTE (CDetourDis::* COPYFUNC)(PBYTE pbDst, PBYTE pbSrc); struct COPYENTRY { USHORT nOpcode; COPYFUNC pfCopy; }; typedef const COPYENTRY * REFCOPYENTRY; struct Branch5 { DWORD Register : 3; DWORD Imm5 : 5; DWORD Padding : 1; DWORD I : 1; DWORD OpCode : 6; }; struct Branch5Target { DWORD Padding : 1; DWORD Imm5 : 5; DWORD I : 1; DWORD Padding2 : 25; }; struct Branch8 { DWORD Imm8 : 8; DWORD Condition : 4; DWORD OpCode : 4; }; struct Branch8Target { DWORD Padding : 1; DWORD Imm8 : 8; DWORD Padding2 : 23; }; struct Branch11 { DWORD Imm11 : 11; DWORD OpCode : 5; }; struct Branch11Target { DWORD Padding : 1; DWORD Imm11 : 11; DWORD Padding2 : 20; }; struct Branch20 { DWORD Imm11 : 11; DWORD J2 : 1; DWORD IT : 1; DWORD J1 : 1; DWORD Other : 2; DWORD Imm6 : 6; DWORD Condition : 4; DWORD Sign : 1; DWORD OpCode : 5; }; struct Branch20Target { DWORD Padding : 1; DWORD Imm11 : 11; DWORD Imm6 : 6; DWORD J1 : 1; DWORD J2 : 1; DWORD Sign : 1; DWORD Padding2 : 11; }; struct Branch24 { DWORD Imm11 : 11; DWORD J2 : 1; DWORD InstructionSet : 1; DWORD J1 : 1; DWORD Link : 1; DWORD Branch : 1; DWORD Imm10 : 10; DWORD Sign : 1; DWORD OpCode : 5; }; struct Branch24Target { DWORD Padding : 1; DWORD Imm11 : 11; DWORD Imm10 : 10; DWORD I2 : 1; DWORD I1 : 1; DWORD Sign : 1; DWORD Padding2 : 7; }; struct LiteralLoad8 { DWORD Imm8 : 8; DWORD Register : 3; DWORD OpCode : 5; }; struct LiteralLoad8Target { DWORD Padding : 2; DWORD Imm8 : 8; DWORD Padding2 : 22; }; struct LiteralLoad12 { DWORD Imm12 : 12; DWORD Register : 4; DWORD OpCodeSuffix : 7; DWORD Add : 1; DWORD OpCodePrefix : 8; }; struct LiteralLoad12Target { DWORD Imm12 : 12; DWORD Padding : 20; }; struct ImmediateRegisterLoad32 { DWORD Imm12 : 12; DWORD DestinationRegister : 4; DWORD SourceRegister: 4; DWORD OpCode : 12; }; struct ImmediateRegisterLoad16 { DWORD DestinationRegister : 3; DWORD SourceRegister: 3; DWORD OpCode : 10; }; struct TableBranch { DWORD IndexRegister : 4; DWORD HalfWord : 1; DWORD OpCodeSuffix : 11; DWORD BaseRegister : 4; DWORD OpCodePrefix : 12; }; struct Shift { DWORD Imm2 : 2; DWORD Imm3 : 3; }; struct Add32 { DWORD SecondOperandRegister : 4; DWORD Type : 2; DWORD Imm2 : 2; DWORD DestinationRegister : 4; DWORD Imm3 : 3; DWORD Padding : 1; DWORD FirstOperandRegister : 4; DWORD SetFlags : 1; DWORD OpCode : 11; }; struct LogicalShiftLeft32 { DWORD SourceRegister : 4; DWORD Padding : 2; DWORD Imm2 : 2; DWORD DestinationRegister : 4; DWORD Imm3 : 3; DWORD Padding2 : 5; DWORD SetFlags : 1; DWORD OpCode : 11; }; struct StoreImmediate12 { DWORD Imm12 : 12; DWORD SourceRegister : 4; DWORD BaseRegister : 4; DWORD OpCode : 12; }; protected: BYTE PureCopy16(BYTE* pSource, BYTE* pDest); BYTE PureCopy32(BYTE* pSource, BYTE* pDest); BYTE CopyMiscellaneous16(BYTE* pSource, BYTE* pDest); BYTE CopyConditionalBranchOrOther16(BYTE* pSource, BYTE* pDest); BYTE CopyUnConditionalBranch16(BYTE* pSource, BYTE* pDest); BYTE CopyLiteralLoad16(BYTE* pSource, BYTE* pDest); BYTE CopyBranchExchangeOrDataProcessing16(BYTE* pSource, BYTE* pDest); BYTE CopyBranch24(BYTE* pSource, BYTE* pDest); BYTE CopyBranchOrMiscellaneous32(BYTE* pSource, BYTE* pDest); BYTE CopyLiteralLoad32(BYTE* pSource, BYTE* pDest); BYTE CopyLoadAndStoreSingle(BYTE* pSource, BYTE* pDest); BYTE CopyLoadAndStoreMultipleAndSRS(BYTE* pSource, BYTE* pDest); BYTE CopyTableBranch(BYTE* pSource, BYTE* pDest); BYTE BeginCopy32(BYTE* pSource, BYTE* pDest); LONG DecodeBranch5(ULONG opcode); USHORT EncodeBranch5(ULONG originalOpCode, LONG delta); LONG DecodeBranch8(ULONG opcode); USHORT EncodeBranch8(ULONG originalOpCode, LONG delta); LONG DecodeBranch11(ULONG opcode); USHORT EncodeBranch11(ULONG originalOpCode, LONG delta); BYTE EmitBranch11(PUSHORT& pDest, LONG relativeAddress); LONG DecodeBranch20(ULONG opcode); ULONG EncodeBranch20(ULONG originalOpCode, LONG delta); LONG DecodeBranch24(ULONG opcode, BOOL& fLink); ULONG EncodeBranch24(ULONG originalOpCode, LONG delta, BOOL fLink); LONG DecodeLiteralLoad8(ULONG instruction); LONG DecodeLiteralLoad12(ULONG instruction); BYTE EmitLiteralLoad8(PUSHORT& pDest, BYTE targetRegister, PBYTE pLiteral); BYTE EmitLiteralLoad12(PUSHORT& pDest, BYTE targetRegister, PBYTE pLiteral); BYTE EmitImmediateRegisterLoad32(PUSHORT& pDest, BYTE reg); BYTE EmitImmediateRegisterLoad16(PUSHORT& pDest, BYTE reg); BYTE EmitLongLiteralLoad(PUSHORT& pDest, BYTE reg, PVOID pTarget); BYTE EmitLongBranch(PUSHORT& pDest, PVOID pTarget); USHORT CalculateExtra(BYTE sourceLength, BYTE* pDestStart, BYTE* pDestEnd); protected: ULONG GetLongInstruction(BYTE* pSource) { return (((PUSHORT)pSource)[0] << 16) | (((PUSHORT)pSource)[1]); } BYTE EmitLongInstruction(PUSHORT& pDstInst, ULONG instruction) { *pDstInst++ = instruction >> 16; *pDstInst++ = (USHORT)instruction; return sizeof(ULONG); } BYTE EmitShortInstruction(PUSHORT& pDstInst, USHORT instruction) { *pDstInst++ = instruction; return sizeof(USHORT); } PBYTE Align4(PBYTE pValue) { return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u); } PBYTE CalculateTarget(PBYTE pSource, LONG delta) { return (pSource + delta + c_PCAdjust); } LONG CalculateNewDelta(PBYTE pTarget, BYTE* pDest) { return (pTarget - (pDest + c_PCAdjust)); } BYTE EmitAdd32(PUSHORT& pDstInst, BYTE op1Reg, BYTE op2Reg, BYTE dstReg, BYTE shiftAmount) { Shift& shift = (Shift&)(shiftAmount); const BYTE shiftType = 0x00; // LSL Add32 add = { op2Reg, shiftType, shift.Imm2, dstReg, shift.Imm3, 0x0, op1Reg, 0x0, 0x758 }; return EmitLongInstruction(pDstInst, (ULONG&)add); } BYTE EmitLogicalShiftLeft32(PUSHORT& pDstInst, BYTE srcReg, BYTE dstReg, BYTE shiftAmount) { Shift& shift = (Shift&)(shiftAmount); LogicalShiftLeft32 shiftLeft = { srcReg, 0x00, shift.Imm2, dstReg, shift.Imm3, 0x1E, 0x00, 0x752 }; return EmitLongInstruction(pDstInst, (ULONG&)shiftLeft); } BYTE EmitStoreImmediate12(PUSHORT& pDstInst, BYTE srcReg, BYTE baseReg, USHORT offset) { StoreImmediate12 store = { offset, srcReg, baseReg, 0xF8C }; return EmitLongInstruction(pDstInst, (ULONG&)store); } protected: PBYTE m_pbTarget; PBYTE m_pbPool; LONG m_lExtra; BYTE m_rbScratchDst[64]; static const COPYENTRY s_rceTable[32]; }; LONG CDetourDis::DecodeBranch5(ULONG opcode) { Branch5& branch = (Branch5&)(opcode); Branch5Target target = {}; target.Imm5 = branch.Imm5; target.I = branch.I; // Return zero-extended value return (LONG&)target; } USHORT CDetourDis::EncodeBranch5(ULONG originalOpCode, LONG delta) { // Too large for a 5 bit branch (5 bit branches can be up to 7 bits due to I and the trailing 0) if (delta < 0 || delta > 0x7F) { return 0; } Branch5& branch = (Branch5&)(originalOpCode); Branch5Target& target = (Branch5Target&)(delta); branch.Imm5 = target.Imm5; branch.I = target.I; return (USHORT&)branch; } LONG CDetourDis::DecodeBranch8(ULONG opcode) { Branch8& branch = (Branch8&)(opcode); Branch8Target target = {}; target.Imm8 = branch.Imm8; // Return sign extended value return (((LONG&)target) << 23) >> 23; } USHORT CDetourDis::EncodeBranch8(ULONG originalOpCode, LONG delta) { // Too large for 8 bit branch (8 bit branches can be up to 9 bits due to the trailing 0) if (delta < (-(int)0x100) || delta > 0xFF) { return 0; } Branch8& branch = (Branch8&)(originalOpCode); Branch8Target& target = (Branch8Target&)(delta); branch.Imm8 = target.Imm8; return (USHORT&)branch; } LONG CDetourDis::DecodeBranch11(ULONG opcode) { Branch11& branch = (Branch11&)(opcode); Branch11Target target = {}; target.Imm11 = branch.Imm11; // Return sign extended value return (((LONG&)target) << 20) >> 20; } USHORT CDetourDis::EncodeBranch11(ULONG originalOpCode, LONG delta) { // Too large for an 11 bit branch (11 bit branches can be up to 12 bits due to the trailing 0) if (delta < (-(int)0x800) || delta > 0x7FF) { return 0; } Branch11& branch = (Branch11&)(originalOpCode); Branch11Target& target = (Branch11Target&)(delta); branch.Imm11 = target.Imm11; return (USHORT&)branch; } BYTE CDetourDis::EmitBranch11(PUSHORT& pDest, LONG relativeAddress) { Branch11Target& target = (Branch11Target&)(relativeAddress); Branch11 branch11 = { target.Imm11, 0x1C }; *pDest++ = (USHORT&)branch11; return sizeof(USHORT); } LONG CDetourDis::DecodeBranch20(ULONG opcode) { Branch20& branch = (Branch20&)(opcode); Branch20Target target = {}; target.Imm11 = branch.Imm11; target.Imm6 = branch.Imm6; target.Sign = branch.Sign; target.J1 = branch.J1; target.J2 = branch.J2; // Sign extend if (target.Sign) { target.Padding2 = UINT_MAX; } return (LONG&)target; } ULONG CDetourDis::EncodeBranch20(ULONG originalOpCode, LONG delta) { // Too large for 20 bit branch (20 bit branches can be up to 21 bits due to the trailing 0) if (delta < (-(int)0x100000) || delta > 0xFFFFF) { return 0; } Branch20& branch = (Branch20&)(originalOpCode); Branch20Target& target = (Branch20Target&)(delta); branch.Imm11 = target.Imm11; branch.Imm6 = target.Imm6; branch.Sign = target.Sign; branch.J1 = target.J1; branch.J2 = target.J2; return (ULONG&)branch; } LONG CDetourDis::DecodeBranch24(ULONG opcode, BOOL& fLink) { Branch24& branch = (Branch24&)(opcode); Branch24Target target = {}; target.Imm11 = branch.Imm11; target.Imm10 = branch.Imm10; target.Sign = branch.Sign; target.I1 = ~(branch.J1 ^ target.Sign); target.I2 = ~(branch.J2 ^ target.Sign); fLink = branch.Link; // Sign extend if (target.Sign) { target.Padding2 = UINT_MAX; } return (LONG&)target; } ULONG CDetourDis::EncodeBranch24(ULONG originalOpCode, LONG delta, BOOL fLink) { // Too large for 24 bit branch (24 bit branches can be up to 25 bits due to the trailing 0) if (delta < static_cast(0xFF000000) || delta > static_cast(0xFFFFFF)) { return 0; } Branch24& branch = (Branch24&)(originalOpCode); Branch24Target& target = (Branch24Target&)(delta); branch.Imm11 = target.Imm11; branch.Imm10 = target.Imm10; branch.Link = fLink; branch.Sign = target.Sign; branch.J1 = ~(target.I1 ^ branch.Sign); branch.J2 = ~(target.I2 ^ branch.Sign); return (ULONG&)branch; } LONG CDetourDis::DecodeLiteralLoad8(ULONG instruction) { LiteralLoad8& load = (LiteralLoad8&)(instruction); LiteralLoad8Target target = {}; target.Imm8 = load.Imm8; return (LONG&)target; } BYTE CDetourDis::EmitLiteralLoad8(PUSHORT& pDest, BYTE targetRegister, PBYTE pLiteral) { // Note: We add 2 (which gets rounded down) because literals must be 32-bit // aligned, but the ldr can be 16-bit aligned. LONG newDelta = CalculateNewDelta((PBYTE)pLiteral + 2, (PBYTE)pDest); LONG relative = ((newDelta > 0 ? newDelta : -newDelta) & 0x3FF); LiteralLoad8Target& target = (LiteralLoad8Target&)(relative); LiteralLoad8 load = { target.Imm8, targetRegister, 0x9 }; return EmitShortInstruction(pDest, (USHORT&)load); } LONG CDetourDis::DecodeLiteralLoad12(ULONG instruction) { LiteralLoad12& load = (LiteralLoad12&)(instruction); LiteralLoad12Target target = {}; target.Imm12 = load.Imm12; return (LONG&)target; } BYTE CDetourDis::EmitLiteralLoad12(PUSHORT& pDest, BYTE targetRegister, PBYTE pLiteral) { // Note: We add 2 (which gets rounded down) because literals must be 32-bit // aligned, but the ldr can be 16-bit aligned. LONG newDelta = CalculateNewDelta((PBYTE)pLiteral + 2, (PBYTE)pDest); LONG relative = ((newDelta > 0 ? newDelta : -newDelta) & 0xFFF); LiteralLoad12Target& target = (LiteralLoad12Target&)(relative); target.Imm12 -= target.Imm12 & 3; LiteralLoad12 load = { target.Imm12, targetRegister, 0x5F, (newDelta > 0), 0xF8 }; return EmitLongInstruction(pDest, (ULONG&)load); } BYTE CDetourDis::EmitImmediateRegisterLoad32(PUSHORT& pDest, BYTE reg) { ImmediateRegisterLoad32 load = { 0, reg, reg, 0xF8D }; return EmitLongInstruction(pDest, (ULONG&)load); } BYTE CDetourDis::EmitImmediateRegisterLoad16(PUSHORT& pDest, BYTE reg) { ImmediateRegisterLoad16 load = { reg, reg, 0x680 >> 2 }; return EmitShortInstruction(pDest, (USHORT&)load); } BYTE CDetourDis::EmitLongLiteralLoad(PUSHORT& pDest, BYTE targetRegister, PVOID pTarget) { *--((PULONG&)m_pbPool) = ((ULONG)pTarget); // ldr rn, target. BYTE size = EmitLiteralLoad12(pDest, targetRegister, m_pbPool); // This only makes sense if targetRegister != PC; // otherwise, we would have branched with the previous instruction anyway if (targetRegister != c_PC) { // ldr rn, [rn] if (targetRegister <= 7) { size += EmitImmediateRegisterLoad16(pDest, targetRegister); } else { size += EmitImmediateRegisterLoad32(pDest, targetRegister); } } return size; } BYTE CDetourDis::EmitLongBranch(PUSHORT& pDest, PVOID pTarget) { // Emit a long literal load into PC BYTE size = EmitLongLiteralLoad(pDest, c_PC, pTarget); return size; } BYTE CDetourDis::PureCopy16(BYTE* pSource, BYTE* pDest) { *(USHORT *)pDest = *(USHORT *)pSource; return sizeof(USHORT); } BYTE CDetourDis::PureCopy32(BYTE* pSource, BYTE* pDest) { *(ULONG *)pDest = *(ULONG*)pSource; return sizeof(DWORD); } USHORT CDetourDis::CalculateExtra(BYTE sourceLength, BYTE* pDestStart, BYTE* pDestEnd) { ULONG destinationLength = pDestEnd - pDestStart; return static_cast((destinationLength > sourceLength) ? (destinationLength - sourceLength) : 0); } BYTE CDetourDis::CopyMiscellaneous16(BYTE* pSource, BYTE* pDest) { USHORT instruction = *(PUSHORT)(pSource); // Compare and branch imm5 (CBZ, CBNZ) if ((instruction & 0x100) && !(instruction & 0x400)) { // (1011x0x1xxxxxxxx) LONG oldDelta = DecodeBranch5(instruction); PBYTE pTarget = CalculateTarget(pSource, oldDelta); m_pbTarget = pTarget; LONG newDelta = CalculateNewDelta(pTarget, pDest); instruction = EncodeBranch5(instruction, newDelta); if (instruction) { // Copy the 16 bit instruction over *(PUSHORT)(pDest) = instruction; return sizeof(USHORT); // The source instruction was 16 bits } // If that fails, re-encode with 'conditional branch' logic, without using the condition flags // For example, cbz r2,+0x56 (0x90432) becomes: // // 001df73a b92a cbnz r2,001df748 // 001df73c e002 b 001df744 // 001df73e bf00 nop // 001df740 0432 dc.h 0432 // 001df742 0009 dc.h 0009 // 001df744 f85ff008 ldr pc,=0x90432 // // Store where we will be writing our conditional branch, and move past it so we can emit a long branch PUSHORT pDstInst = (PUSHORT)(pDest); PUSHORT pConditionalBranchInstruction = pDstInst++; // Emit the long branch instruction BYTE longBranchSize = EmitLongBranch(pDstInst, pTarget); // Invert the CBZ/CBNZ instruction to move past our 'long branch' if the inverse comparison succeeds // Write the CBZ/CBNZ instruction *before* the long branch we emitted above // This had to be done out of order, since the size of a long branch can vary due to alignment restrictions instruction = EncodeBranch5(*(PUSHORT)(pSource), longBranchSize - c_PCAdjust + sizeof(USHORT)); Branch5& branch = (Branch5&)(instruction); branch.OpCode = (branch.OpCode & 0x02) ? 0x2C : 0x2E; // Invert the CBZ/CBNZ comparison *pConditionalBranchInstruction = instruction; // Compute the extra space needed for the branch sequence m_lExtra = CalculateExtra(sizeof(USHORT), pDest, (BYTE*)(pDstInst)); return sizeof(USHORT); // The source instruction was 16 bits } // If-Then Instruction (IT) if ((instruction >> 8 == 0xBF) && (instruction & 0xF)) { //(10111111xxxx(mask != 0b0000)) // ToDo: Implement IT handler ASSERT(false); return sizeof(USHORT); } // ADD/SUB, SXTH, SXTB, UXTH, UXTB, CBZ, CBNZ, PUSH, POP, REV, REV15, REVSH, NOP, YIELD, WFE, WFI, SEV, etc. return PureCopy16(pSource, pDest); } BYTE CDetourDis::CopyConditionalBranchOrOther16(BYTE* pSource, BYTE* pDest) { USHORT instruction = *(PUSHORT)(pSource); // Could be a conditional branch, an Undefined instruction or a Service System Call // Only the former needs special logic if ((instruction & 0xE00) != 0xE00) { // 1101(!=111x)xxxxxxxx LONG oldDelta = DecodeBranch8(instruction); PBYTE pTarget = CalculateTarget(pSource, oldDelta); m_pbTarget = pTarget; LONG newDelta = CalculateNewDelta(pTarget, pDest); instruction = EncodeBranch8(instruction, newDelta); if (instruction) { // Copy the 16 bit instruction over *(PUSHORT)(pDest) = instruction; return sizeof(USHORT); // The source instruction was 16 bits } // If that fails, re-encode as a sequence of branches // For example, bne +0x6E (0x90452) becomes: // // 001df758 d100 bne 001df75c // 001df75a e005 b 001df768 // 001df75c e002 b 001df764 // 001df75e bf00 nop // 001df760 0452 dc.h 0452 // 001df762 0009 dc.h 0009 // 001df764 f85ff008 ldr pc,=0x90452 // // First, reuse the existing conditional branch to, if successful, branch down to a 'long branch' that we will emit below USHORT newInstruction = EncodeBranch8(*(PUSHORT)(pSource), 0); // Due to the size of c_PCAdjust a zero-length branch moves 4 bytes forward, past the following unconditional branch ASSERT(newInstruction); PUSHORT pDstInst = (PUSHORT)(pDest); *pDstInst++ = newInstruction; // Next, prepare to insert an unconditional branch that will be hit if the condition above is not met. This branch will branch over the following 'long branch' // We can't actually encode this branch yet though, because 'long branches' can vary in size PUSHORT pUnconditionalBranchInstruction = pDstInst++; // Then, emit a 'long branch' that will be hit if the original condition is met BYTE longBranchSize = EmitLongBranch(pDstInst, pTarget); // Finally, encode and emit the unconditional branch that will be used to branch past the 'long branch' if the initial condition was not met Branch11 branch11 = { 0x00, 0x1C }; newInstruction = EncodeBranch11(*(DWORD*)(&branch11), longBranchSize - c_PCAdjust + sizeof(USHORT)); ASSERT(newInstruction); *pUnconditionalBranchInstruction = newInstruction; // Compute the extra space needed for the branch sequence m_lExtra = CalculateExtra(sizeof(USHORT), pDest, (BYTE*)(pDstInst)); return sizeof(USHORT); // The source instruction was 16 bits } return PureCopy16(pSource, pDest); } BYTE CDetourDis::CopyUnConditionalBranch16(BYTE* pSource, BYTE* pDest) { ULONG instruction = *(PUSHORT)(pSource); LONG oldDelta = DecodeBranch11(instruction); PBYTE pTarget = CalculateTarget(pSource, oldDelta); m_pbTarget = pTarget; LONG newDelta = CalculateNewDelta(pTarget, pDest); instruction = EncodeBranch11(instruction, newDelta); if (instruction) { // Copy the 16 bit instruction over *(PUSHORT)(pDest) = (USHORT)instruction; return sizeof(USHORT); // The source instruction was 16 bits } // If that fails, re-encode as 32-bit PUSHORT pDstInst = (PUSHORT)(pDest); instruction = EncodeBranch24(0xf0009000, newDelta, FALSE); if (instruction) { // Copy both bytes of the instruction EmitLongInstruction(pDstInst, instruction); m_lExtra = sizeof(DWORD) - sizeof(USHORT); // The destination instruction was 32 bits return sizeof(USHORT); // The source instruction was 16 bits } // If that fails, emit as a 'long branch' if (!instruction) { // For example, b +0x7FE (00090be6) becomes: // 003f6d02 e001 b 003f6d08 // 003f6d04 0be6 dc.h 0be6 // 003f6d06 0009 dc.h 0009 // 003f6d08 f85ff008 ldr pc,=0x90BE6 EmitLongBranch(pDstInst, pTarget); // Compute the extra space needed for the branch sequence m_lExtra = CalculateExtra(sizeof(USHORT), pDest, (BYTE*)(pDstInst)); return sizeof(USHORT); // The source instruction was 16 bits } return sizeof(USHORT); // The source instruction was 16 bits } BYTE CDetourDis::CopyLiteralLoad16(BYTE* pSource, BYTE* pDest) { PBYTE pStart = pDest; USHORT instruction = *(PUSHORT)(pSource); LONG oldDelta = DecodeLiteralLoad8(instruction); PBYTE pTarget = CalculateTarget(Align4(pSource), oldDelta); // Re-encode as a 'long literal load' // For example, ldr r0, [PC + 1E0] (0x905B4) becomes: // // 001df72c f85f0008 ldr r0,=0x905B4 // 001df730 f8d00000 ldr.w r0,[r0] LiteralLoad8& load8 = (LiteralLoad8&)(instruction); EmitLongLiteralLoad((PUSHORT&)pDest, load8.Register, pTarget); m_lExtra = pDest - pStart - sizeof(USHORT); return sizeof(USHORT); // The source instruction was 16 bits } BYTE CDetourDis::CopyBranchExchangeOrDataProcessing16(BYTE* pSource, BYTE* pDest) { ULONG instruction = *(PUSHORT)(pSource); // BX if ((instruction & 0xff80) == 0x4700) { // The target is stored in a register m_pbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_DYNAMIC; } // AND, LSR, TST, ADD, CMP, MOV return PureCopy16(pSource, pDest); } const CDetourDis::COPYENTRY CDetourDis::s_rceTable[32] = { // Shift by immediate, move register // ToDo: Not handling moves from PC /* 0b00000 */ { 0x00, &CDetourDis::PureCopy16 }, /* 0b00001 */ { 0x01, &CDetourDis::PureCopy16 }, /* 0b00010 */ { 0x02, &CDetourDis::PureCopy16 }, // Add/subtract register // Add/subtract immediate /* 0b00011 */ { 0x03, &CDetourDis::PureCopy16}, // Add/subtract/compare/move immediate /* 0b00100 */ { 0x04, &CDetourDis::PureCopy16 }, /* 0b00101 */ { 0x05, &CDetourDis::PureCopy16 }, /* 0b00110 */ { 0x06, &CDetourDis::PureCopy16 }, /* 0b00111 */ { 0x07, &CDetourDis::PureCopy16 }, // Data-processing register // Special data processing // Branch/exchange instruction set /* 0b01000 */ { 0x08, &CDetourDis::CopyBranchExchangeOrDataProcessing16 }, // Load from literal pool /* 0b01001 */ { 0x09, &CDetourDis::CopyLiteralLoad16 }, // Load/store register offset /* 0b01010 */ { 0x0a, &CDetourDis::PureCopy16 }, /* 0b01011 */ { 0x0b, &CDetourDis::PureCopy16 }, // Load/store word/byte immediate offset. /* 0b01100 */ { 0x0c, &CDetourDis::PureCopy16 }, /* 0b01101 */ { 0x0d, &CDetourDis::PureCopy16 }, /* 0b01110 */ { 0x0e, &CDetourDis::PureCopy16 }, /* 0b01111 */ { 0x0f, &CDetourDis::PureCopy16 }, // Load/store halfword immediate offset. /* 0b10000 */ { 0x10, &CDetourDis::PureCopy16 }, /* 0b10001 */ { 0x11, &CDetourDis::PureCopy16 }, // Load from or store to stack /* 0b10010 */ { 0x12, &CDetourDis::PureCopy16 }, /* 0b10011 */ { 0x13, &CDetourDis::PureCopy16 }, // Add to SP or PC /* 0b10100 */ { 0x14, &CDetourDis::PureCopy16 }, // ToDo: Is ADR (T1) blitt-able? // It adds a value to PC and stores the result in a register. // Does this count as a 'target' for detours? /* 0b10101 */ { 0x15, &CDetourDis::PureCopy16 }, // Miscellaneous /* 0b10110 */ { 0x16, &CDetourDis::CopyMiscellaneous16 }, /* 0b10111 */ { 0x17, &CDetourDis::CopyMiscellaneous16 }, // Load/store multiple /* 0b11000 */ { 0x18, &CDetourDis::PureCopy16 }, /* 0b11001 */ { 0x19, &CDetourDis::PureCopy16 }, // ToDo: Are we sure these are all safe? // LDMIA, for example, can include an 'embedded' branch. // Does this count as a 'target' for detours? // Conditional branch /* 0b11010 */ { 0x1a, &CDetourDis::CopyConditionalBranchOrOther16 }, // Conditional branch // Undefined instruction // Service (system) call /* 0b11011 */ { 0x1b, &CDetourDis::CopyConditionalBranchOrOther16 }, // Unconditional branch /* 0b11100 */ { 0x1c, &CDetourDis::CopyUnConditionalBranch16 }, // 32-bit instruction /* 0b11101 */ { 0x1d, &CDetourDis::BeginCopy32 }, /* 0b11110 */ { 0x1e, &CDetourDis::BeginCopy32 }, /* 0b11111 */ { 0x1f, &CDetourDis::BeginCopy32 } }; BYTE CDetourDis::CopyBranch24(BYTE* pSource, BYTE* pDest) { ULONG instruction = GetLongInstruction(pSource); BOOL fLink; LONG oldDelta = DecodeBranch24(instruction, fLink); PBYTE pTarget = CalculateTarget(pSource, oldDelta); m_pbTarget = pTarget; // Re-encode as 32-bit PUSHORT pDstInst = (PUSHORT)(pDest); LONG newDelta = CalculateNewDelta(pTarget, pDest); instruction = EncodeBranch24(instruction, newDelta, fLink); if (instruction) { // Copy both bytes of the instruction EmitLongInstruction(pDstInst, instruction); return sizeof(DWORD); } // If that fails, re-encode as a 'long branch' EmitLongBranch(pDstInst, pTarget); // Compute the extra space needed for the instruction m_lExtra = CalculateExtra(sizeof(DWORD), pDest, (BYTE*)(pDstInst)); return sizeof(DWORD); // The source instruction was 32 bits } BYTE CDetourDis::CopyBranchOrMiscellaneous32(BYTE* pSource, BYTE* pDest) { ULONG instruction = GetLongInstruction(pSource); if ((instruction & 0xf800d000) == 0xf0008000) { // B.W