C++封装IATHOOK类实例

 更新时间:2020年4月25日 17:40  点击:2058

本文实例讲述了C++封装IATHOOK类的实现方法。分享给大家供大家参考。具体方法如下:

1. 定义成类的静态成员,从而实现自动调用

复制代码 代码如下:
static CAPIHOOK sm_LoadLibraryA; 
static CAPIHOOK sm_LoadLibraryW; 
static CAPIHOOK sm_LoadLibraryExA; 
static CAPIHOOK sm_LoadLibraryExW; 
static CAPIHOOK sm_GetProcAddress;

2. ReplaceIATEntryInAllMods中遍历模块的框架

复制代码 代码如下:
void CAPIHOOK::ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod) 

    //取得当前模块句柄 
    HMODULE hModThis = NULL; 
    if (bExcludeAPIHookMod) 
    { 
        MEMORY_BASIC_INFORMATION mbi; 
        if (0 != ::VirtualQuery(ReplaceIATEntryInAllMods, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) //ReplaceIATEntryInAllMods必须为类的static函数 
        { 
            hModThis = (HMODULE)mbi.AllocationBase; 
        } 
    } 
    //取得本进程的模块列表 
    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;  
    MODULEENTRY32 me32; 
    hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); 
    if (INVALID_HANDLE_VALUE == hModuleSnap) 
    { 
        return; 
    } 
    me32.dwSize = sizeof( MODULEENTRY32 );  
    if( !Module32First( hModuleSnap, &me32 ) )  
    {  
        return; 
    } 
    do  
    { //对每一个模块 
        if (me32.hModule != hModThis) 
        { 
            ReplaceIATEntryInOneMod(pszExportMod, pfnCurrent, pfnNewFunc, me32.hModule); 
        } 
    } while( Module32Next( hModuleSnap, &me32 ) );  
 
 
    ::CloseHandle(hModuleSnap); //配对写 
 
}

3. 遍历链表摘除自己的框架

复制代码 代码如下:
CAPIHOOK::~CAPIHOOK(void) 

    //取消对函数的HOOK 
    ReplaceIATEntryInAllMods(m_pszModName, m_pfnHook, m_pfnOrig, TRUE); 
 
    //把自己从链表中删除 
    CAPIHOOK* p = sm_pHeader; 
    if (p == this) 
    { 
        sm_pHeader = this->m_pNext; 
    } 
    else 
    { 
        while(p != NULL) 
        { 
            if (p->m_pNext == this) 
            { 
                p->m_pNext = this->m_pNext; 
                break; 
            } 
            p = p->m_pNext; 
        } 
    } 
}

4. 在cpp中静态变量写好后,再编译,不然容易出现LINK错误

复制代码 代码如下:
CAPIHOOK *CAPIHOOK::sm_pHeader = NULL;

源码:

.cpp源文件如下:

复制代码 代码如下:
#include "APIHOOK.h" 
#include <Tlhelp32.h> 
 
CAPIHOOK *CAPIHOOK::sm_pHeader = NULL; 
CAPIHOOK CAPIHOOK::sm_LoadLibraryA("kernel32.dll", "LoadLibraryA", (PROC)CAPIHOOK::LoadLibraryA, TRUE); 
CAPIHOOK CAPIHOOK::sm_LoadLibraryW("kernel32.dll", "LoadLibraryW", (PROC)CAPIHOOK::LoadLibraryW, TRUE); 
CAPIHOOK CAPIHOOK::sm_LoadLibraryExA("kernel32.dll", "LoadLibraryExA", (PROC)CAPIHOOK::LoadLibraryExA, TRUE); 
CAPIHOOK CAPIHOOK::sm_LoadLibraryExW("kernel32.dll", "LoadLibraryExW", (PROC)CAPIHOOK::LoadLibraryExW, TRUE); 
CAPIHOOK CAPIHOOK::sm_GetProcAddress("kernel32.dll", "GetProcAddress", (PROC)CAPIHOOK::GetProcess, TRUE); 
CAPIHOOK::CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod) 

    //初始化变量 
    m_pszModName = lpszModName; 
    m_pszFuncName = pszFuncName; 
    m_pfnOrig = ::GetProcAddress(::GetModuleHandleA(lpszModName), pszFuncName); 
    m_pfnHook = pfnHook; 
 
    //将此对象加入链表中 
    m_pNext = sm_pHeader; 
    sm_pHeader = this; 
 
    //在当前已加载的模块中HOOK这个函数 
    ReplaceIATEntryInAllMods(lpszModName, m_pfnOrig, m_pfnHook, bExcludeAPIHookMod); 

 
