本帖最后由 TSIR 于 2018-10-5 11:48 编辑
大家好,这里是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。
四.代码编写
我们按照上面的一步一步的写(核心)第一步,找函数[C#] 纯文本查看 复制代码 IntPtr messageBeep = EasyHook.LocalHook.GetProcAddress("user32.dll", "MessageBeep"); 第二步,匹配委托[C#] 纯文本查看 复制代码 [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
delegate bool MessageBeepDelegate(uint uType); 第三步,写hook[C#] 纯文本查看 复制代码 //声明一个用来替换替换原来MessageBeep的函数 也就是hook函数
static private bool MessageBeepHook(uint uType)
{
Console.WriteLine();
Console.WriteLine("----我们自定义的MessageBeepHook函数,- -无声MessageBeep----");
return true;
} 第四步,注入hook[C#] 纯文本查看 复制代码 var hook = EasyHook.LocalHook.Create(messageBeep, messageBeepDelegate, null);
然后是通篇的代码,里面只加了一些修饰,或者其他的胶水代码粘连。
对了,如果需要体验的话,用vs2015新建一个控制台项目然后复制代码到主文件,添加NUGet 在里面搜索 easyHook 导入安装就行了,so easy!
[C#] 纯文本查看 复制代码 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的教程。
如果觉得有帮助,好评给个赞,第一次写帖子,需要动力哈,拜了个拜,溜了溜了! |