bool CreateTrampolineFunction(CREATE_TREMPOLINE_T& ct) { assert(("CreateTrampolineFunction", ct.pTarget != NULL)); #if defined _M_X64 CALL_ABS call = { 0x15FF, 0x00000000 }; JMP_ABS jmp = { 0x25FF, 0x00000000 }; JCC_ABS jcc = { 0x70, 0x02, 0xEB, 0x06, 0x25FF, 0x00000000 }; #elif defined _M_IX86 CALL_REL call = { 0xE8, 0x00000000 }; JMP_REL jmp = { 0xE9, 0x00000000 }; JCC_REL jcc = { 0x800F, 0x00000000 }; #endif size_t oldPos = 0; size_t newPos = 0; uintptr_t jmpDest = 0; // 関数内ジャンプの飛び先アドレス(分岐中判定に使用) bool finished = false; // 関数終了フラグ while (!finished) { uint8_t *pInst = reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos; hde_t hs; hde_disasm(pInst, &hs); if ((hs.flags & F_ERROR) == F_ERROR) { return false; } void* pCopySrc = pInst; size_t copySize = hs.len; if (pInst - reinterpret_cast<uint8_t*>(ct.pTarget) >= sizeof(JMP_REL)) { // ターゲット関数へのジャンプを書き込み、関数を終了 AppendTempAddress(reinterpret_cast<uintptr_t>(pInst), newPos, jmp, ct); pCopySrc = &jmp; copySize = sizeof(jmp); finished = true; } #if defined _M_X64 // RIP相対アドレッシングを使用している命令 (ModR/M = 00???101B) else if ((hs.modrm & 0xC7) == 0x05) { // RIP相対アドレスのみ書き換え AppendRipRelativeAddress(pInst, newPos, hs, ct); // JMP (FF /4)なら関数を終了 if (hs.opcode == 0xFF && hs.modrm_reg == 4) { finished = true; } } #endif // 相対直接CALL else if (hs.opcode == 0xE8) { AppendTempAddress(GetRelativeBranchDestination(pInst, hs, false), newPos, call, ct); pCopySrc = &call; copySize = sizeof(call); } // 相対直接JMP (EB or E9) else if ((hs.opcode & 0xFD) == 0xE9) { uintptr_t dest = GetRelativeBranchDestination(pInst, hs, hs.opcode == 0xEB); // 関数内へのジャンプはそのままコピー(ジャンプ中は命令長が変わるような操作は不可) if (IsInternalJump(ct.pTarget, dest)) { jmpDest = std::max<uintptr_t>(jmpDest, dest); } else { AppendTempAddress(dest, newPos, jmp, ct); pCopySrc = &jmp; copySize = sizeof(jmp); // 分岐中でなければ関数を終了 finished = (reinterpret_cast<uintptr_t>(pInst) >= jmpDest); } } // 相対直接Jcc else if ((hs.opcode & 0xF0) == 0x70 || (hs.opcode & 0xFC) == 0xE0 || (hs.opcode2 & 0xF0) == 0x80) { uintptr_t dest = GetRelativeBranchDestination(pInst, hs, (hs.opcode & 0xF0) == 0x70 || (hs.opcode & 0xFC) == 0xE0); // 関数内へのジャンプはそのままコピー(分岐中は命令長が変わるような操作は不可) if (IsInternalJump(ct.pTarget, dest)) { jmpDest = std::max<uintptr_t>(jmpDest, dest); } else if ((hs.opcode & 0xFC) == 0xE0) // 関数外へのJCXZ, JECXZ には対応しない { return false; } else { AppendTempAddress(dest, newPos, jcc, ct); SetJccOpcode(hs, jcc); pCopySrc = &jcc; copySize = sizeof(jcc); } } // RET (C2 or C3) else if ((hs.opcode & 0xFE) == 0xC2) { // 分岐中でなければトランポリン関数を終了 finished = (reinterpret_cast<uintptr_t>(pInst) >= jmpDest); } // 分岐中は命令長が変わるような操作は不可 if (reinterpret_cast<uintptr_t>(pInst) < jmpDest && copySize != hs.len) { return false; } ct.trampoline.resize(newPos + copySize); memcpy(&ct.trampoline[ newPos ], pCopySrc, copySize); ct.oldIPs.push_back(oldPos); oldPos += hs.len; ct.newIPs.push_back(newPos); newPos += copySize; } // Is there enough place for a long jump? if (oldPos < sizeof(JMP_REL) && !IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos, sizeof(JMP_REL) - oldPos)) { // Is there enough place for a short jump? if (oldPos < sizeof(JMP_REL_SHORT) && !IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) { return false; } // Can we place the long jump above the function? if (!IsExecutableAddress(reinterpret_cast<uint8_t*>(ct.pTarget) - sizeof(JMP_REL))) { return false; } if (!IsCodePadding(reinterpret_cast<uint8_t*>(ct.pTarget) - sizeof(JMP_REL), sizeof(JMP_REL))) { return false; } ct.patchAbove = true; } return true; }
LPVOID CreateBridge(LPVOID lpFunc,LPVOID lpBackup,SIZE_T *dwBackupCodeSize,ULONG_PTR *lpTable) { LPVOID lpBridge=MemAlloc(JUMP_SIZE*6); if (lpBridge) { DWORD dwOldProtect=0; VirtualProtect(lpBridge,JUMP_SIZE*6,PAGE_EXECUTE_READWRITE,&dwOldProtect); #ifdef _AMD64_ CALL_ABS call={0x15FF,0x00000000}; JMP_ABS jmp={0x25FF,0x00000000}; JCC_ABS jcc={0x70,0x02,0xEB,0x06,0x25FF,0x00000000}; int dwTmpAddrsCount=0; #else CALL_REL call={0xE8,0x00000000}; JMP_REL jmp={0xE9,0x00000000}; JCC_REL jcc={0x800F,0x00000000}; #endif TEMP_ADDR TmpAddr[MAX_JUMPS]={0}; int dwTmpAddrCount=0; SIZE_T dwOldPos=0,dwNewPos=0; ULONG_PTR dwJmpDest=0; bool bDone=false; while (!bDone) { hdes hs; LPVOID lpInst=(LPVOID)((ULONG_PTR)lpFunc+dwOldPos); SIZE_T dwCopySize=SizeOfCode(lpInst); if ((hs.flags & F_ERROR) == F_ERROR) break; LPVOID lpCopySrc=lpInst; if ((ULONG_PTR)lpInst-(ULONG_PTR)lpFunc >= sizeof(JMP_REL)) { LPVOID lpTmpAddr=0; #ifdef _AMD64_ lpTmpAddr=&lpTable[dwTmpAddrsCount++]; if (dwTmpAddrsCount > MAX_JUMPS) break; #endif AppendTempAddress(lpInst,dwNewPos,&jmp,&TmpAddr[dwTmpAddrCount++],(void **)lpTmpAddr); if (dwTmpAddrCount > MAX_JUMPS) break; lpCopySrc=&jmp; dwCopySize=sizeof(jmp); bDone=true; } #ifdef _AMD64_ else if ((hs.modrm & 0xC7) == 0x05) // RIP-based { AppendRipRelativeAddress(lpInst,dwNewPos,&hs,&TmpAddr[dwTmpAddrCount++]); if (dwTmpAddrCount > MAX_JUMPS) break; if ((hs.opcode == 0xFF) && (hs.modrm_reg == 4)) // jmp bDone=true; } #endif else if (hs.opcode == 0xE8) // call { LPVOID lpTmpAddr=0; #ifdef _AMD64_ lpTmpAddr=&lpTable[dwTmpAddrsCount++]; if (dwTmpAddrsCount > MAX_JUMPS) break; #endif AppendTempAddress(GetRelativeBranchDestination(lpInst,&hs),dwNewPos,&call,&TmpAddr[dwTmpAddrCount++],(void **)lpTmpAddr); if (dwTmpAddrCount > MAX_JUMPS) break; lpCopySrc=&call; dwCopySize=sizeof(call); } else if ((hs.opcode & 0xFD) == 0xE9) // jmp { LPVOID lpDest=GetRelativeBranchDestination(lpInst,&hs); if (IsInternalJump(lpFunc,(ULONG_PTR)lpDest)) dwJmpDest=max(dwJmpDest,(ULONG_PTR)lpDest); else { LPVOID lpTmpAddr=0; #ifdef _AMD64_ lpTmpAddr=&lpTable[dwTmpAddrsCount++]; if (dwTmpAddrsCount > MAX_JUMPS) break; #endif AppendTempAddress(lpDest,dwNewPos,&jmp,&TmpAddr[dwTmpAddrCount++],(void **)lpTmpAddr); if (dwTmpAddrCount > MAX_JUMPS) break; lpCopySrc = &jmp; dwCopySize = sizeof(jmp); bDone=((ULONG_PTR)lpInst >= dwJmpDest); } } else if (((hs.opcode & 0xF0) == 0x70) || (hs.opcode == 0xE3) || ((hs.opcode2 & 0xF0) == 0x80)) // jcc { LPVOID lpDest=GetRelativeBranchDestination(lpInst,&hs); if (IsInternalJump(lpFunc,(ULONG_PTR)lpDest)) dwJmpDest=max(dwJmpDest,(ULONG_PTR)lpDest); else if (hs.opcode == 0xE3) // jcxz, jecxz { bDone=false; break; } else { LPVOID lpTmpAddr=0; #ifdef _AMD64_ lpTmpAddr=&lpTable[dwTmpAddrsCount++]; if (dwTmpAddrsCount > MAX_JUMPS) break; #endif AppendTempAddress(lpDest,dwNewPos,&jcc,&TmpAddr[dwTmpAddrCount++],(void **)lpTmpAddr); if (dwTmpAddrCount > MAX_JUMPS) break; SetJccOpcode(&hs,&jcc); lpCopySrc=&jcc; dwCopySize=sizeof(jcc); } } else if (((hs.opcode & 0xFE) == 0xC2) || // ret ((hs.opcode & 0xFD) == 0xE9) || // jmp rel (((hs.modrm & 0xC7) == 0x05) && ((hs.opcode == 0xFF) && (hs.modrm_reg == 4))) || // jmp rip ((hs.opcode == 0xFF) && (hs.opcode2 == 0x25))) // jmp abs bDone=((ULONG_PTR)lpInst >= dwJmpDest); if (((ULONG_PTR)lpInst < dwJmpDest) && (dwCopySize != hs.len)) { bDone=false; break; } memcpy((byte*)lpBridge+dwNewPos,lpCopySrc,dwCopySize); dwOldPos+=hs.len; dwNewPos+=dwCopySize; } if (bDone) { memcpy(lpBackup,lpFunc,dwOldPos); *dwBackupCodeSize=dwOldPos; #ifdef _AMD64_ int dwAddrTblPos=0; #endif for (int i=0; i < dwTmpAddrCount; i++) { LPVOID lpAddr; #ifdef _AMD64_ if ((ULONG_PTR)TmpAddr[i].lpAddress < 0x10000) lpAddr=&lpTable[dwAddrTblPos++]; else #endif lpAddr=TmpAddr[i].lpAddress; byte *lpTrampoline=(byte*)lpBridge; *(DWORD*)(lpTrampoline+TmpAddr[i].dwPosition)=(DWORD)lpAddr-((DWORD)lpBridge+TmpAddr[i].dwPc); } return lpBridge; } else MemFree(lpBridge); } return NULL; }