CAPIHOOK::~CAPIHOOK(void) 

    //取消对函数的HOOK 
    ReplaceIATEntryInAllMods(m_pszModName, m_pfnHook, m_pfnOrig, TRUE); 
 
    //把自己从链表中删除 
    CAPIHOOK* p = sm_pHeader; 
    if (p == this) 
    { 
        sm_pHeader = this->m_pNext; 
    } 
    else 
    { 
        while(p != NULL) 
        { 
            if (p->m_pNext == this) 
            { 
                p->m_pNext = this->m_pNext; 
                break; 
            } 
            p = p->m_pNext; 
        } 
    } 

//防止程序运行期间动态加载模块 
void CAPIHOOK::HookNewlyLoadedModule(HMODULE hModule, DWORD dwFlags) 

    if (hModule!=NULL && (dwFlags&LOAD_LIBRARY_AS_DATAFILE)==0) 
    { 
        CAPIHOOK* p = sm_pHeader;  //循环遍历链表,对每个CAPIHOOK进入HOOK 
        if (p != NULL)   
        { 
            ReplaceIATEntryInOneMod(p->m_pszModName, p->m_pfnOrig, p->m_pfnHook, hModule); 
            p = p->m_pNext; 
        } 
    } 

//防止程序运行期间动态调用API函数 
FARPROC WINAPI CAPIHOOK::GetProcess(HMODULE hModule, PCSTR pszProcName) 

    //得到函数的真实地址 
    FARPROC pfn = ::GetProcAddress(hModule, pszProcName); 
    //遍历列表 看是不是要HOOK的函数 
    CAPIHOOK* p = sm_pHeader; 
    while(p != NULL) 
    { 
        if (p->m_pfnOrig == pfn) //是要HOOK的函数 
        { 
            pfn = p->m_pfnHook; //HOOK掉 
            break; 
        } 
        p = p->m_pNext; 
    } 
    return pfn; 

 
void CAPIHOOK::ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller) 

    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hModCaller; 
    IMAGE_OPTIONAL_HEADER* pOpNtHeader = (IMAGE_OPTIONAL_HEADER*)((BYTE*)hModCaller + pDosHeader->e_lfanew + 24); //这里加24 
    IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hModCaller + pOpNtHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 
 
    BOOL bFindDll = FALSE; 
    while (pImportDesc->FirstThunk) 
    { 
        char* pszDllName = (char*)((BYTE*)hModCaller + pImportDesc->Name); 
 
        if (stricmp(pszDllName, pszExportMod) == 0)//如果找到pszExportMod模块,相当于hook messageboxa时的“user32.dll” 
        { 
            bFindDll = TRUE; 
            break; 
        } 
        pImportDesc++;   
    } 
 
    if (bFindDll) 
    { 
        DWORD n = 0; 
        //一个IMAGE_THUNK_DATA就是一个导入函数 
        IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((BYTE*)hModCaller + pImportDesc->OriginalFirstThunk); 
        while (pThunk->u1.Function) 
        { 
            //取得函数名称 
            char* pszFuncName = (char*)((BYTE*)hModCaller+pThunk->u1.AddressOfData+2); //函数名前面有两个.. 
            //printf("function name:%-25s,  ", pszFuncName); 
            //取得函数地址 
            PDWORD lpAddr = (DWORD*)((BYTE*)hModCaller + pImportDesc->FirstThunk) + n; //从第一个函数的地址,以后每次+4字节 
            //printf("addrss:%X\n", lpAddr); 
            //在这里是比较的函数地址 
            if (*lpAddr == (DWORD)pfnCurrent)  //找到iat中的函数地址 
            {                                
                DWORD* lpNewProc = (DWORD*)pfnNewFunc; 
                MEMORY_BASIC_INFORMATION mbi; 
                DWORD dwOldProtect; 
                //修改内存页的保护属性 
                ::VirtualQuery(lpAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); 
                ::VirtualProtect(lpAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect); 
                ::WriteProcessMemory(GetCurrentProcess(), lpAddr, &lpNewProc, sizeof(DWORD), NULL); 
                ::VirtualProtect(lpAddr, sizeof(DWORD), dwOldProtect, NULL); 
                return; 
            }            
            n++; //每次增加一个DWORD 
        }    
    } 

 
