首页
论坛
课程
招聘
[原创]ring3下的Inline hook
2013-3-28 22:03 12782

[原创]ring3下的Inline hook

2013-3-28 22:03
12782
inline hooking
      在IAT hook的时候,如果遇到延迟绑定,即使再IAT hook GetProcAddress,也会使得本来很简单的事情,看起来是那么的复杂。那么有没有一种更好的方法来避免DLL延迟绑定的问题,答案是肯定有的,inline hook会是一种不错的选择。
Inline Hook通过硬编码的方式修改目标函数的内存空间(通常是开始的一段字节,且一般在第一个call之前,很多时候是第一个字节,这么做是主要是为了防止堆栈混乱,如果能够处理好堆栈问题,放在哪个位置都是无所谓的),写入跳转语句,跳转到对应的函数空间里去。这样,该目标函数只要被调用,程序就会跳转到我们的函数中来,我们在自己写的函数里需要完成2个问题:
    1)处理好堆栈平衡。在程序流程中,堆栈的平衡是非常的重要,如果inline hook写入的是call语句,那么需要针对函数是否在函数里面做好了堆栈平衡做相应的处理,所以既要保证返回到目标函数中(如果写入的是jmp语句,就不需要),也要保证目标函数能在顺利执行完毕后返回到我们的函数中来。
    2)执行被覆盖的指令。我们向目标函数地址空间些如跳转指令(jmp xxxxxxxx)时,势必要覆盖原先的一些汇编指令,所以我们一定要保证这些被覆盖的指令能够顺利执行。关于这部分指令的执行,一般是将其放在我们的函数中,让我们的函数“帮助”目标函数执行完被覆盖的指令,然后再跳回目标函数中被覆盖内后后的地址继续执行剩余内容。跳回去的时候,一定要算好是跳回到什么地址,是目标函数起始地址后的第几个字节。最好的处理方法就是跳回去之前,还原之前被覆盖的汇编指令。

如下分析所示:
Before hook:
INT Func()						INT Func()
{								{
	return 10;						mov eax, 0xA
									ret
}								}

After hook:
INT Func()						INT Func()
{								{                       
	ReplaceFunc;						jmp 0xXXXXXX;         
									ret                   
}								}                       
                     
            
目标函数所跳转到的函数,这里只是简单的返回个信息。
VOID ReplaceFunc(VOID)
{
	::MessageBox(NULL, "hello world!", "", MB_OK);
	HookStatus(false, g_TargetFuncAddr);
	//return fnTestDll();
}


Hook函数,获取目标函数的地址,修改函数的起始5个字节。这里使用的是相对跳转,先计算跳转的距离XXXX,得到E9 XXXX(相对地址),写入到目标函数中去。
BOOL InlineHooking
(
 IN LPCTSTR pImageName,
 IN LPCTSTR pTargetFuncName,
 IN int pReplaceFuncAddr
 )
{
	HMODULE hLib = LoadLibrary(pImageName);
	if (NULL == hLib) return FALSE;

	g_TargetFuncAddr = (int)GetProcAddress(hLib, pTargetFuncName);
	if (NULL == g_TargetFuncAddr) return FALSE;

	CopyMemory(g_OldCode,(const void *)g_TargetFuncAddr, 5);
	g_NewCode[0] = 0xE9;
	int dwJmpAddr = pReplaceFuncAddr - g_TargetFuncAddr - 5;
	CopyMemory(&g_NewCode[1], &dwJmpAddr, 4);
	g_bHooked = TRUE;
	HookStatus(true, g_TargetFuncAddr);

	return FALSE;
}


