Hook导入表 —— 实现挂钩FreeLibaray和HOOK延迟加载模块的API
2010-04-29 10:22
477 查看
最近在研究Windows Ring3上的API Hook,对HOOK导入表这种方法进行了研究。HOOK导入表所用的C++类大同小异,不同的就是如何实现HOOK一个延迟加载的模块中的函数,以及FreeLibaray某个函数之后再次LoadLibaray加载这个模块所导致的模块基地址不同的时候,这时该如何HOOK住这个模块中的API。
显然地,挂钩LoadLibarayA/W、LoadLibarayExA/W、GetProcAddress这些函数还不够,还需要挂钩FreeLibrary函数。这里我参考了《Windows核心编程》(第五版)中的一个程序,封装了一个C++类,能够HOOK住FreeLibrary,同时也能解决延迟加载的问题。
以下是这个类的声明:
#include <windows.h>
#include <ImageHlp.h>
#pragma comment(lib, "ImageHlp")
#include "APIHook.h"
#include <tlhelp32.h>
// 从指定地址得到包含该地址的模块句柄
static HMODULE WINAPI ModuleFromAddress(PVOID pv)
// 异常过滤函数
LONG WINAPI InvalidReadExceptionFilter(PEXCEPTION_POINTERS pep)
CApiHook* CApiHook::sm_pHead = NULL; // CApiHook对象链表头结点
BOOL CApiHook::ExcludeAPIHookMod = TRUE; // 是否排除HOOK本模块的函数
PROC CApiHook::sm_pFunFreeLibrary = NULL; // FreeLibrary的内存中的地址
// 构造函数
CApiHook::CApiHook()
// 构造函数
CApiHook::CApiHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook)
CApiHook::~CApiHook()
void CApiHook::Init()
void CApiHook::Uninit()
// 本函数不能为inline类型 —— 得到函数的实际地址
FARPROC WINAPI CApiHook::GetProcAddressRaw(HMODULE hmod, PCSTR pszProcName)
// 在某个模块中HOOK某个API函数 —— 重要
BOOL WINAPI CApiHook::HookApi(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook)
// 撤销挂钩
void WINAPI CApiHook::UnHook()
// 将本进程中所有模块的IAT中的指定函数地址pfnCurrent替换为pfnNew
BOOL CApiHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew)
// 替换模块导入表中的函数地址
void WINAPI CApiHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
// 替换模块导出表中函数的地址
void WINAPI CApiHook::ReplaceEATEntryInOneMod(HMODULE hmod, PCSTR pszFunctionName, PROC pfnNew)
// 替换LoadLibaray*函数和GetProcAddress函数
CApiHook CApiHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CApiHook::LoadLibraryA_Hook);
CApiHook CApiHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CApiHook::LoadLibraryW_Hook);
CApiHook CApiHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CApiHook::LoadLibraryExA_Hook);
CApiHook CApiHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CApiHook::LoadLibraryExW_Hook);
CApiHook CApiHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CApiHook::GetProcAddress_Hook);
CApiHook CApiHook::sm_FreeLibrary("Kernel32.dll", "FreeLibrary",
(PROC) CApiHook::FreeLibrary_Hook);
// 防止运行时加载模块(如线程调用LoadLibarayW等函数)
void CApiHook::FixupNewlyLoadedModule(PCSTR pszModPath, HMODULE hmod, DWORD dwFlags)
// 防止运行时卸载模块(如线程调用FreeLibrary等函数)
BOOL WINAPI CApiHook::FixupNewlyUnLoadModule(HMODULE hmod)
// 挂钩LoadLibarayA的替换函数
HMODULE WINAPI CApiHook::LoadLibraryA_Hook(PCSTR pszModulePath)
// 挂钩LoadLibraryW的替换函数
HMODULE WINAPI CApiHook::LoadLibraryW_Hook(PCWSTR pszModulePath)
// 挂钩LoadLibraryExA的替换函数
HMODULE WINAPI CApiHook::LoadLibraryExA_Hook(PCSTR pszModulePath,
HANDLE hFile, DWORD dwFlags)
// 挂钩LoadLibraryExW的替换函数
HMODULE WINAPI CApiHook::LoadLibraryExW_Hook(PCWSTR pszModulePath,
HANDLE hFile, DWORD dwFlags)
// 挂钩GetProcAddress的替换函数
FARPROC WINAPI CApiHook::GetProcAddress_Hook(HMODULE hmod, PCSTR pszProcName)
// 拦截FreeLibrary的替换函数
// 注意函数采用内联汇编进行编写,需要使用__declspec(naked)标记函数,让编译器不产生框架代码,自己维护堆栈平衡
__declspec(naked) BOOL WINAPI CApiHook::FreeLibrary_Hook(HMODULE hLibModule)
/**///////////////////////////////// End of File //////////////////////////////////
如上就可以实现挂钩FreeLibaray函数的功能了。
同时,这里在HOOK所有LoadLibaray*函数的时候,调用了FixupNewlyLoadedModule函数,该函数会遍历所有CApiHook对象,查看是否存在某个对象的API原地址为NULL,如果是,就检测模块名是否一致,这样就可以通过模块得到这个API原始地址了,这样就可以解决延迟加载的问题。
显然地,挂钩LoadLibarayA/W、LoadLibarayExA/W、GetProcAddress这些函数还不够,还需要挂钩FreeLibrary函数。这里我参考了《Windows核心编程》(第五版)中的一个程序,封装了一个C++类,能够HOOK住FreeLibrary,同时也能解决延迟加载的问题。
以下是这个类的声明:
#include <windows.h>
#include <ImageHlp.h>
#pragma comment(lib, "ImageHlp")
#include "APIHook.h"
#include <tlhelp32.h>
// 从指定地址得到包含该地址的模块句柄
static HMODULE WINAPI ModuleFromAddress(PVOID pv)
// 异常过滤函数
LONG WINAPI InvalidReadExceptionFilter(PEXCEPTION_POINTERS pep)
CApiHook* CApiHook::sm_pHead = NULL; // CApiHook对象链表头结点
BOOL CApiHook::ExcludeAPIHookMod = TRUE; // 是否排除HOOK本模块的函数
PROC CApiHook::sm_pFunFreeLibrary = NULL; // FreeLibrary的内存中的地址
// 构造函数
CApiHook::CApiHook()
// 构造函数
CApiHook::CApiHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook)
CApiHook::~CApiHook()
void CApiHook::Init()
void CApiHook::Uninit()
// 本函数不能为inline类型 —— 得到函数的实际地址
FARPROC WINAPI CApiHook::GetProcAddressRaw(HMODULE hmod, PCSTR pszProcName)
// 在某个模块中HOOK某个API函数 —— 重要
BOOL WINAPI CApiHook::HookApi(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook)
// 撤销挂钩
void WINAPI CApiHook::UnHook()
// 将本进程中所有模块的IAT中的指定函数地址pfnCurrent替换为pfnNew
BOOL CApiHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew)
// 替换模块导入表中的函数地址
void WINAPI CApiHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
// 替换模块导出表中函数的地址
void WINAPI CApiHook::ReplaceEATEntryInOneMod(HMODULE hmod, PCSTR pszFunctionName, PROC pfnNew)
// 替换LoadLibaray*函数和GetProcAddress函数
CApiHook CApiHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CApiHook::LoadLibraryA_Hook);
CApiHook CApiHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CApiHook::LoadLibraryW_Hook);
CApiHook CApiHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CApiHook::LoadLibraryExA_Hook);
CApiHook CApiHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CApiHook::LoadLibraryExW_Hook);
CApiHook CApiHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CApiHook::GetProcAddress_Hook);
CApiHook CApiHook::sm_FreeLibrary("Kernel32.dll", "FreeLibrary",
(PROC) CApiHook::FreeLibrary_Hook);
// 防止运行时加载模块(如线程调用LoadLibarayW等函数)
void CApiHook::FixupNewlyLoadedModule(PCSTR pszModPath, HMODULE hmod, DWORD dwFlags)
// 防止运行时卸载模块(如线程调用FreeLibrary等函数)
BOOL WINAPI CApiHook::FixupNewlyUnLoadModule(HMODULE hmod)
// 挂钩LoadLibarayA的替换函数
HMODULE WINAPI CApiHook::LoadLibraryA_Hook(PCSTR pszModulePath)
// 挂钩LoadLibraryW的替换函数
HMODULE WINAPI CApiHook::LoadLibraryW_Hook(PCWSTR pszModulePath)
// 挂钩LoadLibraryExA的替换函数
HMODULE WINAPI CApiHook::LoadLibraryExA_Hook(PCSTR pszModulePath,
HANDLE hFile, DWORD dwFlags)
// 挂钩LoadLibraryExW的替换函数
HMODULE WINAPI CApiHook::LoadLibraryExW_Hook(PCWSTR pszModulePath,
HANDLE hFile, DWORD dwFlags)
// 挂钩GetProcAddress的替换函数
FARPROC WINAPI CApiHook::GetProcAddress_Hook(HMODULE hmod, PCSTR pszProcName)
// 拦截FreeLibrary的替换函数
// 注意函数采用内联汇编进行编写,需要使用__declspec(naked)标记函数,让编译器不产生框架代码,自己维护堆栈平衡
__declspec(naked) BOOL WINAPI CApiHook::FreeLibrary_Hook(HMODULE hLibModule)
/**///////////////////////////////// End of File //////////////////////////////////
如上就可以实现挂钩FreeLibaray函数的功能了。
同时,这里在HOOK所有LoadLibaray*函数的时候,调用了FixupNewlyLoadedModule函数,该函数会遍历所有CApiHook对象,查看是否存在某个对象的API原地址为NULL,如果是,就检测模块名是否一致,这样就可以通过模块得到这个API原始地址了,这样就可以解决延迟加载的问题。
相关文章推荐
- Hook导入表 —— 实现挂钩FreeLibaray和HOOK延迟加载模块的API
- 用钩子实现API拦截(解决延迟加载模块问题)
- Angular实现预加载延迟模块的示例
- WIN32汇编实现进程导入表HOOK API
- 延迟加载(Lazyload)三种实现方式
- hibernate延迟加载的原理与实现
- jquery.lazyload 插件实现图片延迟加载
- jQuery实现图片延迟加载
- 我的学习笔记之二——修改导入表HOOK API(ring3_iat_exe_hook_Messagebox)
- android hook 框架 ADBI 如何实现so函数挂钩
- 前端性能优化之 —— 图片延迟加载 (原理以及实现方式)
- 利用反射api来加载模块
- EasyHook远程进程注入并hook api的实现
- jQuery实现图片延迟加载
- Android实现类似微信的延迟加载的Fragment——LazyFragment
- 关于JS实现延迟加载
- seajs+backbone实现单页面应用模块自动加载
- API 通过HOOK OpenProcess() 实现进程防杀
- android实现按钮获取焦点延迟加载
- jQuery实现鼠标滚动图片延迟加载效果附源码下载