Bitdefender Hypervisor Memory Introspection
windeployer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "windeployer.h"
6 #include "winagent.h"
7 #include "alerts.h"
8 #include "guests.h"
9 #include "winagent_dummy_Win32.h"
10 #include "winagent_dummy_x64.h"
11 #include "winagent_gather_Win32.h"
12 #include "winagent_gather_x64.h"
13 #include "winagent_killer_Win32.h"
14 #include "winagent_killer_x64.h"
15 #include "winpe.h"
16 #include "winprocesshp.h"
17 
18 
19 static INTSTATUS
21  _In_ QWORD GuestVirtualAddress,
22  _In_ DWORD AgentTag,
23  _In_opt_ void *Context
24  )
39 {
41  INTSTATUS status;
42 
43  UNREFERENCED_PARAMETER(Context);
44 #if LOG_LEVEL == 0
45  UNREFERENCED_PARAMETER(GuestVirtualAddress);
46 #endif
47 
48  LOG("[DEPLOYER] Agent with tag %d at 0x%016llx has just been injected!\n", AgentTag, GuestVirtualAddress);
49 
50  memzero(event, sizeof(*event));
51 
52  event->AgentTag = AgentTag;
53  event->Event = agentInjected;
54 
55  status = IntNotifyIntroEvent(introEventAgentEvent, event, sizeof(*event));
56  if (!INT_SUCCESS(status))
57  {
58  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
59  }
60 
61  // over-write the status
62  status = INT_STATUS_SUCCESS;
63 
64  return status;
65 }
66 
67 
68 static INTSTATUS
70  _In_ QWORD GuestVirtualAddress,
71  _In_ DWORD ErrorCode,
72  _In_ DWORD AgentTag,
73  _In_opt_ void *Context
74  )
88 {
90  INTSTATUS status;
91 
92  UNREFERENCED_PARAMETER(Context);
93 
94 #if LOG_LEVEL == 0
95  UNREFERENCED_PARAMETER(GuestVirtualAddress);
96 #endif
97 
98  memzero(event, sizeof(*event));
99 
100  LOG("[DEPLOYER] Agent with tag %d at 0x%016llx has just been initialized, error: 0x%08x! "
101  "The process may still be running...\n", AgentTag, GuestVirtualAddress, ErrorCode);
102 
103  event->Event = agentInitialized;
104  event->AgentTag = AgentTag;
105  event->ErrorCode = ErrorCode;
106 
107  status = IntNotifyIntroEvent(introEventAgentEvent, event, sizeof(*event));
108  if (!INT_SUCCESS(status))
109  {
110  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
111  }
112 
113  // don't return the status from IntNotifyIntroEvent
114  return INT_STATUS_SUCCESS;
115 }
116 
117 
118 static INTSTATUS
120  _Out_writes_bytes_(Length) char *CommandLine,
121  _In_ DWORD Length
122  )
131 {
132  return IntWinProcGetAgentsAsCli(CommandLine, Length);
133 }
134 
135 
136 INTSTATUS
138  _In_ DWORD AgentTag,
139  _In_opt_ PBYTE AgentContent,
140  _In_opt_ DWORD AgentSize,
141  _In_ const CHAR *Name,
142  _In_opt_ const CHAR *Args
143  )
164 {
165  INTSTATUS status;
166  DWORD procSize;
167  PBYTE procContent;
168  CHAR localArgs[MAX_PATH] = { 0 };
169  BOOLEAN agint;
170 
171  procContent = NULL;
172  procSize = 0;
173  agint = FALSE;
174 
175  if (NULL == AgentContent)
176  {
177  agint = TRUE;
178 
179  if (IG_AGENT_TAG_DUMMY_TOOL == AgentTag)
180  {
181  if (gGuest.Guest64)
182  {
183  procSize = sizeof(gDummyToolx64);
184  procContent = gDummyToolx64;
185  }
186  else
187  {
188  procSize = sizeof(gDummyToolx86);
189  procContent = gDummyToolx86;
190  }
191  }
192  else if (IG_AGENT_TAG_LOG_GATHER_TOOL == AgentTag)
193  {
194  if (gGuest.Guest64)
195  {
196  procSize = sizeof(gGatherAgentx64);
197  procContent = gGatherAgentx64;
198  }
199  else
200  {
201  procSize = sizeof(gGatherAgentWin32);
202  procContent = gGatherAgentWin32;
203  }
204  }
205  else if (IG_AGENT_TAG_AGENT_KILLER_TOOL == AgentTag)
206  {
207  if (gGuest.Guest64)
208  {
209  procSize = sizeof(gAgentKillerx64);
210  procContent = gAgentKillerx64;
211  }
212  else
213  {
214  procSize = sizeof(gAgentKillerWin32);
215  procContent = gAgentKillerWin32;
216  }
217 
218  if (NULL == Args)
219  {
220  status = IntWinFormatAgentKillerCommandLine(localArgs, sizeof(localArgs));
221  if (!INT_SUCCESS(status))
222  {
223  ERROR("[ERROR] IntFormatAgentKillerCommandLine failed: %08x\n", status);
224  return status;
225  }
226 
227  if (0 == strlen(localArgs))
228  {
230  }
231 
232  Args = localArgs;
233 
234  TRACE("[KILLER] Will use `%s` as a command line\n", localArgs);
235  }
236  }
237  else
238  {
239  agint = FALSE; // override this, if we call GetAgentContent, it will become external.
240 
241  status = IntGetAgentContent(AgentTag, gGuest.Guest64, &procSize, &procContent);
242  if (!INT_SUCCESS(status) || (0 == procContent))
243  {
244  ERROR("[ERROR] IntGetAgentContent failed: 0x%08x\n", status);
245  return status;
246  }
247  }
248  }
249  else
250  {
251  procContent = AgentContent;
252  procSize = AgentSize;
253  }
254 
255  if ((NULL == procContent) || (0 == procSize))
256  {
257  ERROR("[ERROR] No proper agent found!\n");
259  }
260 
261  // Before moving on, make sure the injected executable matches the guest architecture. Needed on Windows, on Linux,
262  // we only support 64 bit guests.
263  INTRO_PE_INFO peInfo = { 0 };
264 
265  status = IntPeValidateHeader(0, procContent, procSize, &peInfo, 0);
266  if (!INT_SUCCESS(status))
267  {
268  ERROR("[ERROR] The provided agent does not look like a valid MZ/PE: 0x%08x\n", status);
269  return status;
270  }
271 
272  if (peInfo.Image64Bit && !gGuest.Guest64)
273  {
274  ERROR("[ERROR] The provided agent does not match the OS arch: %s bit\n", gGuest.Guest64 ? "64" : "32");
276  }
277 
278  // Schedule the injection
279  status = IntWinAgentInject(IntWinDepDeploy, IntWinDepComplete, NULL, NULL, procContent, procSize, agint, AgentTag,
280  AGENT_TYPE_PROCESS, Name, 0, Args, 0, NULL);
281  if (!INT_SUCCESS(status))
282  {
283  ERROR("[ERROR] IntAgentInject failed: 0x%08x\n", status);
284  return status;
285  }
286 
287  LOG("[DEPLOYER] Agent with tag %d was scheduled for injection, waiting...\n", AgentTag);
288 
289  return INT_STATUS_SUCCESS;
290 }
291 
292 
293 INTSTATUS
295  _In_ PBYTE FileContent,
296  _In_ DWORD FileSize,
297  _In_ const CHAR *Name
298  )
311 {
312  INTSTATUS status;
313 
314  // Schedule the injection
315  status = IntWinAgentInject(IntWinDepDeploy, IntWinDepComplete, NULL, NULL, FileContent, FileSize, FALSE, 0,
316  AGENT_TYPE_FILE, Name, 0, NULL, 0, NULL);
317  if (!INT_SUCCESS(status))
318  {
319  ERROR("[ERROR] IntAgentInject failed: 0x%08x\n", status);
320  return status;
321  }
322 
323  LOG("[DEPLOYER] File scheduled for injection!\n");
324 
325  return INT_STATUS_SUCCESS;
326 }
#define _In_opt_
Definition: intro_sal.h:16
_Bool BOOLEAN
Definition: intro_types.h:58
Dummy agent used to demo the feature.
Definition: glueiface.h:338
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
#define _Out_writes_bytes_(expr)
Definition: intro_sal.h:38
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
Event structure for agent injection and termination.
Definition: intro_types.h:2345
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
INTSTATUS IntWinDepInjectFile(PBYTE FileContent, DWORD FileSize, const CHAR *Name)
Inject a file inside the Windows guest.
Definition: windeployer.c:294
int INTSTATUS
The status data type.
Definition: introstatus.h:24
#define MAX_PATH
The maximum size of a path (260 characters on windows).
Definition: winpe.h:579
#define LOG(fmt,...)
Definition: glue.h:61
The agent has been successfully injected.
Definition: intro_types.h:2099
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
The process killer agent.
Definition: glueiface.h:350
uint8_t * PBYTE
Definition: intro_types.h:47
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
#define memzero(a, s)
Definition: introcrt.h:35
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
Informational event sent when the remediation tool is injected or terminated. See EVENT_AGENT_EVENT...
Definition: intro_types.h:104
static INTSTATUS IntWinDepDeploy(QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)
Boot agent deployment callback.
Definition: windeployer.c:20
#define TRUE
Definition: intro_types.h:30
#define TRACE(fmt,...)
Definition: glue.h:58
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntWinAgentInject(PFUNC_AgentInjection InjectionCallback, PFUNC_AgentCompletion CompletionCallback, PFUNC_AgentDeliver DeliverCallback, void *Context, PBYTE AgentContent, DWORD AgentSize, BOOLEAN AgentInternal, DWORD AgentTag, AGENT_TYPE AgentType, const CHAR *Name, DWORD Options, const CHAR *Args, DWORD Pid, PWIN_AGENT *Agent)
Schedule an agent injection inside the guest.
Definition: winagent.c:2608
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
EVENT_AGENT_EVENT Agent
Definition: alerts.h:29
uint32_t DWORD
Definition: intro_types.h:49
The log gathering agent.
Definition: glueiface.h:347
INTSTATUS IntPeValidateHeader(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD ImageBaseBufferSize, INTRO_PE_INFO *PeInfo, QWORD Cr3)
Validates a PE header.
Definition: winpe.c:131
INTSTATUS IntGetAgentContent(DWORD AgentTag, BOOLEAN Is64, DWORD *Size, BYTE **Content)
Definition: glue.c:1066
static INTSTATUS IntWinDepComplete(QWORD GuestVirtualAddress, DWORD ErrorCode, DWORD AgentTag, void *Context)
Called once the boot driver finishes starting the agent inside the guest.
Definition: windeployer.c:69
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTSTATUS IntWinProcGetAgentsAsCli(PCHAR CommandLine, DWORD Length)
Returns the name and ID for all the processes injected as agents inside the guest.
Definition: winprocesshp.c:812
INTSTATUS IntWinDepInjectProcess(DWORD AgentTag, PBYTE AgentContent, DWORD AgentSize, const CHAR *Name, const CHAR *Args)
Inject a process inside a Windows guest.
Definition: windeployer.c:137
Process agent. A process will be injected & started inside the guest.
Definition: aghcall.h:47
BOOLEAN Image64Bit
True if the image is 64 bit.
Definition: winpe.h:596
The agent has been initialized.
Definition: intro_types.h:2100
char CHAR
Definition: intro_types.h:56
#define INT_STATUS_INVALID_PARAMETER
Definition: introstatus.h:59
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
File agent. A file will be dropped inside the guest.
Definition: aghcall.h:46
#define FALSE
Definition: intro_types.h:34
static INTSTATUS IntWinFormatAgentKillerCommandLine(char *CommandLine, DWORD Length)
Formats the agent killer command line.
Definition: windeployer.c:119