王艳平的windows程序设计,挂钩API的例子为什么会失败?
在调试版下挂钩,书上也是讲了,如果想在发行版也能挂钩了话,那就把属性页改成读写,
下面是更改代码:
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(lpAddr, &mbi, sizeof(mbi));
VirtualProtect(lpAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
// 修改IAT表项,使其指向我们自定义的函数,
// 相当于语句“*lpAddr = (DWORD)MyMessageBoxA;”
DWORD* lpNewProc = (DWORD*)MyMessageBoxA;
::WriteProcessMemory(GetCurrentProcess(), lpAddr, &lpNewProc, sizeof(DWORD), NULL);
// 恢复页的保护属性
VirtualProtect(lpAddr, sizeof(DWORD), dwOldProtect, 0);
可是上面的代码加上去了,在Release版本下还是不行,谁知道是什么原因啊
问题补充 2011-04-07 13:34
没人知道吗?csdn我又没分,不然问问怎么会跟CSDN比,人家是专业的,问问那么杂,全部的代码在这。谁知道而且愿意回答的话,在调试和发行上运行一下吧,调试里可以,发行版就不行了,而且我还判断了下,发行版也确实是修改了IAT,IAT里挂钩函数前后的地址不一样,但就是不行,也没有哪个函数执行失败,可为什么不行呢?
全部代码:
#include <windows.h>
#include <stdio.h>
// 保存MessageBoxA函数的真实地址
PROC OrgAddr = (PROC)MessageBoxA;
// 定义MessageBoxA函数原型
typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT uType);
// 挂钩指定模块hMod对MessageBoxA的调用
BOOL SetHook(HMODULE hMod,PROC OrgAddr,DWORD *NewAddr,char *DllName);
int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{ return ((PFNMESSAGEBOX)OrgAddr)(hWnd, "新函数", "09HookDemo", uType);}
void main()
{
// 调用原API函数
::MessageBox(NULL, "原函数", "09HookDemo", 0);
// 挂钩后再调用
SetHook(::GetModuleHandle(NULL),OrgAddr,(DWORD *)MyMessageBoxA,"user32.dll");
::MessageBox(NULL, "原函数", "09HookDemo", 0);
}
// 用于替换MessageBoxA的自定义函数
BOOL SetHook(HMODULE hMod,PROC OrgAddr,DWORD *NewAddr,char *DllName)
{ IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hMod;
IMAGE_OPTIONAL_HEADER * pOptHeader =
(IMAGE_OPTIONAL_HEADER *)((BYTE*)hMod + pDosHeader->e_lfanew + 24);
IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)
((BYTE*)hMod + pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// 在导入表中查找user32.dll模块。因为MessageBoxA函数从user32.dll模块导出
while(pImportDesc->FirstThunk)
{ char* pszDllName = (char*)((BYTE*)hMod + pImportDesc->Name);
if(lstrcmpiA(pszDllName,DllName) == 0)
{ break; }
pImportDesc++;
}
if(pImportDesc->FirstThunk)
{ // 一个IMAGE_THUNK_DATA结构就是一个双字,它指定了一个导入函数
// 调入地址表其实是IMAGE_THUNK_DATA结构的数组,也就是DWORD数组
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)
((BYTE*)hMod + pImportDesc->FirstThunk);
while(pThunk->u1.Function)
{ // lpAddr指向的内存保存了函数的地址
DWORD* lpAddr = (DWORD*)&(pThunk->u1.Function);
if(*lpAddr == (DWORD)OrgAddr)
{
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(lpAddr, &mbi, sizeof(mbi));
VirtualProtect(lpAddr, sizeof(DWORD), PAGE_READWRITE , &dwOldProtect);
//修改IAT表项,使其指向我们自定义的函数,
//相当于语句“*lpAddr = (DWORD)MyMessageBoxA;”
DWORD* lpNewProc = (DWORD *)MyMessageBoxA;
::WriteProcessMemory(GetCurrentProcess(), lpAddr, &NewAddr, sizeof(DWORD),NULL);
VirtualProtect(lpAddr, sizeof(DWORD), dwOldProtect, 0);
return TRUE;
}
pThunk++;
}
}
return FALSE;
}