C/C++:Windows编程—IAT Hook实例(程序启动拦截)

前言+思路

本文默认读者有IAT Hook的相关的基础知识了哈,记录笔者在IAT Hook实战中遇到到问题以及解决思路。

笔者想实现一个功能能够拦截到程序的启动。经过调研,大多程序如果是通过双击或者鼠标启动的 一般都是有 Windows资源管理器explorer.exe进程进行创建的。最近刚好学习了IAT Hook就用IAT Hook 实战一下。创建进程Windows API CreateProcessW,所以我们用OD调试证明一下。使用OD 附加 explorer.exe进程,ctrl + g 输入CreateProcessW 然后在这个函数那里用F2打下断点, 然后d打开IE浏览器或者其他程序。

从这里我们可以看到,在桌面通过鼠标打开的程序确实是使用的explorer.exe进程的CreateProcessW方法。我们可以用vs带的命令工具dumpbin 或 DEPENDS.EXE 查看exe或者dll程序的模块依赖情况。从下图,虽然我们看到kernel32.dll在explorer.exe的PE中也有,但是我们上图OD调试中看到 kernel32.CreateProcessW调完了是会回到shell32.dll中的某个地方,所以这里可以看出是使用的shell32.dll中的kernel32.dll的CreateProcessW

到这里我们可能就会这样去做了,以shell32.dll作为起始地址,在shell32.dll的导入表中找kernel32.dll然后在 kernel32.dll的IAT中找CreateProcessW 函数然后进行IAT Hook。笔者当然开始的时候也是这样想的,不过情况没那么简单。下面是笔者在做IAT Hook时的一段分析思路以及遇到的坑。请结合下面的几张图 容易理解些。

  // OD上看,在win7下的explorer.exe中 使用的是SHELL32.dll中的kernel.dll!!!所以这里起始地址应该是SHELL32.dll//HMODULE hModuleExe = GetModuleHandle(_T("SHELL32.dll"));// 起始地址用SHELL32.dll模块,在它的导入表能找到对应的kernel32.dll动态库,但是从在kernel32.dll的IAT找不到CreateProcessW :)// 妈蛋,笔者当然没有放弃,笔者继续分析,网上找了个 DEPENDS.EXE 来分析 kernel32.dll。确实找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模块的导出函数,通过dumpin查看该动态库它函数全部给到kernel32.dll了// 所以这里的起始地址应该为kernel32.dll,然后找它导入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模块,// 然后从API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后进行hook。//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,从kernel32.dll的导入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL的中IAT中找到的函数和内存中的CreateProcessW函数地址仍然对不上号!// 所以笔者又去分析shell32.dll,通过DEPENDS.exe工具发现shell32.dll的PE结构也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看kernel32.dll中链接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好像是个快捷方式 应该是链接的shell32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL// 所以这里的起始地址还是SHELL32.dll模块,同样是去找API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL然后找其中的IAT中的CreateProcessW进行hookHMODULE hModuleExe = GetModuleHandle(_T("shell32.dll"));

分析kernel32.dll

分析shell32.dll

dumpbin查看API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL导出函数情况

实现效果

看不清可以看哔哩哔哩视频演示地址 https://www.bilibili.com/video/av82627683/

Windows编程—IAT Hook实例(实现Windows程序启动拦截效果)

程序代码

笔者开发环境win10-64 + vs2010 32位程序,笔者测试程序运行环境 win7 x86,这里使用DebugView查看dll中打印的日志,使用Process Explorer查看dll注入情况

这里主要使用IAT Hook的hook CreateProcessW,IAT Hook难点是找到需要hook的函数的动态库 以及这个动态库的"母体"!

PE结构中的一个DLL对应一个导入表项,一个函数对应IAT导入地址表中的一个IAT项。

找到母体才能进行遍历该母体的导入表进而找到动态库对应的导入表项,通过找到的导入表项可以找到该动态库的IAT表,再遍历IAT表 找到hook函数对应的IAT表项,有hook函数的导入地址表 就可以更改导入地址表的函数地址了,就可以进行hook了!

下面是IATHookTest.dll的代码

