HOOK GetMessageTime有感

参考文章:http://www.codeproject.com/Articles/21414/Powerful-x-x-Mini-Hook-Engine

Mini-Hook-Engine下载:http://download.csdn.net/detail/friendan/9182677

-----------------------------------------------------------------------------------------------------

我使用 Detours和Mini-Hook-Engine来HOOK GetMessageTime都没有成功,

Detours直接返回失败,Mini-Hook-Engine虽然成功写了JMP,但在HOOK后,调用原GetMessageTime时出错了,原因是其Bridge写错了。。。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

先Copy下Mini-Hook-Engine的原理,后面我们写自己的Bridge时用到:



Let's make a real world example. If the first instructions of the function/API we want to hook are:

mov edi, edi
push ebp
mov ebp, esp
xor ecx, ecx

They will be replaced by our:

00400000 jmp our_code
00400005 xor ecx, ecx

Our bride will look like this:

mov edi, edi
push ebp
mov ebp, esp
jmp 00400005
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我们来看看GetMessageTime的汇编代码:

// GetMessageTime入口原始汇编指令
7608F600 6A 0A                push        0Ah  
7608F602 E8 C7 17 FE FF       call        76070DCE  
7608F607 C3                   ret  
7608F608 81 C2 58 07 00 00    add         edx,758h  
7608F60E E9 B0 27 FE FF       jmp         76071DC3  
7608F613 50                   push        eax  
7608F614 6A 00                push        0
...


// 使用Mini Hook-Engine后,GetMessageTime入口汇编指令被修改如下
7608F600 FF 25 06 F6 08 76    jmp         dword ptr ds:[7608F606h]  
7608F606 18 AB 5B 0F 58 07    sbb         byte ptr [ebx+7580F5Bh],ch  
7608F60C 00 00                add         byte ptr [eax],al  
7608F60E E9 B0 27 FE FF       jmp         76071DC3  
7608F613 50                   push        eax  
7608F614 6A 00                push        0  
...


// Mini Hook-Engine对GetMessageTime的Bridge如下
001E0000 EB 05                jmp         001E0007  
001E0002 90                   nop  
001E0003 90                   nop  
001E0004 90                   nop  
001E0005 90                   nop  
001E0006 90                   nop  
001E0007 FF 25 40 0C E6 74    jmp         dword ptr ds:[74E60C40h]  
001E000D FF 25 13 00 1E 00    jmp         dword ptr ds:[1E0013h]  
001E0013 19 11                sbb         dword ptr [ecx],edx  
001E0015 E6 74                out         74h,al  
001E0017 6A 0A                push        0Ah  			// GetMessageTime原入口第一条指令		
001E0019 E8 C7 17 FE FF       call        001C17E5  // 这里错了。。。,原函数是:call 76070DCE 
001E001E C3                   ret  
001E001F 81 C2 58 07 00 00    add         edx,758h  
001E0025 FF 25 2B 00 1E 00    jmp         dword ptr ds:[1E002Bh]  
001E002B 0E                   push        cs  
001E002C ??                   db          f6h  
001E002D 08 76 00             or          byte ptr [esi],dh  
001E0030 00 00                add         byte ptr [eax],al  
001E0032 00 00                add         byte ptr [eax],al  
001E0034 00 00                add         byte ptr [eax],al  
001E0036 00 00                add         byte ptr [eax],al 

----------------------------------------------------------------------------------------------------------------------

知道了错误原因,我继续使用Mini Hook-Engine来HOOK GetMessageTime,不过Bridge我们得自己写:

我的Bridge代码如下:

VOID  __declspec(naked) GetMessageTime_Bridge(VOID)
{
    _asm
    {
		push  0xA
		//call  g_iGetMessageTimeCallAddr // 这里动态写入,先用5个nop来占位
		nop
		nop
		nop
		nop
		nop
		ret
		//jmp iJmpAddr // 这里动态写入,先用5个nop来占位
		nop
		nop
		nop
		nop
		nop
    }
}


我们的GetMessageTime, HOOK后,GetMessageTime会跳到这里:

LONG WINAPI MyGetMessageTime(VOID)
{
	// 调用原函数
	LONG liRet = 0;
	LONG (WINAPI *pGetMessageTime)(VOID) = NULL;
	//pGetMessageTime = (LONG (__stdcall *)(void))NtHookEngine_GetOriginalFunction((ULONG_PTR)MyGetTickCount);
	pGetMessageTime = (LONG (__stdcall *)(void))GetMessageTime_Bridge;
	if (pGetMessageTime != NULL)
	{
		liRet = pGetMessageTime();
	}

	return liRet;
}

最重要的HOOK GetMessageTime函数:

VOID Hook_GetMessageTime(VOID)
{
	// E8 C7 17 FE FF       call        76070DCE 
	DWORD dwOldProtect = 0;
	VirtualProtect(TrueGetMessageTime, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

	// 这里得到C7 17 FE FF
	int iCallAddr = 0;
	memcpy((VOID*)&iCallAddr, (VOID*)((INT)TrueGetMessageTime + 3), 4);	

	// 将C7 17 FE FF还原成76070DCE
	// ((int)TrueGetMessageTime + 7) == CALL的下一行地址
	iCallAddr = iCallAddr + ((int)TrueGetMessageTime + 7);  

	VirtualProtect(TrueGetMessageTime, 5, dwOldProtect, NULL);

	// 修正我们的GetMessageTime_Bridge
	int iAddr = (int)GetMessageTime_Bridge;
	byte bData[5] = {0};
	byte bKey[5]  = {0x90, 0x90, 0x90, 0x90, 0x90};
	while(true)
	{
		// 查找那5个nop指令的首地址
		VirtualProtect((VOID*)iAddr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
		memcpy(bData, (VOID*)iAddr, 5);
		VirtualProtect((VOID*)iAddr, 5, dwOldProtect, NULL);
		if (memcmp(bData, bKey, 5) != 0)
		{
			iAddr ++;
			continue;
		}

		
		VirtualProtect((VOID*)iAddr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

		// 写入 call     76070DCE 
		// 目标地址 - 当前指令地址的下个指令地址 = 距离
		*((byte*)iAddr) = 0xE8;
		*((int*)(iAddr + 1)) = iCallAddr - (iAddr + 5);

		// 写入 jmp 7608F60C
		// 目标地址 - JMP指令所在地址 - 5 = JMP地址
		*((byte*)(iAddr + 6)) = 0xE9;
		*((int*)(iAddr + 7)) =  ((int)TrueGetMessageTime + 0xC) - (iAddr + 6) - 5;

		VirtualProtect((VOID*)iAddr, 5, dwOldProtect, NULL);
		break;
	}

	// HOOK GetMessageTime
	NtHookEngine_Hook((ULONG_PTR)TrueGetMessageTime, (ULONG_PTR)&MyGetMessageTime);
}

---------------------------------------------------------------------------------------------------

此次收获:

1. 懂得了Bridge的写法和用法,原来函数只是一个地址,我们强制转换就可以了:

LONG (WINAPI *pGetMessageTime)(VOID) = NULL;
pGetMessageTime = (LONG (__stdcall *)(void))GetMessageTime_Bridge;


2. 懂得了CALL 后面的地址的计算方法:

// 目标地址(76070DCE) - 当前CALL指令的下个地址 = CALL后面的4个字节数据:E8 C7 17 FE FF
*((byte*)iAddr) = 0xE8;
*((int*)(iAddr + 1)) = iCallAddr - (iAddr + 5);









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

friendan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值