mov edi,edi

mov edi,edi - hook api
系统: windows xp

查看系统函数的反汇编代码时会发现开头有个"mov edi,edi"(2字节),再往前则是5个nop指令(当然这不会引人注意),可是"mov edi,edi"有什么用了.

上网搜索"mov edi,edi",结果让人惊奇,据说系统函数都添加了这段"无用"的代码,为的是Hot Patching,详细内容请自行搜索.

通过改写代码来挂接API时,一般是移动前几个字节加入jump指令,对于"mov edi,edi"开头的函数也习惯性的这样处理.可现在情况不同了,这7个字节提供了方便,文中提到了更好的办法,在mov指令处(即函数开始处)使用一个短跳转指令(2字节)到上面的nop位置,这5个字节可以插入长跳转或call到远处.

想做个什么,现在这类型的函数修改都可以这样千篇一律,那我要做一个可以hook所有这些函数的接口,之后在自己的dll内根据函数地址分流. 以后想要hook某api只要修改这7个字节,就可以在我们自己的dll函数内收到信息(包括原函数地址,参数列表),还可以选择是否执行原函数.

实现包含几部分
1. 修改待hook api地址处的7个字节(5个nop和mov edi,edi),呼叫接口函数,call偏移为(接口函数地址-原函数地址)
2. 接口函数的编写,需要取得原函数地址,参数列表后呼叫分流函数
3. 分流函数,根据函数地址区分函数,做后续处理

====================================================================
api开头修改,以MessageBoxA为例

77D50506      90            NOP
77D50507      90            NOP
77D50508      90            NOP
77D50509      90            NOP
77D5050A      90            NOP
77D5050B >    8BFF          MOV EDI,EDI
77D5050D /. 55            PUSH EBP

77D5050B为MessageBoxA的地址,改为:

77D50506      E8 3527B304   CALL kernel32.7C882C40 ;接口函数
77D5050B > ^ EB F9         JMP SHORT USER32.77D50506
77D5050D /. 55            PUSH EBP
====================================================================
接口函数,写入kernel32.dll,windows下都会加载
将以下汇编的字节码写入kernel32的.text段的尾部,可能大家xp版本不一样会有些差别

7C882C40    83EC 08         SUB ESP,8                          ; 保存fRet,addEspNum
7C882C43    E8 38000000     CALL kernel32.7C882C80             ; 获取HookFun的地址
7C882C48    85C0            TEST EAX,EAX
7C882C4A    75 08           JNZ SHORT kernel32.7C882C54
7C882C4C    83C4 08         ADD ESP,8
7C882C4F    830424 02       ADD DWORD PTR SS:[ESP],2           ; 返回到原函数地址+2
7C882C53    C3              RETN
7C882C54    8D4C24 04       LEA ECX,DWORD PTR SS:[ESP+4]
7C882C58    54              PUSH ESP                           ; addEspNum
7C882C59    51              PUSH ECX                           ; fRet
7C882C5A    8D4C24 18       LEA ECX,DWORD PTR SS:[ESP+18]
7C882C5E    51              PUSH ECX                           ; args
7C882C5F    8B4C24 14       MOV ECX,DWORD PTR SS:[ESP+14]
7C882C63    51              PUSH ECX                           ; 原函数地址
7C882C64    FFD0            CALL EAX
7C882C66    8B4C24 04       MOV ECX,DWORD PTR SS:[ESP+4]       ; fRet
7C882C6A    85C9            TEST ECX,ECX
7C882C6C ^ 74 DE           JE SHORT kernel32.7C882C4C
7C882C6E    8B5424 0C       MOV EDX,DWORD PTR SS:[ESP+C]       ; 原函数返回地址
7C882C72    8B0C24          MOV ECX,DWORD PTR SS:[ESP]         ; addEspNum
7C882C75    8D640C 10       LEA ESP,DWORD PTR SS:[ESP+ECX+10]
7C882C79    FFE2            JMP EDX                            ; 修改ESP后,跳回去,不用ret
7C882C7B    90              NOP
7C882C7C    90              NOP
7C882C7D    90              NOP
7C882C7E    90              NOP
7C882C7F    90              NOP
7C882C80    A1 0472887C     MOV EAX,DWORD PTR DS:[7C887204]    ; 保存 fun,位于.data段
7C882C85    85C0            TEST EAX,EAX
7C882C87    74 01           JE SHORT kernel32.7C882C8A
7C882C89    C3              RETN
7C882C8A    A1 0072887C     MOV EAX,DWORD PTR DS:[7C887200]    ; 保存 hModule
7C882C8F    85C0            TEST EAX,EAX
7C882C91    75 14           JNZ SHORT kernel32.7C882CA7
7C882C93    68 212C887C     PUSH kernel32.7C882C21             ; ASCII "myHookFun.dll"
7C882C98    E8 DAF0F7FF     CALL kernel32.LoadLibraryA
7C882C9D    A3 0072887C     MOV DWORD PTR DS:[7C887200],EAX
7C882CA2    85C0            TEST EAX,EAX
7C882CA4    75 01           JNZ SHORT kernel32.7C882CA7
7C882CA6    C3              RETN
7C882CA7    68 302C887C     PUSH kernel32.7C882C30             ; ASCII "HookFun"
7C882CAC    50              PUSH EAX
7C882CAD    E8 767FF8FF     CALL kernel32.GetProcAddress
7C882CB2    A3 0472887C     MOV DWORD PTR DS:[7C887204],EAX
7C882CB7    C3              RETN

