Release下IATHOOK失败的原因

书上的一个例子,源码如下


// 09HookDemo.cpp文件



#include <windows.h>
#include <stdio.h>

// 挂钩指定模块hMod对MessageBoxA的调用
BOOL SetHook(HMODULE hMod);
// 定义MessageBoxA函数原型
typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT uType);
// 保存MessageBoxA函数的真实地址
PROC g_orgProc = (PROC)MessageBoxA;

int main()
{
	// 调用原API函数
	::MessageBox(NULL, "原函数", "09HookDemo", 0);
	// 挂钩后再调用
	SetHook(::GetModuleHandle(NULL));
	::MessageBox(NULL, "原函数", "09HookDemo", 0);
        return 0;
}

// 用于替换MessageBoxA的自定义函数
int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
	return ((PFNMESSAGEBOX)g_orgProc)(hWnd, "新函数", "09HookDemo", uType);
}

BOOL SetHook(HMODULE hMod)
{
	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, "user32.dll") == 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)g_orgProc)
			{	
				// 修改IAT表项,使其指向我们自定义的函数,相当于“*lpAddr = (DWORD)MyMessageBoxA;”
				DWORD* lpNewProc = (DWORD*)MyMessageBoxA;
				::WriteProcessMemory(::GetCurrentProcess(), 
						lpAddr, &lpNewProc, sizeof(DWORD), NULL);
				return TRUE;
			}
			
			pThunk++;
		}
	}
	return FALSE;
}


这个源码在Debug模式下可以成功,但是Release下就会失败,但是IAT也修改了~原因如下:

至于为何WriteProcessMemory成功了却没有勾住,我猜你的代码是这样的

MessageBox(....);
HookIAT(...);
MessageBox(....);

然后发现第二次调用MessageBox未受影响,这是因为release下编译器有优化
它发现你要调用两次MessageBox,因此在调用第一次MessageBox前把MessageBox的地址从IAT中读取到一个稳定寄存器中,一般是esi,因为调用约定是esi等在函数调用前后不变
你的HookIAT函数修改的仅仅是IAT中的地址,然而第二次MessageBox调用是call esi,不从IAT中读取了,因此这次调用不受影响



第二个VirtualProtect会失败,内存分配失败指的是lpflOldProtect为NULL
lpflOldProtect  
[out] Pointer to a variable that receives the previous access protection value of the first page in the specified region of pages. If this parameter is NULL or does not point to a valid variable, the function fails.  

函数没替换成功,找个调试器,在WriteProcessMemory后边写个int 3,然后一步步跟这看看..

贴完整代码上来~

程序代码是不可写的,DEBUG版可能采取了特殊措施,把代码拷贝了出来执行的。要修改代码段,用VirtualProtect赋与PAGE_WRITECOPY权限

如果你的代码安排是我所说的,换成
HookIAT(...);
MessageBox(....);
就应该有效

如果 debug 版本正确,把这段代码的编译全局优化关掉试一试

#pragma optimize("g", off)
...// 你的代码
#pragma optimize("", on)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值