大家好,这里是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( "\n按下回车键,将会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( "\n按下回车键 禁用当前的hook(也就是还原MessageBeep函数,调用的时候就是原本的MessageBeep函数了):" );
Console.ReadLine();
hook.ThreadACL.SetExclusiveACL( new int [] { 0 });
//再次调用再次调用PlayMessageBeep 这个是原生的了
MessageBeep(0xFFFFFFFF);
Console.Write( "\n按下回车键 卸载hook并退出" );
Console.ReadLine();
hook.Dispose();
}
}}
|
五.后记
其实,说起来就是想写个hook程序scoket 发包 接包的软件,然后历程几天,终于还是写了出来,但是还是对代码的整体,没有比较好的把握,下一篇如果有的话应该就是远程注入的教程了,关于recv和send hook的教程。