-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathPageHook.cpp
More file actions
182 lines (114 loc) · 4.07 KB
/
Copy pathPageHook.cpp
File metadata and controls
182 lines (114 loc) · 4.07 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include "PageHook.h"
#include <map>
static std::map<LPVOID, PageHook&> gs_pageHook_base;
static std::map<DWORD, PageHook&> gs_pageHook_step;
#pragma code_seg(".hook")
static LPVOID PageAlignment(LPVOID addr) {
return (LPVOID)((UINT_PTR)addr & (UINT_PTR)(~0xfff));
}
static LONG NTAPI ExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) {
// 判断异常类型
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
// 不管3721,先恢复一下这个页面的属性,避免find等函数被链接到同一页面,执行时也出现异常
DWORD oldProtect;
VirtualProtect(ExceptionInfo->ExceptionRecord->ExceptionAddress, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
auto it = gs_pageHook_base.find(PageAlignment(ExceptionInfo->ExceptionRecord->ExceptionAddress));
if (it == gs_pageHook_base.end()) {
// 不是咱们设置的页面属性产生的异常,改回去
VirtualProtect(ExceptionInfo->ExceptionRecord->ExceptionAddress, 1, oldProtect, &oldProtect);
return EXCEPTION_CONTINUE_SEARCH;
}
// 执行的指令与我们的Hook位于同一页面
// 同步一下页面属性
it->second.m_oldProtect = oldProtect;
// 获取发生异常的线程的上下文
LPCONTEXT context = ExceptionInfo->ContextRecord;
// 设置单步触发陷阱,用于单步后重新启用此Hook
context->EFlags |= 0x100;
// 用于识别是否咱们设置的单步
gs_pageHook_step.insert(std::pair<DWORD, PageHook&>(GetCurrentThreadId(), it->second));
#ifdef _WIN64
if ((LPVOID)context->Rip == it->second.m_hookAddr) {
#else
if ((LPVOID)context->Eip == it->second.m_hookAddr) {
#endif
// 是被hook的地址
// 调用回调
it->second.m_callback(context);
}
//异常处理完成 让程序继续执行
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
LPCONTEXT pContext = ExceptionInfo->ContextRecord;
// 判断是否DR寄存器触发的异常
if (pContext->Dr6 & 0xf) {
// 排除DR寄存器触发的单步异常
}
else {
// 单步异常
auto it = gs_pageHook_step.find(GetCurrentThreadId());
if (it == gs_pageHook_step.end()) {
//不是咱们设置的单步断点,不处理
return EXCEPTION_CONTINUE_SEARCH;
}
LPVOID hookAddr = it->second.m_hookAddr;
DWORD* oldProtect = &it->second.m_oldProtect;
gs_pageHook_step.erase(GetCurrentThreadId());
// 恢复Hook
VirtualProtect(hookAddr, 1, *oldProtect, oldProtect);
// 不需要重设TF,单步异常自动将TF置0
// 单步异常是陷阱类异常,无需修复ip
// 异常处理完成 让程序继续执行
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
PageHook::PageHook() {
m_status = Status::invalid;
m_oldProtect = NULL;
m_hookAddr = nullptr;
m_callback = nullptr;
//注册VEH
AddVectoredExceptionHandler(TRUE, ExceptionHandler);
}
PageHook::~PageHook() {
//移除VEH
RemoveVectoredExceptionHandler(ExceptionHandler);
uninstall();
}
BOOL PageHook::install(LPVOID hookAddr, HookCallBack callback) {
if (m_status == Status::valid) {
uninstall();
}
auto it = gs_pageHook_base.find(PageAlignment(hookAddr));
if (it != gs_pageHook_base.end()) {
return FALSE;
}
gs_pageHook_base.insert(std::pair<LPVOID, PageHook&>(PageAlignment(hookAddr), *this));
m_hookAddr = hookAddr;
m_callback = callback;
m_status = Status::valid;
if (!VirtualProtect(hookAddr, 1, PAGE_READWRITE, &m_oldProtect)) {
uninstall();
return FALSE;
}
return TRUE;
}
BOOL PageHook::uninstall() {
if (m_status == Status::invalid) {
return FALSE;
}
if (!VirtualProtect(m_hookAddr, 1, m_oldProtect, &m_oldProtect)) {
return FALSE;
}
gs_pageHook_base.erase(PageAlignment(m_hookAddr));
m_oldProtect = NULL;
m_hookAddr = nullptr;
m_callback = nullptr;
m_status = Status::invalid;
return TRUE;
}
#pragma code_seg()