HOOK GetMessageTime有感

来源:互联网 发布:田岛美工刀架 编辑:程序博客网 时间:2024/06/04 01:14

参考文章: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, edipush ebpmov ebp, espxor ecx, ecx

They will be replaced by our:

00400000 jmp our_code00400005 xor ecx, ecx

Our bride will look like this:

mov edi, edipush ebpmov ebp, espjmp 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来占位nopnopnopnopnopret//jmp iJmpAddr // 这里动态写入,先用5个nop来占位nopnopnopnopnop    }}


我们的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 FFint 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_Bridgeint 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 GetMessageTimeNtHookEngine_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);









0 0
原创粉丝点击