【问题标题】:Detouring a member-function via an injected DLL通过注入的 DLL 绕过成员函数
【发布时间】:2012-06-18 09:01:45
【问题描述】:

原帖:

我试图从我注入的 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;
}

【问题讨论】:

  • 您有义务使用 Detours 吗?或者你可以使用另一个钩子引擎吗?
  • sw。 - 我可以改变它,这是一个个人项目。你有不同的想法吗?

标签: c++ winapi hook reverse-engineering detours


【解决方案1】:

经过数小时的搜索和尝试找到解决方案,我想出了这个不错的小解决方案:

#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;
}

【讨论】:

    【解决方案2】:

    尝试使用:

    union {
      bool (CDetour::*lpMyFunction)(unsigned int);
      PBYTE lpAddr;
    } u;
    

    将指针保存在u.lpMyFunction 并从u.lpAddr 获取

    这能解决你的编译问题吗?

    【讨论】:

    • 我最终用完全不同的东西解决了这个问题。我会更新我原来的帖子。
    • 不能保证指向类成员的指针可以用这样的单个指针表示。这是高度依赖于编译器的行为。
    • @RemyLebeau - 事实问题 - 如何在 c++ 中获取指向成员函数的指针。无论如何,这是代码的地址,并且始终是指针大小。但是 c++ 语法确实使这项任务变得困难,因为这里不允许重新解释强制转换。使用联合解决方案之一(是的,我知道“非活动成员”等)。另一个从没有此类限制的 asm 代码访问它,名称如?My_MemFn@CDetour@@QEAA_NI@Z。接受的解决方案可见时间太长,而且不是原生的
    【解决方案3】:

    是的,我真的很讨厌那些演员表,所以我自己编了:

    // 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));
    

    【讨论】:

      【解决方案4】:

      "void* castToVoidPtr(RET_TYPE(CLASS::*&amp;&amp;pOriginalFunction)(ARGs...))"

      这&&正是你想要写的吗? VS2008编译时报错。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-13
        • 1970-01-01
        • 1970-01-01
        • 2018-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多