void CAPIHOOK::ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod) 

    //取得当前模块句柄 
    HMODULE hModThis = NULL; 
    if (bExcludeAPIHookMod) 
    { 
        MEMORY_BASIC_INFORMATION mbi; 
        if (0 != ::VirtualQuery(ReplaceIATEntryInAllMods, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) //ReplaceIATEntryInAllMods必须为类的static函数 
        { 
            hModThis = (HMODULE)mbi.AllocationBase; 
        } 
    } 
    //取得本进程的模块列表 
    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;  
    MODULEENTRY32 me32; 
    hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); 
    if (INVALID_HANDLE_VALUE == hModuleSnap) 
    { 
        return; 
    } 
    me32.dwSize = sizeof( MODULEENTRY32 );  
    if( !Module32First( hModuleSnap, &me32 ) )  
    {  
        return; 
    } 
    do  
    { //对每一个模块 
        if (me32.hModule != hModThis) 
        { 
            ReplaceIATEntryInOneMod(pszExportMod, pfnCurrent, pfnNewFunc, me32.hModule); 
        } 
    } while( Module32Next( hModuleSnap, &me32 ) );  
 
    ::CloseHandle(hModuleSnap); //配对写 

 
//防止自动加载 
HMODULE WINAPI CAPIHOOK::LoadLibraryA(LPCTSTR lpFileName) 

    HMODULE hModule = LoadLibraryA(lpFileName); 
    HookNewlyLoadedModule(hModule, 0); //这个函数中忆检测hModule 了 
    return hModule; 

HMODULE WINAPI CAPIHOOK::LoadLibraryW(LPCTSTR lpFileName) 

    HMODULE hModule = LoadLibraryW(lpFileName); 
    HookNewlyLoadedModule(hModule, 0); //这个函数中忆检测hModule 了 
    return hModule; 

HMODULE WINAPI CAPIHOOK::LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile,  DWORD dwFlags) 

    HMODULE hModule = LoadLibraryExA(lpFileName, hFile, dwFlags); 
    HookNewlyLoadedModule(hModule, dwFlags); //这个函数中忆检测hModule 了 
    return hModule; 

HMODULE WINAPI CAPIHOOK::LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile,  DWORD dwFlags) 

    HMODULE hModule = LoadLibraryExW(lpFileName, hFile, dwFlags); 
    HookNewlyLoadedModule(hModule, dwFlags); //这个函数中忆检测hModule 了 
    return hModule; 
}

.h头文件如下:

复制代码 代码如下:
#pragma once 
#include <Windows.h> 
 
class CAPIHOOK 

public: 
    CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod = TRUE); 
    ~CAPIHOOK(void); 
 
private: 
    static void ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller); 
    static void ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod); 
    //防止程序运行期间动态加载模块, 当一个新DLL被加载时调用 
    static void HookNewlyLoadedModule(HMODULE hModule,  DWORD dwFlags); 
 
    //跟踪当前进程加载新的DLL 
    static HMODULE WINAPI LoadLibraryA(LPCTSTR lpFileName); 
    static HMODULE WINAPI LoadLibraryW(LPCTSTR lpFileName); 
    static HMODULE WINAPI LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile,  DWORD dwFlags); 
    static HMODULE WINAPI LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile,  DWORD dwFlags); 
    //防止程序运行期间动态调用API函数 对于请求已HOOK的API函数,返回用户自定义的函数地址 
    static FARPROC WINAPI GetProcess(HMODULE hModule, PCSTR pszProcName);
 
private: //定义成静态的,会自动调用,从而实现自动HOOK 
    static CAPIHOOK sm_LoadLibraryA; 
    static CAPIHOOK sm_LoadLibraryW; 
    static CAPIHOOK sm_LoadLibraryExA; 
    static CAPIHOOK sm_LoadLibraryExW; 
    static CAPIHOOK sm_GetProcAddress; 
 
private: 
    static CAPIHOOK* sm_pHeader; //钩子链表 
    CAPIHOOK* m_pNext; 
 
    //要钩子的函数 
    PROC m_pfnOrig; 
    PROC m_pfnHook; 
 
    //要钩子的函数所在的dll 
    LPSTR m_pszModName; 
    //要钩子的函数名称 
    LPSTR m_pszFuncName; 
};

希望本文所述对大家的C++程序设计有所帮助。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能

    这篇文章主要介绍了基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • vue+element-ui表格封装tag标签使用插槽

    这篇文章主要介绍了vue+element-ui表格封装tag标签使用插槽,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-19
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • 图文介绍c#封装方法

    在本篇内容里小编给大家分享的是关于c#使用封装方法以及相关知识点,对此有需要的朋友们可以学习下。...2020-06-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15