Hook
概念
每个Hook都有一个相关的指针列表,后加入的Hook再链表的开始,先加入的在链表的尾部
即后加入先获得控制权
Hook 原理
原本的流程
hook后的流程
就是在执行MessageBoxA的API
时,先jmp
到我的My_MessageBox
,执行完之后再return
回到MessageBoxA
继续执行
利用这个技术,我们可以监控API,比如应用程序会调用loadLibrary,那我们把它Hook了,把Dll路径改成我们的,那加载的就是我们的dll了,当然 Hook的API很多,因为只要是Windows的API都能HOOK
Hook的思路
- 获取
MessageBoxA
函数的地址 - 修改函数的内存保护属性(便于写入
jmp
的二进制) - 找到
MessageBoxA
前的5个字节的位置,写入jmp
Hook实例
手动尝试hook一个程序
源码
编译环境:win10 1909+gcc
#include <windows.h>
int main (){
int a,b;
a=3;
b=2;
int c=a+b;
char tmp[8];
memset(tmp,0,8);
itoa(5,tmp,10);
MessageBox(NULL,tmp,"Hook",0);
return 0;
}
正常情况会弹出一个弹窗,标题栏写着Hook,下面写着5
我们尝试用hook把5改成0
Step1:
ida打开a.exe,找到主函数部分,可以看到代码的大概位置
.text:00401410 ; __unwind {
.text:00401410 lea ecx, [esp+4]
.text:00401414 and esp, 0FFFFFFF0h
.text:00401417 push dword ptr [ecx-4]
.text:0040141A push ebp
.text:0040141B mov ebp, esp
.text:0040141D push ecx
.text:0040141E sub esp, 34h
.text:00401421 call ___main
.text:00401426 mov [ebp+var_C], 3
.text:0040142D mov [ebp+var_10], 2
.text:00401434 mov edx, [ebp+var_C]
.text:00401437 mov eax, [ebp+var_10]
.text:0040143A add eax, edx
.text:0040143C mov [ebp+var_14], eax
.text:0040143F mov dword ptr [esp+8], 8 ; size_t
.text:00401447 mov dword ptr [esp+4], 0 ; int
.text:0040144F lea eax, [ebp+Text]
.text:00401452 mov [esp], eax ; void *
.text:00401455 call _memset
.text:0040145A mov dword ptr [esp+8], 0Ah ; int
.text:00401462 lea eax, [ebp+Text]
.text:00401465 mov [esp+4], eax ; char *
.text:00401469 mov eax, [ebp+var_14]
.text:0040146C mov [esp], eax ; int
.text:0040146F call _itoa
.text:00401474 mov dword ptr [esp+0Ch], 0 ; uType
.text:0040147C mov dword ptr [esp+8], offset Caption ; "Hook"
.text:00401484 lea eax, [ebp+Text]
.text:00401487 mov [esp+4], eax ; lpText
.text:0040148B mov dword ptr [esp], 0 ; hWnd
.text:00401492 call _MessageBoxA@16
.text:00401497 sub esp, 10h
.text:0040149A mov eax, 0
.text:0040149F mov ecx, [ebp+var_4]
.text:004014A2 leave
.text:004014A3 lea esp, [ecx-4]
.text:004014A6 retn
.text:004014A6 ; } // starts at 401410
.text:004014A6 _main endp
正常来说,我们可以用patch来改,这里尝试hook的方式
在赋值3,2
完成之后,写入jmp指令,随便jmp到一块不影响程序,且在程序中的地址上(不一定要紧跟在jmp后面,只要在调用MessageBox
函数之前随便的五个字节,要是没有刚好5个字节的指令,可以凑到至少5个,多的就nop
掉),jmp指令破坏掉的指令要在jmp到的我的hook中修复,这样才能不影响程序原本的运行
Step2:
od定位到相应位置,双击指令,开始修改(也可以在ida中patch修改)eb
我选对程序无影响的地址401305
这块地址
我选择在add eax, edx
后插入jmp 00401305
,因为这条汇编是5个字节,会覆盖掉两条汇编指令,变成了
所以在我的hook,也就是00401305处我要补上
解释一下
mov eax,0x0 ;jmp 来之前eax中的值是5,给覆盖成0
mov dword ptr ss:[ebp-0x14],eax ;这是照着原来的写法,把jmp时覆盖的指令补上
mov dword ptr ss:[esp+0x8],0x8 ;同上
jmp a.00401447 ;这是跳回原来的地方继续执行
step3
保存:右键-->复制到课自行文件-->全部修改
如果发现报错,可执行文件中无法确定数据。首先不管报错,直接保存文件,看看是否可运行,不行考虑换个离源代码位置近的地方去添加跳转代码,再不行就考虑增加区块
Hook实例2
具体参考
HOOK API入门之Hook自己程序的MessageBoxW
原理
windows 系统函数都是以dll封装起来的,程序应用到系统函数的时候,要先将dll加载到进程空间。我们只要在我们要hook程序调用dll之前,jmp
到我们自己构造的dll中,就可以达到效果
几个要点:
-
怎么让被hook的程序加载我们的dll
采用上面文章讲到的方法,调用windows现成的鼠标钩子,响应到所有鼠标点击事件,然后载入我的dll。鼠标钩子只是用来载入我的dll到被hook的程序,做事的还是我的dll
-
怎么加载完成后修复原来被我们的部分
这个方法有很多,可以在我的dll中去修复,先记录下原来的数据,在执行完我们dll的主要内容后再把数据恢复,跳转回去的时候就不会再执行jmp到我们dll了。也可以像上一个实例一样,直接在我定义的dll执行,在调会主函数,再执行进入下个dll
-
怎么在加载正常dll前获取地址
可以调用GetProcAddress函数,来获取dll的入口地址
操作……还没操作,之后再补