#include "stdafx.h"
#include <Windows.h>DWORD g_funcAddrOrigninal = NULL; // CreateProcessW函数的地址
DWORD g_funcIATfuncAddr = NULL; // 导入地址表的地址,就是存放函数地址的地址,用于卸载IAT Hooktypedef BOOL (WINAPI *CreateProcessWFunc)(LPCWSTR               lpApplicationName,LPWSTR                lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL                  bInheritHandles,DWORD                 dwCreationFlags,LPVOID                lpEnvironment,LPCWSTR               lpCurrentDirectory,LPSTARTUPINFOW        lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);BOOL WINAPI MyCreateProcessW(LPCWSTR               lpApplicationName,LPWSTR                lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL                  bInheritHandles,DWORD                 dwCreationFlags,LPVOID                lpEnvironment,LPCWSTR               lpCurrentDirectory,LPSTARTUPINFOW        lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)
{OutputDebugString(_T("MyCreateProcessW enter-----"));OutputDebugString(lpApplicationName);OutputDebugString(lpCommandLine);CreateProcessWFunc func = (CreateProcessWFunc)g_funcAddrOrigninal;BOOL ret = FALSE;CString appName = lpApplicationName;CString strMsg;strMsg.Format(_T("是否打开程序:%s "),appName);if(IDYES == MessageBox(NULL,strMsg,_T("请选择"),MB_YESNO)){ret = func(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);}else{ret = TRUE;}OutputDebugString(_T("MyCreateProcessW exit-----"));return ret;
}void IATHOOKCreateProcessW()
{OutputDebugString(_T("IATHOOKCreateProcessW, enter "));// 获取CreateProcessW函数地址,该函数是Kernel32.dll导出的函数HMODULE hModuleKernel = GetModuleHandle(_T("kernel32.dll")); if(hModuleKernel == NULL){OutputDebugString(_T("IATHOOKCreateProcessW,LoadLibrary kernel32.dll failed !!!"));return;}CreateProcessWFunc CreateProcessWAddress = (CreateProcessWFunc)GetProcAddress(hModuleKernel,"CreateProcessW");if(CreateProcessWAddress == NULL){OutputDebugString(_T("IATHOOKCreateProcessW,GetProcAddress CreateProcessW failed !!!"));return;}g_funcAddrOrigninal = (DWORD)CreateProcessWAddress;//CString addr;//addr.Format(_T("kernel->CreateProcessWAddress = %x"),g_funcAddrOrigninal);//OutputDebugString(addr);//HMODULE hModuleExe = GetModuleHandle(_T("SHELL32.dll"));// OD上看,在win7下的explorer.exe中 使用的是SHELL32.dll中的kernel.dll!!!所以这里起始地址应该是SHELL32.dll// 起始地址用SHELL32.dll模块在它的导入表能找到对应的kernel32.dll动态库,但是从在kernel32.dll的IAT找不到CreateProcessW :)// 妈蛋,笔者当然没有放弃,笔者继续分析,网上找了个 DEPENDS.EXE 来分析 kernel32.dll。确实找到了CreateProcessW是kernel32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模块的导出函数!// 所以这里的起始地址应该为kernel32.dll,然后找它导入表中的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL模块,// 然后从API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL找它的IAT中的CreateProcessW,然后进行hook//HMODULE hModuleExe = GetModuleHandle(_T("kernel32.dll"));// 但是,从kernel32.dll的导入表中找到的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL中IAT中找到的函数和内存中的函数地址仍然对不上号!// 所以笔者又去分析shell32.dll,通过DEPENDS.exe工具发现shell32.dll的PE结构也是有API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL,// 然后再看shell32.dll中链接的API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL好些是个快捷方式 应该是链接的shell32.dll中API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL// 所以这里的起始地址还是SHELL32.dll模块,同样是去找API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL然后找其中的IATHMODULE hModuleExe = GetModuleHandle(_T("shell32.dll"));// 获取PE结构PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)hModuleExe;PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)hModuleExe + pDosHead->e_lfanew);// 保存映像基址和导入表的RVAULONGLONG dwImageBase = pNtHead->OptionalHeader.ImageBase;ULONGLONG dwImpDicRva = pNtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;// 导入表的VA,导入表的一项对应一个DLL模块PIMAGE_IMPORT_DESCRIPTOR pImageDes= (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + dwImpDicRva);PIMAGE_IMPORT_DESCRIPTOR pImageTemp = pImageDes;// 在导入表中查找要hook的模块是否存在bool bFind = false;while(pImageTemp->Name) // 最后一项结构体为全0{char* pName = (char*)(dwImageBase + pImageTemp->Name); // name地址CString cstrName = pName;if(cstrName.CompareNoCase(_T("API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL")) == 0){OutputDebugString(_T("IATHOOKCreateProcessW,find API-MS-WIN-CORE-PROCESSTHREADS-L1-1-0.DLL"));bFind = true;break;}pImageTemp++;}bool bFindFnc = false;// 已经找到要HOOK的DLL模块if(bFind){// 导入地址表,一项对应一个函数,进行遍历 查找到要hook的函数PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(dwImageBase + pImageTemp->FirstThunk);while(pThunk->u1.Function) // 最后一项结构体为全0{DWORD* pFuncAddr = (DWORD*)&(pThunk->u1.Function); // 这个地址上内存存放的是【函数的地址】// 取出函数的地址 和 之前在程序中找到的函数地址做比较,如果一样就找到了该函数的导入地址表了!//CString addr;//addr.Format(_T("IAT->funcAddr = %x"),*pFuncAddr);//OutputDebugString(addr);if(*pFuncAddr == g_funcAddrOrigninal){bFindFnc = true;DWORD dwMyHookAddr = (DWORD)MyCreateProcessW;g_funcIATfuncAddr = (DWORD)pFuncAddr; // 将存放函数地址的内存地址保存,以便后面卸载hookOutputDebugString(_T("IATHOOKCreateProcessW, CreateProcessW was found"));BOOL bRet = WriteProcessMemory(GetCurrentProcess(),pFuncAddr,&dwMyHookAddr,sizeof(DWORD),NULL);if(bRet){OutputDebugString(_T("IATHOOKCreateProcessW,WriteProcessMemory suc"));}else{OutputDebugString(_T("IATHOOKCreateProcessW,WriteProcessMemory fail !!!"));}break;}pThunk++;}}if(bFindFnc == false){OutputDebugString(_T("IATHOOKCreateProcessW, not find CreateProcessW!!!"));}}void UNIATHOOKCreateProcessW()
{OutputDebugString(_T("UNIATHOOKCreateProcessW, enter "));if(g_funcIATfuncAddr){if(g_funcAddrOrigninal){OutputDebugString(_T("UNIATHOOKCreateProcessW,CreateProcessW was found"));BOOL bRet = WriteProcessMemory(GetCurrentProcess(),(LPVOID)g_funcIATfuncAddr,&g_funcAddrOrigninal,sizeof(DWORD),NULL);if(bRet){OutputDebugString(_T("UNIATHOOKCreateProcessW,WriteProcessMemory suc"));}else{OutputDebugString(_T("UNIATHOOKCreateProcessW,WriteProcessMemory fail !!!"));}}}
}BOOL WINAPI DllMain (HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call) {case DLL_PROCESS_ATTACH: {IATHOOKCreateProcessW();}break;case DLL_PROCESS_DETACH: {UNIATHOOKCreateProcessW();}break;case DLL_THREAD_ATTACH: {}break;case DLL_THREAD_DETACH: {}break;}return TRUE;
}

