我想在运行时挂钩从加载的DLL中调用的函数,我使用了“Windows Via C / C ++”一书中的CAPIHook类(通过Install System Wide挂钩完成的DLL注入和通过Modify IAT挂钩) )但只有在可执行文件的IAT中存在DLL名称/符号时,此代码才有效。 (即用于隐式DLL链接)
这是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);
}
这是钩子函数:
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
}
}
作者添加了评论以添加此功能,但我不知道该怎么做
注意:只有导出模块才能挂钩该功能 已加载。解决方案可以是存储功能 作为成员的名字;然后,在钩住的LoadLibrary *处理程序中,解析 CAPIHook实例列表,检查pszCalleeModName 是挂载其导出表的加载模块的名称 重新挂钩所有已加载模块的导入表。
他也在书上写了这个,但我又不知道该怎么做
一种可能的解决方案是使用挂钩的LoadLibrary *函数 检测模块何时导出未修补的挂钩函数和 然后执行两个动作:
再次挂钩已经加载的模块的导入表,因为它是 现在可以调用GetProcAddress并获取指向原始的指针 执行钩子的功能。请注意,该名称 函数需要存储为类成员并在中设置 构造
直接在导出地址表中更新此挂钩函数 导出模块如执行所示 ReplaceEATEntryInOneMod函数。这样,所有新模块调用 钩子函数将调用我们的处理程序
我尝试在加载DLL后修改IAT,但我的钩子函数没有调用
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);
}
那么,如何修改此代码来处理动态加载情况呢?
答案 0 :(得分:8)
我以前做过这个。 你想要的是EAT挂钩代替IAT。此外,挂钩:: LoadLibrary API本身,以便您知道何时加载DLL,并在加载后从DLL挂钩所请求的api。
互联网上有一些关于如何做到这一点的例子。这是我刚才发现的一个: http://board.cheat-project.com/showthread.php?t=10633