API挂钩在整个过程中生效,包括EXE和DLL
API Hooking which takes effect across entire process - both EXE and DLLs
我有一个由单个EXE和多个DLL组成的应用程序。通过C/C++阅读Windows后,我尝试在其中一个DLL中的Sleep
函数上执行钩子,并期望钩子能在EXE和所有DLL中工作。注意,CAPIHook
代码是通过C/C++的示例代码从Windows获得的
在DLL项目中
void WINAPI MySleep( DWORD dwMilliseconds );
CAPIHook g_Sleep("Kernel32.dll", "Sleep", (PROC)MySleep);
typedef void (WINAPI *Sleep_Type)( DWORD dwMilliseconds );
// Hook function.
void WINAPI MySleep( DWORD dwMilliseconds )
{
printf ("-------> In MySleepn");
((Sleep_Type)(PROC)g_Sleep)(dwMilliseconds);
}
// This is an example of an exported function.
DLL_API int dll_function_which_is_going_to_call_sleep(void)
{
printf ("DLL function being calledn");
printf ("Call Sleep in DLL functionn");
Sleep(100);
return 42;
}
在EXE项目中
void CexeDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
printf ("Button being clickedn");
printf ("Call Sleep in EXE functionn");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
printf ("Call Sleep in EXE functionn");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
}
这是我得到的输出
Button being clicked
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
让我感到奇怪的是,我预计CAPIHook
将在整个流程中生效。由于EXE和DLL属于同一进程,因此两者都应该能够访问MySleep
。然而,我的观察是,只有来自EXE的调用才会到达MySleep
,而不是DLL。
我在这里找到了示例代码CAPIHook-doesnt-have-effect-in-entire-process.zip,它包含dll
和exe
项目。
我也曾经在apihaick中顺便用代码替换CHookAPI
。同样的问题仍然存在。挂钩效应不会扩散到整个过程中。
我错过了什么吗?请不要建议我使用EasyHook,Detours。。。,因为我只想知道为什么上面的代码不起作用,以及我如何修复它。
这是因为原始的CAPIHook不替换本地IAT(在您的情况下,是包含CAPIHook二进制文件的DLL项目)。
这背后的原因是为了保护自己免受无限递归的影响,这会导致stackoverflow(用户也会在SO:D中提出问题)。
为了确保加载的任何后续模块都将导入"correct"函数,
CAPIHook搜索并在构建时重定向LoadLibrary和GetProcAddress。
但是,这些函数也由CAPIHook本身使用,因此将本地IAT更改为代理函数(CAPIHook::LoadLibrary或CAPIHook::GetProcAddress)将导致无限递归,因为代理在尝试调用底层操作系统API时无意中调用了自己!
解决这个问题的一种方法是修改CAPIHook以检查是否可以替换本地IAT。
1.)将新属性m_bIncludeLocalIAT添加到CAPIHook并相应地修改ctor/dt
class CAPIHook
{
...
CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT = TRUE);
...
BOOL m_bIncludeLocalIAT;
...
};
CAPIHook::CAPIHook( PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT) {
...
m_bIncludeLocalIAT = bIncludeLocalIAT;
...
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_bIncludeLocalIAT);
}
CAPIHook::~CAPIHook() {
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_bIncludeLocalIAT);
...
}
2.)添加到静态函数CAPIHook::ReplaceIATEntryAllMods的新参数
static void WINAPI ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnOrig, PROC pfnHook, BOOL bReplaceLocalIAT){
HMODULE hmodThisMod = ExcludeAPIHookMod
? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
// Get the list of modules in this process
CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me = { sizeof(me) };
for (BOOL bOk = th.ModuleFirst(&me); bOk; bOk = th.ModuleNext(&me)) {
if (bReplaceLocalIAT || (me.hModule != hmodThisMod)) {
// Hook this function in this module
ReplaceIATEntryInOneMod(
pszCalleeModName, pfnCurrent, pfnNew, me.hModule);
}
}
}
3.)更新静态CAPIHook实例
CAPIHook CAPIHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CAPIHook::LoadLibraryA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CAPIHook::LoadLibraryW, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CAPIHook::LoadLibraryExA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CAPIHook::LoadLibraryExW, FALSE);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CAPIHook::GetProcAddress, FALSE);
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 终端不会为C++文件创建.exe文件吗
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- Windows 10-使用gtkmm-3.0库和g++[包括再现]的分段故障
- 为什么 cmake 许可证<>样式不包括?
- 在Windows中以.exe的形式运行c++
- 计算平均值,不包括上次得分
- Visual Studio mkl_link_tool.exe链接错误
- 从多个源构造一个对象,包括一个对象向量
- PrintWindow函数在notepad.exe中出错
- VSCode C++ 编译的exe感染了Win32:TrojanX-gen[Trj]
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- 在编译中包括 Botan 2
- 获取当前正在运行的 exe 名称(不是路径)
- 将值从另一个数组写入数组,不包括不需要的值 C++
- 从 exe 文件 (Visual Studio ) 启动时调试断言失败
- CreateProcess正在调用cmd.exe,包括没有显示(闪烁)窗口的参数
- 在C++的应用程序中包括文件(dll,txt等.exe
- 包括 <iostream> => 成功的完整构建,但不包括.exe (Netbeans)
- API挂钩在整个过程中生效,包括EXE和DLL