完整项目

项目包含一个InjectDllTool工程代码,使用MFC写的dll注入小程序,然后注入IATHookTest.dll 实现普通程序的启动拦截效果。完整代码可以在这里下载,没分可以在这里github下载最新代码,如果可以的话给点个小星星哟。

C/C++:Windows编程—IAT Hook实例(程序启动拦截)相关推荐

  1. C/C++:Windows编程—Inline Hook内联钩子(上)

    前言 先介绍下Windows中的Hook技术.Hook是Windows中提供的一种用以替换DOS下"中断"的系统机制,中文译为"挂钩"或"钩子&quo ...

  2. Windows编程—杀死指定路径程序文件的进程

    前言 由于Windows命令 taskkill 无法通过程序文件的完整路径匹配来杀死指定进程,通过程序名称容易误杀进程,所有笔者做了一个简单的封装做了个mytaskkill.exe,用来杀死指定路径的 ...

  3. C/C++:Windows编程—Inline Hook内联钩子(下)

    前言 在上节中介绍了 InlineHook 钩子函数,主要是通过jmp 目标地址(转为机器码E9 偏移量) 来实现的,是修改被Hook函数首地址处的 5个字节的内容.这里再介绍另一种方法,修改被Hoo ...

  4. Qt:Windows编程—Qt实现注册表启动项管理

    Qt实现注册表启动项管理 前言 Windows的开机启动项在很多地方都有设置,这次我们在注册表 子键"HKEY_LOCAL_MACHINE\Software\Microsoft\Window ...

  5. C/C++:Windows编程—Hook IE浏览器实现URL拦截及更改(上)

    Hook IE浏览器实现URL拦截及更改(上) 前言+思路 笔者这里有个需求,针对IE浏览器 用户访问URL 做一个判断,是否为 限制访问的url,如果是 在另一个软件上给与警告提示.笔者在拿到这个需 ...

  6. 无法启动此程序,因为计算机中丢失iathook.dll,通过IAT+Hook调试Windows自定义未处理异常过滤器.pdf...

    2009年第12期 计算机系统应用 Hoo n 通过IAT d k调试Wiows自定义未处理 异常过滤器① WindowsCustomFiltersforUnhandled IATHook Debug ...

  7. c#语言经典程序100例,C#入门必看的实例程序100个 - 源码下载|Windows编程|其他小程序|源代码 - 源码中国...

    C#入门必看的实例程序100个\实例01\01.bmp C#入门必看的实例程序100个\实例01\csc编译器路径.txt C#入门必看的实例程序100个\实例01\hello.cs C#入门必看的实 ...

  8. Windows SDK编程之一 窗口示例程序

    /*Win32应用程序框架主要由"初始化窗口类","窗口注册类","窗口的创建"以"窗口消息函数"等组成*/ #incl ...

  9. C/C++:Windows编程—Hook IE浏览器实现URL拦截及更改(下)

    Hook IE浏览器实现URL拦截及更改(下) 前言 接上一篇 C/C++:Windows编程-Hook IE浏览器实现URL拦截及更改(上),本节为了实现上一篇待优化部分.实现IE进程时时监控,当有 ...

