Bitdefender Hypervisor Memory Introspection
lixapi.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixapi.h"
6 #include "decoder.h"
7 #include "drivers.h"
8 #include "lixcrash.h"
9 #include "lixcred.h"
10 #include "lixmm.h"
11 #include "guests.h"
12 #include "crc32.h"
13 #include "lixksym.h"
14 
15 
22 #define __init_detour_entry(fn_name, callback, flags) \
23  { \
24  .FunctionName = #fn_name, \
25  .HijackFunctionName = NULL, \
26  .Callback = (callback), \
27  .Id = det_ ## fn_name, \
28  .EnableFlags = (flags), \
29  }
30 
31 
38 #define __init_detour_entry_regex(fn_name, regex, callback, flags) \
39  { \
40  .FunctionName = #fn_name regex, \
41  .HijackFunctionName = NULL, \
42  .Callback = callback, \
43  .Id = det_ ## fn_name, \
44  .EnableFlags = flags, \
45  }
46 
47 
48 
55 #define __init_detour_entry_hijack(fn_name, hijack_fn_name, callback, flags) \
56  { \
57  .FunctionName = #fn_name, \
58  .HijackFunctionName = #hijack_fn_name, \
59  .Callback = callback, \
60  .Id = det_ ## fn_name ## _ ## hijack_fn_name, \
61  .EnableFlags = flags, \
62  }
63 
64 
65 
70 {
81 
83 
98 
102 };
103 
104 
105 
106 static INTSTATUS
108  _In_ const LIX_FN_DETOUR *FnDetour,
109  _Out_ QWORD *Address
110  )
124 {
125  INTSTATUS status = INT_STATUS_SUCCESS;
126  INSTRUX instrux;
127  QWORD ksymStart = 0;
128  QWORD ksymEnd = 0;
129  QWORD ksymHijack = 0;
130 
131  *Address = 0;
132 
133  ksymHijack = IntKsymFindByName(FnDetour->HijackFunctionName, NULL);
134  if (!ksymHijack)
135  {
136  ERROR("[ERROR] IntLixGuestFindKsymByName failed with status: 0x%08x. (%s)\n",
137  status, FnDetour->HijackFunctionName);
138  return status;
139  }
140 
141  ksymStart = IntKsymFindByName(FnDetour->FunctionName, &ksymEnd);
142  if (!ksymStart)
143  {
144  ERROR("[ERROR] IntLixGuestFindKsymByName failed with status: 0x%08x. (%s)\n", status, FnDetour->FunctionName);
145  return status;
146  }
147 
148  while (ksymStart < ksymEnd)
149  {
150  status = IntDecDecodeInstruction(IG_CS_TYPE_64B, ksymStart, &instrux);
151  if (!INT_SUCCESS(status))
152  {
153  ERROR("[ERROR] IntDecDecodeInstruction failed with status: 0x%08x.\n", status);
154  return status;
155  }
156 
157  if (instrux.Instruction == ND_INS_CALLNR)
158  {
159  QWORD hijackRelativeAddr = ksymHijack - (ksymStart + 5);
160 
161  if (hijackRelativeAddr == instrux.Operands[0].Info.RelativeOffset.Rel)
162  {
163  *Address = ksymStart;
164 
165  return INT_STATUS_SUCCESS;
166  }
167  }
168 
169  ksymStart += instrux.Length;
170  }
171 
172  return INT_STATUS_NOT_FOUND;
173 }
174 
175 
176 static INTSTATUS
178  _In_ const LIX_FN_DETOUR *FnDetour,
179  _Out_ BOOLEAN *MustValidateThreads
180  )
195 {
196  INTSTATUS status = INT_STATUS_SUCCESS;
197  QWORD functionAddress = 0;
198 
199  if (FnDetour->HijackFunctionName == NULL)
200  {
201  functionAddress = IntKsymFindByName(FnDetour->FunctionName, NULL);
202  if (!functionAddress)
203  {
204  ERROR("[ERROR] Critical API '%s' not found! Aborting!\n", FnDetour->FunctionName);
205  return INT_STATUS_NOT_FOUND;
206  }
207 
208  TRACE("[DETOUR] Found function '%s' @ 0x%016llx\n", FnDetour->FunctionName, functionAddress);
209  }
210  else
211  {
212  status = IntLixApiHijackHook(FnDetour, &functionAddress);
213  if (!INT_SUCCESS(status))
214  {
215  ERROR("[ERROR] Critical API '%s' not found! Aborting!\n", FnDetour->FunctionName);
216  return INT_STATUS_NOT_FOUND;
217  }
218  TRACE("[DETOUR] Found hijack function '%s' inside function '%s' @ 0x%016llx\n",
219  FnDetour->HijackFunctionName, FnDetour->FunctionName, functionAddress);
220  }
221 
222  *MustValidateThreads = TRUE;
223 
224  status = IntDetSetLixHook(functionAddress, FnDetour, MustValidateThreads);
225  if (!INT_SUCCESS(status))
226  {
227  ERROR("[ERROR] Failed to detour %s: 0x%08x\n", FnDetour->FunctionName, status);
228 
229  IntDisasmGva(functionAddress, 0x20);
230 
231  return status;
232  }
233 
234  return INT_STATUS_SUCCESS;
235 }
236 
237 
238 static __forceinline BOOLEAN
240  _In_ const char *Name,
241  _In_ DWORD NameHash
242  )
251 {
252  return NameHash == Crc32String(Name, INITIAL_CRC_VALUE);
253 }
254 
255 
256 INTSTATUS
258  void
259  )
270 {
271  INTSTATUS status = INT_STATUS_SUCCESS;
272  BOOLEAN validateThreads = FALSE;
273 
274  for (DWORD i = 0; i < gLixGuest->OsSpecificFields.FunctionsCount; i++)
275  {
276  DWORD descriptorCount = 0;
277  DWORD descriptorNumber = gLixGuest->OsSpecificFields.Functions[i].HookHandler;
278 
279  for (DWORD j = 0; j < ARRAYSIZE(gLixHookHandlersx64); j++)
280  {
281  if (IntLixApiCmpFunctionNameWithHash(gLixHookHandlersx64[j].FunctionName,
283  {
284  if (descriptorCount != descriptorNumber)
285  {
286  descriptorCount++;
287  continue;
288  }
289 
290  descriptorCount++;
291 
292  BOOLEAN mustValidate = FALSE;
293  status = IntLixApiHook(&gLixHookHandlersx64[j], &mustValidate);
294  if (!INT_SUCCESS(status))
295  {
296  ERROR("[ERROR] Failed to set hook, status: 0x%x\n", status);
297  return status;
298  }
299 
300  if (mustValidate)
301  {
302  validateThreads = TRUE;
303  }
304 
305  break;
306  }
307  }
308  }
309 
310  status = IntKernVirtMemWrite(gLixGuest->MmAlloc.Detour.Data.Address, sizeof(QWORD), &gGuest.CoreOptions.Current);
311  if (!INT_SUCCESS(status))
312  {
313  ERROR("[ERROR] IntKernVirtMemWrite failed for 0x%llx with status: 0x%08x\n",
314  gLixGuest->MmAlloc.Detour.Data.Address, status);
315  return status;
316 
317  }
318 
319  TRACE("[DETOUR] Linux detours activated... \n");
320 
321  if (!validateThreads)
322  {
323  LOG("[LIXAPI] No need for validating threads!\n");
324  return INT_STATUS_SUCCESS;
325  }
326 
327  LOG("[LIXAPI] Ensuring no thread will return into our hooks!\n");
328 
330  if (!INT_SUCCESS(status))
331  {
332  ERROR("[ERROR] IntThrSafeCheckThreads failed: 0x%08x\n", status);
333  return status;
334  }
335 
336  return INT_STATUS_SUCCESS;
337 }
338 
339 
340 void
342  void
343  )
349 {
350  IntPauseVcpus();
351 
352  INTSTATUS status = INT_STATUS_SUCCESS;
353 
354  // The memory zone that contains the #LIX_HYPERCALL_PAGE is protected against write/execute
356  ProtectionOptions),
358  if (!INT_SUCCESS(status))
359  {
360  ERROR("[ERROR] IntKernVirtMemPatchQword failed with status: 0x%08x\n", status);
361  }
362 
363  IntResumeVcpus();
364 }
INTSTATUS IntLixTaskHandleDoExit(void *Detour)
Handles the exit() system call.
Definition: lixprocess.c:3481
#define DETOUR_ENABLE_ALWAYS
Can be used as the API_HOOK_DESCRIPTOR.EnableFlags to always enable the detour.
Definition: detours.h:429
LIX_OPAQUE_FIELDS OsSpecificFields
OS-dependent and specific information.
Definition: lixguest.h:579
INTSTATUS IntLixTaskHandleFork(void *Detour)
Handles the fork() system call performed by a linux process.
Definition: lixprocess.c:3179
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
INTSTATUS IntLixVmaAdjust(void *Detour)
Detour handler for in-guest functions adjusting VMA ranges.
Definition: lixmm.c:2052
struct _LINUX_GUEST::@128 MmAlloc
#define OFFSET_OF(Type, Member)
Definition: introlists.h:33
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
DWORD HookHandler
Used to identify the index of the LIX_FN_DETOUR the in the gLixHookHandlersx64.
Definition: lixguest.h:52
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
#define __init_detour_entry_hijack(fn_name, hijack_fn_name, callback, flags)
Create a new LIX_FN_DETOUR entry that is used for middle-function detours.
Definition: lixapi.c:55
INTSTATUS IntLixFtraceHandler(void *Detour)
Handles the incoming &#39;text_poke&#39; patches from the guest.
Definition: lixguest.c:1481
void IntLixApiUpdateHooks(void)
Update the hookable APIs according to the current Introcore options.
Definition: lixapi.c:341
__default_fn_attr void module_param_sysfs_setup(void *module)
Definition: handlers.c:210
INTSTATUS IntLixCrashPanicHandler(void *Detour)
Called if the &#39;panic&#39; or &#39;kcrash_exec&#39; handler is hit.
Definition: lixcrash.c:493
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
DWORD FunctionsCount
The number of function to be hooked.
Definition: lixguest.h:390
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
#define ARRAYSIZE(A)
Definition: introdefs.h:101
#define INTRO_OPT_PROT_KM_LX_TEXT_READS
Enable kernel &#39;_text&#39; section read protection (Linux only).
Definition: intro_types.h:499
INTSTATUS IntLixTaskHandleVmRw(void *Detour)
Handles the process_vm_writev() system call.
Definition: lixprocess.c:3381
__default_fn_attr void text_poke(void *addr, const void *opcode, size_t len)
Definition: handlers.c:441
__default_fn_attr void change_protection(long vma, unsigned long start, unsigned long end, unsigned long newprot, int dirty_accountable, int prot_numa)
Definition: handlers.c:332
#define ERROR(fmt,...)
Definition: glue.h:62
__default_fn_attr long arch_ptrace(long child, long request)
Definition: handlers.c:278
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
INTSTATUS IntLixApiHookAll(void)
Iterates through all APIs that can be hooked and sets requested hooks.
Definition: lixapi.c:257
int INTSTATUS
The status data type.
Definition: introstatus.h:24
INTSTATUS IntLixVmaRemove(void *Detour)
Detour handler for functions that unmap memory for processes.
Definition: lixmm.c:2111
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
const LIX_FN_DETOUR gLixHookHandlersx64[]
An array of the LIX_FN_DETOUR that contains all detours used by the introspection engine...
Definition: lixapi.c:69
__default_fn_attr void vma_adjust(long _vma, unsigned long _start, unsigned long _end, unsigned long _pgoff, void *_insert, void *_expand, long *_skip_call, long saved_vma, long next, long prev)
Definition: handlers.c:381
__default_fn_attr int complete_signal(int sig, void *task, enum pid_type type)
Definition: handlers.c:422
INTSTATUS IntLixJumpLabelHandler(void *Detour)
Handles the incoming read (arch_jmp_label_transform) from the guest.
Definition: lixguest.c:1497
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
INTSTATUS IntThrSafeCheckThreads(QWORD Options)
Checks if any of the guest threads have their RIP or have any stack pointers pointing to regions of c...
__default_fn_attr void module_param_sysfs_remove(void *module)
Definition: handlers.c:218
INTSTATUS IntLixVmaInsert(void *Detour)
Detour handler for "__vma_link_rb" function.
Definition: lixmm.c:1692
__default_fn_attr void wake_up_new_task(long task)
Definition: handlers.c:226
#define LOG(fmt,...)
Definition: glue.h:61
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
static INTSTATUS IntLixApiHook(const LIX_FN_DETOUR *FnDetour, BOOLEAN *MustValidateThreads)
Will hook one function as described by the FnDetour.
Definition: lixapi.c:177
struct _LINUX_GUEST::@128::@131 Detour
INTSTATUS IntLixVmaChangeProtection(void *Detour)
Detour handler for "change_protection" function.
Definition: lixmm.c:1753
__default_fn_attr void expand_downwards(long vma, unsigned long address)
Definition: handlers.c:409
__default_fn_attr size_t process_vm_rw_core(int pid, void *iter, void *rvec, unsigned long riovcnt, unsigned long flags, int vm_write)
Definition: handlers.c:295
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
INTSTATUS IntLixCommitCredsHandle(void *Detour)
Detour handler for "commit_creds" function.
Definition: lixcred.c:694
INTSTATUS IntLixTaskHandleExec(void *Detour)
Handles the exec() system call of a linux process.
Definition: lixprocess.c:2947
unsigned long long QWORD
Definition: intro_types.h:53
QWORD Current
The currently used options.
Definition: guests.h:236
__default_fn_attr void __access_remote_vm(void *task, void *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags)
Definition: handlers.c:474
static BOOLEAN IntLixApiCmpFunctionNameWithHash(const char *Name, DWORD NameHash)
Check if the crc32 of the Name is equal to the provided NameHash.
Definition: lixapi.c:239
#define TRUE
Definition: intro_types.h:30
__default_fn_attr void panic(const char *fmt)
Definition: handlers.c:458
INTSTATUS IntLixAccessRemoteVmHandler(void *Detour)
Detour handler for __access_remote_vm.
Definition: lixprocess.c:5009
__default_fn_attr void do_exit(long code)
Definition: handlers.c:270
#define TRACE(fmt,...)
Definition: glue.h:58
INTSTATUS IntDetSetLixHook(QWORD FunctionAddress, const LIX_FN_DETOUR *FnDetour, BOOLEAN *MultipleInstructions)
Detours a function from guest.
Definition: detours.c:942
__default_fn_attr void ftrace_write(unsigned long ip, const char *val, int size)
Definition: handlers.c:450
LIX_FUNCTION * Functions
An array of LIX_FUNCTION to be hooked.
Definition: lixguest.h:391
#define INTRO_OPT_ENABLE_UM_PROTECTION
Aggregates all the user mode protection flags.
Definition: intro_types.h:561
#define __forceinline
Definition: introtypes.h:61
uint32_t DWORD
Definition: intro_types.h:49
#define THS_CHECK_DETOURS
Will check if any RIP is inside detours.
__default_fn_attr void arch_jump_label_transform(void *entry, enum jump_label_type type)
Definition: handlers.c:466
__default_fn_attr int begin_new_exec(long binprm)
Definition: handlers.c:252
INTSTATUS IntLixTextPokeHandler(void *Detour)
Handles the incoming &#39;text_poke&#39; patches from the guest.
Definition: lixguest.c:1463
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
#define INTRO_OPT_PANIC_CLEANUP
Enable memory cleanup after an OS crash (Linux).
Definition: intro_types.h:470
#define INTRO_OPT_EVENT_OS_CRASH
Enable OS crash events (generates introEventCrashEvent events).
Definition: intro_types.h:447
__default_fn_attr void commit_creds(long *creds)
Definition: handlers.c:192
DWORD NameHash
Crc32 of the function name.
Definition: lixguest.h:51
INTSTATUS IntLixTaskHandlePtrace(void *Detour)
Handles the ptrace() system call.
Definition: lixprocess.c:3423
INTSTATUS IntKernVirtMemPatchQword(QWORD GuestVirtualAddress, QWORD Data)
Writes 8 bytes in the guest kernel memory.
Definition: introcore.c:932
#define __init_detour_entry_regex(fn_name, regex, callback, flags)
Create a new LIX_FN_DETOUR entry that appends the provided &#39;regex&#39; to the end of the &#39;FunctioName&#39;...
Definition: lixapi.c:38
INTSTATUS IntLixCrashHandle(void *Detour)
Sends an event that contains the information about signal received by the current task...
Definition: lixcrash.c:298
DWORD Crc32String(const char *String, DWORD InitialCrc)
Computes the CRC for a NULL-terminated utf-8 string.
Definition: crc32.c:200
64-bit selector.
Definition: glueiface.h:188
__default_fn_attr void vma_rb_erase(long vma, void *root)
Definition: handlers.c:395
__default_fn_attr void __vma_link_rb(void *mm, void *vma, void **rb_link, void *rb_parent)
Definition: handlers.c:308
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
Definition: dumper.c:432
__default_fn_attr int flush_old_exec(long binprm)
Definition: handlers.c:234
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
INTSTATUS IntLixVmaExpandDownwards(void *Detour)
Detour handler for "expand_downwards" function.
Definition: lixmm.c:1906
#define __init_detour_entry(fn_name, callback, flags)
Create a new LIX_FN_DETOUR entry.
Definition: lixapi.c:22
static INTSTATUS IntLixApiHijackHook(const LIX_FN_DETOUR *FnDetour, QWORD *Address)
Fetch the address of the hijack function name provided by the LIX_FN_DETOUR.
Definition: lixapi.c:107
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
INTSTATUS IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
Definition: decoder.c:180
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
#define FALSE
Definition: intro_types.h:34
Describes a Linux-function to be hooked.
Definition: detours.h:416