[英]Detouring a member-function via an injected DLL
原帖:
我试图从我注入的 DLL 中绕过一个成员函数。 我已经获得了我试图挂钩的函数的地址,但无法弄清楚通过 detours 库挂钩它的正确语法或方法。 我已经评论了给我错误消息的行。
我已经阅读了成员函数挂钩的 detours 示例的源代码,这就是此代码所基于的内容,但由于某种原因它不起作用。
任何帮助将不胜感激,谢谢!
#include <windows.h>
#include <detours.h>
class CDetour
{
public:
bool My_MemFn(unsigned int unk1);
static bool (CDetour::* Real_MemFn)(unsigned int);
};
bool CDetour::My_MemFn(unsigned int unk1)
{
/* do stuff here */
return (this->*Real_MemFn)(unk1);
}
typedef bool (CDetour::* MemFn_t)(unsigned int unk1);
MemFn_t CDetour::Real_MemFn= *(MemFn_t *)((void*)0x23234545);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)CDetour::Real_MemFn, *(PBYTE*)&CDetour::My_MemFn); // ERROR: C2440: 'type cast' : cannot convert from 'bool __thiscall CDetour::* )(unsigned int)' to 'PBYTE *'
DetourTransactionCommit();
break;
}
}
return TRUE;
}
解决方案:
#include <windows.h>
#include <detours.h>
typedef void (__thiscall * CClassFunction_t)(void *__this, unsigned int unk1);
CClassFunction_t Real_CClassFunction;
void __fastcall Mine_CClassFunction(void *__this, int edx, unsigned int unk1)
{
Real_CClassFunction(__this, unk1);
}
template<typename T>
void HookFunction(const char *module, char *signature, T &fn_real, PVOID fn_mine)
{
HookFunction<T>(DetourFindFunction(module, signature), fn_real, fn_mine);
}
template<typename T>
void HookFunction(DWORD address, T &fn_real, PVOID fn_mine)
{
HookFunction<T>(reinterpret_cast<PVOID>(address), fn_real, fn_mine);
}
template<typename T>
void HookFunction(PVOID target, T &fn_real, PVOID fn_mine)
{
fn_real = reinterpret_cast<T>(target);
HookFunction<T>(fn_real, fn_mine);
}
template<typename T>
void HookFunction(T &fn_real, PVOID fn_mine)
{
DetourAttach(&(PVOID&)fn_real, fn_mine);
}
void ApplyHooks()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DWORD function_address = 0x12345678;
HookFunction<CClassFunction_t>(address, Real_CClassFunction, Mine_CClassFunction);
DetourTransactionCommit();
}
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
{
DisableThreadLibraryCalls(hInstance);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ApplyHooks, 0, 0, 0);
break;
}
}
return TRUE;
}
经过数小时的搜索并试图找到解决方案,我想出了这个不错的小解决方案:
#include <windows.h>
#include <detours.h>
typedef void (__thiscall * CClassFunction_t)(void *__this, unsigned int unk1);
CClassFunction_t Real_CClassFunction;
void __fastcall Mine_CClassFunction(void *__this, int edx, unsigned int unk1)
{
Real_CClassFunction(__this, unk1);
}
template<typename T>
void HookFunction(const char *module, char *signature, T &fn_real, PVOID fn_mine)
{
HookFunction<T>(DetourFindFunction(module, signature), fn_real, fn_mine);
}
template<typename T>
void HookFunction(DWORD address, T &fn_real, PVOID fn_mine)
{
HookFunction<T>(reinterpret_cast<PVOID>(address), fn_real, fn_mine);
}
template<typename T>
void HookFunction(PVOID target, T &fn_real, PVOID fn_mine)
{
fn_real = reinterpret_cast<T>(target);
HookFunction<T>(fn_real, fn_mine);
}
template<typename T>
void HookFunction(T &fn_real, PVOID fn_mine)
{
DetourAttach(&(PVOID&)fn_real, fn_mine);
}
void ApplyHooks()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DWORD function_address = 0x12345678;
HookFunction<CClassFunction_t>(address, Real_CClassFunction, Mine_CClassFunction);
DetourTransactionCommit();
}
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
{
DisableThreadLibraryCalls(hInstance);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ApplyHooks, 0, 0, 0);
break;
}
}
return TRUE;
}
尝试使用:
union {
bool (CDetour::*lpMyFunction)(unsigned int);
PBYTE lpAddr;
} u;
将指针保存在u.lpMyFunction
并从u.lpAddr
这是否解决了您的编译问题?
是的,我实际上讨厌那些演员表,所以我自己做了:
// Cast a member function pointer that cannot have a reference taken to a void *
template <typename RET_TYPE, typename CLASS, typename...ARGs>
void* castToVoidPtr(RET_TYPE(CLASS::*&&pOriginalFunction)(ARGs...))
{
union
{
RET_TYPE(CLASS::*pMemFn)(ARGs...);
void* voidPtr;
} cast = { pOriginalFunction };
static_assert(sizeof(cast.pMemFn) == sizeof(cast.voidPtr), "Cannot cast this member function pointer to a void*. Not the same size.");
return cast.voidPtr;
}
// Cast a member function pointer to a void*&
template <typename RET_TYPE, typename CLASS, typename...ARGs>
void*& castToVoidPtr(RET_TYPE(CLASS::*&pOriginalFunction)(ARGs...))
{
union
{
RET_TYPE(CLASS::*&pMemFn)(ARGs...);
void*& voidPtr;
} cast = { pOriginalFunction };
static_assert(sizeof(cast.pMemFn) == sizeof(cast.voidPtr), "Cannot cast this member function pointer to a void*. Not the same size.");
return cast.voidPtr;
}
您的解决方案的唯一问题是您将额外的 DWORD 推入堆栈(EDX 寄存器),这是不必要的。 这些强制转换应该适用于您将使用它的所有情况。从我收集的信息来看,它不适用于多继承类函数,这不是您可能用于绕道的东西,并且如果您要尝试就会断言.
这将允许您执行以下操作:
DetourAttach(&castToVoidPtr(CDetour::Real_MemFn), castToVoidPtr(&CDetour::My_MemFn));
"void* castToVoidPtr(RET_TYPE(CLASS::*&&pOriginalFunction)(ARGs...))"
这 && 正是你想写的吗? VS2008 编译时报错。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.