最近看了《加密与解密》,跟着大佬们的思路学习了Hook相关知识,如理解有误请不吝赐教,以免误导他人。
API函数都保存在操作系统提供的DLL文件中,当在程序中调用某个API函数并运行程序后,程序会隐式地将API函数所在的DLL文件加载入内存中,这样,程序就会像调用自己的函数一样调用API。Inline Hook这种方法是在程序流程中直接进行嵌入jmp指令来改变流程的。
简而言之,就是将函数开头修改为jmp指令,跳转到我们自定义的函数上去。
首先用CreateProcessA API写一个测试程序,功能很简单,程序启动后,按下任意键,调用CreateProcessA创建进程,为了直观这里是直接弹一个计算器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <windows.h>
#include <stdio.h>
#include "createprocess.h"
#define EXE_PATH "C:\\Windows\\System32\\calc.exe"
BOOL
CreateProcessR(char
*
szExePath) {
SECURITY_ATTRIBUTES psa
=
{
0
};
SECURITY_ATTRIBUTES tsa
=
{
0
};
STARTUPINFO si
=
{ sizeof(si) };
PROCESS_INFORMATION pi;
BOOL
Ret;
Ret
=
CreateProcessA(szExePath, NULL, &psa, &tsa, false,
0
, NULL, NULL, &si, &pi);
/
/
TerminateProcess(pi.hProcess,
0
);
/
/
结束进程
return
Ret;
}
int
main(
int
argc,char
*
argv[]) {
system(
"pause"
);
CreateProcessR(EXE_PATH);
return
0
;
}
|
下面就HOOK CreateProcessA:
将生成的EXE拖到Xdbg中,定位到CreateProceessA这里,在调用CreateProcessA前有一段汇编代码:
mov edi edi,
push ebp
mov ebp,esp
16进制:8B FF 55 8B EC
HOOK的话肯定要准备一个自定义的函数, call addr ,假如它的地址为12345678,那么我们HOOK的操作就是将上面的命令替换为:JMP 12345678,也就是e9 addr。
解除的HOOK的话就是将替换的字节恢复。
Inline Hook流程
代码如下,关键步骤已注释:
1
2
3
4
5
6
7
8
9
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
|
/
/
Myhook.cpp
#include "Myhook.h"
CHOOK::CHOOK()
{
MyFuncaAddress
=
NULL;
memset(MyOldBytes,
0
,
5
);
memset(MyNewBytes,
0
,
5
);
}
CHOOK::~CHOOK()
{
UnHOOK();
MyFuncaAddress
=
NULL;
memset(MyOldBytes,
0
,
5
);
memset(MyNewBytes,
0
,
5
);
}
BOOL
CHOOK::Hook(LPSTR pszModuleName, LPSTR pszFuncName, PROC pfnHookFunc)
{
HMODULE hModule
=
GetModuleHandle(pszModuleName);
MyFuncaAddress
=
(PROC)GetProcAddress(hModule, pszFuncName);
if
(MyFuncaAddress
=
=
NULL) {
return
FALSE;
}
/
/
读地址 将原来的
5
个字节的数据保存
ReadProcessMemory(GetCurrentProcess(), MyFuncaAddress, MyOldBytes,
5
,
0
);
/
/
JMP ADDRESS JMP
123456789
E9
MyNewBytes[
0
]
=
'\xE9'
;
*
(DWORD
*
)(MyNewBytes
+
1
)
=
(DWORD)pfnHookFunc
-
(DWORD)MyFuncaAddress
-
5
;
WriteProcessMemory(GetCurrentProcess(), MyFuncaAddress, MyNewBytes,
5
,
0
);
return
TRUE;
}
VOID CHOOK::UnHOOK()
{
if
(MyFuncaAddress !
=
NULL) {
WriteProcessMemory(GetCurrentProcess(), MyFuncaAddress, MyOldBytes,
5
,
0
);
}
return
VOID();
}
BOOL
CHOOK::ReHook()
{
if
(MyFuncaAddress !
=
NULL) {
WriteProcessMemory(GetCurrentProcess(), MyFuncaAddress, MyNewBytes,
5
,
0
);
}
return
0
;
}
|
1
2
3
4
5
6
7
8
9
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
55
56
57
58
59
60
61
62
63
64
|
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "Myhook.h"
CHOOK MyHookObject;
BOOL
WINAPI
MyCreateProcessA(
_In_opt_ LPCSTR lpApplicationName,
_Inout_opt_ LPSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_
BOOL
bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOA lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
)
{
if
(MessageBox(NULL,
"是否拦截"
,
"Notice"
, MB_YESNO)
=
=
IDYES)
{
MessageBox(NULL,
"程序已拦截"
,
"Notice"
, MB_OK);
}
else
{
MyHookObject.UnHOOK();
CreateProcessA(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
MyHookObject.ReHook();
}
return
true;
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MyHookObject.Hook((LPSTR)
"Kernel32.dll"
, (LPSTR)
"CreateProcessA"
,(PROC)MyCreateProcessA);
break
;
case DLL_THREAD_ATTACH:
break
;
case DLL_THREAD_DETACH:
break
;
case DLL_PROCESS_DETACH:
MyHookObject.UnHOOK();
break
;
}
return
TRUE;
}
|
效果如下:
IAT Hook是 Address Hook的一种方式,顾名思义就是通过修改函数的地址进行Hook。
IAT(Import Address Table,输入表)是PE中的一种结构,如图:
再用一张图来理解导入表结构:
需要注意的是:因为IAT具体指某个PE模块的IAT,所以他的作用范围只针对被Hook的模块,且必须在以静态链接的方式调用API时才会被Hook,所以它的作用范围只针对被Hook的模块,且必须以静态链接的方式调用API时才会被Hook,在使用Loadlibrary或GetProcAddress进行动态调用时不受影响。要想对已加载的所有模块起作用,就必须遍历进程内的所有模块,对目标API进行Hook。
现在开始Hook,这里是通过注入来Hook其他的程序,将代码写在DLL里面
为了保证原来的函数不受影响,我们先将要被Hook的函数的地址保存下来:
1
|
OldMesageBoxA
=
(FncMessageBoxA)GetProcAddress(GetModuleHandleA(
"user32.dll"
),
"MessageBoxA"
);
|
然后就是解析PE文件,获取函数导入表中的函数地址表,并替换:
解析PE文件前面已经学习过了,下面过程直接走一遍:
1
2
|
PIMAGE_DOS_HEADER pDosHeader
=
(PIMAGE_DOS_HEADER)GetModuleHandleA(NULL);
/
/
当传入参数为NULL时,获取的是PE文件的imagebase,通过类型强制转换就获取到了dos_header
|
1
|
PIMAGE_NT_HEADERS pNtHeader
=
(PIMAGE_NT_HEADERS)((DWORD)pDosHeader
+
pDosHeader
-
>e_lfanew);
|
pDosHeader->e_lfanew的数据类型为DWORD,前面定义了pDosHeader的数据类型为PIMAGE_DOS_HEADER,要和pDosHeader相加需将pDosHeader类型转换为DWORD,最后再将得到的结果转换为PIMAGE_NT_HEADERS。
获取扩展头
1
2
|
PIMAGE_OPTIONAL_HEADER pOptionalHeader
=
(PIMAGE_OPTIONAL_HEADER)&pNtHeader
-
>OptionalHeader;
/
/
扩展头是NT头的一个成员
|
从扩展头中获取数据目录表中的导入表
获取导入表前,要先找到它的偏移:
1
|
DWORD dwImportTableOffset
=
pOptionalHeader
-
>DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
/
/
获取导入表偏移
|
获取导入表:
1
|
PIMAGE_IMPORT_DESCRIPTOR pImportTable
=
(PIMAGE_IMPORT_DESCRIPTOR)(DWORD)pDosHeader
+
dwImportTableOffset;
|
有多个导入表结构,所以要遍历每个导入表:
因为导入表是依靠一个全零的结构来判断结束的,所以我们就采取对比pImportTable->Characteristics为0和pImportTable->FirstThunk为NULL时,来判断结束,然后在其中判断函数地址是否与我们所得到的原函数地址一致,如果一致说明找到了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
DWORD
*
pFirstThunk;
/
/
遍历导入表结构
while
(pImprotTable
-
>Characteristics && pImprotTable
-
>FirstThunk !
=
NULL)
{
pFirstThunk
=
(DWORD
*
)(pImprotTable
-
>FirstThunk
+
(DWORD)pDosHeader);
while
(
*
(DWORD
*
)pFirstThunk !
=
NULL)
{
/
/
如果相当了,就说明当前的数组元素就是我们要找的函数地址表中的函数地址
if
(
*
(DWORD
*
)pFirstThunk
=
=
(DWORD)OldMesageBoxA)
{
DWORD oldProtected;
VirtualProtect(pFirstThunk,
0x1000
, PAGE_EXECUTE_READWRITE, &oldProtected);
DWORD dwFuncAddr
=
(DWORD)MyMessageBoxA;
memcpy(pFirstThunk, (DWORD
*
)&dwFuncAddr,
4
);
VirtualProtect(pFirstThunk,
0x1000
, oldProtected, &oldProtected);
}
pFirstThunk
+
+
;
}
pImprotTable
+
+
;
}
|
最后,为了保证程序的稳定,我们需要构造与被 HOOK 的函数一样结构的函数,同时为了保证原函数功能的正常运行,再定义一个函数指针,在自己的功能执行完成后,调用原来程序正常的功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
typedef
int
(WINAPI
*
FncMessageBoxA)(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType);
FncMessageBoxA OldMesageBoxA
=
NULL;
int
WINAPI MyMessageBoxA(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType)
{
SECURITY_ATTRIBUTES psa
=
{
0
};
SECURITY_ATTRIBUTES tsa
=
{
0
};
STARTUPINFO si
=
{ sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessA(EXE_PATH, NULL, &psa, &tsa, false,
0
, NULL, NULL, &si, &pi);
return
0
;
}
|
要HOOK的API是MessageBoxA (X32),写一个简单的程序:
1
2
3
4
5
6
7
|
#include <windows.h>
int
main() {
system(
"pause"
);
MessageBoxA(
0
,
0
,
0
,
0
);
system(
"pause"
);
return
0
;
}
|
要达到的目的是当测试程序运行时,注入DLL,Hook住MessageBoxA,使其指向CreateProcessA api:
Hook后:
在代码编译为程序后,虚函数表就是一个固定的表了,它位于PE的.data段。在对虚函数表进行Hook时,虽然原理也是查找原函数的位置,修改页面属性,写入Detour函数这样的过程,但是虚函数有些特殊。
同样是Hook地址,它不能像IAT Hook那样直接定义一个函数来替换目标函数,而必须把它定义为类的成员函数。我们知道面向对象的三要素:封装、继承、多态 。在多态里有类特殊的是虚函数(以virtual修饰), 32位系统下,对象里有4个字节保存虚表的数组,其值为每一项虚函数的地址。
针对虚函数的HOOK就是通过保存对象中的虚表的值,针对每一项进行替换。
这次虚函数的Hook就在程序本身执行了,dll注入的方式需要对程序进行逆向分析,暂时放一下:
1
2
3
4
5
6
7
8
9
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
|
#include <stdio.h>
#include <windows.h>
class
MyClass
{
public:
MyClass();
~MyClass();
virtual void
print
();
private:
};
MyClass::MyClass()
{
}
MyClass::~MyClass()
{
}
void MyClass::
print
()
{
printf(
"hello\r\n"
);
}
void Myfunc() {
MessageBoxA(NULL,
"hello"
,
"title"
, NULL);
}
int
main() {
MyClass obj;
MyClass& vobj
=
obj;
vobj.
print
();
/
/
寻找虚表指针,虚表指针通常情况下位于对象的头
4
字节上
int
nAddr
=
*
(
int
*
)&obj;
/
/
更改内存属性
DWORD dwOldProtect
=
0
;
VirtualProtect((void
*
)nAddr,
0x100
, PAGE_EXECUTE_READWRITE,&dwOldProtect);
/
/
将自己的函数地址替换过去,前面说到了数组的值就是虚函数的地址,我们写的测试例子中就写了一个虚函数,所以其地址就是第一个值
(
*
(
int
*
)nAddr)
=
(
int
)Myfunc;
VirtualProtect((void
*
)nAddr,
0x100
, dwOldProtect,&dwOldProtect);
vobj.
print
();
system(
"pause"
);
}
|
效果如下:
热补丁Hook是微软提供的一种安全的Hook的机制,也是将函数开头修改为jmp指令,跳转到自定义的函数地址执行,和IAT Hook类似却又有不同。
以IAT Hook中的测试程序为例:
我们可以看到CreateProcessA函数的首字节为 mov edi,edi(88 FF),这句汇编意思就是将edi的值放入edi,实际上并没有什么用。
我们还看到在这个API上边有大段的int3 中断。这就给了我们一种新的Hook思路,即将前两个字节改为短跳转指令(EB E9),使其跳到函数上边五字节处,这五个字节的int3中断实际上就是一段空闲空间:
然后再将这五个字节改为长跳转指令(E9 xxxxxxxx)。这样,即使Hook失败,也不影响函数的继续执行。
这样,hook函数的时候,先是一个短跳跳到自定义的函数然后执行。如果要恢原流程,则找到函数地址并+2,直接跳过E8 F9 ,从push ebp开始执行。
然后开始写代码,有了其他Hook方式的经验,这次直接写一个通用的Hook:
1
2
3
4
5
6
7
8
9
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
55
|
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <stdio.h>
#include <Windows.h>
#define EXE_PATH "C:\\Windows\\System32\\notepad.exe"
int
WINAPI MyFunc(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType)
{
SECURITY_ATTRIBUTES psa
=
{
0
};
SECURITY_ATTRIBUTES tsa
=
{
0
};
STARTUPINFO si
=
{ sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessA(EXE_PATH, NULL, &psa, &tsa, false,
0
, NULL, NULL, &si, &pi);
return
0
;
}
BOOL
HOOK(const char
*
szModuleName, const char
*
szFuncName, PROC pfnFunc)
{
BYTE ShortJmp[
2
]
=
{
0xEB
,
0xF9
};
/
/
短跳
BYTE LongJmp[
5
]
=
{
0xE9
,
0
, };
/
/
长跳
DWORD dwOldProtect
=
0
;
FARPROC pOldFuncAddr
=
(FARPROC)GetProcAddress(GetModuleHandleA(szModuleName), szFuncName);
/
/
找原函数地址
VirtualProtect((LPVOID)((DWORD)pOldFuncAddr
-
5
),
7
, PAGE_EXECUTE_READWRITE, &dwOldProtect);
/
/
修改页保护属性
DWORD dwAddr
=
((DWORD)pfnFunc
-
(DWORD)pOldFuncAddr);
*
(DWORD
*
)(LongJmp
+
1
)
=
dwAddr;
memcpy((LPVOID)((DWORD)pOldFuncAddr
-
5
), LongJmp,
5
);
memcpy(pOldFuncAddr, ShortJmp,
2
);
VirtualProtect((LPVOID)((DWORD)pOldFuncAddr
-
5
),
7
, dwOldProtect, &dwOldProtect);
/
/
还原页保护属性
return
TRUE;
}
BOOL
APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HOOK(
"User32.dll"
,
"MessageBoxA"
, (PROC)MyFunc);
break
;
case DLL_THREAD_ATTACH:
break
;
case DLL_THREAD_DETACH:
break
;
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
|
还是以这个测试程序为例:
将生成的dll注入,hook后,当执行到MessageboxA时会劫持住它原来流程去执行CreateProcessA,如图弹出了notepad.exe:
补充:并不是所有的api都能使用HotPatch的方式进行Hook,比如CreateProcess,当然或许是我代码写错了:)
简单介绍一下windows的异常机制:
Intel在386开始的IA-32家族处理器中引入了异常和中断。中断是指外部硬件设备或异步事件引发的,而异常是由内部事件产生的,又可分为故障,陷阱和终止三类。故障和陷阱是可恢复的,终止是不可恢复的,如果出现了了终止异常,则需要重启操作系统解决。
Windows中主要的异常处理机制:VEH、SEH、C++EH。
SEH:结构化异常处理。就是平时用的__try
__finally
__try
__except
,是对c的扩展。
VEH:向量异常处理。一般来说用AddVectoredExceptionHandler
去添加一个异常处理函数,可以通过第一个参数决定是否将VEH函数插入到VEH链表头,插入到链表头的函数先执行,如果为1,则会最优先执行。
C++EH是C++提供的异常处理方式,执行顺序将排在最后。
在用户模式下发生异常时,异常处理分发函数在内部会先调用遍历 VEH 记录链表的函数, 如果没有找到可以处理异常的注册函数,再开始遍历 SEH 注册链表。
主要区分一下SEH和VEH:
然后开始写代码,主要流程如下:
在调试模式下,当MessageBox被调用时,会触发int3异常:
将项目编译为PE文件再次运行,已经成功Hook:
代码如下:
1
2
3
4
5
6
7
8
9
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
#include <iostream>
#include <list>
#include <windows.h>
using namespace std;
struct EXCEPTION_HOOK {
ULONG_PTR ExceptionAddress;
UCHAR oldCode;
};
list
<EXCEPTION_HOOK> HookInfo;
/
/
1.
注册一个VEH回调
/
/
2.
找到一个API
/
/
3.API
头部第一个字节改为CC
/
/
4.
当这个API被调用,就会执行到CC,然后出发
int
3
异常,然后异常被VEH回调接管,然后为所欲为。
LONG
Handler(
struct _EXCEPTION_POINTERS
*
ExceptionInfo
)
{
for
(
list
<EXCEPTION_HOOK>::iterator i
=
HookInfo.begin(); i !
=
HookInfo.end();
+
+
i)
{
if
(i
-
>ExceptionAddress
=
=
(ULONG_PTR)ExceptionInfo
-
>ExceptionRecord
-
>ExceptionAddress && ExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
EXCEPTION_BREAKPOINT)
{
ULONG OldProtect;
BOOL
bRet
=
VirtualProtect((PVOID)ExceptionInfo
-
>ContextRecord
-
>Eip,
1
, PAGE_EXECUTE_READWRITE, &OldProtect);
if
(!bRet)
{
cout <<
"属性修改失败"
<< endl;
return
FALSE;
}
*
(UCHAR
*
)ExceptionInfo
-
>ContextRecord
-
>Eip
=
i
-
>oldCode;
/
/
MessageBoxA 已经调用 cc中段 stack 中保存了传入的数据
const char
*
szStr
=
"hello"
;
*
(DWORD
*
)(ExceptionInfo
-
>ContextRecord
-
>Esp
+
0x8
)
=
(DWORD)szStr;
VirtualProtect((PVOID)ExceptionInfo
-
>ContextRecord
-
>Eip,
1
, OldProtect, &OldProtect);
return
EXCEPTION_CONTINUE_EXECUTION;
}
}
return
EXCEPTION_CONTINUE_SEARCH;
}
BOOL
Hook(ULONG_PTR ulAddress) {
EXCEPTION_HOOK ExceptionInfo;
ExceptionInfo.ExceptionAddress
=
ulAddress;
for
(
list
<EXCEPTION_HOOK>::iterator i
=
HookInfo.begin(); i !
=
HookInfo.end();
+
+
i)
{
if
(i
-
>ExceptionAddress
=
=
ulAddress)
{
cout <<
"HOOK success"
<< endl;
return
FALSE;
}
}
ULONG OldProtect;
BOOL
bRet
=
VirtualProtect((PVOID)ulAddress,
1
, PAGE_EXECUTE_READWRITE, &OldProtect);
if
(!bRet)
{
cout <<
"属性修改失败!"
<< endl;
return
FALSE;
}
ExceptionInfo.oldCode
=
*
(UCHAR
*
)ulAddress;
*
(UCHAR
*
)ulAddress
=
0xCC
;
HookInfo.push_back(ExceptionInfo);
BOOL
bRet2
=
VirtualProtect((PVOID)ulAddress,
1
, OldProtect, &OldProtect);
return
TRUE;
}
int
main()
{
PVOID pVeh
=
AddVectoredExceptionHandler(
1
, (PVECTORED_EXCEPTION_HANDLER)Handler);
if
(pVeh
=
=
NULL)
{
cout <<
"AddVectoredExceptionHandler Failed"
<< endl;
system(
"pause"
);
return
-
1
;
}
Hook(ULONG_PTR(MessageBoxA));
MessageBoxA(
0
,
0
,
0
,
0
);
return
0
;
}
|
如果要实现Hook其他程序,只需将函数写到dll文件中然后进行注入:
1
2
3
4
5
6
7
8
9
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
55
56
57
58
59
60
61
62
|
/
/
dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <stdio.h>
#include <Windows.h>
size_t MessageBoxAddr
=
(size_t)GetProcAddress(GetModuleHandleA(
"user32.dll"
),
"MessageBoxA"
);
struct EXCEPTION_HOOK
{
ULONG_PTR ExceptionAddress;
UCHAR OldCode;
};
EXCEPTION_HOOK HookInfo;
LONG
NTAPI Handler(
struct _EXCEPTION_POINTERS
*
ExceptionInfo
) {
if
(ExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
EXCEPTION_BREAKPOINT)
{
if
((ULONG_PTR)ExceptionInfo
-
>ExceptionRecord
-
>ExceptionAddress
=
=
HookInfo.ExceptionAddress)
{
const char
*
szSrt
=
"hello"
;
*
(DWORD
*
)(ExceptionInfo
-
>ContextRecord
-
>Esp
+
0x8
)
=
(DWORD)szSrt;
ExceptionInfo
-
>ContextRecord
-
>Eip
+
=
2
;
return
EXCEPTION_CONTINUE_EXECUTION;
}
return
EXCEPTION_CONTINUE_SEARCH;
}
}
VOID SetHook(ULONG_PTR Address)
{
DWORD dwOldProtect
=
0
;
VirtualProtect((LPVOID)Address,
1
, PAGE_EXECUTE_READWRITE, &dwOldProtect);
HookInfo.ExceptionAddress
=
Address;
HookInfo.OldCode
=
*
(UCHAR
*
)Address;
*
(UCHAR
*
)Address
=
0xCC
;
VirtualProtect((LPVOID)Address,
1
, dwOldProtect, &dwOldProtect);
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AddVectoredExceptionHandler(
1
, Handler);
SetHook(MessageBoxAddr);
break
;
case DLL_THREAD_ATTACH:
break
;
case DLL_THREAD_DETACH:
break
;
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
|
更多【R3 下常用Hook技术】相关视频教程:www.yxfzedu.com