Bitdefender Hypervisor Memory Introspection
drivers.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "drivers.h"
6 #include "guests.h"
7 
12 
21 #define for_each_driver(_var_name) list_for_each (gKernelDrivers, KERNEL_DRIVER, _var_name)
22 
24 #define MAX_DRIVER_EXPORT_CACHE_ENTRIES 10
25 
29 typedef struct _DRIVER_EXPORT_CACHE
30 {
36 
42 
43 
46  _In_ void const *Detour
47  )
60 {
61  INTSTATUS status;
62  IG_ARCH_REGS const *pRegs = &gVcpu->Regs;
63 
64  UNREFERENCED_PARAMETER(Detour);
65 
67  {
68  status = IntLixDrvCreateFromAddress(pRegs->R8, 0);
69  if (!INT_SUCCESS(status))
70  {
71  ERROR("[ERROR] IntLixDrvCreateFromAddress failed for module 0x%016llx: 0x%08x\n", pRegs->Rdi, status);
73  }
74  }
75  else
76  {
77  QWORD args[2];
78  QWORD ldrAddress;
79  DWORD load;
80 
81  status = IntDetGetArguments(Detour, 2, args);
82  if (!INT_SUCCESS(status))
83  {
84  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
85  return status;
86  }
87 
88  ldrAddress = args[0];
89  load = (args[1] & 0xFFFFFFFF) > 0;
90 
91  // The module is unloading, we are not interested in this, we already caught that...
92  if (!load)
93  {
94  return INT_STATUS_SUCCESS;
95  }
96 
98  if (!INT_SUCCESS(status))
99  {
100  ERROR("[ERROR] IntWinDrvCreateFromAddress failed for GVA 0x%016llx: 0x%08x\n", ldrAddress, status);
102  }
103  }
104 
105  return INT_STATUS_SUCCESS;
106 }
107 
108 
109 INTSTATUS
111  _In_ void const *Detour
112  )
125 {
126  INTSTATUS status;
127  IG_ARCH_REGS const *pRegs = &gVcpu->Regs;
128 
129  UNREFERENCED_PARAMETER(Detour);
130 
132  {
133  status = IntLixDrvRemoveFromAddress(pRegs->R8);
134  if (!INT_SUCCESS(status))
135  {
136  ERROR("[ERROR] IntLixDrvRemoveFromAddress failed for GVA 0x%016llx: 0x%08x\n", pRegs->Rdi, status);
138  }
139  }
140  else
141  {
142  QWORD ldrAddress = 0;
143 
144  status = IntDetGetArgument(Detour, 0, NULL, 0, &ldrAddress);
145  if (!INT_SUCCESS(status))
146  {
147  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
148  return status;
149  }
150 
151  status = IntWinDrvRemoveFromAddress(ldrAddress);
152  if (!INT_SUCCESS(status) && (INT_STATUS_NOT_FOUND != status))
153  {
154  ERROR("[ERROR] IntWinDrvRemoveFromAddress failed for GVA 0x%016llx: 0x%08x\n", ldrAddress, status);
156  }
157  }
158 
159  return INT_STATUS_SUCCESS;
160 }
161 
162 
165  _In_ QWORD Gva
166  )
179 {
180  for_each_driver(pDriver)
181  {
182  if (pDriver->BaseVa <= Gva && pDriver->BaseVa + pDriver->Size > Gva)
183  {
184  return pDriver;
185  }
186  }
187 
189  {
190  return NULL;
191  }
192 
193  for_each_driver(pDriver)
194  {
195  if (pDriver->Lix.Initialized)
196  {
197  continue;
198  }
199 
200  if (IN_RANGE_LEN(Gva, pDriver->Lix.InitLayout.Base, pDriver->Lix.InitLayout.Size))
201  {
202  return pDriver;
203  }
204  }
205 
206  return NULL;
207 }
208 
209 
212  _In_ QWORD Gva
213  )
221 {
222  for_each_driver(pDriver)
223  {
224  if (pDriver->BaseVa == Gva)
225  {
226  return pDriver;
227  }
228  }
229 
230  return NULL;
231 }
232 
233 
236  _In_ DWORD LoadOrder
237  )
248 {
249  DWORD currentPosition = 0;
250 
251  for_each_driver(pDriver)
252  {
253  if (LoadOrder == currentPosition)
254  {
255  return pDriver;
256  }
257 
258  currentPosition++;
259  }
260 
261  return NULL;
262 }
263 
264 
267  _In_ const void *Name
268  )
277 {
278  if (NULL == Name)
279  {
280  return NULL;
281  }
282 
283  for_each_driver(pDriver)
284  {
285  int cmp = 1;
286 
287  if (NULL == pDriver->Name)
288  {
289  continue;
290  }
291 
293  {
294  cmp = wstrcasecmp(Name, pDriver->Name);
295  }
296  else
297  {
298  cmp = strcmp(pDriver->Name, Name);
299  }
300 
301  if (0 == cmp)
302  {
303  return pDriver;
304  }
305  }
306 
307  return NULL;
308 }
309 
310 
313  _In_ const WCHAR *Path
314  )
324 {
325  // We have no path on Linux, so no need for it
327  {
328  return NULL;
329  }
330 
331  if (NULL == Path)
332  {
333  return NULL;
334  }
335 
336  for_each_driver(pDriver)
337  {
338  if (NULL == pDriver->Win.Path)
339  {
340  continue;
341  }
342 
343  if (0 == wstrcasecmp(Path, pDriver->Win.Path))
344  {
345  return pDriver;
346  }
347  }
348 
349  return NULL;
350 }
351 
352 
353 void
355  void
356  )
363 {
364  for_each_driver(pDriver)
365  {
366  INTSTATUS status;
367 
368  RemoveEntryList(&pDriver->Link);
369 
371  {
372  status = IntLixDrvRemoveEntry(pDriver);
373  if (!INT_SUCCESS(status))
374  {
375  ERROR("[ERROR] IntLixDrvRemoveEntry failed: 0x%08x\n", status);
376  }
377  }
378  else
379  {
380  status = IntWinDrvRemoveEntry(pDriver);
381  if (!INT_SUCCESS(status))
382  {
383  ERROR("[ERROR] IntWinDrvRemoveEntry failed: 0x%08x\n", status);
384  }
385  }
386  }
387 }
388 
389 
390 void
392  void
393  )
397 {
398  DWORD i = 0;
399 
400  for_each_driver(pDriver)
401  {
403  {
404  LOG(" #%03d I: %d, Core: 0x%016llx, CoreSize: 0x%08llx, CoreTextSize: 0x%08x, "
405  "CoreRoSize: 0x%08x, Name: '%s'\n",
406  i++,
407  pDriver->Lix.Initialized,
408  pDriver->BaseVa,
409  pDriver->Size,
410  pDriver->Lix.CoreLayout.TextSize,
411  pDriver->Lix.CoreLayout.RoSize,
412  (char *)pDriver->Name);
413  }
414  else
415  {
416  LOG(" #%03d Base: 0x%016llx, Size: 0x%08llx, PathHash: 0x%08x, NameHash: 0x%08x, Name: '%s'\n",
417  i++, pDriver->BaseVa, pDriver->Size, pDriver->Win.PathHash,
418  pDriver->NameHash, utf16_for_log(pDriver->Name));
419 
420  if (pDriver->Win.DriverObject)
421  {
422  LOG("------> 0x%016llx : %s\n",
423  pDriver->Win.DriverObject->DriverObjectGva,
424  utf16_for_log(((PWIN_DRIVER_OBJECT)pDriver->Win.DriverObject)->Name));
425  }
426  }
427  }
428 }
429 
430 
431 void
433  _In_ const QWORD Rip
434  )
442 {
443  if (gDriverExportCache.CurrentEntry == MAX_DRIVER_EXPORT_CACHE_ENTRIES)
444  {
445  gDriverExportCache.CurrentEntry = 0;
446  }
447 
448  memzero(&gDriverExportCache.Entry[gDriverExportCache.CurrentEntry], sizeof(DRIVER_EXPORT_CACHE_ENTRY));
449 
450  gDriverExportCache.Entry[gDriverExportCache.CurrentEntry].Rip = Rip;
451  gDriverExportCache.Entry[gDriverExportCache.CurrentEntry].Type.Export = 1;
452 
453  gDriverExportCache.CurrentEntry++;
454 }
455 
456 
457 void
459  _In_ const QWORD Rip
460  )
468 {
469  if (gDriverExportCache.CurrentEntry == MAX_DRIVER_EXPORT_CACHE_ENTRIES)
470  {
471  gDriverExportCache.CurrentEntry = 0;
472  }
473 
474  memzero(&gDriverExportCache.Entry[gDriverExportCache.CurrentEntry], sizeof(DRIVER_EXPORT_CACHE_ENTRY));
475 
476  gDriverExportCache.Entry[gDriverExportCache.CurrentEntry].Rip = Rip;
477  gDriverExportCache.Entry[gDriverExportCache.CurrentEntry].Type.Unknown = 1;
478 
479  gDriverExportCache.CurrentEntry++;
480 }
481 
482 
485  _In_ const QWORD Rip
486  )
494 {
495  for (DWORD index = 0; index < ARRAYSIZE(gDriverExportCache.Entry); index++)
496  {
497  if (Rip == gDriverExportCache.Entry[index].Rip)
498  {
499  return &gDriverExportCache.Entry[index];
500  }
501  }
502 
503  return NULL;
504 }
505 
506 
507 void
509  _In_ const QWORD BaseAddress,
510  _In_ const QWORD Length
511  )
518 {
519  for (DWORD index = 0; index < ARRAYSIZE(gDriverExportCache.Entry); index++)
520  {
521  if (IN_RANGE_LEN(gDriverExportCache.Entry[index].Rip, BaseAddress, Length))
522  {
523  memzero(&gDriverExportCache.Entry[index], sizeof(DRIVER_EXPORT_CACHE_ENTRY));
524  }
525  }
526 }
BYTE Unknown
Set if the function at this RIP is not exported.
Definition: drivers.h:20
struct _DRIVER_EXPORT_CACHE * PDRIVER_EXPORT_CACHE
INTSTATUS IntLixDrvRemoveEntry(KERNEL_DRIVER *Driver)
Disable protection and frees the driver structure from our internal list.
Definition: lixmodule.c:828
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
#define _In_
Definition: intro_sal.h:21
DRIVER_EXPORT_CACHE_ENTRY * IntDriverCacheExportFind(const QWORD Rip)
Finds an entry inside the gDriverExportCache.
Definition: drivers.c:484
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
uint16_t WORD
Definition: intro_types.h:48
void IntDriverCacheInv(const QWORD BaseAddress, const QWORD Length)
Invalidates all cache entries for a given guest memory range.
Definition: drivers.c:508
INTSTATUS IntLixDrvRemoveFromAddress(QWORD DriverGva)
Disable protection and remove the driver structure from our internal list.
Definition: lixmodule.c:866
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define ARRAYSIZE(A)
Definition: introdefs.h:101
#define ERROR(fmt,...)
Definition: glue.h:62
INTSTATUS IntDriverUnloadHandler(void const *Detour)
The detour handler that will be invoked when a guest driver is unloaded.This handles driver unloading...
Definition: drivers.c:110
int INTSTATUS
The status data type.
Definition: introstatus.h:24
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
DRIVER_EXPORT_CACHE_ENTRY Entry[MAX_DRIVER_EXPORT_CACHE_ENTRIES]
The cache entries.
Definition: drivers.c:34
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
struct _DRIVER_EXPORT_CACHE DRIVER_EXPORT_CACHE
Driver export cache.
struct _DRIVER_EXPORT_CACHE_ENTRY::@23 Type
INTSTATUS IntWinDrvCreateFromAddress(QWORD ModuleInfo, QWORD Flags)
Adds a driver to introspection&#39;s LoadedModuleList (gKernelDrivers). This way we avoid lots of mapping...
Definition: windriver.c:305
BYTE Export
Set if the function at this RIP is exported.
Definition: drivers.h:21
#define LOG(fmt,...)
Definition: glue.h:61
Describes a kernel driver.
Definition: drivers.h:30
static DRIVER_EXPORT_CACHE gDriverExportCache
The driver exports cache.
Definition: drivers.c:41
INTSTATUS IntDriverLoadHandler(void const *Detour)
The detour handler that will be invoked when a guest loads a new driver.This handles driver loading i...
Definition: drivers.c:45
LIST_HEAD gKernelDrivers
List of all the drivers currently loaded inside the guest.
Definition: drivers.c:11
void IntDriverCacheCreateUnknown(const QWORD Rip)
Adds a new entry to the gDriverExportCache.
Definition: drivers.c:458
void IntDriverDump(void)
Prints all the currently loaded drivers.
Definition: drivers.c:391
QWORD Rip
The guest RIP for which this entry exists.
Definition: drivers.h:16
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
Holds information about a driver object.
Definition: windrvobj.h:13
#define memzero(a, s)
Definition: introcrt.h:35
unsigned long long QWORD
Definition: intro_types.h:53
void IntDriverUninit(void)
Uninitializes the drivers submodule.
Definition: drivers.c:354
#define IN_RANGE_LEN(x, start, len)
Definition: introdefs.h:175
KERNEL_DRIVER * IntDriverFindByPath(const WCHAR *Path)
Searches for a driver by its module path.
Definition: drivers.c:312
INTSTATUS IntWinDrvRemoveEntry(KERNEL_DRIVER *Driver)
Removes the KERNEL_DRIVER from the internal structures.
Definition: windriver.c:1696
KERNEL_DRIVER * IntDriverFindByName(const void *Name)
Searches for a driver by its name.
Definition: drivers.c:266
KERNEL_DRIVER * IntDriverFindByLoadOrder(DWORD LoadOrder)
Searches a driver by its module load order.
Definition: drivers.c:235
INTSTATUS IntDetGetArgument(void const *Detour, DWORD Index, BYTE const *StackBuffer, DWORD StackBufferSize, QWORD *Value)
Reads the specified argument for a detour.
Definition: detours.c:2237
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
uint16_t WCHAR
Definition: intro_types.h:63
uint32_t DWORD
Definition: intro_types.h:49
Driver export cache.
Definition: drivers.c:29
KERNEL_DRIVER * IntDriverFindByAddress(QWORD Gva)
Returns the driver in which Gva resides.
Definition: drivers.c:164
INTSTATUS IntDetGetArguments(void const *Detour, DWORD Argc, QWORD *Argv)
Reads multiple arguments from a detour.
Definition: detours.c:2296
WORD CurrentEntry
The number of valid entries inside the Entry array.
Definition: drivers.c:32
INTSTATUS IntLixDrvCreateFromAddress(QWORD DriverGva, QWORD StaticDetected)
Create the KERNEL_DRIVER object from the provided &#39;module struct&#39; address and activate the protection...
Definition: lixmodule.c:696
INTSTATUS IntWinDrvRemoveFromAddress(QWORD ModuleInfo)
Removes a driver from the introspection&#39;s loaded modules list (gKernelDrivers).
Definition: windriver.c:522
#define IntDbgEnterDebugger()
Definition: introcore.h:381
#define MAX_DRIVER_EXPORT_CACHE_ENTRIES
Maximum entries inside the DRIVER_EXPORT_CACHE.
Definition: drivers.c:24
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
void IntDriverCacheCreateExport(const QWORD Rip)
Adds a new export entry to the gDriverExportCache.
Definition: drivers.c:432
int wstrcasecmp(const WCHAR *buf1, const WCHAR *buf2)
Definition: introcrt.c:98
#define LIST_HEAD_INIT(Name)
Definition: introlists.h:39
The object was detected when it was created.
Definition: winguest.h:152
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
Describes an entry in the gDriverExportCache.
Definition: drivers.h:14
Holds register state.
Definition: glueiface.h:30
KERNEL_DRIVER * IntDriverFindByBase(QWORD Gva)
Searches a driver object by its module base.
Definition: drivers.c:211
#define for_each_driver(_var_name)
Iterates the gKernelDrivers linked list.
Definition: drivers.c:21