首页
社区
课程
招聘
[求助][求助]如何使用detours库hook类成员函数
发表于: 2010-7-20 18:38 26747

[求助][求助]如何使用detours库hook类成员函数

2010-7-20 18:38
26747
刚拿到会员资格,就来求助,感到很是汗颜,希望各位大大多多包涵。

问题描述:
需要远程注入dll hook的目标函数是一个类成员函数(是通过IDA分析得知),目前仅知道该函数在内存中的首地址0x00E00A20(假设地址),如何使用detours库来hook这个类成员函数?

通常情况下,知道函数地址,使用远程注入dll hook函数是使用以下方法,但这个方法在此明显是行不通的:

static int dwAddr = 0x00E00A20;
typedef int (WINAPI *SrcFunc)(int, int);
static SrcFunc RealFunc = (SrcFunc)dwAddr;

int WINAPI HookFunc(int v1, int v2)
{
   //the code
   return RealFunc(v1, v2);
}
省略DllMain函数编写。

自己google了一下相关的信息,有人给出的解决方法如下:

Hook类成员函数通过在static函数指针来实现
还是举例说明,假如有个类定义如下:
class CData
{
public:
    CData(void);
    virtual ~CData(void);
    int Run(const char* cmd);
};

现在需要hook int CData::Run(const char*) 这个函数,可以按照以下几步:
a) 声明用于hook的类
class CDataHook
{
public:
    int DetourRun(const char* cmd);
    static int (CDataHook::* RealRun)(const char* cmd);
};

b) 初始化类中的static函数指针
     int (CDataHook::* CDataHook::RealRun)(const char* cmd) = (int (CDataHook::*)(const char*))&CData::Run;
c) 定义detour函数
   int CDataHook::DetourRun(const char* cmd)
{
    //添加任意你想添加的代码
    int iRet = (this->*RealRun)(cmd);
    return iRet;
}
e)     调用detourAttach函数
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)CDataHook::RealRun, (PVOID)(&(PVOID&)CDataHook::DetourRun));
    if(DetourTransactionCommit() == NO_ERROR)
    {
        //error
    }
但这个方法的前提是知道要hook的目标类定义,所以这个方法压根行不通(在仅知道类成员函数地址的情况下)。
不知道各位大大有没有别的解决方法共享一下。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
2
IDA里面看不出原型?

你只要搞对参数个数和返回类型就行了啊.参数一律DWORD.
声明对应原型的函数指针.memcpy或者强转成DWORD*赋值就行了.

利用detour只用提供如下3个数据就行了.
1.detoured函数的地址(就是被HOOK的函数地址)
2.detoured函数原型(ASM级别的原型就行.参数数量,返回地址和调用约定)
3.和detoured函数原型一致的detour函数地址(就是用来hook的函数地址.ASM级别上原型一致).

就是C++不支持DWORD向_thiscall *的转换.为了重入方便往往将detoured函数地址存入相应的函数指针.所以赋值的时候要强转成DWORD *.

可以参考Detour Sample
member.cpp

上面讲的类型都是针对x86.
x64没研究过.也没有付费版的detour.
2010-7-20 23:36
0
雪    币: 12
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
看了member.cpp里面的教程跟我上文说到的是一样的:
//////////////////////////////////////////////////////////////// Target Class.
//
class CMember
{
  public:
    void Target(void);
};

void CMember::Target(void)
{
    printf("  CMember::Target!   (this:%p)\n", this);
}

//////////////////////////////////////////////////////////////// Detour Class.
//
class CDetour /* add ": public CMember" to enable access to member variables... */
{
  public:
    void Mine_Target(void);
    static void (CDetour::* Real_Target)(void);

    // Class shouldn't have any member variables or virtual functions.
};

void CDetour::Mine_Target(void)
{
    printf("  CDetour::Mine_Target! (this:%p)\n", this);
    (this->*Real_Target)();
}

void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))&CMember::Target;

//////////////////////////////////////////////////////////////////////////////
上面红色加粗代码&CMember::Target,在我的程序里是未知的,只知道一个地址,这个如何编写?
2010-7-21 10:36
0
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
4
*(DWORD *)&CDetour::Real_Target = 0xXXXXXXXX;
Or
ver = 0xXXXXXXXX;
memcpy((LPVOID)&CDetour::Real_Target,ver,4);
2010-7-22 13:33
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
typedef void (__cdecl * VPF)(void);
VPF tt ;

#define TTT( a , b ) (a)=(b)
TTT(tt,classTmp.classFn2); 或memcpy( tt,(void*)classTmp.classFn2,4); 都不行,

error C2440: '=' : cannot convert from 'void (__thiscall TestClass::*)(void)' to 'void (__cdecl *)(void)'
2010-8-6 22:43
0
雪    币: 12
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
对于只知道类成员函数地址的情况,detours库貌似是存在问题的,我研究之后发现问题的原因是
由于类成员函数会隐式传递this指针,所以在hook函数中返回原函数时,由于堆栈不平衡导致被hook的程序崩溃

解决办法:
1. 迂回解决,hook一个目标函数的附近的函数,利用堆栈信息找到自己需要的地址与内存(现在在我那个项目是这样解决的,解决了99.99%问题)
2. 据某位大大说,在hook函数调用返回原函数时,直接用反汇编call地址,并ret相应的字节(需要一个一个的调整),但我尝试了n次,没能成功

