Bitdefender Hypervisor Memory Introspection
scan_engines.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "scan_engines.h"
6 #include "guests.h"
7 #include "alerts.h"
8 
19 
20 static void
22  _In_ PIG_ARCH_REGS ArchRegs,
23  _Out_ PINTRO_GPRS IntroGprs
24  )
31 {
32  IntroGprs->RegRax = ArchRegs->Rax;
33  IntroGprs->RegRcx = ArchRegs->Rcx;
34  IntroGprs->RegRdx = ArchRegs->Rdx;
35  IntroGprs->RegRbx = ArchRegs->Rbx;
36  IntroGprs->RegRsp = ArchRegs->Rsp;
37  IntroGprs->RegRbp = ArchRegs->Rbp;
38  IntroGprs->RegRsi = ArchRegs->Rsi;
39  IntroGprs->RegRdi = ArchRegs->Rdi;
40  IntroGprs->RegR8 = ArchRegs->R8;
41  IntroGprs->RegR9 = ArchRegs->R9;
42  IntroGprs->RegR10 = ArchRegs->R10;
43  IntroGprs->RegR11 = ArchRegs->R11;
44  IntroGprs->RegR12 = ArchRegs->R12;
45  IntroGprs->RegR13 = ArchRegs->R13;
46  IntroGprs->RegR14 = ArchRegs->R14;
47  IntroGprs->RegR15 = ArchRegs->R15;
48  IntroGprs->RegFlags = ArchRegs->Flags;
49  IntroGprs->RegRip = ArchRegs->Rip;
50  IntroGprs->RegCr2 = ArchRegs->Cr2;
51  IntroGprs->RegDr7 = ArchRegs->Dr7;
52 }
53 
54 
55 static void
57  _In_ PINTRO_GPRS IntroGprs,
58  _Out_ PIG_ARCH_REGS ArchRegs
59  )
66 {
67  ArchRegs->Rax = IntroGprs->RegRax;
68  ArchRegs->Rcx = IntroGprs->RegRcx;
69  ArchRegs->Rdx = IntroGprs->RegRdx;
70  ArchRegs->Rbx = IntroGprs->RegRbx;
71  ArchRegs->Rsp = IntroGprs->RegRsp;
72  ArchRegs->Rbp = IntroGprs->RegRbp;
73  ArchRegs->Rsi = IntroGprs->RegRsi;
74  ArchRegs->Rdi = IntroGprs->RegRdi;
75  ArchRegs->R8 = IntroGprs->RegR8;
76  ArchRegs->R9 = IntroGprs->RegR9;
77  ArchRegs->R10 = IntroGprs->RegR10;
78  ArchRegs->R11 = IntroGprs->RegR11;
79  ArchRegs->R12 = IntroGprs->RegR12;
80  ArchRegs->R13 = IntroGprs->RegR13;
81  ArchRegs->R14 = IntroGprs->RegR14;
82  ArchRegs->R15 = IntroGprs->RegR15;
83  ArchRegs->Flags = IntroGprs->RegFlags;
84  ArchRegs->Rip = IntroGprs->RegRip;
85  ArchRegs->Cr2 = IntroGprs->RegCr2;
86  ArchRegs->Dr7 = IntroGprs->RegDr7;
87 }
88 
89 
90 static INTSTATUS
92  _In_ PENG_NOTIFICATION_CODE_EXEC ExecNotification
93  )
102 {
103  DWORD offset, csType;
104  IG_ARCH_REGS archRegs = { 0 };
105  BYTE *pPage;
106 
107  offset = ExecNotification->ExecutionData.ExecContext.Registers.RegRip & PAGE_OFFSET;
108  csType = ExecNotification->ExecutionData.Code64 ? IG_CS_TYPE_64B : IG_CS_TYPE_32B;
109  pPage = ExecNotification->ExecutionData.ExecContext.RipCode;
110 
111  IntEngCopyIntroGprsToArchRegs(&ExecNotification->ExecutionData.ExecContext.Registers, &archRegs);
112  IntDumpCode(pPage, offset, csType, &archRegs);
113  IntDumpArchRegs(&archRegs);
114 
115  return INT_STATUS_SUCCESS;
116 }
117 
118 
119 static INTSTATUS
121  _In_ PENG_NOTIFICATION_CODE_EXEC ExecNotification
122  )
129 {
130  INTSTATUS status;
132  INTRO_ACTION_REASON reason;
133 
134  pEvent = &gAlert.EngineDetection;
135  memzero(pEvent, sizeof(*pEvent));
136 
138 
140 
141  pEvent->Header.Action = ExecNotification->Header.RequestedAction;
142  pEvent->Header.Reason = reason;
143 
144  pEvent->Header.Flags = IntAlertProcGetFlags(0, NULL, reason, ALERT_FLAG_FROM_ENGINES);
146 
147  // fill up context we had available at the moment of execution
148  memcpy(&pEvent->ExecViolation, &ExecNotification->ExecutionData, sizeof(INTRO_EXEC_DATA));
149 
150  memcpy(&pEvent->DetectionName[0], &ExecNotification->Header.DetectionName[0], ALERT_MAX_DETECTION_NAME);
151  pEvent->DetectionName[ALERT_MAX_DETECTION_NAME - 1] = 0;
152  memcpy(&pEvent->EnginesVersion[0], &ExecNotification->Header.EnginesVersion[0], ALERT_MAX_ENGINES_VERSION - 1);
153 
154  memcpy(&pEvent->Header.CurrentProcess, &ExecNotification->ExecutionData.Process, sizeof(INTRO_PROCESS));
155 
157  pEvent,
159  if (!INT_SUCCESS(status))
160  {
161  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
162  }
163 
164  return status;
165 }
166 
167 
168 static INTSTATUS
170  _In_ PIG_ARCH_REGS Registers,
171  _Out_ PENG_NOTIFICATION_CODE_EXEC ExecNotification
172  )
181 {
182  INTSTATUS status;
183  DWORD csType;
184 
185  if (NULL == Registers)
186  {
188  }
189 
190  if (NULL == ExecNotification)
191  {
193  }
194 
195  ExecNotification->Header.Type = introEngineNotificationCodeExecution;
196  ExecNotification->Header.OsType = gGuest.OSType;
197 
198  status = IntGetCurrentMode(gVcpu->Index, &csType);
199  if (!INT_SUCCESS(status))
200  {
201  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
202  return status;
203  }
204 
205  ExecNotification->ExecutionData.Code64 = IG_CS_TYPE_64B == csType;
206 
207  // Don't memcpy, as modifying one structure could lead to bad things...
208  IntEngCopyArchRegsToIntroGprs(Registers, &ExecNotification->ExecutionData.ExecContext.Registers);
209 
210  return INT_STATUS_SUCCESS;
211 }
212 
213 
214 INTSTATUS
216  _In_ LIX_TASK_OBJECT *Task,
217  _In_ PIG_ARCH_REGS Registers,
218  _In_ PINTRO_EXEC_INFO ExecInfo
219  )
230 {
231  INTSTATUS status;
232  ENG_NOTIFICATION_CODE_EXEC *pExecNotification;
233 
234  pExecNotification = NULL;
235 
236  if (NULL == Task)
237  {
239  }
240 
241  if (NULL == Registers)
242  {
244  }
245 
246  if (NULL == ExecInfo)
247  {
249  }
250 
251  pExecNotification = HpAllocWithTag(sizeof(ENG_NOTIFICATION_CODE_EXEC), IC_TAG_ENGINE_NOT);
252  if (NULL == pExecNotification)
253  {
254  ERROR("[ERROR] HpAllocWithTag failed!");
256  goto _cleanup_and_exit;
257  }
258 
259  IntAlertFillLixProcess(Task, &pExecNotification->ExecutionData.Process);
260  IntAlertFillExecContext(0, &pExecNotification->ExecutionData.ExecContext);
261 
262  status = IntEngFillExecDetails(Registers, pExecNotification);
263  if (!INT_SUCCESS(status))
264  {
265  WARNING("[WARNING] IntEngFillExecDetails failed: 0x%08x\n", status);
266  goto _cleanup_and_exit;
267  }
268 
269  memcpy(&pExecNotification->ExecutionData.StackInfo, ExecInfo, sizeof(INTRO_EXEC_INFO));
270 
271  status = IntNotifyEngines(pExecNotification);
272  if (!INT_SUCCESS(status))
273  {
274  ERROR("[ERROR] IntNotifyEngines failed: 0x%08x\n", status);
275  }
276 
277 _cleanup_and_exit:
278 
279  if (!INT_SUCCESS(status))
280  {
281  // need to cleanup, since we won't expect the result callback for this event
282  if (pExecNotification)
283  {
284  HpFreeAndNullWithTag(&pExecNotification, IC_TAG_ENGINE_NOT);
285  }
286  }
287 
288  return status;
289 }
290 
291 
292 INTSTATUS
294  _In_ PWIN_PROCESS_OBJECT Process,
295  _In_ PIG_ARCH_REGS Registers,
296  _In_ PINTRO_EXEC_INFO ExecInfo
297  )
308 {
309  INTSTATUS status;
310  ENG_NOTIFICATION_CODE_EXEC *pExecNotification;
311 
312  pExecNotification = NULL;
313 
314  if (NULL == Process)
315  {
317  }
318 
319  if (NULL == Registers)
320  {
322  }
323 
324  if (NULL == ExecInfo)
325  {
327  }
328 
329  pExecNotification = HpAllocWithTag(sizeof(ENG_NOTIFICATION_CODE_EXEC), IC_TAG_ENGINE_NOT);
330  if (NULL == pExecNotification)
331  {
332  ERROR("[ERROR] HpAllocWithTag failed!");
334  goto _cleanup_and_exit;
335  }
336 
337  IntAlertFillWinProcess(Process, &pExecNotification->ExecutionData.Process);
338  IntAlertFillExecContext(0, &pExecNotification->ExecutionData.ExecContext);
339 
340  status = IntEngFillExecDetails(Registers, pExecNotification);
341  if (!INT_SUCCESS(status))
342  {
343  WARNING("[WARNING] IntEngFillExecDetails failed: 0x%08x\n", status);
344  goto _cleanup_and_exit;
345  }
346 
347  memcpy(&pExecNotification->ExecutionData.StackInfo, ExecInfo, sizeof(INTRO_EXEC_INFO));
348 
349  status = IntNotifyEngines(pExecNotification);
350  if (!INT_SUCCESS(status))
351  {
352  ERROR("[ERROR] IntNotifyEngines failed: 0x%08x\n", status);
353  }
354 
355 _cleanup_and_exit:
356 
357  if (!INT_SUCCESS(status))
358  {
359  // need to cleanup, since we won't expect the result callback for this event
360  if (pExecNotification)
361  {
362  HpFreeAndNullWithTag(&pExecNotification, IC_TAG_ENGINE_NOT);
363  }
364  }
365 
366  return status;
367 }
368 
369 
370 INTSTATUS
372  _In_ PENG_NOTIFICATION_CODE_EXEC ExecNotification
373  )
384 {
385  INTSTATUS status;
386 
387  if (introGuestNotAllowed != ExecNotification->Header.RequestedAction)
388  {
389  goto _cleanup_and_exit;
390  }
391 
392  LOG("[CODE EXECUTION] [%s] [code execution violation] Process: %s with PID:%u CR3:0x%llx "
393  "and command line:%s has been exploited! Detection name: %s\n",
394  ExecNotification->Header.OsType == introGuestWindows ? "WIN" : "LIX",
395  ExecNotification->ExecutionData.Process.ImageName,
396  ExecNotification->ExecutionData.Process.Pid,
397  ExecNotification->ExecutionData.Process.Cr3,
398  strlen_s(ExecNotification->ExecutionData.Process.CmdLine, 512) == 0 ?
399  "N/A" : ExecNotification->ExecutionData.Process.CmdLine,
400  ExecNotification->Header.DetectionName
401  );
402 
403  LOG("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MALWARE ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n");
404 
405  IntEngDumpCodeAndRegs(ExecNotification);
406 
407  status = IntEngSendExecViolation(ExecNotification);
408  if (!INT_SUCCESS(status))
409  {
410  WARNING("[ERROR] IntEngSendExecViolation failed: 0x%08x\n", status);
411  }
412 
413 _cleanup_and_exit:
414 
415  if (ExecNotification)
416  {
417  HpFreeAndNullWithTag(&ExecNotification, IC_TAG_ENGINE_NOT);
418  }
419 
420  return INT_STATUS_SUCCESS;
421 }
INTRO_EXEC_CONTEXT ExecContext
The context of the execution.
Definition: intro_types.h:1131
TIMER_FRIENDLY void IntDumpArchRegs(IG_ARCH_REGS const *Registers)
This function dumps the register values in a user friendly format.
Definition: dumper.c:20
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
INTRO_EXEC_DATA ExecutionData
Execution information.
Definition: intro_types.h:2074
#define _Out_
Definition: intro_sal.h:22
static INTSTATUS IntEngSendExecViolation(PENG_NOTIFICATION_CODE_EXEC ExecNotification)
Send an EVENT_ENGINES_DETECTION_VIOLATION event to the integrator (a malicious code execution was det...
Definition: scan_engines.c:120
uint8_t BYTE
Definition: intro_types.h:47
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
INTRO_ENG_NOTIF_TYPE Type
The type of the alert.
Definition: intro_types.h:1868
Holds register state information.
Definition: intro_types.h:1088
void IntAlertFillWinProcess(const WIN_PROCESS_OBJECT *Process, INTRO_PROCESS *EventProcess)
Saves information about a windows process inside an alert.
Definition: alerts.c:689
static void IntEngCopyIntroGprsToArchRegs(PINTRO_GPRS IntroGprs, PIG_ARCH_REGS ArchRegs)
Obtains an IG_ARCH_REGS structure from an INTRO_GPRS structure.
Definition: scan_engines.c:56
static INTSTATUS IntEngFillExecDetails(PIG_ARCH_REGS Registers, PENG_NOTIFICATION_CODE_EXEC ExecNotification)
Fill the execution details inside the ENG_NOTIFICATION_CODE_EXEC structure.
Definition: scan_engines.c:169
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
Sent for third party engines detections. See EVENT_ENGINES_DETECTION_VIOLATION.
Definition: intro_types.h:119
#define PAGE_OFFSET
Definition: pgtable.h:32
#define ERROR(fmt,...)
Definition: glue.h:62
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
INTSTATUS IntHandleExecCallback(PENG_NOTIFICATION_CODE_EXEC ExecNotification)
Handle the code execution scan result provided by the engines.
Definition: scan_engines.c:371
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1867
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
#define ALERT_MAX_DETECTION_NAME
The maximum size of a detection name as given by a third party scan engine.
Definition: intro_types.h:709
#define LOG(fmt,...)
Definition: glue.h:61
32-bit selector.
Definition: glueiface.h:187
QWORD IntAlertProcGetFlags(QWORD ProtectionFlag, const void *Process, INTRO_ACTION_REASON Reason, QWORD AdditionalFlags)
Returns the flags for an alert.
Definition: alerts.c:425
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
Exposes the functions used to schedule an asynchronous code execution scan and receives its result...
INTSTATUS IntGetCurrentMode(DWORD CpuNumber, DWORD *Mode)
Read the current CS type.
Definition: introcpu.c:977
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
INTSTATUS IntLixEngExecSendNotification(LIX_TASK_OBJECT *Task, PIG_ARCH_REGS Registers, PINTRO_EXEC_INFO ExecInfo)
Notify the scan engines about a possible malicious code execution in a Linux guest.
Definition: scan_engines.c:215
Event structure for detections provided by additional scan engines.
Definition: intro_types.h:1865
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
static void IntEngCopyArchRegsToIntroGprs(PIG_ARCH_REGS ArchRegs, PINTRO_GPRS IntroGprs)
Obtains an INTRO_GPRS structure from an IG_ARCH_REGS structure.
Definition: scan_engines.c:21
#define memzero(a, s)
Definition: introcrt.h:35
Execution notification for scan engines.
Definition: intro_types.h:2071
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
INTSTATUS IntNotifyEngines(void *Parameters)
Definition: glue.c:1004
void IntDumpCode(BYTE *Page, DWORD Offset, IG_CS_TYPE CsType, IG_ARCH_REGS *Registers)
This function dumps an entire page (textual disassembly and opcodes).
Definition: dumper.c:637
INTRO_PROCESS Process
The process in which the execution was attempted.
Definition: intro_types.h:1130
#define ALERT_FLAG_FROM_ENGINES
If set, the alert was generated due to a third party scan engines detection.
Definition: intro_types.h:678
#define WARNING(fmt,...)
Definition: glue.h:60
uint32_t DWORD
Definition: intro_types.h:49
#define strlen_s(s, n)
Definition: introcrt.h:34
INTSTATUS IntWinEngExecSendNotification(PWIN_PROCESS_OBJECT Process, PIG_ARCH_REGS Registers, PINTRO_EXEC_INFO ExecInfo)
Notify the scan engines about a possible malicious code execution in a Windows guest.
Definition: scan_engines.c:293
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTRO_EXEC_INFO StackInfo
Stack information.
Definition: intro_types.h:1132
Execution attempt result.
Definition: intro_types.h:131
static INTSTATUS IntEngDumpCodeAndRegs(PENG_NOTIFICATION_CODE_EXEC ExecNotification)
Dump the malicious code and registers (used when a malicious code execution is detected).
Definition: scan_engines.c:91
CHAR EnginesVersion[ALERT_MAX_ENGINES_VERSION]
A NULL-terminated string with the engines versions.
Definition: intro_types.h:1873
CHAR DetectionName[ALERT_MAX_DETECTION_NAME]
A NULL-terminated string with the detection name, as provided by the engines.
Definition: intro_types.h:1871
#define IC_TAG_ENGINE_NOT
Used for asynchronous engine notifications.
Definition: memtags.h:132
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
Holds the data related to an execution attempt.
Definition: intro_types.h:1128
Holds information about an execution attempt.
Definition: intro_types.h:999
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
64-bit selector.
Definition: glueiface.h:188
#define ALERT_MAX_ENGINES_VERSION
The maximum size of the third party scan engines version.
Definition: intro_types.h:710
Holds register state.
Definition: glueiface.h:30
Exploitation for Client Execution.
Definition: intro_types.h:1157
Describes a guest process.
Definition: intro_types.h:901
EVENT_ENGINES_DETECTION_VIOLATION EngineDetection
Definition: alerts.h:33
void IntAlertFillLixProcess(const LIX_TASK_OBJECT *Task, INTRO_PROCESS *EventProcess)
Saves information about a Linux process inside an event.
Definition: alerts.c:1264
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
INTRO_EXEC_DATA ExecViolation
Execution context.
Definition: intro_types.h:1880
This structure describes a running process inside the guest.
Definition: winprocess.h:83
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68