【加密与解密(第四版)】第十三章笔记

第十三章 HOOK技术

13.1 Hook概述

IAT HOOK(改地址)

cpp 复制代码
BOOL IAT_InstallHook()

{

BOOL bResult = FALSE ;

HMODULE hCurExe = GetModuleHandle(NULL);

PULONG_PTR pt ;

ULONG_PTR OrginalAddr;

bResult = InstallModuleIATHook(hCurExe,"user32.dll","MessageBoxA",(PVOID)My_MessageBoxA,&pt,&OrginalAddr);

if (bResult)

{

printf("[*]Hook安装完毕! pThunk=0x%p  OriginalAddr = 0x%p\n",pt,OrginalAddr);

g_PointerToIATThunk = pt ;

OldMessageBox = (PFN_MessageBoxA)OrginalAddr ;

}

return bResult;



}



//************************************

// FullName:    InstallModuleIATHook

// Description: 为指定模块安装IAT Hook

// Access:      public

// Returns:     BOOL

// Parameter:   HMODULE hModToHook , 待Hook的模块基址

// Parameter:   char * szModuleName , 目标函数所在模块的名字

// Parameter:   char * szFuncName , 目标函数的名字

// Parameter:   PVOID DetourFunc , Detour函数地址

// Parameter:   PULONG * pThunkPointer , 用以接收指向修改的位置的指针

// Parameter:   ULONG * pOriginalFuncAddr , 用以接收原始函数地址

//************************************

BOOL InstallModuleIATHook(

    HMODULE hModToHook,// 要钩取的模块的句柄

    char *szModuleName,// 要钩取的模块的名称

    char *szFuncName,// 要钩取的函数的名称

    PVOID DetourFunc,// 替换原始函数的钩子函数的地址

    PULONG_PTR *pThunkPointer,// 用于存储指向导入地址的指针的指针

    ULONG_PTR *pOriginalFuncAddr// 用于存储原始函数地址的指针

    )

{

    PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor; // 指向导入描述符表的指针

    PIMAGE_THUNK_DATA         pThunkData; // 指向导入函数表的指针

    ULONG ulSize; // 导入描述符表的大小

    HMODULE hModule=0; // 加载模块的句柄

    ULONG_PTR TargetFunAddr; // 目标函数的地址

    PULONG_PTR lpAddr; // 导入地址的指针

    char *szModName; // 当前模块的名称

    BOOL result = FALSE ; // 返回值,默认为失败

    BOOL bRetn = FALSE; // 操作结果,默认为失败



    hModule = LoadLibrary(szModuleName); // 加载要钩取的模块

    TargetFunAddr = (ULONG_PTR)GetProcAddress(hModule,szFuncName); // 获取要钩取的函数的地址

    printf("[*]Address of %s:0x%p\n",szFuncName,TargetFunAddr); // 输出目标函数的地址

    printf("[*]Module To Hook at Base:0x%p\n",hModToHook); // 输出要钩取的模块的基地址

    pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModToHook, TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); // 获取导入描述符表的地址

    printf("[*]Find ImportTable,Address:0x%p\n",pImportDescriptor); // 输出导入描述符表的地址

    while (pImportDescriptor->FirstThunk) // 遍历导入描述符表,直到遇到空描述符

    {

        szModName = (char*)((PBYTE)hModToHook+pImportDescriptor->Name) ; // 获取当前模块的名称

        printf("[*]Cur Module Name:%s\n",szModName); // 输出当前模块的名称

        if (stricmp(szModName,szModuleName) != 0) // 若当前模块名称与要钩取的模块名称不匹配

        {

            printf("[*]Module Name does not match, search next...\n"); // 输出模块名称不匹配的信息

            pImportDescriptor++; // 继续下一个导入描述符表

            continue; // 继续下一次循环

        }

        // 程序的导入表处理完毕后OriginalFirstThunk可能是无效的,不能再根据名称来查找,而是遍历FirstThunk直接根据地址判断

        pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hModToHook + pImportDescriptor->FirstThunk); // 获取导入函数表的地址

        while(pThunkData->u1.Function) // 遍历导入函数表,直到遇到空条目

        {

            lpAddr = (ULONG_PTR*)pThunkData; // 获取导入地址的指针

            // 找到了地址

            if((*lpAddr) == TargetFunAddr) // 如果导入地址与目标函数地址相等

            {

                printf("[*]Find target address!\n"); // 输出找到目标地址的信息

                // 通常情况下导入表所在内存页都是只读的,因此需要先修改内存页的属性为可写

                DWORD dwOldProtect; // 旧的保护属性

                MEMORY_BASIC_INFORMATION  mbi; // 内存页信息结构体

                VirtualQuery(lpAddr,&mbi,sizeof(mbi)); // 获取内存页的信息

                bRetn = VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOldProtect); // 修改内存页的保护属性为可写

                if (bRetn) // 如果修改成功

                {

                    // 内存页属性修改成功,继续下一步操作,先保存原始数据

                    if (pThunkPointer != NULL) // 如果指针不为空

                    {

                        *pThunkPointer = lpAddr ; // 将导入地址的指针赋值给pThunkPointer

                    }

                    if (pOriginalFuncAddr != NULL) // 如果指针不为空

                    {

                        *pOriginalFuncAddr = *lpAddr ; // 将导入地址的值赋值给pOriginalFuncAddr

                    }

                    // 修改地址

                    *lpAddr = (ULONG_PTR)DetourFunc; // 将导入地址的值修改为钩子函数的地址

                    result = TRUE ; // 操作成功

                    // 恢复内存页的属性

                    VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOldProtect,0); // 恢复内存页的保护属性

                    printf("[*]Hook ok.\n"); // 输出钩子成功的信息

                }

               

                break; // 跳出循环

            }

            //---------

            pThunkData++; // 继续下一个导入函数表条目

        }

        pImportDescriptor++; // 继续下一个导入描述符表

    }

   

    FreeLibrary(hModule); // 释放加载的模块

    return result; // 返回操作结果

}