最新文章

  1. 浅析 SpringMVC 中返回对象的循环引用问题
  2. SpringBoot整合Minio 项目中使用自己文件存储服务器
  3. 软件测试国际化测试指标,国际化软件测试内容解析(2)
  4. 【数据分享】某产品付费用户数据
  5. 如何将程序下载到单片机
  6. 基于MATLAB的战术手势识别功能的设计与实现
  7. 开发老铁们,就参考这个图灵畅销新书书单加购!
  8. WPS论文编写问题集(参考文献制作、公式居中及编号、公式影响行间距...)_长期更新中ing...
  9. 2.1数据库-MySQL
  10. 【上班摸鱼系列】文字选择类游戏:《职员默示录 - 启》末日丧尸爆发,你,是什么下场!?
  11. SONET/SDH技术讲解
  12. 《一千年以后》最后一百元
  13. 普通视图和物化视图的区别(转)
  14. data.length提示undefined
  15. 7-1 找第k小的数(反思),a++和++a的区别,运算符优先级,递归分制思想
  16. c/c++ 线程进程
  17. 特来电、星星充、国家电网三足鼎立的充电桩遭巨头偷袭
  18. 数据结构包括哪几种基本结构,各有什么特点
  19. UEFI无法进入WIN10的系统?BIOS找不到ssd硬盘?reboot and select proper boot device的另一种解决思路
  20. java测试单个方法 @Test

热门文章

  1. java main函数_一行JAVA代码如何运行起来?
  2. 1.9 编程基础之顺序查找 05 最大值和最小值的差 python
  3. 判断form表单里面的元素属性是否有数据_html form标签的action属性是什么意思?又有哪些用法?(附实例)...
  4. g++ 安装python_卧槽,又一款Python神器
  5. Linux笔记-iptables规则原理和组成
  6. HTTPS|SSL笔记-SSL双向认证成功握手过程(含wireshark分析)
  7. C++Qt笔记-完美屏蔽IDEA中accept2弹窗(无需重装软件、无需重装系统)
  8. SpringBoot笔记-注册后发送邮箱点击激活(异步)
  9. Qt|OpenGL学习笔记-绕X轴、Y轴、以及XY轴旋转的四边体
  10. Java高级语法笔记-内部类