首页
社区
课程
招聘
[求助]Detours拦截类成员函数问题
发表于: 2021-10-11 01:43 7618

[求助]Detours拦截类成员函数问题

2021-10-11 01:43
7618

最近在汉化一个游戏 发现这个游戏没有使用gdi去绘制游戏字体,所以只好慢慢去找显示文本的call,发现这个call是个成员函数。Detours这方面的资料实在太少,也翻看过很多资料。始终还是不行,执行到需要绘制字体的地方就会崩溃。

 

od上找到的代码如下:
00441B4B |. 8B4424 10 mov eax,dword ptr ss:[esp+0x10]
00441B4F |> 68 0000803F push 0x3F800000
00441B54 |. 68 8000FFFF push 0xFFFF0080
00441B59 |. 50 push eax
00441B5A |> 8B8E D8000000 mov ecx,dword ptr ds:[esi+0xD8]
00441B60 |. 53 push ebx
00441B61 |. 51 push ecx 显示内容
00441B62 |. 8BCE mov ecx,esi esi是this指针
00441B64 |. FF15 00CF4F00 call dword ptr ds:[<&UIToolKit.csCompone>; uitoolki.csComponent::Text

 

dll代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
typedef void (__fastcall *pFunc)(void* pthis,const char* text, DWORD a1, DWORD a2,unsigned int a3,float a4);
pFunc FuncToDetour = (pFunc)(0x004FCF00);
 
void Hook()
{
    DetourRestoreAfterWith();//恢复原来状态
    DetourTransactionBegin();//拦截开始
    DetourUpdateThread(GetCurrentThread());//刷新当前线程
    DetourAttach((void**)&FuncToDetour, (void**)StubFunction);
    OutputDebugString(L"Hook!");
    DetourTransactionCommit();//拦截生效
}
 
void  __stdcall StubFunction(void* pthis, const char* text, DWORD a1, DWORD a2, unsigned int a3, float a4) {
 
    __asm pushad
     CString temp;
     temp += text;
     OutputDebugString(temp);
     __asm popad
 
     __asm
    {
        push a4
        push a3
        push a2
        push a1
        push text
        mov ecx, pthis
        call FuncToDetour
        ret 0x20
    }
 
}

希望有大神能指点迷津。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-10-11 01:49 被郁人编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (15)
雪    币: 12848
活跃值: (9142)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
2
int (__fastcall *)(int pthis, int dummy, int argstack1, int argstack2 , int argstack3...)
2021-10-11 08:34
0
雪    币: 6977
活跃值: (1786)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
hzqst int (__fastcall *)(int pthis, int dummy, int argstack1, int argstack2 , int argstack3...)
 利用fastcall的调用约定,ecx,edx,加栈参数,是这个意思吗
2021-10-11 10:42
0
雪    币: 918
活跃值: (1875)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
hook接管函数声明成裸函数自己维护
2021-10-11 10:50
0
雪    币: 228
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5

肯定不是fastcall 也不是__stdcall ,因为vc编译器的this传参为特定寄存器的缘故,你只能手写汇编或者自己构造一个c++成员函数指针


这篇文章的 inline hook 原理 教程 - 0xc - 博客园 (cnblogs.com)  的<6> thiscall hook的方法 有细说。


2021-10-11 13:39
0
雪    币: 6
活跃值: (856)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
可以跟踪调试一下,调用前后堆栈,寄存器是否还原了。
建议把整个都pushad  popad试试。
很久很久没有搞windows了
2021-10-11 14:21
0
雪    币: 3532
活跃值: (1862)
能力值: ( LV6,RANK:93 )
在线值:
发帖
回帖
粉丝
7
detour有thiscall的example,另外的方法如dllspec_naked + asm直接hook任意位置也行
2021-10-11 15:11
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
感谢各位大神的积极帮助,非常感谢大家。已经解决问题,目前采用的解决方案是4楼大佬提供的那篇文章并且我从Detours换成了MinHook 仔细按照文章的方法已经达到了我想要的效果。直接实现自己操作然后调用原函数即可,不用自己使用内联汇编去维护是最简单的方案。接下来其他大佬给出的方案我还会继续尝试,我会在下一楼放出我的代码,各位朋友参照即可。
2021-10-11 20:50
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
mb_hgrbqfun 肯定不是fastcall 也不是__stdcall ,因为vc编译器的this传参为特定寄存器的缘故,你只能手写汇编或者自己构造一个c++成员函数指针。这篇文章的&nbsp;inline ho ...
感谢大神的解决方案,您提供的文章特别的详细,感谢!
2021-10-11 20:50
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
mb_hgrbqfun 肯定不是fastcall 也不是__stdcall ,因为vc编译器的this传参为特定寄存器的缘故,你只能手写汇编或者自己构造一个c++成员函数指针。这篇文章的&nbsp;inline ho ...
#include "pch.h"
#include "MinHook.h"
#include "atlstr.h"
#if defined _M_X64
#pragma comment(lib, "MinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "MinHook.x86.lib")
#endif


__declspec(dllexport) void ExportFunc(void)
{
}

class CDetour 
{
public:
    void Mine_Target(const char* text, int a1, int a2, unsigned int a3, float a4);
};


typedef void(__thiscall* tofunc)(CDetour*, const char* text, int a1, int a2, unsigned int a3, float a4);
tofunc testfun = nullptr;

void CDetour::Mine_Target(const char* text, int a1, int a2, unsigned int a3, float a4)
{
    OutputDebugString(L"流经我的方法!");
    CString temp;
    temp += text;
    OutputDebugString(temp);
    testfun(this, text, a1, a2, a3, a4);

}


void Hook() {
    MH_Initialize();
    void (CDetour:: * pfMine)(const char* text, int a1, int a2, unsigned int a3, float a4) = &CDetour::Mine_Target;
    auto s = MH_CreateHook(*(PBYTE*)(0x004FCF00), *(PBYTE*)&pfMine,
        (void**)&testfun);
    if (s == MH_OK) {
        MH_EnableHook(MH_ALL_HOOKS);
    }

}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        Hook();
        OutputDebugString(L"MinHook!");
        break;

    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


2021-10-11 20:52
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11

2021-10-11 20:53
0
雪    币: 6124
活跃值: (4651)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
12
mb_hgrbqfun 肯定不是fastcall 也不是__stdcall ,因为vc编译器的this传参为特定寄存器的缘故,你只能手写汇编或者自己构造一个c++成员函数指针。这篇文章的&nbsp;inline ho ...
thiscall就是fastcall 只不过修饰掉了edx
2021-10-13 07:21
0
雪    币: 228
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
黑洛 thiscall就是fastcall 只不过修饰掉了edx
学习了。
2021-10-13 14:19
0
雪    币: 3253
活跃值: (3296)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
14
郁人 #include "pch.h" #include "MinHook.h" #inclu ...

Detour __fastcall 方式hook类成员函数例子

//////////////////////////////////////////////////////////////// Target Class.
//
class CMember
{
  public:
    int Target(int a, int b);
};

int CMember::Target(int a, int b)
{
    printf("  CMember::Target!   (this:%p) %d, %d\n", this, a, b);
    return 0;
}

//////////////////////////////////////////////////////////////////////////////
// __fastcall 前4个参数分别是 rcx rdx r8 r9进行传参.多余的通过栈传参.从右向左入栈.
#ifdef _WIN64 
typedef int(__fastcall *CMember_Target)(void *, int, int);
CMember_Target CMember_Target_Real = nullptr;

int __fastcall Mine_Target_fastcall(void *ccx, int a, int b)
{
    printf("  Mine_Target_fastcall begin! (this:%p) %d, %d\n", ccx, a, b);
    int ret = CMember_Target_Real(ccx, a, b);
    printf("  Mine_Target_fastcall end! (this:%p) %d, %d %d\n", ccx, a, b, ret);

    return 1;
}
#else
typedef int(__fastcall *CMember_Target)(void *, int, int, int);
CMember_Target CMember_Target_Real = nullptr;

int __fastcall Mine_Target_fastcall(void *ecx, int edx, int a, int b)
{
    printf("  Mine_Target_fastcall begin! (this:%p) %d, %d\n", ecx, a, b);
    int ret = CMember_Target_Real(ecx, edx, a, b);
    printf("  Mine_Target_fastcall end! (this:%p) %d, %d %d\n", ecx, a, b, ret);

    return 1;
}
#endif // _WIN64

//////////////////////////////////////////////////////////////////////////////
//
int main(int argc, char **argv)
{
    (void)argc;
    (void)argv;

    //////////////////////////////////////////////////////////////////////////
    //
    //CMember_Target_Real = (CMember_Target)0x12345687;

    int (CMember::* pfTarget)(int, int) = &CMember::Target;
    CMember_Target_Real = *(CMember_Target *)&pfTarget;

    Verify("Real_Target_fastcall", *(PBYTE *)&CMember_Target_Real);
    Verify("Mine_Target ", (PBYTE*)Mine_Target_fastcall);

    printf("\n");

    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());

    DetourAttach(&(PVOID&)CMember_Target_Real, Mine_Target_fastcall);

    LONG l = DetourTransactionCommit();
    printf("DetourTransactionCommit = %ld\n", l);
    printf("\n");

    Verify("Real_Target_fastcall", *(PBYTE *)&CMember_Target_Real);
    Verify("Mine_Target ", (PBYTE *)Mine_Target_fastcall);
    printf("\n");

    //////////////////////////////////////////////////////////////////////////
    //
    CMember target;
    printf("Calling CMember (will be detoured):\n");
    int ret = target.Target(1, 4);
    printf("ret: %d\n", ret);

    return 0;
}


最后于 2024-3-6 10:12 被小调调编辑 ,原因:
2024-3-5 18:36
1
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
作者是“小调调”的答复精彩绝伦!这个答案是最优正解!
2024-7-28 16:38
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
小调调 郁人 #include&nbsp;"pch.h" #include&nbsp;"MinHo ...
这个解答太优秀了!非常正确!
2024-7-28 16:42
0
游客
登录 | 注册 方可回帖
返回
//