/
HWBreakPointHook.cpp
112 lines (91 loc) · 2.88 KB
/
HWBreakPointHook.cpp
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
#include "polyhook2/Exceptions/HWBreakPointHook.hpp"
PLH::HWBreakPointHook::HWBreakPointHook(const uint64_t fnAddress, const uint64_t fnCallback, HANDLE hThread) : AVehHook() {
m_fnCallback = fnCallback;
m_fnAddress = fnAddress;
auto entry = AVehHookImpEntry(fnAddress, this);
assert(m_impls.find(entry) == m_impls.end());
m_impls.insert(entry);
m_hThread = hThread;
}
PLH::HWBreakPointHook::HWBreakPointHook(const char* fnAddress, const char* fnCallback, HANDLE hThread) : AVehHook() {
m_fnCallback = (uint64_t)fnCallback;
m_fnAddress = (uint64_t)fnAddress;
auto entry = AVehHookImpEntry((uint64_t)fnAddress, this);
assert(m_impls.find(entry) == m_impls.end());
m_impls.insert(entry);
m_hThread = hThread;
}
bool PLH::HWBreakPointHook::hook()
{
CONTEXT ctx;
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(m_hThread, &ctx)) {
Log::log("Failed to get thread context", ErrorLevel::SEV);
return false;
}
bool freeReg = false;
for (m_regIdx = 0; m_regIdx < 4; m_regIdx++) {
if ((ctx.Dr7 & (1ULL << (m_regIdx * 2))) == 0) {
freeReg = true;
break;
}
}
if (!freeReg) {
Log::log("All HW BP's are used", ErrorLevel::SEV);
return false;
}
assert(m_regIdx < 4);
switch (m_regIdx) {
case 0:
ctx.Dr0 = (decltype(ctx.Dr0))m_fnAddress;
break;
case 1:
ctx.Dr1 = (decltype(ctx.Dr1))m_fnAddress;
break;
case 2:
ctx.Dr2 = (decltype(ctx.Dr2))m_fnAddress;
break;
case 3:
ctx.Dr3 = (decltype(ctx.Dr3))m_fnAddress;
break;
}
ctx.Dr7 &= ~(3ULL << (16 + 4 * m_regIdx)); //00b at 16-17, 20-21, 24-25, 28-29 is execute bp
ctx.Dr7 &= ~(3ULL << (18 + 4 * m_regIdx)); // size of 1 (val 0), at 18-19, 22-23, 26-27, 30-31
ctx.Dr7 |= 1ULL << (2 * m_regIdx);
// undefined, suspendthread needed
if (!SetThreadContext(m_hThread, &ctx)) {
Log::log("Failed to set thread context", ErrorLevel::SEV);
}
m_hooked = true;
return true;
}
bool PLH::HWBreakPointHook::unHook() {
assert(m_hooked);
if (!m_hooked) {
Log::log("HWBPHook unhook failed: no hook present", ErrorLevel::SEV);
return false;
}
CONTEXT ctx;
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (!GetThreadContext(m_hThread, &ctx)) {
Log::log("Failed to get thread context", ErrorLevel::SEV);
return false;
}
ctx.Dr7 &= ~(1ULL << (2 * m_regIdx));
//Still need to call suspend thread
if (!SetThreadContext(m_hThread, &ctx)) {
Log::log("Failed to set thread context", ErrorLevel::SEV);
return false;
}
m_hooked = false;
return true;
}
LONG PLH::HWBreakPointHook::OnException(EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP)
return EXCEPTION_CONTINUE_SEARCH;
ExceptionInfo->ContextRecord->Dr7 &= ~(1ULL << (2 * m_regIdx));
ExceptionInfo->ContextRecord->XIP = (decltype(ExceptionInfo->ContextRecord->XIP))m_fnCallback;
return EXCEPTION_CONTINUE_EXECUTION;
}