内存访问异常hook

参考文献:

《游戏外挂攻防艺术7.2.2》

[原创]基于页面异常的Hook:原理与实现 https://bbs.pediy.com/thread-273172.htm

比较好用的异常hook就是页面异常hook 这种方法可以用来反dump

Page Hook

原理

1
2
1.修改指令处所属页面的属性未RW  not  X
2.是的此页面被执行时发生异常,接管此异常即可

13年的外挂攻防艺术用的是VEH和SEH的硬件断点来进行接管异常

这里看一下他的源码 https://github.com/yuyuaqwq/YPage-Hook

还是注册的VEH进行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
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include "YPageHook.h"
#include <map>
#include <iostream>using namespace std;

#pragma code_seg(".func")

void func() {
std::cout << "test1";
}

#pragma code_seg("")
void HookCallBack(LPCONTEXT context) {
std::cout << "mypackhook";

}


int main(int argc char* argv[]) {
PageHook hook;

hook.install(char)(func, HookCallBack);
func();
std::cout << "验证";
system("pause");
return 0;
}

struct PageRecord {
LPVOID pageBase;
size_t count;
DWORD protect;
};
static std::map<LPVOID, PageRecord> gs_pageHook_base;
static std::map<LPVOID, PageHook&> gs_pageHook_addr;
static std::map<DWORD, PageRecord&> gs_pageHook_step;



//页对齐
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) {

LPVOID pageBase = PageAlignment(ExceptionInfo->ExceptionRecord->ExceptionAddress);
auto it_base = gs_pageHook_base.find(pageBase);
if (it_base == gs_pageHook_base.end()) {
.
// 不是咱们设置的页面属性产生的异常,忽略
return EXCEPTION_CONTINUE_SEARCH;
}

// 执行的指令与我们的Hook位于同一页面,恢复原有属性
DWORD uselessProtect;
VirtualProtect(pageBase, 0x1000, it_base->second.protect, &uselessProtect);


// 获取发生异常的线程的上下文
LPCONTEXT context = ExceptionInfo->ContextRecord;


auto it_addr = gs_pageHook_addr.find(ExceptionInfo->ExceptionRecord->ExceptionAddress);
if (it_addr != gs_pageHook_addr.end()) {
// 是被hook的地址

// 调用回调 实现hook
it_addr->second.m_callback(context);
}

context->EFlags |= 0x100;

// 用于识别是否咱们设置的单步
gs_pageHook_step.insert(std::pair<DWORD, PageRecord&>(GetCurrentThreadId(), it_base->second));


//异常处理完成 让程序继续执行
return EXCEPTION_CONTINUE_EXECUTION;


}
else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
LPCONTEXT pContext = ExceptionInfo->ContextRecord;

// 判断是否DR寄存器触发的异常
if (pContext->Dr6 & 0xf) {
// 排除DR寄存器触发的单步异常
return EXCEPTION_CONTINUE_SEARCH;
}
else {
// 单步异常
auto it = gs_pageHook_step.find(GetCurrentThreadId());
if (it == gs_pageHook_step.end()) {
//不是咱们设置的单步断点,不处理
return EXCEPTION_CONTINUE_SEARCH;
}


DWORD uselessProtect;
// 恢复Hook
VirtualProtect(it->second.pageBase, 0x1000, PAGE_READWRITE, &uselessProtect);

gs_pageHook_step.erase(GetCurrentThreadId());

// 不需要重设TF,单步异常自动将TF置0
// 单步异常是陷阱类异常,无需修复ip

// 异常处理完成 让程序继续执行
return EXCEPTION_CONTINUE_EXECUTION;
}

}

return EXCEPTION_CONTINUE_SEARCH;
}



YPageHook::YPageHook() {
m_status = Status::invalid;
m_hookAddr = nullptr;
m_callback = nullptr;

//注册VEH
m_exceptionHandlerHandle = AddVectoredExceptionHandler(TRUE, ExceptionHandler);
}

YPageHook::~YPageHook() {
//移除VEH
RemoveVectoredExceptionHandler(m_exceptionHandlerHandle);

uninstall();
}


//install就是装载hook
void YPageHook::install(LPVOID hookAddr, HookCallBack callback) {

if (m_status == Status::valid) {
throw Error::repeatInstall;
}

auto it_addr = gs_pageHook_addr.find(hookAddr);
if (it_addr != gs_pageHook_addr.end()) {
throw Error::duplicateAddress;
}

LPVOID pageBase = PageAlignment(hookAddr);

m_hookAddr = hookAddr;
m_callback = callback;
m_status = Status::valid;

gs_pageHook_addr.insert(std::pair<LPVOID, PageHook&>(hookAddr, *this)); //校准插入hook基址
auto it_base = gs_pageHook_base.find(pageBase);
if (it_base == gs_pageHook_base.end()) {
PageRecord pageRecord;
pageRecord.count = 1;
pageRecord.pageBase = pageBase;
pageRecord.protect = 0;
gs_pageHook_base.insert(std::pair<LPVOID, PageRecord>(pageBase, pageRecord));
it_base = gs_pageHook_base.find(pageBase);
if (!VirtualProtect(pageBase, 0x1000, PAGE_READWRITE, &it_base->second.protect)) {
uninstall();//判断是否可执行 如果可执行就直接uninstall跳过 因为我们要 装载->执行->卸载 。这样就能hook
///所以在装载的其中就要为源代码故意多了单页面多个异常点hook的技术强制RW权限导致报错 进而引入到我们的hook.最后uninstall恢复我们的属性
//因为都是分开写的,导致可以单页面多个异常点hook的技术
throw Error::setProtectFailed;
}
}
else {
++it_base->second.count;
}
}

void YPageHook::uninstall() {
if (m_status == Status::invalid) {
throw Error::repeatUninstall;
}

LPVOID pageBase = PageAlignment(m_hookAddr);
auto it_base = gs_pageHook_base.find(pageBase);

if (it_base != gs_pageHook_base.end()) {
if (it_base->second.count == 1) {
if (!VirtualProtect(pageBase, 0x1000, it_base->second.protect, &it_base->second.protect)) {
throw Error::setProtectFailed;
}
gs_pageHook_base.erase(it_base);
}
else {
--it_base->second.count;
}
}

gs_pageHook_addr.erase(m_hookAddr);

m_hookAddr = nullptr;
m_callback = nullptr;

m_status = Status::invalid;

}


外挂使用EIP实现hook

context->Eip = (DWORD) & ReturnOrigianlFunc


内存访问异常hook
http://example.com/内存访问异常hook.html
Author
CDxiaodong
Posted on
November 9, 2022
Licensed under