修改内存
bool HookStatus( bool blnIsHook, IN int pTargetFuncAddr )
{
	DWORD oldACC,newACC;
	if (!g_bHooked) {return false;}
	//覆盖原先的一些汇编指令
	if (blnIsHook)
	{
		VirtualProtect((LPVOID)pTargetFuncAddr, 5, PAGE_WRITECOPY, &oldACC);
		CopyMemory((void *)pTargetFuncAddr, g_NewCode, 5);
		VirtualProtect((LPVOID)pTargetFuncAddr, 5, oldACC, &newACC);
	}
	//还原之前的汇编指令,这部分代码会引发多线程的问题,后面会介绍它对应的解决办法
	else
	{
		VirtualProtect((LPVOID)pTargetFuncAddr, 5, PAGE_WRITECOPY, &oldACC);
		CopyMemory((void *)pTargetFuncAddr, g_OldCode, 5);
		VirtualProtect((LPVOID)pTargetFuncAddr, 5, oldACC, &newACC);
	}
	return true;
}


      确实,这个办法要比IAT HOOK好很多。我们不需要针对每个模块逐个HOOK了,也不担心GetProcAddress引起的问题。但是,这个方法确不能很好地在多线程环境中工作,当有多个线程执行了我们 inline Hook 的目标函数的时候,一个线程在使用修改之前的 目标函数 ,一个线程在使用修改之后的目标函数,就会导致修改之前的目标函数函数不能够实现挂钩的效果。针对这种问题我们可以给这个函数加锁或者信号量,但这样会使效率降低,只能同时一个线程使用它。有一种方法可以很好的避免这个问题,就是只要不还原之前的汇编指令,每一个线程都是使用修改之后的目标函数,我们把被覆盖的那部分指令搬到ReplaceFunc函数中去,在调回目标函数前,先执行该部分汇编指令。

    通过上面例子的详述,我们可以知道inline hook的强大,它既可以用到JUMP XXXX,也可以使用为CALL XXXX,当然也可以添加其它你想要实现的功能的汇编指令。当然在HOOK之前你必须考虑到一个问题,就是即将被HOOK的目标函数是否有足够的空间来覆盖原先的汇编代码。

[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (12)
雪    币: 65
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
su汪妮 活跃值 2013-3-29 00:20
2
0
????怎么跑这来发了.
雪    币: 20
活跃值: 活跃值 (128)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MagicFuzzX 活跃值 2013-3-29 09:38
3
0
如何检测inline hook和iat hook呢
雪    币: 121
活跃值: 活跃值 (24)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hostzhen 活跃值 1 2013-3-29 10:11
4
0
IAT hook检测可以枚举输入表的导入函数地址与GetProcAddress获取的地址比较一下,不同为HOOK

inline hook检测
最简单的是抓取函数头的少部分字节进行对比,不同为HOOK
也可以对该函数先进行控制流分析,获得所有的BB块(基本块)进行对比,不同为HOOK
在高级点的就是进一步反编译出来,伪代码也可以,相同的二进制代码在反编译引擎得到的高级语言肯定一样的,不同为HOOK
雪    币: 35757
活跃值: 活跃值 (153657)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 活跃值 2013-3-29 11:29
5
0
Thanks for share.
雪    币: 8670
活跃值: 活跃值 (770)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2013-3-29 11:33
6
0
当目标没有足够空间的时候,可以用0xEB构造短跳去一个有空间的临近位置再jmp或者call
雪    币: 12
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
safeboy 活跃值 2013-3-29 12:55
7
0
连发两个精华帖,楼主是个有故事的人
雪    币: 218
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
誓言剑 活跃值 2013-3-29 23:38
8
0
我想楼主对于x64下inline hook有什么看法
雪    币: 408
活跃值: 活跃值 (177)
能力值: ( LV13,RANK:367 )
在线值:
发帖
回帖
粉丝
bitt 活跃值 5 2013-4-1 11:40
9
0
hot patch那意思
雪    币: 50
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
dswang 活跃值 2013-4-3 14:45
10
0
终于看到了inline hook了,谢谢,学习了
雪    币: 45
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
llongwei 活跃值 2013-4-7 09:27
11
0
学习~~~~支持
雪    币: 79
活跃值: 活跃值 (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cqzj70 活跃值 2014-1-16 16:57
12
0
mark
雪    币: 62
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
稻天 活跃值 2014-2-17 11:36
13
0
讲解的也太浅显了吧,而且执行代码也不是你能随便就修改的,你用RtlCopyMemory肯定会BSoD的!
游客
登录 | 注册 方可回帖
返回