大家好,這里是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的教程。