您的位置:首页 > 其它

如何修改栈结构统计每个DLL的函数使用信息

2010-08-02 14:38 393 查看
在文章如何Hook Windows API中,我们讨论了如何Hook Windows API。此种方式的结果是每个DLL都会跳转到相同的函数,所以不便实现针对每个DLL的函数使用信息。如果希望得到基于每个DLL的信息,可以通过修改栈的结构的方式实现。

假设现在要Hook的函数是: void __stdcall Func(int, int);

其调用时的栈结构如图1所示:





图1: Thunk对栈结构的调整

现在我们把Hook的函数替换成如下的thunk代码:

#pragma pack(push,1)
struct _stdcallThunk
{
BYTE m_push[3];// push dword ptr [esp]
DWORD m_mov; // move dword ptr [esp+0x4],pThis
DWORD m_this; // pThis, which serves as the operand for mov instruction
BYTE m_jmp; // jmp proc
DWORD m_relproc; // proc, which serves as the operand for jmp instruction

VOID Init(INT_PTR proc, INT_PTR pThis, INT_PTR pThunk)
{
m_push[0] = 0xFF;
m_push[1] = 0x34;
m_push[2] = 0x24;
m_mov = 0x042444C7;
m_this = (DWORD)pThis;
m_jmp = 0xE9;
m_relproc = (DWORD)(proc - (pThunk + sizeof(_stdcallThunk)));
FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallThunk));
}
};

那么当函数调用转到Hook之后,其栈结构会被调整,如图1所示。调整之后的栈结构正好是一个对C++对象的成员函数调用之后的栈结构。所以只要我们定义一个C++类,使其中的一个非静态成员函数拥有和被Hook函数相同的声明,我们就可以利用上面的Thunk把函数的调用分发给为每个DLL创建的该C++类的对象,从而记录每个DLL中对该函数的使用信息。

使用thunk的步骤如下:

定义一个C++类,使其一个非静态成员函数拥有和被Hook函数相同的声明;

创建该类的一个对象;

创建一个_stdcallThunk对象,调用其Init()函数,参数设置如下表所示.

把Hook函数的地址设成thunk对象的首地址。

参数名取值
proc步骤1中定义的非静态成员函数的函数指针
pThis步骤2中创建对象的指针
pThunk步骤3中创建的对象的指针
这里有如下几个问题需要注意:

1. 如何取得非静态C++函数的地址
C++标准不允许用提取静态成员函数的方式提取非静态函数的地址,可以使用如下的方式:
a) 定义如下共用体:
union {
INT_PTR dwFunc;
RETURN_TYPE (CLASS::*pfn)(ARGS);
} pfn;
b)把非静态函数指针赋值给pfn.pfn,然后通过pfn.dwFunc取出值。

2. 防止DEP设置导致程序crash
由于thunk是堆上的对象,所以如果OS打开DEP,那么程序可能会crash。解决方法是使用VirtualAlloc()创建一个具有read/write/execute属性的内存地址,把thunk分到该地址空间中。

3. 对齐地址防止cache不同步
需要对thunk的起始地址进行对齐,以防止代码被加载到指令缓存的时候出现不同步,从而导致程序crash。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