WINDOWS下HOOK函数的方法

 

前两天和dvff谈论的一些技术总结。

程序代码:
/////////////////////////////////////////////////////////////////////////////////////
//                    HOOKAPI DEMO PROGRAM
//文件名:HOOKTEST.C
//
//描述: 演示WINNT下HOOK系统API过程及方法
//      (扩充为HOOK任意函数的方法)
//
//作者:东海一鱼
//
//时间: 2010.7.22       
//
//使用编译器: VC2003
//
//使用第三方库: NULL
//
//
//Bug、修复纪录:
//          1、2010.8.4 增加HOOK私有函数代码(被hook函数名TestFn,hook函数名MyHookFn2)
//
//            2、2010.8.6 增加HOOK类虚拟函数代码(被hook函数名TestVirtualFn,
//               hook函数名TestVirtualFn2)
//
//               HOOK类成员函数,主要难度在于成员函数地址的获得。
//             普通成员函数指针在VC6下无法进行强制类型转换,
//             解决手段见GetClassFnAddress辅助函数。
//             类虚拟成员函数HOOK需要获得类实例对象虚表中的虚拟函数指针。                   
////////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

//#pragma pointers_to_members(best_case)

#ifdef _X86_

#define FLATJMPCODE_LENGTH 5            //x86 平坦内存模式下,绝对跳转指令长度
#define FLATJMPCMD_LENGTH  1            //机械码0xe9长度
#define FLATJMPCMD         0xe9

#else

#error WINVER ERRORSLECT  ONLY USES ON X86!!!

#endif

///////////////////////////////////////////////////////////////////////////
//测试类函数HOOK
class TestHookFnClass
{
public:
    virtual void TestVirtualFn(char* szPlay);
    virtual void TestVirtualFn2(char* szPlay);
    void TestHookFn(char* szPlay);
    void TestHookFn2(char* szPlay);   
};

void TestHookFnClass::TestHookFn(char* szPlay)
{
    printf("%s\n",szPlay);
}

void TestHookFnClass::TestHookFn2(char* szPlay)
{
    printf("%s - %s\n ",szPlay,"类函数已被HOOK!");
}

void TestHookFnClass::TestVirtualFn(char* szPlay)
{
    printf("%s\n",szPlay);
}

void TestHookFnClass::TestVirtualFn2(char* szPlay)
{
    printf("%s - %s\n",szPlay,"Virtual2 HOOKS");
}

/////////////////////////////////////////////////////////////////////////
#ifdef _X86_
//利用C变参特性,进行类成员函数指针类型转换
LPVOID GetClassFnAddress(...)                    //Add  2010.8.6
{
    LPVOID FnAddress;
   
    __asm
    {
        lea eax,FnAddress
        mov edx,[ebp+8]
        mov [eax],edx
    }
    return FnAddress;
}
#endif

//获得类虚拟成员函数指针
LPVOID GetClassVirtualFnAddress(LPVOID pthis,int Index) //Add 2010.8.6
{
    LPVOID FnAddress;
   
    *(int*)&FnAddress = *(int*)pthis;                       //lpvtable
    *(int*)&FnAddress = *(int*)((int*)FnAddress + Index);
    return FnAddress;
}
/////////////////////////////////////////////////////////////////////////
//我的新API函数
int __stdcall MyHookFn(HWND hwnd,char* sztext,char* szTitle,int stly)
{          
   
    return printf("%s - %s\n",sztext,"原API函数已被HOOK!");   //
}

//我的新私有桩函数
void MyHookFn2(char* szTxt)
{
    char* pBuf = (char*)malloc(strlen(szTxt) + sizeof(char*) * 32);
   
    __try
    {
        sprintf(pBuf,"%s - %s",szTxt," 原函数已被HOOK!");
        printf("%s\n",pBuf);
    }
    __finally
    {
        free(pBuf);
    }
}

//私有测试函数
void TestFn(char* szTitle)
{
    printf("%s",szTitle);
}

//////////////////////////////////////////////////////////////////////
//HOOK函数
BOOL HookApi(LPVOID ApiFun,LPVOID HookFun)
{
    BOOL    IsSuccess = FALSE;
    DWORD   TempProtectVar;              //临时保护属性变量
    MEMORY_BASIC_INFORMATION MemInfo;    //内存分页属性信息
   
    VirtualQuery(ApiFun,&MemInfo,sizeof(MEMORY_BASIC_INFORMATION)); 
   
    if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,
        PAGE_READWRITE,&MemInfo.Protect))                            //修改页面为可写
    {
        *(BYTE*)ApiFun = FLATJMPCMD;                                     
        *(DWORD*)((BYTE*)ApiFun + FLATJMPCMD_LENGTH) = (DWORD)HookFun -
            (DWORD)ApiFun - FLATJMPCODE_LENGTH;
       
        VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,
            MemInfo.Protect,&TempProtectVar);                               //改回原属性
       
        IsSuccess = TRUE;
    }
   
    return IsSuccess;
}

int main(int argc,char** argv)
{
    HMODULE hDll;
    LPVOID  OldFun;    

    TestHookFnClass* TestClass = new TestHookFnClass();

    __try
    {
        hDll = GetModuleHandle("User32.dll");
        OldFun = GetProcAddress(hDll,"MessageBoxA");  //要HOOK的API函数
   
        if(OldFun)
        {
            if(HookApi(OldFun,MyHookFn))  //如果HOOK成功
                MessageBoxA(0,"call Api MessageBox","Is Hookd?",MB_OK); //调用原API,测试HOOK

            if(HookApi(TestFn,MyHookFn2))
                TestFn("Private Function Hook Test");  //调用私有函数,测试HOOK   
           
            if(HookApi(GetClassFnAddress(TestHookFnClass::TestHookFn),
                GetClassFnAddress(TestHookFnClass::TestHookFn2)))
                TestClass->TestHookFn("Hook Class Member Function Test!");//调用类成员函数,测试HOOK

            if(HookApi(GetClassVirtualFnAddress(TestClass,0),
                GetClassFnAddress(TestHookFnClass::TestHookFn2)))
                TestClass->TestVirtualFn("Call Class Virtual Function Test!");//调用类虚拟函数,测试HOOK
           
            if(HookApi(GetClassVirtualFnAddress(TestClass,0),
                GetClassVirtualFnAddress(TestClass,1)))                    
                TestClass->TestVirtualFn("Call Class Virtual Function Test2!");//同上,桩函数为另一虚函数
        }
    }
    __finally
    {
        if(hDll)
            FreeLibrary(hDll);
        if(TestClass)
            delete(TestClass);
    }
   
    return 0;
}
posted @ 2012-11-15 19:04  zearin  阅读(4069)  评论(2编辑  收藏  举报