Пример #1
0
	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;
	}
Пример #2
0
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;
}