Bitdefender Hypervisor Memory Introspection
lixdeployer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixdeployer.h"
6 #include "guests.h"
7 #include "kernvm.h"
8 #include "alerts.h"
9 #include "lixfiles.h"
10 #include "lixagent_ondemand.h"
11 
12 
13 
14 static INTSTATUS
16  _In_ LIX_AGENT *Agent)
17 {
18  LOG("[LIX-DEPLOYER] Agent with tag %d has just been initialized, error: 0x%08x.",
19  Agent->TagEx, 0);
20 
21  IntLixAgentSendEvent(agentInitialized, Agent->TagEx, 0);
22 
23  return INT_STATUS_SUCCESS;
24 }
25 
26 
27 static INTSTATUS
29  _In_ LIX_AGENT *Agent)
30 {
31  LOG("[LIX-DEPLOYER] Agent with tag %d has just been initialized, error: 0x%08x.",
32  Agent->TagEx, 0);
33 
34  return INT_STATUS_SUCCESS;
35 }
36 
37 
38 static INTSTATUS
40  _In_ DWORD Tag,
41  _Out_ BYTE **Address,
42  _Out_ DWORD *Length)
43 {
45 
46  switch (Tag)
47  {
49  {
50  *Address = gLixGatherAgentx64;
51  *Length = sizeof(gLixGatherAgentx64);
52 
53  break;
54  }
55 
57  {
58  *Address = gLixKillerAgentx64;
59  *Length = sizeof(gLixKillerAgentx64);
60 
61  break;
62  }
63 
64  default:
65  {
66  status = IntGetAgentContent(Tag, gGuest.Guest64, Length, Address);
67  if (!INT_SUCCESS(status) || (*Address == NULL))
68  {
69  ERROR("[ERROR] IntGetAgentContent failed with status: 0x%08x.", status);
70  return status;
71  }
72 
73  break;
74  }
75  }
76 
77  return INT_STATUS_SUCCESS;
78 }
79 
80 
81 static INTSTATUS
83  _In_ DWORD Tag,
84  _In_ DWORD Length,
85  _Out_ char *Args)
86 {
87  switch (Tag)
88  {
90  {
91  INTSTATUS status = IntLixTaskGetAgentsAsCli(Args, Length);
92  if (!INT_SUCCESS(status))
93  {
94  ERROR("[ERROR] IntLixTaskGetAgentsAsCli failed with status: 0x%08x.", status);
95  return status;
96  }
97 
98  break;
99  }
100 
101  default:
102  ERROR("[LIX-DEPLOYER] Found an invalid agent tag %d ...", Tag);
103  return INT_STATUS_NOT_FOUND;
104  }
105 
106  return INT_STATUS_SUCCESS;
107 }
108 
109 
110 static INTSTATUS
112  _In_ LIX_AGENT *Agent
113  )
123 {
124  INTSTATUS status = INT_STATUS_SUCCESS;
125  LIX_AGENT_THREAD *pThread = Agent->Thread;
126  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
127  DWORD writeLength = 0;
128  DWORD maxWriteLength = PAGE_SIZE_2M;
129 
130  if (pThread->Content.CurrentOffset == pThread->Content.Size)
131  {
132  TRACE("[LIX-DEPLOYER] File '%s' deployed.", Agent->Name);
133  pRegs->Rax = writeLength;
134  goto _exit;
135  }
136  else if (pThread->Content.Size - pThread->Content.CurrentOffset > maxWriteLength)
137  {
138  writeLength = maxWriteLength;
139  }
140  else if (pThread->Content.Size - pThread->Content.CurrentOffset < maxWriteLength)
141  {
142  writeLength = pThread->Content.Size - pThread->Content.CurrentOffset;
143  }
144 
146  pRegs->R8,
147  writeLength,
148  pThread->Content.Address + pThread->Content.CurrentOffset,
149  IG_CS_RING_0);
150  if (!INT_SUCCESS(status))
151  {
152  ERROR("[ERROR] IntVirtMemWrite failed with status: 0x%08x.", status);
153 
154  pRegs->Rax = (QWORD)(-1);
155  goto _exit;
156  }
157 
158  pThread->Content.CurrentOffset += writeLength;
159 
160  pRegs->Rax = writeLength;
161 
162 _exit:
163  status = IntSetGprs(gVcpu->Index, pRegs);
164  if (!INT_SUCCESS(status))
165  {
166  return status;
167  }
168 
169  return INT_STATUS_SUCCESS;
170 }
171 
172 
173 INTSTATUS
175  _In_ BYTE *Content,
176  _In_ DWORD Size,
177  _In_ const CHAR *Name
178  )
196 {
197  INTSTATUS status = INT_STATUS_SUCCESS;
198  LIX_AGENT_HANDLER *pHandler = NULL;
199  LIX_AGENT_THREAD_DEPLOY_FILE_ARGS *pArgs = NULL;
200 
201  if (Content == NULL)
202  {
204  }
205 
206  if (Size == 0)
207  {
209  }
210 
211  if (Name == NULL)
212  {
214  }
215 
217  if (pHandler == NULL)
218  {
219  return INT_STATUS_NOT_FOUND;
220  }
221 
222  pArgs = pHandler->Args.Content;
223 
224  pArgs->KernelVersion = gLixGuest->Version.Value;
225 
226  if (gGuest.OSVersion < LIX_CREATE_VERSION(3, 0, 0))
227  {
228  pArgs->Umh.UhmWaitExec = 0;
229  pArgs->Umh.UhmWaitProc = 1;
230  }
231  else
232  {
233  pArgs->Umh.UhmWaitExec = 1;
234  pArgs->Umh.UhmWaitProc = 2;
235  }
236 
237  strlcpy(pArgs->FilePath.Name, Name, sizeof(pArgs->FilePath.Name));
238 
240  0,
244  Name,
245  Content,
246  Size);
248  {
249  TRACE("[LIX-DEPLOYER] A file with already running or pending.\n");
251  }
252 
253  if (!INT_SUCCESS(status))
254  {
255  ERROR("[ERROR] IntLixAgentThreadInject failed with status: 0x%08x\n", status);
256  return status;
257  }
258 
259  LOG("[LIX-DEPLOYER] File '%s' scheduled for injection ...", Name);
260 
261  return INT_STATUS_SUCCESS;
262 }
263 
264 
265 INTSTATUS
267  _In_ const CHAR *CommandLine
268  )
279 {
280  INTSTATUS status = INT_STATUS_SUCCESS;
281  LIX_AGENT_HANDLER *pHandler = NULL;
282  LIX_AGENT_THREAD_RUN_CLI_ARGS *pArgs = NULL;
283 
284  if (CommandLine == NULL)
285  {
287  }
288 
290  if (pHandler == NULL)
291  {
292  return INT_STATUS_NOT_FOUND;
293  }
294 
295  pArgs = pHandler->Args.Content;
296 
297  if (gGuest.OSVersion < LIX_CREATE_VERSION(3, 0, 0))
298  {
299  pArgs->Umh.UhmWaitExec = 0;
300  pArgs->Umh.UhmWaitProc = 1;
301  }
302  else
303  {
304  pArgs->Umh.UhmWaitExec = 1;
305  pArgs->Umh.UhmWaitProc = 2;
306  }
307 
308  strlcpy(pArgs->Exec.Args, CommandLine, sizeof(pArgs->Exec.Args));
309 
311  0,
313  NULL,
315  NULL,
316  NULL,
317  0);
319  {
320  TRACE("[LIX-DEPLOYER] A file already running or pending...\n");
322  }
323 
324  if (!INT_SUCCESS(status))
325  {
326  ERROR("[ERROR] IntLixAgentThreadInject failed with status: 0x%08x\n", status);
327  return status;
328  }
329 
330  LOG("[LIX-DEPLOYER] Command line '%s' scheduled for execution...", CommandLine);
331 
332  return INT_STATUS_SUCCESS;
333 }
334 
335 
336 INTSTATUS
338  _In_ DWORD AgentTag,
339  _In_opt_ BYTE *Content,
340  _In_ DWORD Size,
341  _In_ const char *Name,
342  _In_opt_ const char *Args
343  )
365 {
366  INTSTATUS status = INT_STATUS_SUCCESS;
367  LIX_AGENT_HANDLER *pHandler = NULL;
369  BYTE *pContent = NULL;
370  DWORD contentSize = 0;
371  char pArgsLocal[LIX_MAX_PATH] = { 0 };
372 
373  TRACE("[LIX-DEPLOYER] Requested to inject agent with tag '%d' ...", AgentTag);
374 
375  if (Name == NULL)
376  {
378  }
379 
380  if (Content == NULL)
381  {
382  status = IntLixDepGetInternalContent(AgentTag, &pContent, &contentSize);
383  if (!INT_SUCCESS(status))
384  {
385  ERROR("[ERROR] IntLixDepGetInternalContent failed with status: 0x%08x.", status);
386  return status;
387  }
388 
389  if (Args == NULL)
390  {
391  status = IntLixDepGetInternalArgs(AgentTag, sizeof(pArgsLocal), pArgsLocal);
392  if (!INT_SUCCESS(status))
393  {
394  ERROR("[ERROR] IntLixDepGetInternalArgs failed with status: 0x%08x.", status);
395  return status;
396  }
397 
398  if (strlen(pArgsLocal) == 0)
399  {
401  }
402  }
403  else
404  {
405  strlcpy(pArgsLocal, Args, sizeof(pArgsLocal));
406  }
407 
408  }
409  else
410  {
411  pContent = Content;
412  contentSize = Size;
413  strlcpy(pArgsLocal, Args, sizeof(pArgsLocal));
414  }
415 
416  if ((pContent == NULL) || (contentSize == 0))
417  {
418  ERROR("[ERROR] No proper agent found.");
420  }
421 
423  if (pHandler == NULL)
424  {
425  return INT_STATUS_NOT_FOUND;
426  }
427 
428  pArgs = pHandler->Args.Content;
429  pArgs->KernelVersion = gLixGuest->Version.Value;
430  pArgs->FilePathOffset = (QWORD)LIX_FIELD(Ungrouped, FilePath);
431 
432  if (gGuest.OSVersion < LIX_CREATE_VERSION(3, 0, 0))
433  {
434  pArgs->Umh.UhmWaitExec = 0;
435  pArgs->Umh.UhmWaitProc = 1;
436  }
437  else
438  {
439  pArgs->Umh.UhmWaitExec = 1;
440  pArgs->Umh.UhmWaitProc = 2;
441  }
442 
443 
444  strlcpy(pArgs->FilePath.Name, Name, sizeof(pArgs->FilePath.Name));
445  snprintf(pArgs->Exec.Args, LIX_AGENT_MAX_ARGS_LENGTH, "%c%s %s", pArgs->FilePath.Root, Name, pArgsLocal);
446 
448  AgentTag,
452  Name,
453  pContent,
454  contentSize);
456  {
457  TRACE("[DEPLOYER] A file already running or pending...\n");
459  }
460 
461  if (!INT_SUCCESS(status))
462  {
463  ERROR("[ERROR] IntLixAgentThreadInject failed with status: 0x%08x\n", status);
464  return status;
465  }
466 
467  LOG("[LIX-DEPLOYER] File '%s' scheduled for execution using command line '%s' ...", Name, pArgs->Exec.Args);
468 
469  return INT_STATUS_SUCCESS;
470 }
static INTSTATUS IntLixDepComplete(LIX_AGENT *Agent)
Definition: lixdeployer.c:15
#define _In_opt_
Definition: intro_sal.h:16
#define _Out_
Definition: intro_sal.h:22
Describes a handlers that contains the data required by the agent.
Definition: lixagent.h:217
char Args[LIX_AGENT_MAX_ARGS_LENGTH]
The command line to be executed.
Definition: lixagent.h:366
uint8_t BYTE
Definition: intro_types.h:47
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
struct _LIX_AGENT_THREAD_DEPLOY_FILE_ARGS::@111 Umh
QWORD UhmWaitExec
The value of UMH_WAIT_EXEC of current guest.
Definition: lixagent.h:372
Arguments of the run command-line agent.
Definition: lixagent.h:362
Describes an agent-thread running inside the guest.
Definition: lixagent.h:119
QWORD UhmWaitProc
The value of UMH_WAIT_PROC of current guest.
Definition: lixagent.h:317
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
static INTSTATUS IntLixDepGetInternalArgs(DWORD Tag, DWORD Length, char *Args)
Definition: lixdeployer.c:82
Run a custom command.
Definition: lixagent.h:69
Describe an agent running inside the guest.
Definition: lixagent.h:149
Arguments of the exec agent.
Definition: lixagent.h:327
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
INTSTATUS IntLixDepInjectFile(BYTE *Content, DWORD Size, const CHAR *Name)
Injects an agent that deploy a file with the provided content and name on the disk.
Definition: lixdeployer.c:174
#define ERROR(fmt,...)
Definition: glue.h:62
Arguments of the deploy-file agent.
Definition: lixagent.h:299
QWORD KernelVersion
The current guest kernel version.
Definition: lixagent.h:329
char Name[LIX_AGENT_MAX_NAME_LENGTH]
The name of the deployed file.
Definition: lixagent.h:312
int INTSTATUS
The status data type.
Definition: introstatus.h:24
static INTSTATUS IntLixDepDeployFileHypercall(LIX_AGENT *Agent)
Writes a chunk of the file into a allocated buffer by the agent.
Definition: lixdeployer.c:111
INTSTATUS IntLixAgentThreadInject(LIX_AGENT_TAG Tag, DWORD TagEx, AGENT_TYPE AgentType, PFUNC_AgentCallbackHypercall HypercallCallback, PFUNC_AgentCallbackCompletion CompletionCallback, const char *Name, BYTE *ContentAddress, DWORD ContentSize)
Schedule an thread-agent injection inside the guest.
Definition: lixagent.c:954
DWORD OSVersion
Os version.
Definition: guests.h:281
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
QWORD UhmWaitProc
The value of UMH_WAIT_PROC of current guest.
Definition: lixagent.h:371
struct _LIX_AGENT_THREAD_DEPLOY_FILE_EXEC_ARGS::@115 Umh
#define LIX_CREATE_VERSION(K, Patch, Sublevel)
Definition: lixguest.h:596
#define LOG(fmt,...)
Definition: glue.h:61
INTSTATUS IntLixDepRunCommand(const CHAR *CommandLine)
Injects an agent that creates a process that will execute the provided command line.
Definition: lixdeployer.c:266
The process killer agent.
Definition: glueiface.h:350
QWORD UhmWaitExec
The value of UMH_WAIT_EXEC of current guest.
Definition: lixagent.h:318
struct _LIX_AGENT_THREAD_DEPLOY_FILE_ARGS::@110 FilePath
BYTE * Address
A pointer to the content provided by the integrator.
Definition: lixagent.h:134
static INTSTATUS IntLixDepRunCommandComplete(LIX_AGENT *Agent)
Definition: lixdeployer.c:28
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:290
unsigned long long QWORD
Definition: intro_types.h:53
INTSTATUS IntLixTaskGetAgentsAsCli(char *CommandLine, DWORD Length)
Returns a string with the command lines of all active agents.
Definition: lixprocess.c:4525
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:429
#define TRACE(fmt,...)
Definition: glue.h:58
struct _LIX_AGENT_HANDLER::@101 Args
size_t strlcpy(char *dst, const char *src, size_t dest_size)
Definition: introcrt.c:1093
unsigned char gLixGatherAgentx64[7784]
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
struct _LIX_AGENT_THREAD_DEPLOY_FILE_EXEC_ARGS::@113 FilePath
void IntLixAgentSendEvent(AGENT_EVENT_TYPE Event, DWORD AgentTag, DWORD ErrorCode)
Send an event to the integrator that contains the AGENT_EVENT_TYPE, tag of the agent and the last err...
Definition: lixagent.c:2119
INTSTATUS IntVirtMemSafeWrite(QWORD Cr3, QWORD VirtualAddress, DWORD Size, void *Buffer, DWORD Ring)
Safely modify guest memory.
Definition: kernvm.c:498
QWORD UhmWaitProc
The value of UMH_WAIT_PROC of current guest.
Definition: lixagent.h:352
static INTSTATUS IntLixDepGetInternalContent(DWORD Tag, BYTE **Address, DWORD *Length)
Definition: lixdeployer.c:39
INTSTATUS IntLixDepInjectProcess(DWORD AgentTag, BYTE *Content, DWORD Size, const char *Name, const char *Args)
Injects an agent that deploy a file to the disk and creates a process that execute the deployed file...
Definition: lixdeployer.c:337
uint32_t DWORD
Definition: intro_types.h:49
Execute a file (process).
Definition: lixagent.h:68
The log gathering agent.
Definition: glueiface.h:347
QWORD KernelVersion
The current guest kernel version.
Definition: lixagent.h:301
#define LIX_MAX_PATH
The maximum length of a dentry-path.
Definition: lixfiles.h:33
DWORD CurrentOffset
Used when the HypecallCallback is called as an offset in the content buffer.
Definition: lixagent.h:138
#define PAGE_SIZE_2M
Definition: pgtable.h:15
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
Definition: introcpu.c:905
INTSTATUS IntGetAgentContent(DWORD AgentTag, BOOLEAN Is64, DWORD *Size, BYTE **Content)
Definition: glue.c:1066
char Root
The root directory (eg. &#39;/&#39;)
Definition: lixagent.h:340
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
void * Content
The content of the arguments.
Definition: lixagent.h:225
LIX_AGENT_HANDLER * IntLixAgentThreadGetHandlerByTag(LIX_AGENT_TAG AgentTag, LIX_AGENT_TAG ThreadTag)
Iterates through all thread-agent handlers and search the entry that has the provided tag...
Definition: lixaghnd.c:432
struct _LIX_AGENT_THREAD_DEPLOY_FILE_EXEC_ARGS::@114 Exec
char Args[LIX_AGENT_MAX_ARGS_LENGTH]
The arguments given to the process.
Definition: lixagent.h:347
The create thread agent.
Definition: lixagent.h:64
QWORD FilePathOffset
The offset of struct file.path.
Definition: lixagent.h:330
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
char Name[LIX_AGENT_MAX_NAME_LENGTH]
The name of the deployed file.
Definition: lixagent.h:341
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
QWORD UhmWaitExec
The value of UMH_WAIT_EXEC of current guest.
Definition: lixagent.h:353
Deploy a file.
Definition: lixagent.h:67
Process agent. A process will be injected & started inside the guest.
Definition: aghcall.h:47
Holds register state.
Definition: glueiface.h:30
unsigned char gLixKillerAgentx64[7640]
The agent has been initialized.
Definition: intro_types.h:2100
BYTE Version
The version field of the version string.
Definition: lixguest.h:487
char CHAR
Definition: intro_types.h:56
struct _LIX_AGENT_THREAD::@97 Content
struct _LIX_AGENT_THREAD_RUN_CLI_ARGS::@117 Umh
struct _LIX_AGENT_THREAD_RUN_CLI_ARGS::@116 Exec
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
File agent. A file will be dropped inside the guest.
Definition: aghcall.h:46
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
DWORD Size
The size of the content provided by the integrator.
Definition: lixagent.h:135
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68
#define LIX_AGENT_MAX_ARGS_LENGTH
Definition: lixagent.h:14