Bitdefender Hypervisor Memory Introspection
visibility.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "visibility.h"
6 #include "guests.h"
7 #include "winprocesshp.h"
8 
9 
10 //
11 // IntWinGetStartUpTime
12 //
15  _Out_ QWORD *StartUpTime
16  )
31 {
32  INTSTATUS status;
33  PWIN_PROCESS_OBJECT systemProc;
34 
35  if (NULL == StartUpTime)
36  {
38  }
39 
40  systemProc = IntWinProcFindObjectByPid(4);
41  if (NULL == systemProc)
42  {
44  }
45 
46  // CreateTime is represented as a FILETIME on both x86 and x64
47  status = IntKernVirtMemFetchQword(systemProc->EprocessAddress + WIN_KM_FIELD(Process, CreateTime),
48  StartUpTime);
49  if (!INT_SUCCESS(status))
50  {
51  ERROR("[ERROR] IntKernVirtMemFetchQword failed: 0x%08x\n", status);
52  return status;
53  }
54 
55  return INT_STATUS_SUCCESS;
56 }
57 
58 
59 //
60 // A lot of this is based on http://www.alex-ionescu.com/?p=196
61 //
62 // * From a EPROCESS we read a pointer to a _HANDLE_TABLE struct (Eprocess.ObjectTable)
63 // * From that HandleTable we can get the handles array assigned to our process from the TableCode field. TableCode
64 // can be interpreted in different ways. If the lower 3 bits are cleared, tableCode is a pointer to the start of
65 // the handle table. If tableCode[0-2] = 1, we have a 2-level or a 3-level handle table. When the maximum valid
66 // handle value is reached, it is reseted and we use it to index the next handle table.
67 // * A Handle value is used as an index inside this table. The lower 2 bits of a handle value are ignored and 0x0
68 // is not a valid handle value, so the lowest valid handle value is 0x4. The first (possible) valid handle
69 // is HandleTable[4 * sizeof _HANDLE_TABLE_ENTRY]
70 // * HandleCount is equal to the number of open handles. A free handle can be found between two open handles. In
71 // order to make sure we return all the open handles we need to determine the free ones. We can use
72 // HandleTable.FirstFreeHandleEntry, HandleTable.LastFreeHandleEntry and HandleTableEntry.NextFreeHandleEntry.
73 // Starting with Windows 8, FirstFreeHandleEntry and NextFreeHandleEntry point directly to the handle table entry
74 // structure. On Windows 7 it is equal to the handle value of the free handle. LastFreeHandleEntry is always a
75 // pointer to a handle table entry.
76 // Or we could do a little trick: a valid handle will point to a object header. This means that the pointer must be
77 // a valid kernel pointer. It seems that free handles don't have a valid kernel address in ObjectPtr.
78 // If this method backfires we will use the first.
79 // * Starting with Windows 8, the first field of the _HANDLE_TABLE_ENTRY (DWORD on x86, QWORD on x64) is actually
80 // a pointer to a _OBJECT_HEADER that describes the object related to this handle. The lowest 3 bits are used to
81 // store additional info about the object (Audit, Inherited, Protected for x64 and Lock, Audit, Inherited for x86,
82 // see the above link for additional details.
83 // * the Object we search for is always stored after the ObjectHeader structure so we can get to it by simply adding
84 // the offset at which Quad is in _OBJECT_HEADER.
85 // * user mode sockets (WSA) are nothing more than file objects. File objects that represent sockets have the file
86 // name "\Endpoint" and have a pointer to a Afd.sys object list in FsContext (AfdEndpointListHead is the start of
87 // this list). Also FileObject.DeviceObject points to a device from Afd.sys
88 //
89 
90 
91 static void
93  _In_ QWORD Mask
94  )
102 {
103  const CHAR *privs2str[] =
104  {
105  /* 00 */ NULL,
106  /* 01 */ NULL,
107  /* 02 */ "SeCreateTokenPrivilege",
108  /* 03 */ "SeAssignPrimaryTokenPrivilege",
109  /* 04 */ "SeLockMemoryPrivilege",
110  /* 05 */ "SeIncreaseQuotaPrivilege",
111  /* 06 */ "SeMachineAccountPrivilege",
112  /* 07 */ "SeTcbPrivilege",
113  /* 08 */ "SeSecurityPrivilege",
114  /* 09 */ "SeTakeOwnershipPrivilege",
115  /* 10 */ "SeLoadDriverPrivilege",
116  /* 11 */ "SeSystemProfilePrivilege",
117  /* 12 */ "SeSystemtimePrivilege",
118  /* 13 */ "SeProfileSingleProcessPrivilege",
119  /* 14 */ "SeIncreaseBasePriorityPrivilege",
120  /* 15 */ "SeCreatePagefilePrivilege",
121  /* 16 */ "SeCreatePermanentPrivilege",
122  /* 17 */ "SeBackupPrivilege",
123  /* 18 */ "SeRestorePrivilege",
124  /* 19 */ "SeShutdownPrivilege",
125  /* 20 */ "SeDebugPrivilege",
126  /* 21 */ "SeAuditPrivilege",
127  /* 22 */ "SeSystemEnvironmentPrivilege",
128  /* 23 */ "SeChangeNotifyPrivilege",
129  /* 24 */ "SeRemoteShutdownPrivilege",
130  /* 25 */ "SeUndockPrivilege",
131  /* 26 */ "SeSyncAgentPrivilege",
132  /* 27 */ "SeEnableDelegationPrivilege",
133  /* 28 */ "SeManageVolumePrivilege",
134  /* 29 */ "SeImpersonatePrivilege",
135  /* 30 */ "SeCreateGlobalPrivilege",
136  /* 31 */ "SeTrustedCredManAccessPrivilege",
137  /* 32 */ "SeRelabelPrivilege",
138  /* 33 */ "SeIncreaseWorkingSetPrivilege",
139  /* 34 */ "SeTimeZonePrivilege",
140  /* 35 */ "SeCreateSymbolicLinkPrivilege",
141  };
142 
143  for (DWORD i = 0; i < 63; i++)
144  {
145  if (BIT(i) & Mask)
146  {
147  if (i >= ARRAYSIZE(privs2str) || privs2str[i] == NULL)
148  {
149  LOG("%d Unknown Privilege\n", i);
150  }
151  else
152  {
153  LOG("%d %s\n", i, privs2str[i]);
154  }
155  }
156  }
157 }
158 
159 
160 //
161 // IntWinDumpPrivileges
162 //
163 INTSTATUS
165  _In_ INTRO_TOKEN_PRIVILEGES const *Privileges
166  )
175 {
176  if (NULL == Privileges)
177  {
179  }
180 
181  LOG("Present: \n");
182  IntWinDumpPrivilegesMask(Privileges->Present);
183 
184  LOG("Enabled: \n");
185  IntWinDumpPrivilegesMask(Privileges->Enabled);
186 
187  LOG("Enabled By Default: \n");
188  IntWinDumpPrivilegesMask(Privileges->EnabledByDefault);
189 
190  return INT_STATUS_SUCCESS;
191 }
192 
193 //
194 // IntWinReadSid
195 //
196 INTSTATUS
198  _In_ QWORD SidAndAttributesGva,
200  )
216 {
217  INTSTATUS status;
218  QWORD sidGva;
219 
220  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, SidAndAttributesGva))
221  {
223  }
224 
225  if (NULL == Sid)
226  {
228  }
229 
230  if (gGuest.Guest64)
231  {
232  SID_AND_ATTRIBUTES64 sa = {0};
233 
234  status = IntKernVirtMemRead(SidAndAttributesGva, sizeof(sa), &sa, NULL);
235  if (!INT_SUCCESS(status))
236  {
237  return status;
238  }
239 
240  Sid->Attributes = sa.Attributes;
241  sidGva = sa.Sid;
242  }
243  else
244  {
245  SID_AND_ATTRIBUTES32 sa = {0};
246 
247  status = IntKernVirtMemRead(SidAndAttributesGva, sizeof(sa), &sa, NULL);
248  if (!INT_SUCCESS(status))
249  {
250  return status;
251  }
252 
253  Sid->Attributes = sa.Attributes;
254  sidGva = sa.Sid;
255  }
256 
257  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, sidGva))
258  {
260  }
261 
262  status = IntKernVirtMemRead(sidGva, sizeof(INTRO_WIN_SID), &Sid->Sid, NULL);
263  if (!INT_SUCCESS(status))
264  {
265  return status;
266  }
267 
268  Sid->Sid.SubAuthorityCount = MIN(Sid->Sid.SubAuthorityCount, INTRO_WIN_SID_MAX_SUB_AUTHORITIES);
269 
270  return IntKernVirtMemRead(sidGva + FIELD_OFFSET(INTRO_WIN_SID, SubAuthority),
271  sizeof(DWORD) * Sid->Sid.SubAuthorityCount, &Sid->Sid.SubAuthority, NULL);
272 }
273 
274 
275 //
276 // IntWinReadToken
277 //
278 INTSTATUS
280  _In_ QWORD TokenGva,
281  _Out_ INTRO_WIN_TOKEN *Token
282  )
297 {
298  INTSTATUS status;
299 
300  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, TokenGva))
301  {
303  }
304 
305  if (NULL == Token)
306  {
308  }
309 
310  // read the privileges
311  status = IntKernVirtMemRead(TokenGva + WIN_KM_FIELD(Token, Privs),
312  sizeof(INTRO_TOKEN_PRIVILEGES), &Token->Privileges, NULL);
313  if (!INT_SUCCESS(status))
314  {
315  return status;
316  }
317 
318  // read User and Groups SIDs
319  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, UserCount),
320  &Token->SidCount);
321  if (!INT_SUCCESS(status))
322  {
323  return status;
324  }
325 
326  // assume that the buffers are large enough
327  Token->SidsBufferTooSmall = Token->RestrictedSIdsBufferTooSmall = FALSE;
328 
329  if (0 != Token->SidCount)
330  {
331  QWORD gva = 0;
332  size_t incrementSize;
333 
334  if (Token->SidCount > INTRO_SIDS_MAX_COUNT)
335  {
336  Token->SidCount = INTRO_SIDS_MAX_COUNT;
337  Token->SidsBufferTooSmall = TRUE;
338  }
339 
340  if (gGuest.Guest64)
341  {
342  incrementSize = sizeof(SID_AND_ATTRIBUTES64);
343  status = IntKernVirtMemFetchQword(TokenGva + WIN_KM_FIELD(Token, Users), &gva);
344  }
345  else
346  {
347  incrementSize = sizeof(SID_AND_ATTRIBUTES32);
348  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, Users), (PDWORD)&gva);
349  gva &= 0xFFFFFFFF;
350  }
351  if (!INT_SUCCESS(status))
352  {
353  WARNING("[WARNING] Failed to read Token.UserAndGroups: 0x%08x\n", status);
354  return status;
355  }
356 
357  for (DWORD i = 0; i < Token->SidCount; i++)
358  {
359  status = IntWinReadSid(gva + i * incrementSize, &Token->SidsAndAttributes[i]);
360  if (!INT_SUCCESS(status))
361  {
362  return status;
363  }
364 
365  Token->SidsAndAttributes[i].IsRestricted = FALSE;
366  }
367  }
368 
369  // read Restricted SIDs
370  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, RestrictedCount),
371  &Token->RestrictedSidCount);
372  if (!INT_SUCCESS(status))
373  {
374  return status;
375  }
376 
377  if (0 != Token->RestrictedSidCount)
378  {
379  QWORD gva = 0;
380  size_t incrementSize;
381 
382  if (Token->RestrictedSidCount > INTRO_SIDS_MAX_COUNT)
383  {
384  Token->RestrictedSidCount = INTRO_SIDS_MAX_COUNT;
385  Token->RestrictedSIdsBufferTooSmall = TRUE;
386  }
387 
388  if (gGuest.Guest64)
389  {
390  incrementSize = sizeof(SID_AND_ATTRIBUTES64);
391  status = IntKernVirtMemFetchQword(TokenGva + WIN_KM_FIELD(Token, RestrictedSids), &gva);
392  }
393  else
394  {
395  incrementSize = sizeof(SID_AND_ATTRIBUTES32);
396  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, RestrictedSids), (PDWORD)&gva);
397  gva &= 0xFFFFFFFF;
398  }
399  if (!INT_SUCCESS(status))
400  {
401  return status;
402  }
403 
404  for (DWORD i = 0; i < Token->RestrictedSidCount; i++)
405  {
406  status = IntWinReadSid(gva + i * incrementSize, &Token->RestrictedSids[i]);
407  if (!INT_SUCCESS(status))
408  {
409  return status;
410  }
411 
412  Token->RestrictedSids[i].IsRestricted = TRUE;
413  }
414  }
415 
416  // this might not be a valid Token
417  if (0 == Token->SidCount && 0 == Token->RestrictedSidCount)
418  {
419  QWORD gva = 0;
420 
421  // try to read UserAndGroups
422  if (gGuest.Guest64)
423  {
424  status = IntKernVirtMemFetchQword(TokenGva + WIN_KM_FIELD(Token, Users), &gva);
425  }
426  else
427  {
428  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, Users), (PDWORD)&gva);
429  }
430  if (!INT_SUCCESS(status) || !IS_KERNEL_POINTER_WIN(gGuest.Guest64, gva))
431  {
432  return INT_STATUS_NOT_FOUND;
433  }
434 
435  // try to read restricted SIDs (the pointer can be null)
436  if (gGuest.Guest64)
437  {
438  status = IntKernVirtMemFetchQword(TokenGva + WIN_KM_FIELD(Token, RestrictedCount), &gva);
439  }
440  else
441  {
442  status = IntKernVirtMemFetchDword(TokenGva + WIN_KM_FIELD(Token, RestrictedCount), (PDWORD)&gva);
443  }
444  if (!INT_SUCCESS(status) || !IS_KERNEL_POINTER_WIN(gGuest.Guest64, gva))
445  {
446  return INT_STATUS_NOT_FOUND;
447  }
448  }
449 
450  return status;
451 }
452 
453 
454 //
455 // IntWinGetAccessTokenFromProcess
456 //
457 INTSTATUS
459  _In_ DWORD ProcessId,
460  _In_ QWORD EprocessGva,
461  _Out_ INTRO_WIN_TOKEN *Token
462  )
478 {
479  INTSTATUS status;
480  QWORD tokenGva = 0;
481  PWIN_PROCESS_OBJECT pProcess = NULL;
482 
483  if (NULL == Token)
484  {
486  }
487 
488  if (0 == EprocessGva)
489  {
490  status = IntWinProcGetObjectByPid(ProcessId, &pProcess);
491  if (!INT_SUCCESS(status))
492  {
493  ERROR("[ERROR] IntWinProcGetObjectByPid failed for %d: 0x%x\n", ProcessId, status);
494  return status;
495  }
496 
497  EprocessGva = pProcess->EprocessAddress;
498  }
499 
500  // the Token pointer is stored as EX_FAST_REF, we have to clear the lower bits before using it
501  if (gGuest.Guest64)
502  {
503  status = IntKernVirtMemFetchQword(EprocessGva + WIN_KM_FIELD(Process, Token), &tokenGva);
504  }
505  else
506  {
507  status = IntKernVirtMemFetchDword(EprocessGva + WIN_KM_FIELD(Process, Token), (PDWORD)&tokenGva);
508  }
509  if (!INT_SUCCESS(status))
510  {
511  ERROR("[ERROR] Failed to read Token from Eprocess 0x%016llx: 0x%08x\n", EprocessGva, status);
512  return status;
513  }
514 
515  tokenGva = EX_FAST_REF_TO_PTR(gGuest.Guest64, tokenGva);
516  return IntWinReadToken(tokenGva, Token);
517 }
518 
519 
520 //
521 // IntWinGetAccesTokenFromThread
522 //
523 INTSTATUS
525  _In_ QWORD EthreadGva,
526  _Out_ INTRO_WIN_TOKEN *Token
527  )
540 {
541  INTSTATUS status;
542  QWORD tokenGva = 0;
543 
544  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, EthreadGva))
545  {
547  }
548 
549  if (NULL == Token)
550  {
552  }
553 
554  if (gGuest.Guest64)
555  {
556  status = IntKernVirtMemFetchQword(EthreadGva + WIN_KM_FIELD(Thread, ClientSecurity), &tokenGva);
557  }
558  else
559  {
560  status = IntKernVirtMemFetchDword(EthreadGva + WIN_KM_FIELD(Thread, ClientSecurity), (PDWORD)&tokenGva);
561  }
562  if (!INT_SUCCESS(status))
563  {
564  ERROR("[ERROR] Failed to read Token from Ethread 0x%016llx: 0x%08x\n", EthreadGva, status);
565  return status;
566  }
567 
568  // Ethread.ClientSecurity is of type _PS_CLIENT_SECURITY_CONTEXT, clear bits 0-2
569  tokenGva &= ~((QWORD)0x7);
570  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, tokenGva))
571  {
572  return INT_STATUS_NOT_FOUND;
573  }
574 
575  return IntWinReadToken(tokenGva, Token);
576 }
577 
578 
579 //
580 // IntWinDumpSid
581 //
582 void
584  _In_ INTRO_SID_ATTRIBUTES const *Sid
585  )
591 {
592  if (NULL == Sid)
593  {
594  return;
595  }
596 
597  if (Sid->IsRestricted)
598  {
599  LOG("Restricted SID\n");
600  }
601 
602  LOG("Attributes: 0x%x\n", Sid->Attributes);
603 
604  LOG("Revision: %d\n", Sid->Sid.Revision);
605 
606  LOG("Identifier Authority: ");
607  for (DWORD i = 0; i < 6; i++)
608  {
609  NLOG("%d ", Sid->Sid.IdentifierAuthority[i]);
610  }
611  NLOG("\n");
612 
613  LOG("Sub authority: ");
614  for (DWORD i = 0; i < Sid->Sid.SubAuthorityCount; i++)
615  {
616  NLOG("%d ", Sid->Sid.SubAuthority[i]);
617  }
618  NLOG("\n");
619 }
620 
621 
622 //
623 // IntWinDumpToken
624 //
625 void
627  _In_ INTRO_WIN_TOKEN const *Token
628  )
634 {
635  if (NULL == Token)
636  {
637  return;
638  }
639 
640  if (Token->ImpersonationToken)
641  {
642  LOG("Impersonation token\n");
643  }
644 
645  LOG("Privileges: \n");
646  IntWinDumpPrivileges(&Token->Privileges);
647 
648  LOG("User and Groups: \n");
649  for (DWORD i = 0; i < Token->SidCount; i++)
650  {
651  IntWinDumpSid(&Token->SidsAndAttributes[i]);
652  }
653 
654  LOG("Restricted SIDs: \n");
655  for (DWORD i = 0; i < Token->RestrictedSidCount; i++)
656  {
657  IntWinDumpSid(&Token->RestrictedSids[i]);
658  }
659 }
DWORD Sid
Pointer to a _SID structure.
Definition: wddefs.h:601
static void IntWinDumpPrivilegesMask(QWORD Mask)
Prints the name of the privileges available.
Definition: visibility.c:92
#define _Out_
Definition: intro_sal.h:22
#define EX_FAST_REF_TO_PTR(is64, p)
Converts a _EX_FAST_REF value to a pointer.
Definition: wddefs.h:100
A Windows token structure as reported by Introcore alerts.
Definition: intro_types.h:861
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
#define BIT(x)
Definition: common.h:68
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define ARRAYSIZE(A)
Definition: introdefs.h:101
Windows SID attributes.
Definition: intro_types.h:840
QWORD Sid
Pointer to a _SID structure.
Definition: wddefs.h:592
#define INTRO_WIN_SID_MAX_SUB_AUTHORITIES
The maximum number of sub authorities contained in a SID.
Definition: intro_types.h:831
#define ERROR(fmt,...)
Definition: glue.h:62
int INTSTATUS
The status data type.
Definition: introstatus.h:24
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
#define MIN(a, b)
Definition: introdefs.h:146
#define LOG(fmt,...)
Definition: glue.h:61
uint32_t * PDWORD
Definition: intro_types.h:49
PWIN_PROCESS_OBJECT IntWinProcFindObjectByPid(DWORD Pid)
Finds a process by its ID.
Definition: winprocesshp.c:126
void IntWinDumpToken(INTRO_WIN_TOKEN const *Token)
Prints a INTRO_WIN_TOKEN structure.
Definition: visibility.c:626
INTSTATUS IntWinDumpPrivileges(INTRO_TOKEN_PRIVILEGES const *Privileges)
Prints a INTRO_TOKEN_PRIVILEGES structure.
Definition: visibility.c:164
DWORD Attributes
A combination of SE_GROUP_* values.
Definition: wddefs.h:593
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
INTSTATUS IntWinGetAccesTokenFromThread(QWORD EthreadGva, INTRO_WIN_TOKEN *Token)
Reads the contents of a _TOKEN Windows structure assigned to a thread.
Definition: visibility.c:524
Windows process token privileges.
Definition: intro_types.h:796
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
INTSTATUS IntWinGetAccessTokenFromProcess(DWORD ProcessId, QWORD EprocessGva, INTRO_WIN_TOKEN *Token)
Reads the contents of a _TOKEN Windows structure assigned to a process.
Definition: visibility.c:458
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
#define INTRO_SIDS_MAX_COUNT
The maximum SID count included in an alert.
Definition: intro_types.h:856
struct _SID_AND_ATTRIBUTES32 SID_AND_ATTRIBUTES32
#define TRUE
Definition: intro_types.h:30
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
void IntWinDumpSid(INTRO_SID_ATTRIBUTES const *Sid)
Prints a INTRO_SID_ATTRIBUTES structure.
Definition: visibility.c:583
A security identifier.
Definition: intro_types.h:820
INTSTATUS IntWinProcGetObjectByPid(DWORD Pid, WIN_PROCESS_OBJECT **Process)
This function looks for a process with the given PID inside gWinProcesses and returns its WIN_PROCESS...
Definition: winprocess.c:4003
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntWinReadToken(QWORD TokenGva, INTRO_WIN_TOKEN *Token)
Reads the contents of a _TOKEN Windows structure.
Definition: visibility.c:279
struct _SID_AND_ATTRIBUTES64 SID_AND_ATTRIBUTES64
#define WIN_KM_FIELD(Structure, Field)
Macro used to access kernel mode fields inside the WIN_OPAQUE_FIELDS structure.
Definition: winguest.h:740
uint32_t DWORD
Definition: intro_types.h:49
#define INT_STATUS_INVALID_DATA_VALUE
Definition: introstatus.h:136
INTSTATUS IntWinGetStartUpTime(QWORD *StartUpTime)
Gets the system startup time.
Definition: visibility.c:14
QWORD EprocessAddress
This will be the address of the ActiveProcess field.
Definition: winprocess.h:90
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
#define FIELD_OFFSET(type, field)
Definition: introdefs.h:239
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define NLOG(fmt,...)
Definition: glue.h:43
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
DWORD Attributes
A combination of SE_GROUP_* values.
Definition: wddefs.h:602
INTSTATUS IntWinReadSid(QWORD SidAndAttributesGva, INTRO_SID_ATTRIBUTES *Sid)
Reads the contents of a _SID_AND_ATTRIBUTES Windows structure.
Definition: visibility.c:197
char CHAR
Definition: intro_types.h:56
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:83
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68