📄 detours.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
//
// Module: detours.lib
// File: detours.cpp
// Author: Galen Hunt
//
// Detours for binary functions. Version 1.2. (Build 35)
//
// Copyright 1995-1999, Microsoft Corporation
//
// http://research.microsoft.com/sn/detours
//
#include <ole2.h>
#include <imagehlp.h>
#include "detours.h"
//////////////////////////////////////////////////////////////////////////////
//
enum {
OP_JMP_DS = 0x25,
OP_JA = 0x77,
OP_NOP = 0x90,
OP_CALL = 0xe8,
OP_JMP = 0xe9,
OP_PREFIX = 0xff,
OP_MOV_EAX = 0xa1,
OP_SET_EAX = 0xb8,
OP_JMP_EAX = 0xe0,
OP_RET_POP = 0xc2,
OP_RET = 0xc3,
OP_BRK = 0xcc,
SIZE_OF_JMP = 5,
SIZE_OF_NOP = 1,
SIZE_OF_BRK = 1,
SIZE_OF_TRP_OPS = SIZE_OF_JMP /* + SIZE_OF_BRK */,
};
class CEnableWriteOnCodePage
{
public:
CEnableWriteOnCodePage(PBYTE pbCode, LONG cbCode = DETOUR_TRAMPOLINE_SIZE)
{
m_pbCode = pbCode;
m_cbCode = cbCode;
m_dwOldPerm = 0;
m_hProcess = GetCurrentProcess();
if (m_pbCode && m_cbCode) {
if (!FlushInstructionCache(m_hProcess, pbCode, cbCode)) {
return;
}
if (!VirtualProtect(pbCode,
cbCode,
PAGE_EXECUTE_READWRITE,
&m_dwOldPerm)) {
return;
}
}
}
~CEnableWriteOnCodePage()
{
if (m_dwOldPerm && m_pbCode && m_cbCode) {
DWORD dwTemp = 0;
if (!FlushInstructionCache(m_hProcess, m_pbCode, m_cbCode)) {
return;
}
if (!VirtualProtect(m_pbCode, m_cbCode, m_dwOldPerm, &dwTemp)) {
return;
}
}
}
BOOL SetPermission(DWORD dwPerms)
{
if (m_dwOldPerm && m_pbCode && m_cbCode) {
m_dwOldPerm = dwPerms;
return TRUE;
}
return FALSE;
}
BOOL IsValid(VOID)
{
return m_pbCode && m_cbCode && m_dwOldPerm;
}
private:
HANDLE m_hProcess;
PBYTE m_pbCode;
LONG m_cbCode;
DWORD m_dwOldPerm;
};
//////////////////////////////////////////////////////////////////////////////
//
static BOOL detour_insert_jump(PBYTE pbCode, PBYTE pbDest, LONG cbCode)
{
if (cbCode < SIZE_OF_JMP)
return FALSE;
*pbCode++ = OP_JMP;
LONG offset = (LONG)pbDest - (LONG)(pbCode + 4);
*((PDWORD&)pbCode)++ = offset;
for (cbCode -= SIZE_OF_JMP; cbCode > 0; cbCode--)
*pbCode++ = OP_BRK;
return TRUE;
}
static BOOL detour_insert_detour(PBYTE pbTarget,
PBYTE pbTrampoline,
PBYTE pbDetour)
{
PBYTE pbCont = pbTarget;
for (LONG cbTarget = 0; cbTarget < SIZE_OF_TRP_OPS;) {
BYTE bOp = *pbCont;
pbCont = DetourCopyInstruction(NULL, pbCont, NULL);
cbTarget = pbCont - pbTarget;
if (bOp == OP_JMP ||
bOp == OP_JMP_DS ||
bOp == OP_JMP_EAX ||
bOp == OP_RET_POP ||
bOp == OP_RET) {
break;
}
}
if (cbTarget < SIZE_OF_TRP_OPS) {
// Too few instructions.
return FALSE;
}
if (cbTarget > (DETOUR_TRAMPOLINE_SIZE - SIZE_OF_JMP - 1)) {
// Too many instructions.
return FALSE;
}
//////////////////////////////////////////////////////// Finalize Reroute.
//
CEnableWriteOnCodePage ewTrampoline(pbTrampoline, DETOUR_TRAMPOLINE_SIZE);
CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
if (!ewTrampoline.SetPermission(PAGE_EXECUTE_READWRITE))
return FALSE;
if (!ewTarget.IsValid())
return FALSE;
PBYTE pbSrc = pbTarget;
PBYTE pbDst = pbTrampoline;
for (LONG cbCopy = 0; cbCopy < cbTarget;) {
pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
cbCopy = pbSrc - pbTarget;
pbDst = pbTrampoline + cbCopy;
}
if (cbCopy != cbTarget) // Count came out different!
return FALSE;
if (!detour_insert_jump(pbDst, pbTarget + cbTarget, SIZE_OF_JMP))
return FALSE;
pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1] = (BYTE)cbTarget;
if (!detour_insert_jump(pbTarget, pbDetour, cbTarget))
return FALSE;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,
PBYTE pbDetour)
{
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbDetour = DetourFindFinalCode(pbDetour);
////////////////////////////////////// Verify that Trampoline is in place.
//
LONG cbTarget = pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1];
if (cbTarget == 0 || cbTarget >= DETOUR_TRAMPOLINE_SIZE - 1) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pbTrampoline[cbTarget] != OP_JMP) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
LONG offset = *((PDWORD)&pbTrampoline[cbTarget + 1]);
PBYTE pbTarget = pbTrampoline + cbTarget + SIZE_OF_JMP + offset - cbTarget;
if (pbTarget[0] != OP_JMP) { // Missing detour.
SetLastError(ERROR_INVALID_BLOCK);
return FALSE;
}
offset = *((PDWORD)&pbTarget[1]);
PBYTE pbTargetDetour = pbTarget + SIZE_OF_JMP + offset;
if (pbTargetDetour != pbDetour) {
SetLastError(ERROR_INVALID_ACCESS);
return FALSE;
}
/////////////////////////////////////////////////////// Remove the Detour.
CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
PBYTE pbSrc = pbTrampoline;
PBYTE pbDst = pbTarget;
for (LONG cbCopy = 0; cbCopy < cbTarget; pbDst = pbTarget + cbCopy) {
pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
cbCopy = pbSrc - pbTrampoline;
}
if (cbCopy != cbTarget) { // Count came out different!
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
return TRUE;
}
PBYTE WINAPI DetourFunction(PBYTE pbTarget,
PBYTE pbDetour)
{
PBYTE pbTrampoline = new BYTE [DETOUR_TRAMPOLINE_SIZE];
if (pbTrampoline == NULL)
return NULL;
pbTarget = DetourFindFinalCode(pbTarget);
pbDetour = DetourFindFinalCode(pbDetour);
if (detour_insert_detour(pbTarget, pbTrampoline, pbDetour))
return pbTrampoline;
delete[] pbTrampoline;
return NULL;
}
BOOL WINAPI DetourFunctionWithEmptyTrampoline(PBYTE pbTrampoline,
PBYTE pbTarget,
PBYTE pbDetour)
{
return DetourFunctionWithEmptyTrampolineEx(pbTrampoline, pbTarget, pbDetour,
NULL, NULL, NULL);
}
BOOL WINAPI DetourFunctionWithEmptyTrampolineEx(PBYTE pbTrampoline,
PBYTE pbTarget,
PBYTE pbDetour,
PBYTE *ppbRealTrampoline,
PBYTE *ppbRealTarget,
PBYTE *ppbRealDetour)
{
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbTarget = DetourFindFinalCode(pbTarget);
pbDetour = DetourFindFinalCode(pbDetour);
if (ppbRealTrampoline)
*ppbRealTrampoline = pbTrampoline;
if (ppbRealTarget)
*ppbRealTarget = pbTarget;
if (ppbRealDetour)
*ppbRealDetour = pbDetour;
if (pbTrampoline == NULL || pbDetour == NULL || pbTarget == NULL)
return FALSE;
if (pbTrampoline[0] != OP_NOP ||
pbTrampoline[1] != OP_NOP) {
return FALSE;
}
return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
}
BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline,
PBYTE pbDetour)
{
return DetourFunctionWithTrampolineEx(pbTrampoline, pbDetour, NULL, NULL);
}
BOOL WINAPI DetourFunctionWithTrampolineEx(PBYTE pbTrampoline,
PBYTE pbDetour,
PBYTE *ppbRealTrampoline,
PBYTE *ppbRealTarget)
{
PBYTE pbTarget = NULL;
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbDetour = DetourFindFinalCode(pbDetour);
if (ppbRealTrampoline)
*ppbRealTrampoline = pbTrampoline;
if (ppbRealTarget)
*ppbRealTarget = NULL;
if (pbTrampoline == NULL || pbDetour == NULL)
return FALSE;
if (pbTrampoline[0] != OP_NOP ||
pbTrampoline[1] != OP_NOP ||
pbTrampoline[2] != OP_CALL ||
pbTrampoline[7] != OP_PREFIX ||
pbTrampoline[8] != OP_JMP_EAX) {
return FALSE;
}
PVOID (__fastcall * pfAddr)(VOID);
pfAddr = (PVOID (__fastcall *)(VOID))(pbTrampoline +
SIZE_OF_NOP + SIZE_OF_NOP + SIZE_OF_JMP +
*(LONG *)&pbTrampoline[3]);
pbTarget = DetourFindFinalCode((PBYTE)(*pfAddr)());
if (ppbRealTarget)
*ppbRealTarget = pbTarget;
return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////
//
typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(LPAPI_VERSION AppVersion);
typedef BOOL (NTAPI *PF_SymInitialize)(IN HANDLE hProcess,
IN LPSTR UserSearchPath,
IN BOOL fInvadeProcess);
typedef DWORD (NTAPI *PF_SymSetOptions)(IN DWORD SymOptions);
typedef DWORD (NTAPI *PF_SymGetOptions)(VOID);
typedef BOOL (NTAPI *PF_SymLoadModule)(IN HANDLE hProcess,
IN HANDLE hFile,
IN PSTR ImageName,
IN PSTR ModuleName,
IN DWORD BaseOfDll,
IN DWORD SizeOfDll);
typedef BOOL (NTAPI *PF_SymGetModuleInfo)(IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PIMAGEHLP_MODULE ModuleInfo);
typedef BOOL (NTAPI *PF_SymGetSymFromName)(IN HANDLE hProcess,
IN LPSTR Name,
OUT PIMAGEHLP_SYMBOL Symbol);
typedef BOOL (NTAPI *PF_BindImage)(IN LPSTR pszImageName,
IN LPSTR pszDllPath,
IN LPSTR pszSymbolPath);
static HANDLE s_hProcess = NULL;
static HINSTANCE s_hImageHlp = NULL;
static PF_ImagehlpApiVersionEx s_pfImagehlpApiVersionEx = NULL;
static PF_SymInitialize s_pfSymInitialize = NULL;
static PF_SymSetOptions s_pfSymSetOptions = NULL;
static PF_SymGetOptions s_pfSymGetOptions = NULL;
static PF_SymLoadModule s_pfSymLoadModule = NULL;
static PF_SymGetModuleInfo s_pfSymGetModuleInfo = NULL;
static PF_SymGetSymFromName s_pfSymGetSymFromName = NULL;
static PF_BindImage s_pfBindImage = NULL;
static BOOL LoadImageHlp(VOID)
{
if (s_hImageHlp)
return TRUE;
if (s_hProcess == NULL) {
s_hProcess = GetCurrentProcess();
s_hImageHlp = LoadLibraryA("imagehlp.dll");
if (s_hImageHlp == NULL)
return FALSE;
s_pfImagehlpApiVersionEx
= (PF_ImagehlpApiVersionEx)GetProcAddress(s_hImageHlp,
"ImagehlpApiVersionEx");
s_pfSymInitialize
= (PF_SymInitialize)GetProcAddress(s_hImageHlp, "SymInitialize");
s_pfSymSetOptions
= (PF_SymSetOptions)GetProcAddress(s_hImageHlp, "SymSetOptions");
s_pfSymGetOptions
= (PF_SymGetOptions)GetProcAddress(s_hImageHlp, "SymGetOptions");
s_pfSymLoadModule
= (PF_SymLoadModule)GetProcAddress(s_hImageHlp, "SymLoadModule");
s_pfSymGetModuleInfo
= (PF_SymGetModuleInfo)GetProcAddress(s_hImageHlp, "SymGetModuleInfo");
s_pfSymGetSymFromName
= (PF_SymGetSymFromName)GetProcAddress(s_hImageHlp, "SymGetSymFromName");
s_pfBindImage
= (PF_BindImage)GetProcAddress(s_hImageHlp, "BindImage");
API_VERSION av;
ZeroMemory(&av, sizeof(av));
av.MajorVersion = API_VERSION_NUMBER;
if (s_pfImagehlpApiVersionEx) {
(*s_pfImagehlpApiVersionEx)(&av);
}
if (s_pfImagehlpApiVersionEx == NULL || av.MajorVersion < API_VERSION_NUMBER) {
FreeLibrary(s_hImageHlp);
s_hImageHlp = NULL;
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -