c++ - API Hooking 在整个过程中生效——包括 EXE 和 DLL

标签 c++ windows hook

我有一个由单个 EXE 和多个 DLL 组成的应用程序。看完Windows via C/C++ ,我尝试在其中一个 DLL 中对 Sleep 函数执行 Hook ,并期望该 Hook 适用于 EXE 和所有 DLL。请注意,CAPIHook 代码来自 Windows via C/C++'s sample code

在 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 MySleep\n");
    ((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 called\n");
    printf ("Call Sleep in DLL function\n");
    Sleep(100);

    return 42;
}

在 EXE 项目中

void CexeDlg::OnBnClickedButton1()
{
    // TODO: Add your control notification handler code here
    printf ("Button being clicked\n");

    printf ("Call Sleep in EXE function\n");
    Sleep(100);

    dll_function_which_is_going_to_call_sleep();

    printf ("Call Sleep in EXE function\n");
    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 , 它包含 dllexe 项目。

我也曾经用 apihijack 中的代码替换 CHookAPI .同样的问题仍然发生。 Hook 效应不会遍及整个过程。

有什么我遗漏的吗?请不要建议我使用 EasyHook、Detours、...,因为我只是想知道为什么上面的代码不起作用,以及如何修复它。

最佳答案

这是因为原始的 CAPIHook 没有替换本地 IAT(在您的情况下,是包含 CAPIHook 二进制文件的 DLL 项目)。

这背后的原因是为了保护自己免受导致 stackoverflow 的无限递归(用户也会在 SO :D 中发布问题)。

为确保加载的任何后续模块将导入“正确的”函数,
CAPIHook 搜索并重定向LoadLibraryGetProcAddress 在构造时。

然而,这些函数也被 CAPIHook 本身使用,因此将本地 IAT 更改为代理函数(CAPIHook::LoadLibrary 或 CAPIHook::GetProcAddress)将导致无限递归,因为代理在尝试调用底层操作系统 API 时无意中调用了自身!


解决这个问题的一种方法是修改 CAPIHook 来检查是否可以替换本地 IAT。

1.) 新属性 m_bIncludeLocalIAT 添加到 CAPIHook 并相应地修改了 ctor/dtor。

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::ReplaceIATEntryInAllMods 的新参数。

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);

关于c++ - API Hooking 在整个过程中生效——包括 EXE 和 DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6501228/

相关文章:

c++ - 是否可以在编译时/运行时生成标记字符串的全局列表?

C++ STL 优先级队列插入 bad_alloc 异常

c++ - 为什么即使输入有效也总是设置 cin.failbit?

Windows 10 专业版 - Docker 容器系统区域设置

windows - 用于在 Windows 上进行符号链接(symbolic link)转换的 Git Hook

C++生成随机数-1

c - 如何向包含 UTC 时间的 tm 结构添加分钟?

c - 在命令提示符下生成一个 "readable"退格键

django - 服务器 : respond to collectstatic with "yes" 上的自动 django 接收 Hook

testing - 在每个浏览器的钩子(Hook)之前运行