c++ - 如何修改运行时加载的 DLL 的导入地址表

标签 c++ winapi hook dll-injection setwindowshookex

我想 Hook 在运行时从加载的 DLL 调用的函数,我使用了“Windows Via C/C++”一书中的 CAPIHook 类(通过安装系统范围 Hook 完成的 DLL 注入(inject)和通过修改 IAT Hook ) 但只有当 DLL 名称/符号存在于可执行文件的 IAT 中时,此代码才有效。 (即隐式 DLL 链接)

这是动态链接库代码:

   CAPIHook::CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook) {

   // Note: the function can be hooked only if the exporting module 
   //       is already loaded. A solution could be to store the function
   //       name as a member; then, in the hooked LoadLibrary* handlers, parse
   //       the list of CAPIHook instances, check if pszCalleeModName
   //       is the name of the loaded module to hook its export table and 
   //       re-hook the import tables of all loaded modules.

   m_pNext  = sm_pHead;    // The next node was at the head
   sm_pHead = this;        // This node is now at the head

   // Save information about this hooked function
   m_pszCalleeModName   = pszCalleeModName;
   m_pszFuncName        = pszFuncName;
   m_pfnHook            = pfnHook;
   m_pfnOrig            =  GetProcAddressRaw(GetModuleHandleA(pszCalleeModName), m_pszFuncName);

   // If function does not exit,... bye bye
   // This happens when the module is not already loaded
   if (m_pfnOrig == NULL)
   {
      wchar_t szPathname[MAX_PATH];
      GetModuleFileNameW(NULL, szPathname, _countof(szPathname));
      wchar_t sz[1024];
      StringCchPrintfW(sz, _countof(sz), 
         TEXT("[%4u - %s] impossible to find %S\r\n"), 
         GetCurrentProcessId(), szPathname, pszFuncName);
      OutputDebugString(sz);
      return;
   }

   // Hook this function in all currently loaded modules
   ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook);
}

这是钩子(Hook)函数:

HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryA(pszModulePath);
   FixupNewlyLoadedModule(hmod, 0);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryW(pszModulePath);
   FixupNewlyLoadedModule(hmod, 0);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath, 
   HANDLE hFile, DWORD dwFlags) {

   HMODULE hmod = ::LoadLibraryExA(pszModulePath, hFile, dwFlags);
   FixupNewlyLoadedModule(hmod, dwFlags);
   return(hmod);
}

HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath, 
   HANDLE hFile, DWORD dwFlags) {

   HMODULE hmod = ::LoadLibraryExW(pszModulePath, hFile, dwFlags);
   FixupNewlyLoadedModule(hmod, dwFlags);
   return(hmod);
}

替换IAT的方法:

void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, 
   PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) {

   // Get the address of the module's import section
   ULONG ulSize;

   // An exception was triggered by Explorer (when browsing the content of 
   // a folder) into imagehlp.dll. It looks like one module was unloaded...
   // Maybe some threading problem: the list of modules from Toolhelp might 
   // not be accurate if FreeLibrary is called during the enumeration.
   PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL;
   __try {
      pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
         hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
   } 
   __except (InvalidReadExceptionFilter(GetExceptionInformation())) {
      // Nothing to do in here, thread continues to run normally
      // with NULL for pImportDesc 
   }

   if (pImportDesc == NULL)
      return;  // This module has no import section or is no longer loaded


   // Find the import descriptor containing references to callee's functions
   for (; pImportDesc->Name; pImportDesc++) {
      PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
      if (lstrcmpiA(pszModName, pszCalleeModName) == 0) {

         // Get caller's import address table (IAT) for the callee's functions
         PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) 
            ((PBYTE) hmodCaller + pImportDesc->FirstThunk);

         // Replace current function address with new function address
         for (; pThunk->u1.Function; pThunk++) {

            // Get the address of the function address
            PROC* ppfn = (PROC*) &pThunk->u1.Function;

            // Is this the function we're looking for?
            BOOL bFound = (*ppfn == pfnCurrent);
            if (bFound) {
               if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, 
                    sizeof(pfnNew), NULL) && (ERROR_NOACCESS == GetLastError())) {
                  DWORD dwOldProtect;
                  if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY, 
                     &dwOldProtect)) {

                     WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, 
                        sizeof(pfnNew), NULL);
                     VirtualProtect(ppfn, sizeof(pfnNew), dwOldProtect, 
                        &dwOldProtect);
                  }
               }
               return;  // We did it, get out
            }
         }
      }  // Each import section is parsed until the right entry is found and patched
   }
}

作者添加了注释以添加此功能,但我不确定该怎么做

Note: the function can be hooked only if the exporting module is already loaded. A solution could be to store the function name as a member; then, in the hooked LoadLibrary* handlers, parse the list of CAPIHook instances, check if pszCalleeModName is the name of the loaded module to hook its export table and re-hook the import tables of all loaded modules.

他也把这个写在书上了,但是我又不知道该怎么做

A possible solution is to use the hooked LoadLibrary* functions to detect when a module is exporting an unpatched hooked function and then execute two actions:

Hook again the import table of the module already loaded because it is now possible to call GetProcAddress and get a pointer to the original implementation of the function to hook. Notice that the name of the function needs to be stored as a class member and set in the constructor.

Directly update this hooked function in the Export Address Table of the exporting module as shown by the implementation of the ReplaceEATEntryInOneMod function. That way, all new modules calling the hooked function will call our handler

我尝试在加载 DLL 后修改 IAT,但是我的 Hook 函数没有被调用

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath) {

   HMODULE hmod = ::LoadLibraryW(pszModulePath);

   if (StrCmpIW(pszModulePath, myDLLUnicodeName.c_str()) == 0 ) {
        PROC proc =  GetProcAddressRaw(GetModuleHandleA(myDLLName.c_str()), myFunctionName.c_str());

        if ( proc != NULL ) {
            for (CAPIHook* p = sm_pHead; p != NULL; p = p->m_pNext) {
                 if (StrCmpIA(p->m_pszCalleeModName, myDLLName.c_str()) == 0) {
                    MessageBox(NULL, L"This is the New Dynamic DLL", L"Test!", 0);
                    ReplaceIATEntryInAllMods(p->m_pszCalleeModName, proc , p->m_pfnHook);  
                 }
            }
        }
    }

   FixupNewlyLoadedModule(hmod, 0);
   return(hmod);
}

那么,如何修改这段代码来处理动态加载的情况?

最佳答案

我以前做过。 你想要的是 EAT Hook 而不是 IAT。此外, Hook ::LoadLibrary API 本身,以便您知道何时加载 DLL,并在加载后从 DLL Hook 请求的 api。

Internet 上有一些关于如何执行此操作的示例。这是我刚刚找到的一个: http://board.cheat-project.com/showthread.php?t=10633

关于c++ - 如何修改运行时加载的 DLL 的导入地址表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11592446/

相关文章:

c++ - top 如何查看内存使用情况

cocoa - 如何在屏幕上的特定点找到窗口以进行屏幕截图/屏幕录制?

c++ - 在 notepad.exe 中 Hook CreateFile 不会捕获 API 调用

c++ - 编译后 C++ 构造函数的真实签名是什么

C++ 连接字符串导致 "invalid operands of types ‘const char*’ 和 ‘const char"

python - Pyqt5 已安装但在导入时出现 dll 加载失败错误?

c# - 开发应用程序的Windows 'class name'是什么?

c# - 这个 SeBackupPrivilege(备份模式)实现有什么问题?

python - openpyxl 不能作为 EXE 运行

c++ - 在不释放内存的情况下销毁 std::vector