求助:
利用上面的第一个方法解决了当前项目的问题,但我另一个项目遇到的情况是目标函数附近没有独立的函数可以hook(全是类成员函数),所以我必须hook类成员函数- -b 郁闷啊,不知道论坛的大侠有没有办法搞定啊!!
2010-8-25 10:52
0
雪    币: 62
活跃值: (72)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
7
传送门    http://bbs.pediy.com/showthread.php?t=115449
2010-8-25 13:39
0
雪    币: 12
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
没有仔细研究这个hook类,但这个好像是用于hook API的自己封装的一个类吧,我现在遇到的麻烦是需要hook一个类成员函数哦- -b
2010-8-25 15:29
0
雪    币: 62
活跃值: (72)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
9
只要知道类成员函数地址及可以进行hook了,类成员函数地址可以这样获取
class A
{
public:
      void func();
}

(int)A::func
2010-8-26 09:46
0
雪    币: 12
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
已经解决问题了,用的还是detours,方法稍后放出
2010-8-27 11:42
0
雪    币: 12
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
术语说明:
原函数:被hook的target
hook函数:指自己写的函数,也即让原函数jmp到该函数
原因分析:
用detours hook类成员函数,因为成员函数会有一个this指针,如果在hook函数中调用原函数,没有传入this指针,那么原函数的调用将会出错。
解决方法是:
1. 首先在ollydbg中找到这个this指针。其实也就是那个类的对象地址,一般来说,在ollydbg中调用原函数时,也即在call原函数之前,总会有一条指令mov ecx,xxx或者lea ecx,xxx,那个ecx就是我们要找的this指针!
2. 在hook函数调用原函数时使用内联汇编代码调用,push所有的参数之后,然后初始化ecx为this指针的值!然后在call原函数,这样call原函数就不会出现崩溃。

需要注意的地方:
1. 注意原函数是否能自动平衡堆栈,如不行,则需要在hook函数中自己手动平衡堆栈
2. hook函数返回时,必须是手动编写汇编返回(ret),不要让系统帮忙返回!在带有参数的hook例子中,系统帮忙放回必定出错!
3. ret后面的值与传入hook函数的参数有关,一般来说,该值=4*参数个数

2010-8-27 16:57
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
可以先查看类内成员函数布局情况,然后找出该成员函数的地址,
代替的函数原型第一个参数加this即可。
2011-4-16 22:22
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
13
就这么办即可,自己补加一个参数this即可
2011-11-6 13:35
0
雪    币: 276
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
这才是国人应该有的态度,好多人提问后自己解决了问题从来不说的。
2011-11-7 06:26
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
参数this的值又怎么去获取呢?
2011-11-7 09:58
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
16
/*
ÀûÓÃDetours Hook±ê×¼APIºÍÀà³ÉÔ±º¯Êý
×Ô¼ºÊµÏÖHookÀàµÄÐ麯Êý:Ò»¡¢ÐÞ¸ÄÐé±í ¶þ¡¢Detours Hook
*/

#include "stdafx.h"
#include <windows.h>
#include "Ring3Hook.h"
#include "detours.h"
#pragma comment(lib,"detours.lib")

/*
Detours Hook±ê×¼API£¨µ¼³ö»òδµ¼³öº¯Êý£©: MessageBoxW
*/
typedef int (WINAPI *pfMessageBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);
pfMessageBoxW RealMessageBoxW = MessageBoxW;
int WINAPI HookMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
        //¸Ä±ä¿í×Ö·û
        return RealMessageBoxW(hWnd,L"caonima",lpCaption,uType);
}
//ÕâÀïÊÇHookÀà³ÉÔ±º¯Êý
typedef void (WINAPI *pfTest)(int a,int b);
pfTest RealTest = (pfTest)0x00401023;
void WINAPI HookTest(int a,int b);
//nakedº¯Êý£º×Ô¼ºÆ½ºâ¶ÑÕ»µÄº¯Êý
_declspec(naked) void  StubFunction(int a,int b)
{
        _asm
        {
                push ebp
                mov ebp,esp
                push ecx
        }
        HookTest(a,b);
        _asm
        {
                add esp,4
                pop ebp
                ret 8  //ÕâÀï¶Ñջƽºâ²ÎÊý
        }
}
void WINAPI HookTest(int a,int b)
{
        //±£´æthisÖ¸Õë
        a=a+1;
        b=b+1;
        _asm
        {
                push ecx
                mov ecx,[ebp+0x10]  //ebp+4+²ÎÊý¸öÊý*4+4,Õ»Öб£´æµÄecx
        }
        RealTest(a,b);
        _asm
        {
                pop ecx
        }
}

DetoursHookInfo _StandardWinApi[]=
{
        {(DWORD*)&RealMessageBoxW, (DWORD)HookMessageBoxW},
        {(DWORD*)&RealTest,(DWORD)StubFunction}
};

VOID StartDetoursHook()
{
        //ÀûÓÃÒ»¸öforÑ­»·HookÈ«²¿
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        for(int i=0; i< sizeof(_StandardWinApi)/sizeof(DetoursHookInfo); i++)
        {
                DetourAttach(&(PVOID&)*(DWORD*)(_StandardWinApi[i].OldAddress), (PVOID)_StandardWinApi[i].NewAddress);
        }
        DetourTransactionCommit();
}
2011-11-7 12:22
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
我知道这个成员函数的地址 请问怎么hook 实在是没看明白!
2020-12-1 18:56
0
游客
登录 | 注册 方可回帖
返回
//