热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

C++封装IATHOOK类实例

这篇文章主要介绍了C++封装IATHOOK类的实现方法,对IAT的HOOK实例进行了封装,非常具有实用价值,需要的朋友可以参考下

本文实例讲述了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  
 
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  
 
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++程序设计有所帮助。


推荐阅读
  • 如何在Windows 10中彻底禁用用户账户控制弹窗
    如何在Windows 10中彻底禁用用户账户控制弹窗 ... [详细]
  • 这是一道涉及数学计算的问题。假设步行速度为 \(a\),车速为 \(b\),总距离为 \(c\)。Teddy 的步行时间为 \(T_1\),WhereIsHeroFrom 的步行时间为 \(T_2\),总时间为 \(T\)。通过分析不同时间段内的速度变化,可以得出最优的车辆使用策略,以最小化总的旅行时间。具体来说,需要计算在不同情况下步行和乘车的时间分配,以确保整体效率最大化。 ... [详细]
  • 在Android平台上,视频监控系统的优化与应用具有重要意义。尽管已有相关示例(如http:www.open-open.comlibviewopen1346400423609.html)展示了基本的监控功能实现,但若要提升系统的稳定性和性能,仍需进行深入研究和优化。本文探讨了如何通过改进算法、优化网络传输和增强用户界面来提高Android视频监控系统的整体效能,以满足更复杂的应用需求。 ... [详细]
  • 如何在Windows 10系统中正确安装Xbox控制器? ... [详细]
  • 将解压缩版Tomcat集成至系统服务
    将解压缩版Tomcat集成至系统服务的方法如下:首先,在命令行中导航至Tomcat的`bin`目录,运行`service.bat install`命令以安装服务。需要注意的是,服务名称和显示名称已在`service.bat`脚本中预设,默认情况下会随不同版本有所变化。此外,建议检查并配置相关参数,确保服务能够稳定运行。 ... [详细]
  • 本指南详细介绍了在Linux环境中高效连接MySQL数据库的方法。用户可以通过安装并使用`mysql`客户端工具来实现本地连接,具体命令为:`mysql -u 用户名 -p 密码 -h 主机`。例如,使用管理员账户连接本地MySQL服务器的命令为:`mysql -u root -p pass`。此外,还提供了多种配置优化建议,以确保连接过程更加稳定和高效。 ... [详细]
  • Python默认字符解析:深入理解Python中的字符串处理
    在Python中,字符串是编程中最基本且常用的数据类型之一。尽管许多初学者是从C语言开始接触字符串,通常通过经典的“Hello, World!”程序入门,但Python对字符串的处理方式更为灵活和强大。本文将深入探讨Python中的字符串处理机制,包括字符串的创建、操作、格式化以及编码解码等方面,帮助读者全面理解Python字符串的特性和应用。 ... [详细]
  • 题目探讨了在无向图中求解点连通数的问题,具体涉及UVA1660和POJ1966两个经典问题。通过最小割算法的应用,分析了如何高效地确定网络中的关键节点和路径,为电缆电视网络的优化设计提供了理论支持。该研究不仅验证了最小割算法的有效性,还为进一步探索复杂网络的连通性和鲁棒性奠定了基础。 ... [详细]
  • 在 POJ1651 的乘法谜题挑战中,如果选手按相反顺序选择卡片,即先选 50,再选 20,最后选 1,则最终得分会有所不同。题目要求输入的第一行包含... 改写后的摘要:在 POJ1651 的乘法谜题挑战中,如果选手按照逆序选取卡片,例如依次选择 50、20 和 1,最终的得分将发生变化。题目首先要求输入的第一行包括... ... [详细]
  • 如何配置电脑在休眠时自动关闭特定应用程序?
    如何配置电脑在休眠时自动关闭特定应用程序? ... [详细]
  • 资源管理器的基础架构包括三个核心组件:1)资源池,用于将CPU和内存等资源分配给不同的容器;2)负载组,负责承载任务并将其分配到相应的资源池;3)分类函数,用于将不同的会话映射到合适的负载组。该系统提供了两种主要的资源管理策略。 ... [详细]
  • WebStorm 是一款强大的集成开发环境,支持多种现代 Web 开发技术,包括 Node.js、CoffeeScript、TypeScript、Dart、Jade、Sass、LESS 和 Stylus。它为开发者提供了丰富的功能和工具,帮助高效构建和调试复杂的 Node.js 应用程序。 ... [详细]
  • 如何在Linux系统中实现Windows风格的桌面环境:将Ubuntu 18.04定制为Windows主题界面
    如果您是从Windows转到Linux系统的用户,可能会觉得默认的Ubuntu主题和桌面环境缺乏吸引力和可定制性。尤其是对于习惯了Windows风格的任务栏和主题的用户,Ubuntu 18.04的橙色主题可能显得过于简洁。为了提升用户体验,可以通过安装特定的桌面环境和主题来实现类似Windows的界面效果。本文将详细介绍如何在Ubuntu 18.04中配置和定制桌面环境,使其具备Windows风格的外观和功能。 ... [详细]
  • AngularJS 进阶指南:第三部分深入解析
    在本文中,我们将深入探讨 AngularJS 的指令模型,特别是 `ng-model` 指令。`ng-model` 指令用于将 HTML 元素与应用程序数据进行双向绑定,支持多种数据类型验证,如数字、电子邮件地址和必填项检查。此外,我们还将介绍如何利用该指令优化表单验证和数据处理流程,提升开发效率和用户体验。 ... [详细]
  • 如何在低配置电脑上下载并运行《绝地求生》游戏? ... [详细]
author-avatar
嘻嘻520000000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有