7C882C20 00 6D 79 68 6F 6F 6B 61 70 69 2E 64 6C 6C 00 00 .myHookFun.dll
7C882C30 48 6F 6F 6B 46 75 6E 00 00 00 00 00 00 00 00 90 HookFun
7C882C40 83 EC 08 E8 38 00 00 00 85 C0 75 08 83 C4 08 83
7C882C50 04 24 02 C3 8D 4C 24 04 54 51 8D 4C 24 18 51 8B
7C882C60 4C 24 14 51 FF D0 8B 4C 24 04 85 C9 74 DE 8B 54
7C882C70 24 0C 8B 0C 24 8D 64 0C 10 FF E2 90 90 90 90 90
7C882C80 A1 04 72 88 7C 85 C0 74 01 C3 A1 00 72 88 7C 85
7C882C90 C0 75 14 68 21 2C 88 7C E8 DA F0 F7 FF A3 00 72
7C882CA0 88 7C 85 C0 75 01 C3 68 30 2C 88 7C 50 E8 76 7F
7C882CB0 F8 FF A3 04 72 88 7C C3

以上地址为内存中的虚拟地址,7c882c20的文件地址为82020h(我的文件是这样)
====================================================================
分流函数,自己编写的dll,文件名"myHookFun.dll",导出函数"HookFun"

typedef int (__stdcall *PROC4)(int,int,int,int);

//proc 原函数地址; args 参数列表; fRet 非0返回上级,否则继续执行原函数; addEspNum 退栈数量
//如需执行原函数应该使用proc+2,从"mov edi,edi"之后执行
__declspec(dllexport) int __stdcall HookFun(PROC proc,int *args,BOOL *fRet,int *addEspNum)
{
if (proc==(PROC)0x77D5050B) //MessageBoxA的地址,暂时直接指明
{
   PROC4 p4=(PROC4)((BYTE*)proc+2);
   *fRet=1;
   *addEspNum=16;   //不从原函数返回的话要告知退栈数量,调用者退栈的(__cdecl)设为0
   return p4(args[0],args[1],(int)"HookFun",args[3]); //修改对话框的标题
}
*fRet=0;
return 0;
}
这个HookFun只是个示例
====================================================================

我修改了kernel32.dll文件,在dos下覆盖了原来的(之前有备份),新添加的汇编码只在修改了api开头的字节后才会被调用.测试程序可通过od启动,或者使用winHex修改待hook程序的进程内存(就7个字节,注意call地址的计算).
动态修改所有的内存也行(包括kernel32),接口函数也可以放在其它地方,甚至和分流函数合并,都放入自己的dll也行,注入dll就可以了.

posted @ 2012-07-06 14:04  特洛伊人  阅读(2881)  评论(0编辑  收藏  举报