-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDriver.c
More file actions
275 lines (235 loc) · 9.39 KB
/
Driver.c
File metadata and controls
275 lines (235 loc) · 9.39 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
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
264
265
266
267
268
269
270
271
272
273
274
275
#include <ntifs.h>
#include <wdm.h>
#include <aux_klib.h>
#include "x86Core.h"
/**
* The following Zydis defines are required to build Zydis as part of a kernel-mode driver:
* * #define ZYDIS_STATIC_BUILD
* * #define ZYAN_MSVC
* * #define ZYAN_KERNEL
*/
#include <Zydis.h>
#define SIG_CALL_REL_ADDR_OFFSET 0x12U // 18U
#define CALL_INST_SIZE (sizeof(BYTE) + sizeof(DWORD32)) // 5
GLOBAL HANDLE g_hThread = NULL;
STATIC GLOBAL CONST BYTE g_abyCallHallEfiSetEnvironentVariableSignature[] = {
0x4D, 0x8B, 0xCF, // MOV R9, R15
0x4C, 0x89, 0x6C, 0x24, 0x20, // MOV [RSP+20h], R13
0x44, 0x8B, 0xC7, // mov R8D, EDI
0x49, 0x8B, 0xD4, // mov RDX, R12
0x49, 0x8B, 0xCE, // mov RCX, R14
0xE8 // CALL <relative address>
};
VOID DriverUnload(
_In_ PDRIVER_OBJECT DriverObject
) {
DbgPrint("[RTSChecker] Driver unloaded\n");
}
STATIC LPCVOID GetExportByName(
_In_ CONST WCHAR* wszName
) {
if (NULL == wszName) {
return NULL;
}
UNICODE_STRING usName;
RtlInitUnicodeString(&usName, wszName);
return MmGetSystemRoutineAddress(&usName);
}
STATIC LPCVOID SearchForSignature(
_In_ LPCBYTE lpcSignature,
_In_ SIZE_T dwSignatureSize,
_In_ LPCBYTE lpcSearchBase,
_In_ SIZE_T dwSearchSize
) {
for (
SIZE_T i = 0;
i <= dwSearchSize - dwSignatureSize;
i++
) {
if (dwSignatureSize != RtlCompareMemory(
lpcSearchBase + i,
lpcSignature,
dwSignatureSize
)) {
continue;
}
return (LPCVOID) (lpcSearchBase + i);
}
return NULL;
}
STATIC NTSTATUS RTSCheck(
VOID
) {
LPCBYTE lpcHalSetEnvironmentVariableEx = GetExportByName(L"HalSetEnvironmentVariableEx");
if (NULL == lpcHalSetEnvironmentVariableEx) {
DbgPrint("[RTSChecker] Failed to get HalSetEnvironmentVariableEx address\n");
return STATUS_UNSUCCESSFUL;
}
if (!MmIsAddressValid((PVOID) lpcHalSetEnvironmentVariableEx)) {
DbgPrint("[RTSChecker] HalSetEnvironmentVariableEx address 0x%p not valid\n", lpcHalSetEnvironmentVariableEx);
return STATUS_UNSUCCESSFUL;
}
DbgPrint("[RTSChecker] HalSetEnvironmentVariableEx address: 0x%p\n", lpcHalSetEnvironmentVariableEx);
CONST DWORD32 cdwSafetyBoundarySigSearch = 0x200;
LPCVOID lpcSignatureAddress = SearchForSignature(
g_abyCallHallEfiSetEnvironentVariableSignature,
sizeof(g_abyCallHallEfiSetEnvironentVariableSignature),
lpcHalSetEnvironmentVariableEx,
cdwSafetyBoundarySigSearch
);
if (NULL == lpcSignatureAddress) {
DbgPrint("[RTSChecker] Failed to locate call to HalSetEnvironmentVariableEx\n");
return STATUS_UNSUCCESSFUL;
}
DbgPrint(
"[RTSChecker] Signature for call to HalSetEnvironmentVariableEx found at 0x%p\n",
lpcSignatureAddress
);
// lands at reladdr operand of CALL instruction
lpcSignatureAddress = (LPCBYTE) lpcSignatureAddress + SIG_CALL_REL_ADDR_OFFSET;
DbgPrint(
"[RTSChecker] Call to HalSetEnvironmentVariableEx located at 0x%08llX\n",
(QWORD) lpcSignatureAddress - 1 // (-1 to include the CALL opcode byte)
);
if (!MmIsAddressValid((PVOID) lpcSignatureAddress)) {
DbgPrint("[RTSChecker] Signature address 0x%p not valid\n", lpcSignatureAddress);
return STATUS_UNSUCCESSFUL;
}
DbgPrint(
"[RTSChecker] Relative address offset: 0x%08X\n",
*(DWORD32*) ((QWORD) lpcSignatureAddress)
);
LPCBYTE lpcHalEfiSetEnvironmentVariable = (LPCBYTE) (
((QWORD) lpcSignatureAddress - 1) // -1 to include the CALL opcode byte
+ *(DWORD32*) ((QWORD) lpcSignatureAddress)
+ CALL_INST_SIZE
);
if (!MmIsAddressValid((PVOID) lpcHalEfiSetEnvironmentVariable)) {
DbgPrint(
"[RTSChecker] HalEfiSetEnvironmentVariable address 0x%p not valid\n",
lpcHalEfiSetEnvironmentVariable
);
return STATUS_UNSUCCESSFUL;
}
DbgPrint(
"[RTSChecker] HalEfiSetEnvironmentVariable address: 0x%p\n",
lpcHalEfiSetEnvironmentVariable
);
PHAL_EFI_RUNTIME_SERVICES_TABLE lpHalEfiRuntimeServicesTable = NULL;
CONST DWORD32 cdwSafetyBoundaryTableSearch = 0x40;
ZydisDisassembledInstruction disasmInstruction;
LPCBYTE lpcInstructionAddress = lpcHalEfiSetEnvironmentVariable;
for (
DWORD32 i = 0;
i < cdwSafetyBoundaryTableSearch
&&
ZYAN_SUCCESS(ZydisDisassembleIntel(
ZYDIS_MACHINE_MODE_LONG_64,
(ZyanU64) lpcInstructionAddress,
lpcInstructionAddress,
0xF,
&disasmInstruction
));
lpcInstructionAddress += disasmInstruction.info.length
) {
if (
ZYDIS_MNEMONIC_MOV == disasmInstruction.info.mnemonic
&&
2 == disasmInstruction.info.operand_count
&&
ZYDIS_OPERAND_TYPE_REGISTER == disasmInstruction.operands[0].type
&&
ZYDIS_OPERAND_TYPE_MEMORY == disasmInstruction.operands[1].type
) {
lpHalEfiRuntimeServicesTable = (PHAL_EFI_RUNTIME_SERVICES_TABLE) (*(LPQWORD) (
(QWORD) (
lpcInstructionAddress
+
disasmInstruction.operands[1].mem.disp.value
+
disasmInstruction.info.length
)
));
break;
}
}
if (NULL == lpHalEfiRuntimeServicesTable) {
DbgPrint("[RTSChecker] Failed to locate HAL_EFI_RUNTIME_SERVICES_TABLE\n");
return STATUS_UNSUCCESSFUL;
}
DbgPrint("[RTSChecker] HAL_EFI_RUNTIME_SERVICES_TABLE located at 0x%p\n", lpHalEfiRuntimeServicesTable);
DbgPrint(
"[RTSChecker] RTS Addresses:\n"
" * GetTime................... @ 0x%p [PHYS: 0x%08llX]\n"
" * SetTime................... @ 0x%p [PHYS: 0x%08llX]\n"
" * ResetSystem............... @ 0x%p [PHYS: 0x%08llX]\n"
" * GetVariable............... @ 0x%p [PHYS: 0x%08llX]\n",
lpHalEfiRuntimeServicesTable->GetTime, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->GetTime),
lpHalEfiRuntimeServicesTable->SetTime, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->SetTime),
lpHalEfiRuntimeServicesTable->ResetSystem, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->ResetSystem),
lpHalEfiRuntimeServicesTable->GetVariable, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->GetVariable)
);
DbgPrint(
" * GetNextVariableName....... @ 0x%p [PHYS: 0x%08llX]\n"
" * SetVariable............... @ 0x%p [PHYS: 0x%08llX]\n"
" * UpdateCapsule............. @ 0x%p [PHYS: 0x%08llX]\n"
" * QueryCapsuleCapabilities.. @ 0x%p [PHYS: 0x%08llX]\n"
" * QueryVariableInfo......... @ 0x%p [PHYS: 0x%08llX]\n",
lpHalEfiRuntimeServicesTable->GetNextVariableName, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->GetNextVariableName),
lpHalEfiRuntimeServicesTable->SetVariable, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->SetVariable),
lpHalEfiRuntimeServicesTable->UpdateCapsule, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->UpdateCapsule),
lpHalEfiRuntimeServicesTable->QueryCapsuleCapabilities, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->QueryCapsuleCapabilities),
lpHalEfiRuntimeServicesTable->QueryVariableInfo, VirtualToPhysical((QWORD) lpHalEfiRuntimeServicesTable->QueryVariableInfo)
);
DbgPrint("[RTSChecker] Analyzing RTS addresses for risk score...\n");
// if RTS_MSB_FROM_TRUSTED_BASELINE==0, first address will be used as trusted MSB baseline
QWORD64 aqwRtsAddresses[] = {
(QWORD64) lpHalEfiRuntimeServicesTable->GetTime,
(QWORD64) lpHalEfiRuntimeServicesTable->SetTime,
(QWORD64) lpHalEfiRuntimeServicesTable->ResetSystem,
(QWORD64) lpHalEfiRuntimeServicesTable->GetVariable,
(QWORD64) lpHalEfiRuntimeServicesTable->GetNextVariableName,
(QWORD64) lpHalEfiRuntimeServicesTable->SetVariable,
(QWORD64) lpHalEfiRuntimeServicesTable->UpdateCapsule,
(QWORD64) lpHalEfiRuntimeServicesTable->QueryCapsuleCapabilities,
(QWORD64) lpHalEfiRuntimeServicesTable->QueryVariableInfo
};
DWORD32 dwRiskScore = AnalyzeRtsAddresses(
aqwRtsAddresses,
ARRAYSIZE(aqwRtsAddresses)
);
if (0 == dwRiskScore) {
DbgPrint("[RTSChecker] RTS address analysis completed, no issues found.\n");
} else {
DbgPrint("[RTSChecker] RTS address analysis completed, RISK SCORE: %u\n", dwRiskScore);
}
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
) {
UNREFERENCED_PARAMETER(RegistryPath);
#if defined(USE_KDMAPPER) && (USE_KDMAPPER == 1)
UNREFERENCED_PARAMETER(DriverObject);
#else
DriverObject->DriverUnload = DriverUnload;
#endif
NTSTATUS Status = STATUS_SUCCESS;
DbgPrint("[RTSChecker] DriverEntry called\n");
#if defined(USE_KDMAPPER) && (USE_KDMAPPER == 1)
// Create a thread to run the check, then exit DriverEntry
Status = PsCreateSystemThread(
&g_hThread,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
(PKSTART_ROUTINE) RTSCheck,
NULL
);
#else
Status = RTSCheck();
#endif
return Status;
}