我有一个应用程序,包含一个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。同样的问题仍然发生。挂钩效果不会在整个过程中扩散。

我有什么错过的吗?请不要建议我使用EasyHook,Detours等,因为我只想知道上面的代码为什么不起作用以及如何解决。

最佳答案

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

其背后的原因是为了保护自己免受无限递归的影响,这会导致堆栈溢出(用户也将在SO:D中发布问题)。

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

但是,这些函数也由CAPIHook本身使用,因此将本地IAT更改为代理函数(CAPIHook::LoadLibrary或CAPIHook::GetProcAddress)将导致无限递归,因为代理在尝试调用底层OS 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);

10-08 09:44