大家好,这里是TSIR,当大牛们,都在讨论如何去hook的时候,哪种hook方式比较方便,我却在为hook是什么而发愁,于是决定写下这篇帖子,一是作为自己学习的笔记,二是给和我一样存在困惑的哥们,抛个砖,引个玉。当然了,毕竟是小白,里面的言论可能会出现错误,望大佬斧正(本文参考了easyHook官方教程第一章,奈若何,官方的教程有点难懂,故有此篇)。
一.什么是hook
首先说下我理解的hook,简而言之就是偷天换日之术,假如程序中有一个sayHello的函数,它会输出字符串 ”hello”,那么我们也定义一个sayHello(当然名字为了区分可能叫做sayHelloHook,这样一来感觉高大上多了),然后让它返回字符串 “你好”。再经过各种代码,一顿操作,程序里面调用sayHello的时候 就会直接执行我们的sayHelloHook函数。当然,hook可以操作的事情并非这些,还有很多,具体就靠大家的奇思妙想了。
二.开始学习之前
我用的是easyHook,语言采用C#,系统win10,代码编辑器VS2015。别问我为什么,因为用他们写代码贼鸡儿简单,方便小白。三.正文(序言)我们先大致的思考一个小问题,如何hook,虽然我们有神器easyHook,但是他总要有个步骤,声控写代码是不可能的(我想hook这个函数,嗯 还有这个函数,不对不对还有那个函数)。一般而言分为四个步骤,我提炼出来的话就是: EasyHook函数四步走
- 找函数
- 匹配委托
- 编写hook函数
- 注入hook(这里包含了装载hook和卸载hook)
我们来解释下,首先第一步骤,我们应该了解,windows下的很多api,都是已经写好了的,我们程序中写的很多函数都是依靠他们作为底层来完成的,我们直接拿来用就行,就我们的程序而言,就是哪个动态链接库(这里写了一堆一堆的函数),里面的哪个函数,可以做什么。所以第一步,我们需要知道这个函数在哪里,其实也就是easyHook需要知道,他要hook哪个函数的地址。第二步,匹配委托,这个可能有点不好理解,说实在的我现在对委托还是一头雾水,但是简单的理解就是,函数指针(再通俗点就是我们编写函数的地址),要替换函数,要知道替换函数的地址,还要知道我们自己写的函数地址才能实现注入,注意这里写委托一定要和欲hook的函数参数和返回值一样,否则,就会出现大问题,我知道你不想搞一个大事情,所以,老老实实按照原型写委托吧。第三步,编写我们自己的函数就是上文中说到的sayHelloHook,我们自己实现函数要做哪些事情,最后别忘了一定要和原函数,参数,返回值对应。第四步,最轻松的一步,由easyHook替我们完成,他会自己实现函数的替换,注入啥的。我们只需要声明调用就ok。
四.代码编写
我们按照上面的一步一步的写(核心)第一步,找函数
|
1
|
IntPtr messageBeep = EasyHook.LocalHook.GetProcAddress("user32.dll", "MessageBeep"); |
第二步,匹配委托
|
1
2
|
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] delegate bool MessageBeepDelegate(uint uType); |
第三步,写hook
|
1
2
3
4
5
6
7
|
//声明一个用来替换替换原来MessageBeep的函数 也就是hook函数 static private bool MessageBeepHook(uint uType) { Console.WriteLine(); Console.WriteLine("----我们自定义的MessageBeepHook函数,- -无声MessageBeep----"); return true; } |
第四步,注入hook
|
1
|
var hook = EasyHook.LocalHook.Create(messageBeep, messageBeepDelegate, null); |
然后是通篇的代码,里面只加了一些修饰,或者其他的胶水代码粘连。
对了,如果需要体验的话,用vs2015新建一个控制台项目然后复制代码到主文件,添加NUGet 在里面搜索 easyHook 导入安装就行了,so easy!
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
using System;using System.Runtime.InteropServices;namespace easyHook{ class Program { //C#中要调用MessageBeep函数必须这样写,没辙 [DllImport("user32.dll")] static extern bool MessageBeep(uint uType); //二.----------------------匹配委托------------------------------ [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] delegate bool MessageBeepDelegate(uint uType); //声明一个用来替换替换原来MessageBeep的函数 也就是hook函数 //三.----------------------编写hook函数------------------------------ static private bool MessageBeepHook(uint uType) { Console.WriteLine(); Console.WriteLine("----我们自定义的MessageBeepHook函数,- -无声MessageBeep----"); return true; } static void Main(string[] args) { //一.----------------------找函数------------------------------ IntPtr messageBeep = EasyHook.LocalHook.GetProcAddress("user32.dll", "MessageBeep"); MessageBeepDelegate messageBeepDelegate = new MessageBeepDelegate(MessageBeepHook); Console.WriteLine("1.当程序载入的时候就调用一次MessageBeep函数,这里的MessageBeep还没有被hook"); MessageBeep(0xFFFFFFFF); Console.Write("
按下回车键,将会hook MessageBeep(也就是程序调用MessageBeep时,会替换成我们自定义的MessageBeepHook函数):"); Console.ReadLine(); // 创建local hook 使用我们自己定义的 MessageBeepDelegate and MessageBeepHook 函数 //四.----------------------创建hook------------------------------ var hook = EasyHook.LocalHook.Create(messageBeep, messageBeepDelegate, null); hook.ThreadACL.SetInclusiveACL(new int[] { 0 }); MessageBeep(0xFFFFFFFF); Console.Write("
按下回车键 禁用当前的hook(也就是还原MessageBeep函数,调用的时候就是原本的MessageBeep函数了):"); Console.ReadLine(); hook.ThreadACL.SetExclusiveACL(new int[] { 0 }); //再次调用再次调用PlayMessageBeep 这个是原生的了 MessageBeep(0xFFFFFFFF); Console.Write("
按下回车键 卸载hook并退出"); Console.ReadLine(); hook.Dispose(); } }} |
五.后记
其实,说起来就是想写个hook程序scoket 发包 接包的软件,然后历程几天,终于还是写了出来,但是还是对代码的整体,没有比较好的把握,下一篇如果有的话应该就是远程注入的教程了,关于recv和send hook的教程。