InLine Hook(改内容)

13.2 HOOK的分类

名目繁多的 Hook,总结起来其实只有两种:Address Hook和Inline Hook。

Address Hook:IAT、EAT、user32.dll的回调函数表、IDT(中断描述符表)、SSDT(系统服务描述符表)、C++类的虚函数表、COM接口的功能函数表、处理例程地址、特殊寄存器中的地址、特定的函数指针

Inline Hook:

基于异 处理的HOOK

13.3 HOOK位置的挑选

影响最小的 Hook:应用程序中的call Hook,可精确到特定位置对特定 API的调用。

影响最大的Hook:在系统内核中,大部分Hook的位置都会影响整个系统的调用过程,越往下就越明显。

在内核中,KiFastCallEnlry和KeServiceDescriptorTable(含 Shadow)是两个绝佳的Hook位置。

13.4 HOOK的典型过程

Address Hook 的实施过程:定义Detour()函数、定义函数指针、查表(遍历匹配)替换原函数地址、关闭写保护、写入Detour()函数的地址

Inline Hook 的实施过程:确定 Hook方式及需要在Trampoline 中执行的指令、准备TrampolineFun函数、准备jmp指令并写入、CALLL HOOK

二次HOOK

13.5 Detour函数的典型用法

检查参数、检查结果、拦截调用或下发

13.6 HOOK中的注意事项

多线程安全、保存和恢复现场、注意返回值、避免重入

13.7 HOOK在X64平台上的新问题

指针的定义与操作、内存地址对齐、PE格式、调用约定的变化、跳转指令的问题、PatchGuard问题

13.8 HOOK技术的应用

实现增强的二次开发或补丁、信息截获、安全防护

13.9 HOOK的检测、恢复与对抗

相关推荐
AltmanChan35 分钟前
大语言模型安全威胁
人工智能·安全·语言模型
马船长1 小时前
红帆OA iorepsavexml.aspx文件上传漏洞
安全
咔叽布吉1 小时前
【论文阅读笔记】CamoFormer: Masked Separable Attention for Camouflaged Object Detection
论文阅读·笔记·目标检测
johnny2331 小时前
《大模型应用开发极简入门》笔记
笔记·chatgpt
亦枫Leonlew1 小时前
微积分复习笔记 Calculus Volume 1 - 4.7 Applied Optimization Problems
笔记·数学·微积分·1024程序员节
小肥象不是小飞象1 小时前
(六千字心得笔记)零基础C语言入门第八课——函数(上)
c语言·开发语言·笔记·1024程序员节
星LZX1 小时前
WireShark入门学习笔记
笔记·学习·wireshark
努力变厉害的小超超3 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
aloha_7898 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
hairenjing11238 小时前
使用 Mac 数据恢复从 iPhoto 图库中恢复照片
windows·stm32·嵌入式硬件·macos·word