Bitdefender Hypervisor Memory Introspection
winsecdesc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "introcore.h"
6 #include "winsecdesc.h"
7 #include "guests.h"
8 #include "hook.h"
9 #include "alerts.h"
10 #include "gpacache.h"
11 #include "kernvm.h"
12 #include "crc32.h"
13 
14 // Please note that the SECURITY_DESCRIPTOR structure is not the one described on MSDN
15 // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
16 // Below, there is windbg dump showing how the actual SECURITY_DESCRIPTOR looks like.
17 //
18 // 1) Let`s get the _EPROCESS for system process
19 // 0: kd > !process 0 0 system
20 // PROCESS ffffa103dd2652c0
21 // SessionId : none Cid : 0004 Peb : 00000000 ParentCid : 0000
22 // DirBase : 001ad002 ObjectTable : ffff8b8278c06e40 HandleCount : 2334.
23 // Image : System
24 //
25 // 2) The security descriptor address is located word size (#gGuest.WordSize) before the _EPROCESS (part of
26 // the _OBJECT_HEADER structure).
27 // 0 : kd > dq ffffa103dd2652c0 - 8 l 1
28 // ffffa103`dd2652b8 ffff8b82`78c094ec
29 //
30 // 3) Now we have the address (ffff8b82`78c094ec). Let`s zero out the last 4 bits (see #EX_FAST_REF_TO_PTR) and dump
31 // the security descriptor.
32 // 0: kd > !sd ffff8b82`78c094e0
33 // ->Revision: 0x1
34 // ->Sbz1 : 0x0
35 // ->Control : 0x8814
36 // SE_DACL_PRESENT
37 // SE_SACL_PRESENT
38 // SE_SACL_AUTO_INHERITED
39 // SE_SELF_RELATIVE
40 // ->Owner : S - 1 - 5 - 32 - 544
41 // ->Group : S - 1 - 5 - 18
42 // ->Dacl :
43 // ->Dacl : ->AclRevision : 0x2 ________________________________________________________________________
44 // ->Dacl : ->Sbz1 : 0x0 |
45 // ->Dacl : ->AclSize : 0x3c |
46 // ->Dacl : ->AceCount : 0x2 |
47 // ->Dacl : ->Sbz2 : 0x0 |
48 // ->Dacl : ->Ace[0] : ->AceType : ACCESS_ALLOWED_ACE_TYPE |
49 // ->Dacl : ->Ace[0] : ->AceFlags : 0x0 |
50 // ->Dacl : ->Ace[0] : ->AceSize : 0x14 |
51 // ->Dacl : ->Ace[0] : ->Mask : 0x001fffff |
52 // ->Dacl : ->Ace[0] : ->SID : S - 1 - 5 - 18 |
53 // |
54 // ->Dacl : ->Ace[1] : ->AceType : ACCESS_ALLOWED_ACE_TYPE |
55 // ->Dacl : ->Ace[1] : ->AceFlags : 0x0 |
56 // ->Dacl : ->Ace[1] : ->AceSize : 0x18 |
57 // ->Dacl : ->Ace[1] : ->Mask : 0x00121411 |
58 // ->Dacl : ->Ace[1] : ->SID : S - 1 - 5 - 32 - 544 |
59 // |
60 // ->Sacl : |
61 // ->Sacl : ->AclRevision : 0x2 _____________________________________________________ |
62 // ->Sacl : ->Sbz1 : 0x0 | |
63 // ->Sacl : ->AclSize : 0x1c | |
64 // ->Sacl : ->AceCount : 0x1 | |
65 // ->Sacl : ->Sbz2 : 0x0 | |
66 // ->Sacl : ->Ace[0] : ->AceType : SYSTEM_MANDATORY_LABEL_ACE_TYPE | |
67 // ->Sacl : ->Ace[0] : ->AceFlags : 0x0 | |
68 // ->Sacl : ->Ace[0] : ->AceSize : 0x14 | |
69 // ->Sacl : ->Ace[0] : ->Mask : 0x00000003 | |
70 // ->Sacl : ->Ace[0] : ->SID : S - 1 - 16 - 16384 | |
71 // | |
72 // 0 : kd > db ffff8b82`78c094e0 l 100 | |
73 // | |
74 // _______________________________________________| |
75 // | |
76 // ffff8b82`78c094e0 01 00 14 88 | 6c 00 00 00 - 7c 00 00 00 14 00 00 00 ....l... | ....... |
77 // ffff8b82`78c094f0 30 00 00 00 |->02 00 1c 00 - 01 00 00 00 11 00 14 00 0............... |
78 // ffff8b82`78c09500 03 00 00 00 01 01 00 00 - 00 00 00 10 00 40 00 00 .............@.. |
79 // __________________________________________________________________________________|
80 // |
81 // ffff8b82`78c09510 |->02 00 3c 00 02 00 00 00 - 00 00 14 00 ff ff 1f 00 .. < .............
82 // ffff8b82`78c09520 01 01 00 00 00 00 00 05 - 12 00 00 00 00 00 18 00 ................
83 // ffff8b82`78c09530 11 14 12 00 01 02 00 00 - 00 00 00 05 20 00 00 00 ............ ...
84 // ffff8b82`78c09540 20 02 00 00 00 00 00 00 - 00 00 00 00 01 02 00 00 ...............
85 // ffff8b82`78c09550 00 00 00 05 20 00 00 00 - 20 02 00 00 01 01 00 00 .... ... .......
86 // ffff8b82`78c09560 00 00 00 05 12 00 00 00 - 00 00 00 00 00 00 00 00 ................
87 // ffff8b82`78c09570 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
88 // ffff8b82`78c09580 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
89 // ffff8b82`78c09590 a7 47 db 42 f4 bb 9b c6 - 00 00 00 00 00 00 00 00. G.B............
90 //
91 // 4) Please note that the AclSize also takes into account the "header", not only the contents (ACEs). For example,
92 // SACL starts at ffff8b82`78c094f4 and ends at ffff8b82`78c09510 (the difference is exactly 1c, as the AclSize).
93 //
94 // 5) Same goes for DACL.
95 
97 
99 STATIC_ASSERT(sizeof(ACL) == sizeof(QWORD), "Sizeof of ACL is not a QWORD");
100 
103  "INTRO_SECURITY_DESCRIPTOR_SIZE is too small");
104 
108 #define INT_MAX_ACE_COUNT 1820
109 
110 static char *
112  _In_ BYTE AceTypeValue
113  )
122 {
123  char *aceType;
124 
125  switch (AceTypeValue)
126  {
129  break;
132  break;
135  break;
138  break;
141  break;
144  break;
147  break;
150  break;
153  break;
156  break;
159  break;
162  break;
165  break;
168  break;
171  break;
174  break;
177  break;
180  break;
183  break;
186  break;
189  break;
192  break;
193  default:
194  aceType = NULL;
195  }
196 
197  return aceType;
198 }
199 
200 
201 INTSTATUS
203  _In_ DWORD BufferSize,
204  _In_ BYTE *SecurityDescriptorBuffer,
205  _Inout_ DWORD *ReadSize,
206  _Out_ ACL **Sacl,
207  _Out_ ACL **Dacl
208  )
222 {
223  ACL *sacl = NULL;
224  ACL *dacl = NULL;
225 
226  *Sacl = NULL;
227  *Dacl = NULL;
228 
229  if (BufferSize < sizeof(SECURITY_DESCRIPTOR) ||
230  BufferSize < sizeof(ACL) ||
231  BufferSize < sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL))
232  {
234  }
235 
236  sacl = (ACL *)((QWORD)SecurityDescriptorBuffer + sizeof(SECURITY_DESCRIPTOR));
237 
238  // Please note that the sacl->AclSize also takes into account the ACL structure.
239  // Here we bail out even if (QWORD)sacl + sizeof(ACL) = (QWORD)SecurityDescriptorBuffer + BufferSize because we
240  // expect at least one ACE entry for the given ACL.
241  if ((QWORD)sacl >= (QWORD)SecurityDescriptorBuffer + BufferSize ||
242  (QWORD)sacl + sizeof(ACL) >= (QWORD)SecurityDescriptorBuffer + BufferSize ||
243  sacl->AclSize > BufferSize ||
244  sacl->AclSize < sizeof(ACL) ||
245  sacl->AclSize + sizeof(SECURITY_DESCRIPTOR) > BufferSize ||
246  sacl->AclSize + sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL) > BufferSize ||
247  sacl->AclRevision > MAX_ACL_REVISION ||
248  sacl->AclSize < sacl->AceCount * sizeof(ACE_HEADER) ||
249  sacl->Sbz1 != 0 ||
250  sacl->Sbz2 != 0)
251  {
252  WARNING("[WARNING] It seems that the SaclSize is unexpected\n");
253 
255  }
256 
257  *Sacl = sacl;
258  *ReadSize += sacl->AclSize;
259 
260  dacl = (ACL *)((QWORD)sacl + sacl->AclSize);
261 
262  // Please note that the dacl->AclSize also takes into account the ACL structure.
263  // Here we bail out even if (QWORD)dacl + sizeof(ACL) = (QWORD)SecurityDescriptorBuffer + BufferSize because we
264  // expect at least one ACE entry for the given ACL.
265  if ((QWORD)dacl >= (QWORD)SecurityDescriptorBuffer + BufferSize ||
266  (QWORD)dacl + sizeof(ACL) >= (QWORD)SecurityDescriptorBuffer + BufferSize ||
267  dacl->AclSize > BufferSize ||
268  dacl->AclSize < sizeof(ACL) ||
269  dacl->AclSize + sizeof(SECURITY_DESCRIPTOR) > BufferSize ||
270  ((QWORD)sacl->AclSize + dacl->AclSize + sizeof(SECURITY_DESCRIPTOR)) > BufferSize ||
271  dacl->AclRevision > MAX_ACL_REVISION ||
272  dacl->AclSize < dacl->AceCount * sizeof(ACE_HEADER) ||
273  dacl->Sbz1 != 0 ||
274  dacl->Sbz2 != 0)
275  {
276  WARNING("[WARNING] It seems that the DaclSize is unexpected\n");
277 
279  }
280 
281  *Dacl = dacl;
282  *ReadSize += dacl->AclSize;
283 
284  return INT_STATUS_SUCCESS;
285 }
286 
287 
288 static BOOLEAN
290  _In_ ACL *Acl,
291  _In_ ACE_HEADER *Ace
292  )
303 {
304  // IntWinSDFindAcls may return a NULL Sacl/Dacl.
305  if (NULL == Acl || NULL == Ace)
306  {
307  return FALSE;
308  }
309 
310  // Please note that in IntWinSDReadSecDesc, we make sure that #ACL::AclSize is inside the Security Descriptor
311  // buffer - otherwise the returned ACL (Sacl/Dacl) will be NULL.
312  if ((QWORD)Ace >= (QWORD)Acl + Acl->AclSize ||
313  (QWORD)Ace + sizeof(ACE_HEADER) > (QWORD)Acl + Acl->AclSize ||
314  (QWORD)Ace + Ace->AceSize > (QWORD)Acl + Acl->AclSize ||
315  Ace->AceSize >= Acl->AclSize ||
316  Ace->AceSize < sizeof(ACE_HEADER))
317  {
318  return FALSE;
319  }
320 
321  return TRUE;
322 }
323 
324 
325 static BOOLEAN
327  _In_ BYTE *Buffer,
328  _In_ DWORD BufferSize,
329  _In_ ACE_HEADER *Ace
330 )
341 {
342  if (NULL == Buffer || NULL == Ace)
343  {
344  return FALSE;
345  }
346 
347  if ((QWORD)Ace >= (QWORD)Buffer + BufferSize ||
348  (QWORD)Ace + sizeof(ACL) > (QWORD)Buffer + BufferSize ||
349  (QWORD)Ace + sizeof(ACE_HEADER) > (QWORD)Buffer + BufferSize ||
350  (QWORD)Ace + sizeof(ACE_HEADER) + sizeof(ACE_BODY) > (QWORD)Buffer + BufferSize ||
351  Ace->AceSize > BufferSize ||
352  Ace->AceSize < sizeof(ACE_HEADER))
353  {
354  return FALSE;
355  }
356 
357  return TRUE;
358 }
359 
360 
361 INTSTATUS
363  _In_ QWORD SecurityDescriptorGva,
364  _In_ DWORD BufferSize,
365  _Out_writes_bytes_ (BufferSize) BYTE *SecurityDescriptorBuffer,
366  _Out_ DWORD *ReadSize,
367  _Out_ ACL **Sacl,
368  _Out_ ACL **Dacl
369  )
388 {
389  INTSTATUS status;
390  VA_TRANSLATION tr = { 0 };
391 
392  if (0 == SecurityDescriptorGva || NULL == SecurityDescriptorBuffer ||
393  NULL == ReadSize || NULL == Sacl || NULL == Dacl)
394  {
396  }
397 
398  *ReadSize = 0;
399  *Sacl = NULL;
400  *Dacl = NULL;
401 
402  if (BufferSize < INTRO_SECURITY_DESCRIPTOR_SIZE)
403  {
405  }
406 
407  status = IntTranslateVirtualAddressEx(SecurityDescriptorGva, gGuest.Mm.SystemCr3, TRFLG_PG_MODE, &tr);
408  if (!INT_SUCCESS(status))
409  {
410  WARNING("[WARNING] IntTranslateVirtualAddressEx failed: 0x%08x\n", status);
411  return status;
412  }
413 
414  if (0 == (tr.Flags & PT_P))
415  {
417  }
418 
420  tr.PhysicalAddress,
421  BufferSize,
422  (BYTE *)SecurityDescriptorBuffer);
423  if (INT_STATUS_NOT_SUPPORTED == status)
424  {
425  // This happens if the buffer is spread on more than one page.
426  status = IntKernVirtMemRead(SecurityDescriptorGva, BufferSize, SecurityDescriptorBuffer, NULL);
427  if (!INT_SUCCESS(status))
428  {
430  {
431  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
432  }
433  return status;
434  }
435  }
436  else if (!INT_SUCCESS(status))
437  {
438  ERROR("[ERROR] IntGpaCacheFetchAndAdd failed: 0x%08x\n", status);
439  return status;
440  }
441 
442  *ReadSize = sizeof(SECURITY_DESCRIPTOR);
443 
444  status = IntWinSDFindAcls(BufferSize,
445  SecurityDescriptorBuffer,
446  ReadSize,
447  Sacl,
448  Dacl);
449  if (!INT_SUCCESS(status))
450  {
451  WARNING("[WARNING] IntWinSDFindAcls failed: 0x%08x\n", status);
452  }
453 
454  return status;
455 }
456 
457 
458 static void
460  _In_ ACL *Acl,
461  _In_ BOOLEAN IsSacl,
462  _In_ BYTE *SecurityDescriptorBuffer,
463  _In_ DWORD BufferSize
464  )
473 {
475 #define INT_SID_CHAR_SIZE 512
476 #define INT_MAX_SUB_AUTHORITY_COUT 30
478 
479  ACE_HEADER *aceHeader;
480  ACE_BODY *aceBody;
481  DWORD *subAuthority;
482  int writtenBytes;
483  char *aclName = IsSacl ? "Sacl" : "Dacl";
484  char *aceType = NULL;
485  static char sidChar[INT_SID_CHAR_SIZE];
486 
487  LOG("->%s :\n", aclName);
488  LOG("->%s : ->AclRevision : 0x%x\n", aclName, Acl->AclRevision);
489  LOG("->%s : ->Sbz1 : 0x%x\n", aclName, Acl->Sbz1);
490  LOG("->%s : ->AclSize : 0x%x\n", aclName, Acl->AclSize);
491  LOG("->%s : ->AceCount : 0x%x\n", aclName, Acl->AceCount);
492  LOG("->%s : ->Sbz2 : 0x%x\n", aclName, Acl->Sbz2);
493 
494  if (__unlikely(Acl->AceCount > INT_MAX_ACE_COUNT))
495  {
496  WARNING("[WARNING] The maximum number of ACEs has been exceeded:0x%x\n", Acl->AceCount);
497  return;
498  }
499 
500  aceHeader = (ACE_HEADER *)((QWORD)Acl + sizeof(ACL));
501 
502  for (DWORD i = 0; i < Acl->AceCount; i++)
503  {
504  if (!IntWinSDIsAceInsideBuffer(SecurityDescriptorBuffer, BufferSize, aceHeader))
505  {
506  return;
507  }
508 
509  aceBody = (ACE_BODY*)((QWORD)aceHeader + sizeof(ACE_HEADER));
510 
511  memset(sidChar, 0, INT_SID_CHAR_SIZE);
512 
513  writtenBytes = snprintf(sidChar, INT_SID_CHAR_SIZE, "->%s : ->Ace[%d] : ->SID: S-%u-%u",
514  aclName, i, (BYTE)aceBody->Sid.Revision,
515  (BYTE)aceBody->Sid.IdentifierAuthority.Value[5]);
516  if (writtenBytes < 0 || writtenBytes >= INT_SID_CHAR_SIZE)
517  {
518  ERROR("[ERROR] snprintf failed with return value: %d, buffer size: %d\n", writtenBytes, INT_SID_CHAR_SIZE);
519  return;
520  }
521 
522  aceType = IntWinSDGetAceTypeName(aceHeader->AceType);
523  if (aceType)
524  {
525  LOG("->%s : ->Ace[%d] : ->AceType: %s\n", aclName, i, aceType);
526  }
527  else
528  {
529  LOG("->%s : ->Ace[%d] : ->AceType: UNKNOWN(0x%x)\n", aclName, i, (BYTE)aceHeader->AceType);
530  }
531 
532  LOG("->%s : ->Ace[%d] : ->AceFlags: 0x%x\n", aclName, i, (BYTE)aceHeader->AceFlags);
533  LOG("->%s : ->Ace[%d] : ->AceSize: 0x0%x\n", aclName, i, (WORD)aceHeader->AceSize);
534  LOG("->%s : ->Ace[%d] : ->Mask: 0x%08x\n", aclName, i, (DWORD)aceBody->Mask);
535 
536  subAuthority = (DWORD *)((QWORD)aceBody + sizeof(ACE_BODY));
537 
538  for (DWORD j = 0; j < aceBody->Sid.SubAuthorityCount; j++)
539  {
541  {
542  WARNING("[WARNING] The maximum number of sub authorities has been exceeded:0x%x\n",
543  (UCHAR)aceBody->Sid.SubAuthorityCount);
544  break;
545  }
546 
547  if ((QWORD)&subAuthority[j] >= (QWORD)SecurityDescriptorBuffer + BufferSize ||
548  (QWORD)&subAuthority[j] + sizeof(DWORD) > (QWORD)SecurityDescriptorBuffer + BufferSize)
549  {
550  break;
551  }
552 
553  int ret = snprintf(&sidChar[writtenBytes], (QWORD)INT_SID_CHAR_SIZE - writtenBytes,
554  "-%u", subAuthority[j]);
555  if (ret < 0 || ret >= INT_SID_CHAR_SIZE - writtenBytes)
556  {
557  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, INT_SID_CHAR_SIZE - writtenBytes);
558  }
559  else
560  {
561  writtenBytes += ret;
562  }
563  }
564 
565  LOG("%s\n", sidChar);
566  LOG("->%s :\n", aclName);
567 
568  aceHeader = (ACE_HEADER *)((QWORD)aceHeader + aceHeader->AceSize);
569  }
570 
571 #undef INT_SID_CHAR_SIZE
572 #undef INT_MAX_SUB_AUTHORITY_COUT
573 }
574 
575 
576 static void
578  _In_ WIN_PROCESS_OBJECT *Process,
579  _In_ BYTE *SecurityDescriptorBuffer,
580  _In_ DWORD BufferSize,
581  _In_ BOOLEAN Original
582  )
592 {
593  SECURITY_DESCRIPTOR *secDesc = (SECURITY_DESCRIPTOR *)SecurityDescriptorBuffer;
594  DWORD readSize = sizeof(SECURITY_DESCRIPTOR);
595  INTSTATUS status;
596  ACL *sacl;
597  ACL *dacl;
598 
599  if (NULL != Process)
600  {
601  LOG("[ACL] Dumping %s security descriptor for process 0x%llx (%d / %s)\n",
602  Original ? "OLD" : "NEW",
603  Process->EprocessAddress, Process->Pid, Process->Name);
604  }
605 
606  if (BufferSize < sizeof(SECURITY_DESCRIPTOR))
607  {
608  return;
609  }
610 
611  LOG("->Revision: 0x%x\n", secDesc->Revision);
612  LOG("->Sbz1: 0x%x\n", secDesc->Sbz1);
613  LOG("->Control: 0x%x\n", secDesc->Control);
614  LOG("->Owner: 0x%llx\n", secDesc->Owner);
615  LOG("->Group: 0x%llx\n", secDesc->Group);
616 
617  status = IntWinSDFindAcls(BufferSize,
618  SecurityDescriptorBuffer,
619  &readSize,
620  &sacl,
621  &dacl);
622  if (!INT_SUCCESS(status))
623  {
624  WARNING("[WARNING] IntWinSDFindAcls failed: 0x%08x\n", status);
625  return;
626  }
627 
628  IntWinSDDumpAclEntries(dacl, FALSE, SecurityDescriptorBuffer, BufferSize);
629  IntWinSDDumpAclEntries(sacl, TRUE, SecurityDescriptorBuffer, BufferSize);
630 }
631 
632 
633 static INTSTATUS
635  _Inout_ WIN_PROCESS_OBJECT *Process
636  )
646 {
647  INTSTATUS status;
648  DWORD totalSize = 0;
649  ACL *sacl = NULL;
650  ACL *dacl = NULL;
651  static BYTE securityDescriptorBuffer[INTRO_SECURITY_DESCRIPTOR_SIZE];
652 
653  if (0 == Process->SecurityDescriptor.SecurityDescriptorGva)
654  {
655  // When a new process is created, the security descriptor pointer seems to be NULL.
656  // We`ll try again at the next integrity check.
658  }
659 
660  memset(securityDescriptorBuffer, 0, INTRO_SECURITY_DESCRIPTOR_SIZE);
661 
662  status = IntWinSDReadSecDesc(Process->SecurityDescriptor.SecurityDescriptorGva,
664  securityDescriptorBuffer,
665  &totalSize,
666  &sacl,
667  &dacl);
669  {
670  return status;
671  }
672  else if (!INT_SUCCESS(status))
673  {
674  WARNING("[WARNING] IntWinSDReadSecDesc failed for process 0x%llx (%d / %s) with status : 0x%08x\n",
675  Process->EprocessAddress, Process->Pid, Process->Name, status);
676 
677  return status;
678  }
679 
680  TRACE("[ACL] SACL/DACL for process 0x%llx (%d / %s) have been found: SD:0x%llx SACL AclSize:0x%x, AceCount:0x%x "
681  "AclRevision:0x%x - DACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x - Total size 0x%x\n",
682  Process->EprocessAddress, Process->Pid, Process->Name,
683  Process->SecurityDescriptor.SecurityDescriptorGva,
684  sacl->AclSize, sacl->AceCount, sacl->AclRevision,
685  dacl->AclSize, dacl->AceCount, dacl->AclRevision, totalSize);
686 
687  Process->SecurityDescriptor.RawBufferSize = totalSize;
688  memcpy(&Process->SecurityDescriptor.RawBuffer[0], securityDescriptorBuffer, totalSize);
689  memcpy(&Process->SecurityDescriptor.Sacl, sacl, sizeof(ACL));
690  memcpy(&Process->SecurityDescriptor.Dacl, dacl, sizeof(ACL));
691 
692  return status;
693 }
694 
695 
696 static INTSTATUS
698  _In_ WIN_PROCESS_OBJECT *Process,
699  _Out_ QWORD *SecurityDescriptorAddressGva
700  )
710 {
711  INTSTATUS status;
712  VA_TRANSLATION tr = { 0 };
713 
714  *SecurityDescriptorAddressGva = 0;
715 
716  // The security descriptor address is the last element of the OBJECT_HEADER structure that is always located just
717  // before the start of the start of the _EPROCESS.
718  status = IntTranslateVirtualAddressEx(Process->EprocessAddress - gGuest.WordSize,
721  &tr);
722  if (!INT_SUCCESS(status))
723  {
724  ERROR("[ERROR] IntTranslateVirtualAddressEx failed: 0x%08x\n", status);
725  return status;
726  }
727 
728  if (0 == (tr.Flags & PT_P))
729  {
731  }
732 
734  tr.PhysicalAddress,
736  (PBYTE)SecurityDescriptorAddressGva);
737  if (!INT_SUCCESS(status))
738  {
739  ERROR("[ERROR] IntGpaCacheFetchAndAdd failed: 0x%08x\n", status);
740  return status;
741  }
742 
743  *SecurityDescriptorAddressGva = EX_FAST_REF_TO_PTR(gGuest.Guest64, *SecurityDescriptorAddressGva);
744 
745  return status;
746 }
747 
748 
749 INTSTATUS
751  _Inout_ WIN_PROCESS_OBJECT *Process
752  )
761 {
762  INTSTATUS status;
763  QWORD securityDescriptor = 0;
764 
765  if (NULL == Process)
766  {
768  }
769 
770  status = IntWinSDFetchSecDescAddress(Process, &securityDescriptor);
771  if (!INT_SUCCESS(status))
772  {
773  ERROR("[ERROR] IntWinSDFetchSecDescAddress failed: 0x%08x\n", status);
774  return status;
775  }
776 
777  Process->SecurityDescriptor.SecurityDescriptorGva = securityDescriptor;
778 
779  status = IntWinSDGatherAcl(Process);
780  if (!INT_SUCCESS(status))
781  {
782  // Sometimes we might have an invalid security descriptor pointer - try again next time on integrity.
783  Process->SecurityDescriptor.SecurityDescriptorGva = 0;
784 
785  WARNING("[WARNING] IntWinSDGatherAcl failed: 0x%08x\n", status);
786  }
787 
788  return status;
789 }
790 
791 
792 static INTSTATUS
794  _In_ WIN_PROCESS_OBJECT *Process,
795  _Out_ QWORD *OldValue,
796  _Out_ QWORD *NewValue
797  )
809 {
810  INTSTATUS status;
811  QWORD newValue = 0;
812 
813  status = IntWinSDFetchSecDescAddress(Process, &newValue);
814  if (!INT_SUCCESS(status))
815  {
816  ERROR("[ERROR] IntWinSDFetchSecDescAddress failed: 0x%08x\n", status);
817  return status;
818  }
819 
820  *OldValue = Process->SecurityDescriptor.SecurityDescriptorGva;
821  *NewValue = newValue;
822 
823  return INT_STATUS_SUCCESS;
824 }
825 
826 
827 _Success_(return == TRUE)
828 BOOLEAN
830  _In_ WIN_PROCESS_OBJECT *Process,
831  _Inout_opt_ WIN_PROCESS_OBJECT **VictimProcess,
832  _Out_opt_ QWORD *OldValue,
833  _Out_opt_ QWORD *NewValue
834  )
849 {
850  INTSTATUS status;
851  WIN_PROCESS_OBJECT *victimProcess = NULL;
852  QWORD oldValue = 0;
853  QWORD newValue = 0;
854 
855  if (NULL == Process)
856  {
857  ERROR("[ERROR] Process is NULL\n");
858  return FALSE;
859  }
860 
861  status = IntWinSDFetchSecDescValues(Process, &oldValue, &newValue);
862  if (!INT_SUCCESS(status))
863  {
864  ERROR("[ERROR] IntWinSDFetchSecDescAddress failed: 0x%08x\n", status);
865  return FALSE;
866  }
867 
868  if (OldValue)
869  {
870  *OldValue = oldValue;
871  }
872 
873  if (NewValue)
874  {
875  *NewValue = newValue;
876  }
877 
878  if (0 == oldValue && 0 != newValue)
879  {
880  // When a new process is created, the security descriptor pointer seems to be NULL.
881  Process->SecurityDescriptor.SecurityDescriptorGva = newValue;
882  status = IntWinSDGatherAcl(Process);
883  if (!INT_SUCCESS(status))
884  {
885  WARNING("[WARNING] IntWinSDGatherAcl failed: 0x%08x\n", status);
886  }
887 
888  return FALSE;
889  }
890 
891  if (oldValue == newValue)
892  {
893  return FALSE;
894  }
895 
896  list_for_each(gWinProcesses, WIN_PROCESS_OBJECT, pProcess)
897  {
898  if (pProcess->SecurityDescriptor.SecurityDescriptorGva == newValue &&
899  pProcess->EprocessAddress != Process->EprocessAddress)
900  {
901  victimProcess = pProcess;
902  }
903  }
904 
905  if (VictimProcess)
906  {
907  *VictimProcess = victimProcess;
908  }
909 
910  return TRUE;
911 }
912 
913 
914 _Success_(return == TRUE)
915 BOOLEAN
917  _In_ WIN_PROCESS_OBJECT *Process,
918  _In_ DWORD BufferSize,
919  _Out_writes_bytes_(BufferSize) BYTE *SecurityDescriptorBuffer,
920  _Out_ DWORD *ReadSize,
921  _Out_ ACL **NewSacl,
922  _Out_ ACL **NewDacl
923  )
939 {
940  INTSTATUS status;
941  ACL *sacl = NULL;
942  ACL *dacl = NULL;
943  BOOLEAN securityDescriptorAltered = FALSE;
944  BOOLEAN updateSecurityDescriptorInfo = FALSE;
945 
946  if (NULL == Process || 0 == Process->SecurityDescriptor.SecurityDescriptorGva || 0 == BufferSize ||
947  NULL == SecurityDescriptorBuffer || NULL == ReadSize || NULL == NewSacl || NULL == NewDacl)
948  {
949  goto cleanup_and_exit;
950  }
951 
952  *NewDacl = NULL;
953  *NewSacl = NULL;
954 
955  status = IntWinSDReadSecDesc(Process->SecurityDescriptor.SecurityDescriptorGva,
956  BufferSize,
957  SecurityDescriptorBuffer,
958  ReadSize,
959  &sacl,
960  &dacl);
962  {
963  goto cleanup_and_exit;
964  }
965  else if (!INT_SUCCESS(status) && INT_STATUS_DATA_BUFFER_TOO_SMALL != status)
966  {
967  WARNING("[WARNING] IntWinSDReadSecDesc failed for process 0x%llx (%d / %s): 0x%08x\n",
968  Process->EprocessAddress, Process->Pid, Process->Name, status);
969 
970  goto cleanup_and_exit;
971  }
972 
973  // If an attacker modifies the AceSize we may end up failing the read function and thus, allowing the modification.
974  if (NULL != sacl)
975  {
976  *NewSacl = sacl;
977 
978  if (0 != sacl->AclSize && 0 == Process->SecurityDescriptor.Sacl.AclSize)
979  {
980  // Some processes start with an incomplete SACL (taskhost.exe, etc.) - we allow the modification.
981  updateSecurityDescriptorInfo = TRUE;
982  goto cleanup_and_exit;
983  }
984 
985  if (sacl->AclSize != Process->SecurityDescriptor.Sacl.AclSize)
986  {
987  securityDescriptorAltered = TRUE;
988  goto cleanup_and_exit;
989  }
990  }
991 
992  if (NULL != dacl)
993  {
994  *NewDacl = dacl;
995 
996  if (0 != dacl->AclSize && 0 == Process->SecurityDescriptor.Dacl.AclSize)
997  {
998  // Some processes start with an incomplete DACL (msmpeng.exe, etc.) - we allow the modification.
999  updateSecurityDescriptorInfo = TRUE;
1000  goto cleanup_and_exit;
1001  }
1002 
1003  if (dacl->AclSize != Process->SecurityDescriptor.Dacl.AclSize)
1004  {
1005  securityDescriptorAltered = TRUE;
1006  goto cleanup_and_exit;
1007  }
1008  }
1009 
1010  if (*ReadSize != Process->SecurityDescriptor.RawBufferSize)
1011  {
1012  securityDescriptorAltered = TRUE;
1013  goto cleanup_and_exit;
1014  }
1015 
1016  if (memcmp_len(SecurityDescriptorBuffer,
1017  Process->SecurityDescriptor.RawBuffer,
1018  *ReadSize,
1019  Process->SecurityDescriptor.RawBufferSize))
1020  {
1021  securityDescriptorAltered = TRUE;
1022  goto cleanup_and_exit;
1023  }
1024 
1025 cleanup_and_exit:
1026  if (updateSecurityDescriptorInfo)
1027  {
1028  Process->SecurityDescriptor.RawBufferSize = *ReadSize;
1029 
1030  memcpy(&Process->SecurityDescriptor.RawBuffer[0], SecurityDescriptorBuffer, *ReadSize);
1031 
1032  if (sacl)
1033  {
1034  memcpy(&Process->SecurityDescriptor.Sacl, sacl, sizeof(ACL));
1035  }
1036 
1037  if (dacl)
1038  {
1039  memcpy(&Process->SecurityDescriptor.Dacl, dacl, sizeof(ACL));
1040  }
1041  }
1042 
1043  return securityDescriptorAltered;
1044 }
1045 
1046 
1047 static INTSTATUS
1049  _In_ WIN_PROCESS_OBJECT *Process,
1050  _In_opt_ WIN_PROCESS_OBJECT *Victim,
1051  _In_ QWORD OldValue,
1052  _In_ QWORD NewValue,
1053  _In_ BYTE *SecDescBuffer,
1054  _In_ DWORD SecDescSize,
1055  _In_ DWORD SecDescHash,
1056  _In_ INTRO_ACTION Action,
1057  _In_ INTRO_ACTION_REASON Reason
1058  )
1074 {
1075  EVENT_INTEGRITY_VIOLATION *pIntViolation;
1076  INTSTATUS status;
1077 
1078  pIntViolation = &gAlert.Integrity;
1079  memzero(pIntViolation, sizeof(*pIntViolation));
1080 
1081  pIntViolation->Header.Action = Action;
1082  pIntViolation->Header.Reason = Reason;
1083  pIntViolation->Header.MitreID = idAccessToken;
1084 
1085  pIntViolation->Header.CpuContext.Valid = FALSE;
1086  pIntViolation->Header.Flags = IntAlertCoreGetFlags(INTRO_OPT_PROT_KM_SD_ACL, Reason);
1087 
1088  IntAlertFillWinProcess(Process, &pIntViolation->Header.CurrentProcess);
1089  IntAlertFillWinProcess(Process, &pIntViolation->Victim.Process);
1090  if (Victim)
1091  {
1092  // In this case we have 2 "Victims".
1093  IntAlertFillWinProcess(Victim, &pIntViolation->Originator.Process);
1094  }
1095 
1096  pIntViolation->Victim.Type = introObjectTypeSecDesc;
1098 
1099  pIntViolation->Size = SecDescSize;
1100  pIntViolation->BaseAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1101  pIntViolation->VirtualAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1102 
1103  pIntViolation->SecDescWriteInfo.OldAddress = OldValue;
1104  pIntViolation->SecDescWriteInfo.NewAddress = NewValue;
1105 
1106  pIntViolation->SecDescWriteInfo.NewSecDescHash = SecDescHash;
1107 
1108  memcpy(&pIntViolation->SecDescWriteInfo.OldSecDesc[0], Process->SecurityDescriptor.RawBuffer,
1109  MIN(sizeof(pIntViolation->SecDescWriteInfo.OldSecDesc), Process->SecurityDescriptor.RawBufferSize));
1110 
1111  pIntViolation->SecDescWriteInfo.OldSecDescSize = Process->SecurityDescriptor.RawBufferSize;
1112 
1113  memcpy(&pIntViolation->SecDescWriteInfo.NewSecDesc[0], SecDescBuffer,
1114  MIN(sizeof(pIntViolation->SecDescWriteInfo.NewSecDesc), SecDescSize));
1115 
1116  pIntViolation->SecDescWriteInfo.NewSecDescSize = SecDescSize;
1117 
1118  IntAlertFillVersionInfo(&pIntViolation->Header);
1119 
1120  status = IntNotifyIntroEvent(introEventIntegrityViolation, pIntViolation, sizeof(*pIntViolation));
1121  if (!INT_SUCCESS(status))
1122  {
1123  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1124  }
1125 
1126  return INT_STATUS_SUCCESS;
1127 }
1128 
1129 
1130 static INTSTATUS
1132  _In_ WIN_PROCESS_OBJECT *Process,
1133  _In_ BYTE *SecDescBuffer,
1134  _In_ DWORD SecDescSize,
1135  _In_ DWORD SecDescHash,
1136  _In_ INTRO_ACTION Action,
1137  _In_ INTRO_ACTION_REASON Reason
1138  )
1151 {
1152  EVENT_INTEGRITY_VIOLATION *pIntViolation;
1153  INTSTATUS status;
1154 
1155  pIntViolation = &gAlert.Integrity;
1156  memzero(pIntViolation, sizeof(*pIntViolation));
1157 
1158  pIntViolation->Header.Action = Action;
1159  pIntViolation->Header.Reason = Reason;
1160  pIntViolation->Header.MitreID = idAccessToken;
1161 
1162  pIntViolation->Header.CpuContext.Valid = FALSE;
1163  pIntViolation->Header.Flags = IntAlertCoreGetFlags(INTRO_OPT_PROT_KM_SD_ACL, Reason);
1164 
1165  IntAlertFillWinProcess(Process, &pIntViolation->Header.CurrentProcess);
1166  IntAlertFillWinProcess(Process, &pIntViolation->Victim.Process);
1167 
1168  pIntViolation->Victim.Type = introObjectTypeAcl;
1169  memcpy(pIntViolation->Victim.Name, VICTIM_PROCESS_ACL, sizeof(VICTIM_PROCESS_ACL));
1170 
1171  pIntViolation->Size = SecDescSize;
1172  pIntViolation->BaseAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1173  pIntViolation->VirtualAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1174 
1175  // The address has not been changed in this case.
1176  pIntViolation->SecDescWriteInfo.OldAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1177  pIntViolation->SecDescWriteInfo.NewAddress = Process->SecurityDescriptor.SecurityDescriptorGva;
1178 
1179  pIntViolation->SecDescWriteInfo.NewSecDescHash = SecDescHash;
1180 
1181  memcpy(&pIntViolation->SecDescWriteInfo.OldSecDesc[0], Process->SecurityDescriptor.RawBuffer,
1182  MIN(sizeof(pIntViolation->SecDescWriteInfo.OldSecDesc), Process->SecurityDescriptor.RawBufferSize));
1183 
1184  pIntViolation->SecDescWriteInfo.OldSecDescSize = Process->SecurityDescriptor.RawBufferSize;
1185 
1186  memcpy(&pIntViolation->SecDescWriteInfo.NewSecDesc[0], SecDescBuffer,
1187  MIN(sizeof(pIntViolation->SecDescWriteInfo.NewSecDesc), SecDescSize));
1188 
1189  pIntViolation->SecDescWriteInfo.NewSecDescSize = SecDescSize;
1190 
1191  IntAlertFillVersionInfo(&pIntViolation->Header);
1192 
1193  IntAlertFillVersionInfo(&pIntViolation->Header);
1194 
1195  status = IntNotifyIntroEvent(introEventIntegrityViolation, pIntViolation, sizeof(*pIntViolation));
1196  if (!INT_SUCCESS(status))
1197  {
1198  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1199  }
1200 
1201  return INT_STATUS_SUCCESS;
1202 }
1203 
1204 
1205 static void
1207  _Inout_ ACL *Acl,
1208  _In_ WORD CalculatedSize
1209  )
1216 {
1217  BYTE *aclEnd;
1218  WORD sizeToClear;
1219 
1220  aclEnd = (BYTE *)((QWORD)Acl + CalculatedSize);
1221  sizeToClear = Acl->AclSize - CalculatedSize;
1222 
1223  if (Acl->AclSize <= CalculatedSize ||
1224  (QWORD)aclEnd + sizeToClear > (QWORD)Acl + Acl->AclSize)
1225  {
1226  return;
1227  }
1228 
1229  memset(aclEnd, 0, sizeToClear);
1230 }
1231 
1232 
1233 static void
1235  _Inout_ ACL *Acl
1236  )
1242 {
1243  // We have 2 types of SIDs: "well-known" and "custom".
1244  //
1245  // 1) "well-known" SIDs https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows
1246  // Example: SID: S-1-5-19 NT Authority Local Service
1247  // Only one sub-authority (19).
1248  //
1249  // 2) "custom" SIDs
1250  // Example: SID: S-1-15-3-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194
1251  // 8 sub-authorities (3, 3624051433, 2125758914, etc.).
1252  //
1253  // Our problem is that the "custom" ACEs are allocated dynamically (each time the security descriptor pointer is
1254  // being replaced, at least one or two bytes are different in "custom" SIDs which means we can`t use a hash to sign
1255  // these changes). One relatively easy fix is to clear the SID if it exceeds a threshold (#INT_STD_ACE_MAX_SIZE)
1256  // before sending the buffer to the exception mechanism. Please note that we are not going to clear the #ACE_HEADER.
1257 
1258  ACE_HEADER *ace = (ACE_HEADER *)((QWORD)Acl + sizeof(ACL));
1259  WORD totalSize = sizeof(ACL);
1260 
1261  if (__unlikely(Acl->AceCount > INT_MAX_ACE_COUNT))
1262  {
1263  WARNING("[WARNING] The maximum number of ACEs has been exceeded:0x%x\n", Acl->AceCount);
1264  return;
1265  }
1266 
1267  for (DWORD i = 0; i < Acl->AceCount; i++)
1268  {
1269  if (!IntWinSDIsAceInsideAcl(Acl, ace))
1270  {
1271  return;
1272  }
1273 
1274  if (ace->AceSize > INT_STD_ACE_MAX_SIZE)
1275  {
1276  BYTE *aceContents = (BYTE *)((QWORD)ace + sizeof(ACE_HEADER));
1277  memset(aceContents, 0, ace->AceSize - sizeof(ACE_HEADER));
1278  }
1279 
1280  totalSize += ace->AceSize;
1281 
1282  ace = (ACE_HEADER *)((QWORD)ace + ace->AceSize);
1283  }
1284 
1285  if (Acl->AclSize != totalSize)
1286  {
1287  IntWinSDClearAclEnd(Acl, totalSize);
1288  }
1289 }
1290 
1291 
1292 static INTSTATUS
1294  _In_ WIN_PROCESS_OBJECT *Process
1295  )
1307 {
1308  static BYTE securityDescriptorBuffer[INTRO_SECURITY_DESCRIPTOR_SIZE];
1309  INTSTATUS status;
1310  QWORD newValue = 0;
1311  QWORD oldValue = 0;
1312  DWORD processedSecDescHash = 0;
1313  WIN_PROCESS_OBJECT *victimProcess = NULL;
1314  EXCEPTION_KM_ORIGINATOR originator = { 0 };
1315  EXCEPTION_VICTIM_ZONE victim = { 0 };
1316  INTRO_ACTION action;
1317  INTRO_ACTION_REASON reason;
1318  DWORD totalSize = 0;
1319  ACL *newSacl = NULL;
1320  ACL *newDacl = NULL;
1321 
1322  if (NULL == Process)
1323  {
1325  }
1326 
1327  if (!IntWinSDIsSecDescPtrAltered(Process, &victimProcess, &oldValue, &newValue))
1328  {
1329  return INT_STATUS_SUCCESS;
1330  }
1331 
1332  memset(securityDescriptorBuffer, 0, INTRO_SECURITY_DESCRIPTOR_SIZE);
1333 
1334  // From: https://www.matteomalvica.com/blog/2019/07/06/windows-kernel-shellcode/
1335  // The original paper from Cesar Cerrudo from 2012 shows how we can find the SecurityDescriptor of a privileged
1336  // process and override it with NULL.If a process has not SecurityDescriptor, the kernel assumes that has been
1337  // created with a NULL DACL which means that everyone(every other process) can access it.However, Microsoft has
1338  // introduced a patch on Windows10 1607 Redstone 1, where it now maps a table of pointers to object structures,
1339  // and if a pointer to the SecurityDescriptor is set to NULL, it will trigger a Blue Screen Of Death(BSOD).
1340  if (0 == newValue)
1341  {
1342  goto check_exceptions;
1343  }
1344 
1345  status = IntWinSDReadSecDesc(newValue,
1347  securityDescriptorBuffer,
1348  &totalSize,
1349  &newSacl,
1350  &newDacl);
1352  {
1353  return INT_STATUS_SUCCESS;
1354  }
1355  else if (!INT_SUCCESS(status) && INT_STATUS_DATA_BUFFER_TOO_SMALL != status)
1356  {
1357  WARNING("[WARNING] IntWinSDReadSecDesc failed for process 0x%llx (%d / %s): 0x%08x\n",
1358  Process->EprocessAddress, Process->Pid, Process->Name, status);
1359 
1360  return INT_STATUS_SUCCESS;
1361  }
1362 
1363  // There are some cases in which the security descriptor pointer is being swapped but the contents are not
1364  // initialized yet.
1365  if (NULL == newSacl || NULL == newDacl)
1366  {
1367  Process->SecurityDescriptor.SecurityDescriptorGva = newValue;
1368  status = IntWinSDGatherAcl(Process);
1369  if (!INT_SUCCESS(status))
1370  {
1371  WARNING("[WARNING] IntWinSDGatherAcl failed: 0x%08x\n", status);
1372  }
1373 
1375  }
1376 
1377  if (newSacl)
1378  {
1379  IntWinSDProcessAcl(newSacl);
1380  }
1381 
1382  if (newDacl)
1383  {
1384  IntWinSDProcessAcl(newDacl);
1385  }
1386 
1387 check_exceptions:
1388  // The originator is only dummy. Complete just the elements so that we can go through exceptions.
1389  originator.Original.NameHash = INITIAL_CRC_VALUE;
1390  originator.Return.NameHash = INITIAL_CRC_VALUE;
1391 
1392  // Since we don't have an INTEGRITY_REGION associated, we'll complete the victim in-place.
1393  victim.Object.Process = Process;
1394  victim.Object.NameHash = Process->NameHash;
1396  victim.ZoneFlags |= ZONE_WRITE | ZONE_INTEGRITY;
1398 
1399  // We are going to provide the new security descriptor buffer pointer to the exception mechanism (a hash will be
1400  // generated and used to check the available signatures).
1401  victim.Integrity.Buffer = securityDescriptorBuffer;
1402  victim.Integrity.BufferSize = totalSize;
1403 
1404  processedSecDescHash = Crc32Compute(securityDescriptorBuffer, totalSize, INITIAL_CRC_VALUE);
1405 
1406  memcpy(&victim.WriteInfo.OldValue[0], &Process->SecurityDescriptor.Sacl, sizeof(ACL));
1407  if (newSacl)
1408  {
1409  memcpy(&victim.WriteInfo.NewValue[0], newSacl, sizeof(ACL));
1410  }
1411 
1412  memcpy(&victim.WriteInfo.OldValue[1], &Process->SecurityDescriptor.Dacl, sizeof(ACL));
1413  if (newDacl)
1414  {
1415  memcpy(&victim.WriteInfo.NewValue[1], newDacl, sizeof(ACL));
1416  }
1417 
1418  victim.WriteInfo.OldValue[2] = oldValue;
1419  victim.WriteInfo.NewValue[2] = newValue;
1420 
1421  IntExcept(&victim, &originator, exceptionTypeKm, &action, &reason, introEventIntegrityViolation);
1422 
1423  if (introGuestNotAllowed == action || introReasonAllowedFeedback == reason)
1424  {
1425  // Read the security descriptor again because we used IntWinSDProcessAcl before IntExcept to
1426  // clear "specific" SIDs.
1427  status = IntWinSDReadSecDesc(newValue,
1429  securityDescriptorBuffer,
1430  &totalSize,
1431  &newSacl,
1432  &newDacl);
1433  if (INT_SUCCESS(status))
1434  {
1435  IntWinSDDumpSecDesc(Process,
1436  Process->SecurityDescriptor.RawBuffer,
1437  Process->SecurityDescriptor.RawBufferSize,
1438  TRUE);
1439 
1440  IntWinSDDumpSecDesc(Process, securityDescriptorBuffer, totalSize, FALSE);
1441 
1442  status = IntWinSDSendSecDescIntViolation(Process, victimProcess, oldValue, newValue,
1443  securityDescriptorBuffer, totalSize, processedSecDescHash,
1444  action, reason);
1445  if (!INT_SUCCESS(status))
1446  {
1447  ERROR("[ERROR] IntWinSDSendSecDescIntViolation failed: 0x%08x\n", status);
1448  }
1449  }
1450  }
1451 
1452  if (introGuestNotAllowed != action)
1453  {
1454  Process->SecurityDescriptor.SecurityDescriptorGva = newValue;
1455  status = IntWinSDGatherAcl(Process);
1456  if (!INT_SUCCESS(status))
1457  {
1458  WARNING("[WARNING] IntWinSDGatherAcl failed: 0x%08x\n", status);
1459  }
1460  }
1461  else
1462  {
1463  IntPauseVcpus();
1464 
1465  // The security descriptor address is the last element of the OBJECT_HEADER structure that is always located
1466  // just before the start of the start of the _EPROCESS.
1468  Process->EprocessAddress - gGuest.WordSize,
1469  gGuest.WordSize,
1470  &oldValue,
1471  0);
1472  if (!INT_SUCCESS(status))
1473  {
1474  ERROR("[ERROR] IntVirtMemSafeWrite failed: 0x%08x\n", status);
1475  }
1476 
1477  IntResumeVcpus();
1478  }
1479 
1480  return INT_STATUS_SUCCESS;
1481 }
1482 
1483 
1484 static INTSTATUS
1486  _In_ WIN_PROCESS_OBJECT *Process
1487  )
1497 {
1498  INTSTATUS status;
1499  ACL *newSacl = NULL;
1500  ACL *newDacl = NULL;
1501  DWORD processedSecDescHash = 0;
1502  EXCEPTION_KM_ORIGINATOR originator = { 0 };
1503  EXCEPTION_VICTIM_ZONE victim = { 0 };
1506  INTRO_ACTION bestAction = introGuestNotAllowed;
1508  DWORD totalSize = 0;
1509  static BYTE securityDescriptorBuffer[INTRO_SECURITY_DESCRIPTOR_SIZE];
1510 
1511  if (0 == Process->SecurityDescriptor.SecurityDescriptorGva)
1512  {
1514  }
1515 
1516  memset(securityDescriptorBuffer, 0, INTRO_SECURITY_DESCRIPTOR_SIZE);
1517 
1518  if (!IntWinSDIsAclEdited(Process, INTRO_SECURITY_DESCRIPTOR_SIZE, securityDescriptorBuffer,
1519  &totalSize, &newSacl, &newDacl))
1520  {
1521  return INT_STATUS_SUCCESS;
1522  }
1523 
1524  // There are some cases in which the security descriptor pointer is being swapped but the contents are not
1525  // initialized yet.
1526  if (NULL == newSacl || NULL == newDacl)
1527  {
1528  LOG("[WARNING] SACL or DACL is NULL for process process 0x%llx (%d / %s)\n",
1529  Process->EprocessAddress, Process->Pid, Process->Name);
1530 
1531  return INT_STATUS_SUCCESS;
1532  }
1533 
1534  if (newSacl)
1535  {
1536  IntWinSDProcessAcl(newSacl);
1537  }
1538 
1539  if (newDacl)
1540  {
1541  IntWinSDProcessAcl(newDacl);
1542  }
1543 
1544  // The originator is only dummy. Complete just the elements so that we can go through exceptions.
1545  originator.Original.NameHash = INITIAL_CRC_VALUE;
1546  originator.Return.NameHash = INITIAL_CRC_VALUE;
1547 
1548  // Since we don't have an INTEGRITY_REGION associated, we'll complete the victim in-place.
1549  victim.Object.Type = introObjectTypeAcl;
1550  victim.ZoneFlags |= ZONE_WRITE | ZONE_INTEGRITY;
1552 
1553  // We are going to provide the new security descriptor buffer pointer to the exception mechanism (a hash will be
1554  // generated and used to check the available signatures).
1555  victim.Integrity.Buffer = securityDescriptorBuffer;
1556  victim.Integrity.BufferSize = totalSize;
1557 
1558  processedSecDescHash = Crc32Compute(securityDescriptorBuffer, totalSize, INITIAL_CRC_VALUE);
1559 
1560  memcpy(&victim.WriteInfo.OldValue[0], &Process->SecurityDescriptor.Sacl, sizeof(ACL));
1561  if (newSacl)
1562  {
1563  memcpy(&victim.WriteInfo.NewValue[0], newSacl, sizeof(ACL));
1564  }
1565 
1566  memcpy(&victim.WriteInfo.OldValue[1], &Process->SecurityDescriptor.Dacl, sizeof(ACL));
1567  if (newDacl)
1568  {
1569  memcpy(&victim.WriteInfo.NewValue[1], newDacl, sizeof(ACL));
1570  }
1571 
1572  // There are some cases in which multiple processes share the same Security Descriptor pointer, so depending upon
1573  // the order in which they are stored within our #gWinProcesses, we may find an exception only after iterating the
1574  // entire process list.
1575  list_for_each(gWinProcesses, WIN_PROCESS_OBJECT, pProcess)
1576  {
1577  if (pProcess->SecurityDescriptor.SecurityDescriptorGva == Process->SecurityDescriptor.SecurityDescriptorGva)
1578  {
1579  victim.Object.Process = pProcess;
1580  victim.Object.NameHash = pProcess->NameHash;
1581 
1582  IntExcept(&victim, &originator, exceptionTypeKm, &action, &reason, introEventIntegrityViolation);
1583 
1584  if (introGuestAllowed == action)
1585  {
1586  bestAction = action;
1587  bestReason = reason;
1588  }
1589 
1590  if (introReasonAllowed == reason)
1591  {
1592  goto found_exception;
1593  }
1594  }
1595  }
1596 
1597 found_exception:
1598  if (introGuestNotAllowed == bestAction || introReasonAllowedFeedback == bestReason)
1599  {
1600  // Read the security descriptor again because we used IntWinSDProcessAcl before IntExcept to
1601  // clear "specific" SIDs.
1602  status = IntWinSDReadSecDesc(Process->SecurityDescriptor.SecurityDescriptorGva,
1604  securityDescriptorBuffer,
1605  &totalSize,
1606  &newSacl,
1607  &newDacl);
1608  if (INT_SUCCESS(status))
1609  {
1610  IntWinSDDumpSecDesc(Process,
1611  Process->SecurityDescriptor.RawBuffer,
1612  Process->SecurityDescriptor.RawBufferSize,
1613  TRUE);
1614 
1615  IntWinSDDumpSecDesc(Process, securityDescriptorBuffer, totalSize, FALSE);
1616 
1617  status = IntWinSDSendAclIntegrityViolation(Process, securityDescriptorBuffer, totalSize,
1618  processedSecDescHash, bestAction, bestReason);
1619  if (!INT_SUCCESS(status))
1620  {
1621  ERROR("[ERROR] IntWinSDSendAclIntegrityViolation failed: 0x%08x\n", status);
1622  }
1623  }
1624  }
1625 
1626  if (introGuestNotAllowed != bestAction)
1627  {
1628  status = IntWinSDGatherAcl(Process);
1629  if (!INT_SUCCESS(status))
1630  {
1631  WARNING("[WARNING] IntWinSDGatherAcl failed: 0x%08x\n", status);
1632  }
1633  }
1634  else
1635  {
1636  IntPauseVcpus();
1637 
1639  Process->SecurityDescriptor.SecurityDescriptorGva,
1640  Process->SecurityDescriptor.RawBufferSize,
1641  Process->SecurityDescriptor.RawBuffer,
1642  0);
1643  if (!INT_SUCCESS(status))
1644  {
1645  ERROR("[ERROR] IntVirtMemSafeWrite failed: 0x%08x\n", status);
1646  }
1647 
1648  IntResumeVcpus();
1649  }
1650 
1651  return INT_STATUS_SUCCESS;
1652 }
1653 
1654 
1657  void
1658  )
1665 {
1666  INTSTATUS status;
1667 
1668  if (!gGuest.GuestInitialized)
1669  {
1671  }
1672 
1674  {
1676  }
1677 
1679  {
1681  }
1682 
1684 
1685  list_for_each(gWinProcesses, WIN_PROCESS_OBJECT, pProcess)
1686  {
1687  status = IntWinSDCheckSecDescIntegrity(pProcess);
1688  if (!INT_SUCCESS(status) &&
1690  {
1691  ERROR("[ERROR] IntWinSDCheckSecDescIntegrity failed for process 0x%llx (%d / %s) "
1692  "status:0x%08x\n",
1693  pProcess->EprocessAddress, pProcess->Pid, pProcess->Name, status);
1694  }
1695 
1696  if (INT_STATUS_SKIP_OTHER_CALLBACKS != status)
1697  {
1698  status = IntWinSDCheckAclIntegrity(pProcess);
1699  if (!INT_SUCCESS(status) &&
1701  {
1702  ERROR("[ERROR] IntWinSDCheckAclIntegrity failed for process 0x%llx (%d / %s) "
1703  "status:0x%08x\n",
1704  pProcess->EprocessAddress, pProcess->Pid, pProcess->Name, status);
1705  }
1706  }
1707  }
1708 
1710 
1711  return INT_STATUS_SUCCESS;
1712 }
1713 
static INTSTATUS IntWinSDCheckSecDescIntegrity(WIN_PROCESS_OBJECT *Process)
This function checks the integrity of the security descriptor for the given process. In case the security descriptor pointer has been altered, the VCPUs will be paused in order to restore the original value, the victim process will be found (in case there is one) and an alert will be sent.
Definition: winsecdesc.c:1293
static INTSTATUS IntWinSDFetchSecDescAddress(WIN_PROCESS_OBJECT *Process, QWORD *SecurityDescriptorAddressGva)
This function reads the security descriptor address for the given process using the GPA cache...
Definition: winsecdesc.c:697
#define ACCESS_DENIED_OBJECT_ACE_TYPE_STRING
Printable version of ACCESS_DENIED_OBJECT_ACE_TYPE.
Definition: wddefs.h:700
#define ACCESS_ALLOWED_OBJECT_ACE_TYPE_STRING
Printable version of ACCESS_ALLOWED_OBJECT_ACE_TYPE.
Definition: wddefs.h:698
#define _In_opt_
Definition: intro_sal.h:16
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
Definition: introstatus.h:438
QWORD PhysicalAddress
The physical address to which VirtualAddress translates to.
Definition: introcore.h:107
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
#define INT_MAX_ACE_COUNT
The maximum number of ACEs that are allowed within a single ACL. "The maximum size of an ACL is 64 ki...
Definition: winsecdesc.c:108
#define __unlikely(x)
Definition: common.h:64
Measures the integrity checks on the process security descriptor.
Definition: stats.h:108
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
static void IntWinSDDumpSecDesc(WIN_PROCESS_OBJECT *Process, BYTE *SecurityDescriptorBuffer, DWORD BufferSize, BOOLEAN Original)
This function dumps the security descriptor for a given process.
Definition: winsecdesc.c:577
QWORD IntAlertCoreGetFlags(QWORD ProtectionFlag, INTRO_ACTION_REASON Reason)
Returns the flags for an alert.
Definition: alerts.c:366
#define INT_STATUS_SKIP_OTHER_CALLBACKS
Definition: introstatus.h:348
#define EX_FAST_REF_TO_PTR(is64, p)
Converts a _EX_FAST_REF value to a pointer.
Definition: wddefs.h:100
DWORD Mask
The access mask of the given SID (https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask...
Definition: winsecdesc.h:44
uint8_t BYTE
Definition: intro_types.h:47
#define SYSTEM_SCOPED_POLICY_ID_ACE_TYPE_STRING
Printable version of SYSTEM_SCOPED_POLICY_ID_ACE_TYPE.
Definition: wddefs.h:726
#define SYSTEM_ALARM_ACE_TYPES_STRING
Printable version of SYSTEM_ALARM_ACE_TYPE.
Definition: wddefs.h:694
QWORD ZoneFlags
The flags of the modified zone.
Definition: exceptions.h:898
DWORD Crc32Compute(const void *Buffer, size_t Size, DWORD InitialCrc)
Computes the CRC for a byte array.
Definition: crc32.c:103
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
struct _SECURITY_DESCRIPTOR SECURITY_DESCRIPTOR
uint16_t WORD
Definition: intro_types.h:48
struct _ACE_HEADER ACE_HEADER
An access control entry header.
#define SYSTEM_ACCESS_FILTER_ACE_TYPE_STRING
Printable version of SYSTEM_ACCESS_FILTER_ACE_TYPE.
Definition: wddefs.h:730
#define STATS_EXIT(id)
Definition: stats.h:160
#define _Out_writes_bytes_(expr)
Definition: intro_sal.h:38
void IntAlertFillWinProcess(const WIN_PROCESS_OBJECT *Process, INTRO_PROCESS *EventProcess)
Saves information about a windows process inside an alert.
Definition: alerts.c:689
#define SYSTEM_AUDIT_ACE_TYPE_STRING
Printable version of SYSTEM_AUDIT_ACE_TYPE.
Definition: wddefs.h:692
Event structure for integrity violations on monitored structures.
Definition: intro_types.h:1572
#define ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE_STRING
Printable version of ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE.
Definition: wddefs.h:710
#define _Success_(expr)
Definition: intro_sal.h:47
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define SYSTEM_AUDIT_CALLBACK_ACE_TYPE_STRING
Printable version of SYSTEM_AUDIT_CALLBACK_ACE_TYPE.
Definition: wddefs.h:714
static BOOLEAN IntWinSDIsAceInsideBuffer(BYTE *Buffer, DWORD BufferSize, ACE_HEADER *Ace)
This function checks whether the ACE fits inside the given buffer.
Definition: winsecdesc.c:326
#define INTRO_SECURITY_DESCRIPTOR_SIZE
The size of the buffers in which we store the security descriptors. The security descriptor is compos...
Definition: intro_types.h:740
BOOLEAN IntWinSDIsAclEdited(WIN_PROCESS_OBJECT *Process, DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **NewSacl, ACL **NewDacl)
This function reads the ACLs for the given process (returning the data using the provided buffer and ...
Definition: winsecdesc.c:916
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
INTRO_OBJECT_TYPE Type
Definition: intro_types.h:1589
BOOLEAN ProtectionActivated
Definition: guests.h:297
The action was not allowed because there was no reason to allow it.
Definition: intro_types.h:183
struct _EVENT_INTEGRITY_VIOLATION::@304 Victim
BOOLEAN IntWinSDIsSecDescPtrAltered(WIN_PROCESS_OBJECT *Process, WIN_PROCESS_OBJECT **VictimProcess, QWORD *OldValue, QWORD *NewValue)
This function checks if the security descriptor pointer of a process has been altered or not...
Definition: winsecdesc.c:829
#define SYSTEM_ALARM_CALLBACK_ACE_TYPE_STRING
Printable version of SYSTEM_ALARM_CALLBACK_ACE_TYPE.
Definition: wddefs.h:716
#define ACCESS_ALLOWED_CALLBACK_ACE_TYPE_STRING
Printable version of ACCESS_ALLOWED_CALLBACK_ACE_TYPE.
Definition: wddefs.h:706
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
struct _ACE_BODY ACE_BODY
The internal representation of an Access Control Entry body.
#define ERROR(fmt,...)
Definition: glue.h:62
int INTSTATUS
The status data type.
Definition: introstatus.h:24
static int memcmp_len(const void *buf1, const void *buf2, size_t len_buf1, size_t len_buf2)
Definition: introcrt.h:282
static BOOLEAN IntWinSDIsAceInsideAcl(ACL *Acl, ACE_HEADER *Ace)
This function checks whether the ACE fits inside the ACL (the ACL structure must be obtained using In...
Definition: winsecdesc.c:289
static void IntWinSDClearAclEnd(ACL *Acl, WORD CalculatedSize)
This function clears the last bytes of the ACL in case the ACL size is greater than the sum of its AC...
Definition: winsecdesc.c:1206
#define SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE_STRING
Printable version of SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE.
Definition: wddefs.h:718
#define INT_STD_ACE_MAX_SIZE
The maximum size of a standard access control entry (empirically chosen value).
Definition: winsecdesc.h:11
Describes a kernel-mode originator.
Definition: exceptions.h:943
BYTE Sbz1
Definition: wddefs.h:640
#define ACCESS_ALLOWED_ACE_TYPE_STRING
Printable version of ACCESS_ALLOWED_ACE_TYPE.
Definition: wddefs.h:688
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
static INTSTATUS IntWinSDSendAclIntegrityViolation(WIN_PROCESS_OBJECT *Process, BYTE *SecDescBuffer, DWORD SecDescSize, DWORD SecDescHash, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
This function sends an integrity violation caused by a modified ACL (SACL/DACL).
Definition: winsecdesc.c:1131
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
LIST_HEAD gWinProcesses
The list of all the processes inside the guest.
Definition: winprocesshp.c:11
Process ACL (SACL/DACL) was modified.
Definition: intro_types.h:272
#define MIN(a, b)
Definition: introdefs.h:146
struct _EXCEPTION_KM_ORIGINATOR::@63 Return
static INTSTATUS IntWinSDGatherAcl(WIN_PROCESS_OBJECT *Process)
This function gathers the 2 ACLs (SACL/DACL) and stores them in the WIN_PROCESS_OBJECT structure of t...
Definition: winsecdesc.c:634
UCHAR Revision
S-1-5-32-554 - The SID revision (in this case 1).
Definition: winsecdesc.h:33
#define INTRO_OPT_PROT_KM_SD_ACL
Enable integrity protection over the Security Descriptor pointer and the 2 ACLs (SACL/DACL).
Definition: intro_types.h:522
An access control list.
Definition: wddefs.h:637
#define LOG(fmt,...)
Definition: glue.h:61
SID_IDENTIFIER_AUTHORITY IdentifierAuthority
S-1-5-32-554 - The authority (in this case 5).
Definition: winsecdesc.h:37
struct _ACL ACL
An access control list.
static void IntWinSDProcessAcl(ACL *Acl)
This function clears the SIDs that have more than one sub authority for a given ACL.
Definition: winsecdesc.c:1234
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
#define VICTIM_PROCESS_ACL
Printable name used for introObjectTypeAcl objects.
Definition: intro_types.h:761
BYTE AceFlags
Definition: wddefs.h:654
BYTE * Buffer
The new security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSecDesc or intr...
Definition: exceptions.h:810
#define ZONE_INTEGRITY
Used for integrity zone.
Definition: exceptions.h:738
#define SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE_STRING
Printable version of SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE.
Definition: wddefs.h:724
INTSTATUS IntWinSDFindAcls(DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **Sacl, ACL **Dacl)
This function looks for the Sacl/Dacl within the SecurityDescriptorBuffer and makes sure they are wit...
Definition: winsecdesc.c:202
Access Token Manipulation.
Definition: intro_types.h:1153
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
EXCEPTION_VICTIM_OBJECT Object
The modified object.
Definition: exceptions.h:895
#define ACCESS_ALLOWED_COMPOUND_ACE_TYPE_STRING
Printable version of ACCESS_ALLOWED_COMPOUND_ACE_TYPE.
Definition: wddefs.h:696
DWORD BufferSize
The size of the new security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSec...
Definition: exceptions.h:813
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
#define _Inout_opt_
Definition: intro_sal.h:31
#define _Inout_
Definition: intro_sal.h:20
QWORD Flags
The entry that maps VirtualAddress to PhysicalAddress, together with all the control bits...
Definition: introcore.h:119
#define SYSTEM_MANDATORY_LABEL_ACE_TYPE_STRING
Printable version of SYSTEM_MANDATORY_LABEL_ACE_TYPE.
Definition: wddefs.h:722
#define _Out_opt_
Definition: intro_sal.h:30
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
DWORD Size
The size of the modified memory area.
Definition: intro_types.h:1618
#define ACCESS_DENIED_ACE_TYPE_STRING
Printable version of ACCESS_DENIED_ACE_TYPE.
Definition: wddefs.h:690
The modified object is inside an integrity hook.
Definition: exceptions.h:749
#define STATS_ENTER(id)
Definition: stats.h:153
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
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
static INTSTATUS IntWinSDCheckAclIntegrity(WIN_PROCESS_OBJECT *Process)
This function checks the integrity of the ACLs (SACL/DACL) for the given process. In case the ACLs ha...
Definition: winsecdesc.c:1485
#define memzero(a, s)
Definition: introcrt.h:35
#define PT_P
Definition: pgtable.h:83
INTSTATUS IntGpaCacheFetchAndAdd(PGPA_CACHE Cache, QWORD Gpa, DWORD Size, PBYTE Buffer)
Fetch data from a cached entry, or add it to the cache, of not already present.
Definition: gpacache.c:508
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
QWORD Current
The currently used options.
Definition: guests.h:236
SID_INTERNAL Sid
The containing SID.
Definition: winsecdesc.h:46
TIMER_FRIENDLY INTSTATUS IntWinSDCheckIntegrity(void)
This function checks the integrity of the security descriptor for all the processes inside gWinProces...
Definition: winsecdesc.c:1656
void * GpaCache
The currently used GPA cache.
Definition: guests.h:403
QWORD VirtualAddress
The guest virtual address which was modified.
Definition: intro_types.h:1616
#define TRUE
Definition: intro_types.h:30
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1574
BOOLEAN GuestInitialized
True if the OS-specific portion has been initialized.
Definition: guests.h:293
#define TRACE(fmt,...)
Definition: glue.h:58
#define ACCESS_DENIED_CALLBACK_ACE_TYPE_STRING
Printable version of ACCESS_DENIED_CALLBACK_ACE_TYPE.
Definition: wddefs.h:708
WORD AclSize
Definition: wddefs.h:641
WORD AceCount
Definition: wddefs.h:642
WORD AceSize
Definition: wddefs.h:655
unsigned char UCHAR
Definition: intro_types.h:55
DWORD NameHash
The hash of the modified object.
Definition: exceptions.h:854
#define TIMER_FRIENDLY
Definition: introdefs.h:83
BYTE AceType
Definition: wddefs.h:653
Kernel-mode exception.
Definition: exceptions.h:61
static void IntWinSDDumpAclEntries(ACL *Acl, BOOLEAN IsSacl, BYTE *SecurityDescriptorBuffer, DWORD BufferSize)
This function dumps the access control entries (ACE) for a given access control list (ACL)...
Definition: winsecdesc.c:459
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
#define INT_SID_CHAR_SIZE
INTRO_OBJECT_TYPE Type
The type of the modified object.
Definition: exceptions.h:852
ZONE_TYPE ZoneType
The type of the modified zone.
Definition: exceptions.h:897
DWORD OldSecDescSize
The size of the old security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSec...
Definition: intro_types.h:1023
BYTE OldSecDesc[INTRO_SECURITY_DESCRIPTOR_SIZE]
The old security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSecDesc or intr...
Definition: intro_types.h:1020
INTSTATUS IntTranslateVirtualAddressEx(QWORD Gva, QWORD Cr3, DWORD Flags, VA_TRANSLATION *Translation)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1863
An access control entry header.
Definition: wddefs.h:651
#define SYSTEM_AUDIT_OBJECT_ACE_TYPE_STRING
Printable version of SYSTEM_AUDIT_OBJECT_ACE_TYPE.
Definition: wddefs.h:702
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntVirtMemSafeWrite(QWORD Cr3, QWORD VirtualAddress, DWORD Size, void *Buffer, DWORD Ring)
Safely modify guest memory.
Definition: kernvm.c:498
Describes the modified zone.
Definition: exceptions.h:893
#define TRFLG_PG_MODE
Obtains the translation mode flag for the currently used paging mode.
Definition: introcore.h:92
BYTE NewSecDesc[INTRO_SECURITY_DESCRIPTOR_SIZE]
The new security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSecDesc or intr...
Definition: intro_types.h:1027
#define ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE_STRING
Printable version of ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE.
Definition: wddefs.h:712
#define INT_STATUS_DATA_BUFFER_TOO_SMALL
Definition: introstatus.h:194
struct _EXCEPTION_VICTIM_ZONE::@58::@60 WriteInfo
static char * IntWinSDGetAceTypeName(BYTE AceTypeValue)
This function obtains the printable name for a given ACE type.
Definition: winsecdesc.c:111
WCHAR Name[ALERT_PATH_MAX_LEN]
NULL-terminated string with a human readable description of the modified object.
Definition: intro_types.h:1591
uint32_t DWORD
Definition: intro_types.h:49
BOOLEAN Valid
Set to True if the information in the structure is valid, False otherwise.
Definition: intro_types.h:965
enum _INTRO_ACTION INTRO_ACTION
Event actions.
static INTSTATUS IntWinSDSendSecDescIntViolation(WIN_PROCESS_OBJECT *Process, WIN_PROCESS_OBJECT *Victim, QWORD OldValue, QWORD NewValue, BYTE *SecDescBuffer, DWORD SecDescSize, DWORD SecDescHash, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
This function sends an integrity violation caused by a modified security descriptor pointer...
Definition: winsecdesc.c:1048
#define SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE_STRING
Printable version of SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE.
Definition: wddefs.h:720
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
static INTSTATUS IntWinSDFetchSecDescValues(WIN_PROCESS_OBJECT *Process, QWORD *OldValue, QWORD *NewValue)
This function obtains the original security descriptor value (from the WIN_PROCESS_OBJECT structure) ...
Definition: winsecdesc.c:793
UCHAR SubAuthorityCount
S-1-5-32-554 - The number of sub authorities (in this case 2 -> sub-authority 32 and sub-authority 54...
Definition: winsecdesc.h:35
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
INTSTATUS IntWinSDProtectSecDesc(WIN_PROCESS_OBJECT *Process)
This function saves the security descriptor address and ACLs into the WIN_PROCESS_OBJECT structure...
Definition: winsecdesc.c:750
SECURITY_DESCRIPTOR_CONTROL Control
Definition: wddefs.h:626
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTSTATUS IntWinSDReadSecDesc(QWORD SecurityDescriptorGva, DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **Sacl, ACL **Dacl)
This function reads the ACLs (along with the ACEs) from the given GVA and returns the data using the ...
Definition: winsecdesc.c:362
void * Process
The internal structure of the modified process.
Definition: exceptions.h:881
DWORD NewSecDescHash
The CRC32 hash of the new security descriptor (after zeroing out SIDs with more than one sub-authorit...
Definition: intro_types.h:1016
EVENT_INTEGRITY_VIOLATION Integrity
Definition: alerts.h:23
#define SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE_STRING
Printable version of SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE.
Definition: wddefs.h:728
struct _EXCEPTION_KM_ORIGINATOR::@64 Original
STATIC_ASSERT(sizeof(ACL)==sizeof(QWORD), "Sizeof of ACL is not a QWORD")
We are using the EXCEPTION_VICTIM_ZONE.WriteInfo to send the New/Old SACL/DACL.
struct _EVENT_INTEGRITY_VIOLATION::@302 Originator
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
Definition: introstatus.h:434
BYTE AclRevision
Definition: wddefs.h:639
QWORD BaseAddress
The guest virtual address at which the monitored integrity region starts.
Definition: intro_types.h:1614
#define MAX_ACL_REVISION
Definition: wddefs.h:748
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
Encapsulates information about a virtual to physical memory translation.
Definition: introcore.h:102
INTRO_PROCESS Process
The module to which the current code return to.
Definition: intro_types.h:1579
QWORD OldAddress
The old security descriptor address.
Definition: intro_types.h:1013
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
#define INT_MAX_SUB_AUTHORITY_COUT
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
The internal representation of an Access Control Entry body.
Definition: winsecdesc.h:41
Sent for integrity violation alerts. See EVENT_INTEGRITY_VIOLATION.
Definition: intro_types.h:92
EXCEPTION_VICTIM_INTEGRITY Integrity
Valid if the modified zone is Integrity.
Definition: exceptions.h:908
#define VICTIM_PROCESS_SECURITY_DESCRIPTOR
Printable name used for introObjectTypeSecDesc objects.
Definition: intro_types.h:759
#define SYSTEM_ALARM_OBJECT_ACE_TYPE_STRING
Printable version of SYSTEM_ALARM_OBJECT_ACE_TYPE.
Definition: wddefs.h:704
#define INT_STATUS_INVALID_PARAMETER
Definition: introstatus.h:59
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
Process security descriptor pointer.
Definition: intro_types.h:271
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
DWORD NewSecDescSize
The size of the new security descriptor buffer (valid only if INTRO_OBJECT_TYPE is introObjectTypeSec...
Definition: intro_types.h:1030
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3357
WORD Sbz2
Definition: wddefs.h:643
INTRO_SEC_DESC_INFO SecDescWriteInfo
Definition: intro_types.h:1610
DWORD NameHash
The namehash of the originator return driver.
Definition: exceptions.h:947
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:83