Bitdefender Hypervisor Memory Introspection
lixagent.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixagent.h"
6 #include "alerts.h"
7 #include "callbacks.h"
8 #include "glue.h"
9 #include "guests.h"
10 #include "hnd_remediation.h"
11 #include "hnd_loggather.h"
12 #include "icache.h"
13 #include "memcloak.h"
14 #include "slack.h"
15 #include "lixksym.h"
16 
17 
18 static INTSTATUS
20  _In_ LIX_AGENT *Agent
21  );
22 
23 static INTSTATUS
25  _In_ LIX_AGENT *Agent
26  );
27 
28 
37 typedef struct _LIX_AGENT_NAME
38 {
40 
43 
45  size_t Length;
46 
49 
50 
54 typedef struct _LIX_AGENT_STATE
55 {
58 
60 
63 
67 
68 
70 {
71  .PendingAgents = LIST_HEAD_INIT(gLixAgentState.PendingAgents),
72  .AgentNames = LIST_HEAD_INIT(gLixAgentState.AgentNames)
73 };
74 
75 
76 
77 static QWORD
79  void
80  )
86 {
87  return __rdtsc();
88 }
89 
90 
91 static INTSTATUS
93  _In_ BYTE MinLen,
94  _Out_ QWORD *InstructionVa,
95  _Out_ BYTE *InstructionLen,
96  _Out_writes_bytes_(ND_MAX_INSTRUCTION_LENGTH) BYTE *InstructionBytes
97  )
113 {
114  INTSTATUS status;
115  BYTE *pSyscallCode = NULL;
116  QWORD syscallGva = 0;
117  size_t parsed = 0;
118  BYTE stiCount, neededStiCount;
119  BOOLEAN bFound, bStiFound;
120 
122 
123  bFound = bStiFound = FALSE;
124  neededStiCount = 1;
125  stiCount = 0;
126 
127  pSyscallCode = HpAllocWithTag(PAGE_SIZE, IC_TAG_ALLOC);
128  if (NULL == pSyscallCode)
129  {
131  }
132 
133  if (LIX_FIELD(Info, HasAlternateSyscall))
134  {
135  syscallGva = gLixGuest->PropperSyscallGva;
136  }
137  else
138  {
139  syscallGva = gLixGuest->SyscallAddress;
140  }
141 
142  status = IntKernVirtMemRead(syscallGva, PAGE_SIZE, pSyscallCode, NULL);
143  if (!INT_SUCCESS(status))
144  {
145  ERROR("[ERROR] IntKernVirtMemRead failed for syscall 0x%016llx: 0x%08x\n", syscallGva, status);
146  goto _exit;
147  }
148 
149  while (parsed + 16 < PAGE_SIZE)
150  {
151  INSTRUX instrux;
152 
153  NDSTATUS ndstatus = NdDecodeEx(&instrux, pSyscallCode + parsed, PAGE_SIZE - parsed, ND_CODE_64, ND_DATA_64);
154  if (!ND_SUCCESS(ndstatus))
155  {
156  ERROR("[ERROR] NdDecodeEx failed at 0x%016llx: 0x%08x\n", syscallGva + parsed, ndstatus);
157 
158  status = INT_STATUS_DISASM_ERROR;
159  goto _exit;
160  }
161 
162  if (!bStiFound)
163  {
164  if (ND_INS_STI == instrux.Instruction)
165  {
166  if (++stiCount == neededStiCount)
167  {
168  bStiFound = TRUE;
169  }
170  }
171  }
172  else if ((instrux.Length >= MinLen) && !ND_HAS_PREDICATE(&instrux)) // Avoid conditional instructions.
173  {
174  bFound = TRUE;
175 
176  *InstructionVa = syscallGva + parsed;
177  *InstructionLen = instrux.Length;
178 
179  memcpy(InstructionBytes, instrux.InstructionBytes, ND_MAX_INSTRUCTION_LENGTH);
180 
181  break;
182  }
183 
184  parsed += instrux.Length;
185  }
186 
187  if (bFound)
188  {
189  status = INT_STATUS_SUCCESS;
190  }
191  else
192  {
193  status = INT_STATUS_NOT_FOUND;
194  }
195 
196 _exit:
197  HpFreeAndNullWithTag(&pSyscallCode, IC_TAG_ALLOC);
198 
199  return status;
200 }
201 
202 
203 static BOOLEAN
205  _In_ const char *Name
206  )
214 {
215  size_t nameLength = MIN(strlen(Name), IMAGE_BASE_NAME_LEN - 1);
216 
217  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
218  {
219  if (memcmp_len(pName->Name, Name, pName->Length, nameLength) == 0)
220  {
221  ERROR("[ERROR] An agent with the name '%s' is already injected!\n", Name);
222  return TRUE;
223  }
224  }
225 
226  return FALSE;
227 }
228 
229 
230 static INTSTATUS
232  _In_ const char *Name,
233  _In_ DWORD Tag,
234  _In_ DWORD Agid,
235  _Out_ LIX_AGENT_NAME **AgentName
236  )
248 {
250  if (pName == NULL)
251  {
253  }
254 
255  strlcpy(pName->Name, Name, sizeof(pName->Name));
256  pName->Length = strlen(pName->Name);
257  pName->Agid = Agid;
258  pName->AgentTag = Tag;
259  pName->RefCount = 0;
260 
261  *AgentName = pName;
262 
263  InsertTailList(&gLixAgentState.AgentNames, &pName->Link);
264 
265  return INT_STATUS_SUCCESS;
266 }
267 
268 
269 static void
272  )
278 {
279  RemoveEntryList(&Name->Link);
281 }
282 
283 
284 void
286  _In_ DWORD Agid
287  )
293 {
294  if (IsListEmpty(&gLixAgentState.AgentNames))
295  {
296  return;
297  }
298 
299  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
300  {
301  if (Agid == pName->Agid)
302  {
303  IntLixAgentNameRemove(pName);
304 
305  return;
306  }
307  }
308 }
309 
310 
311 DWORD
313  _In_ DWORD Agid
314  )
322 {
323  if (IsListEmpty(&gLixAgentState.AgentNames))
324  {
325  return lixAgTagNone;
326  }
327 
328  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
329  {
330  if (Agid == pName->Agid)
331  {
332  return pName->AgentTag;
333  }
334  }
335 
336  return lixAgTagNone;
337 }
338 
339 
340 static INTSTATUS
342  _In_ LIX_AGENT_THREAD *Thread
343  )
353 {
354  if (Thread->Data.Code != NULL)
355  {
356  HpFreeAndNullWithTag(&Thread->Data.Code, IC_TAG_LAGE);
357  }
358 
359  if (Thread->Content.Address)
360  {
361  IntReleaseBuffer(Thread->Content.Address, Thread->Content.Size);
362  }
363 
365 
366  return INT_STATUS_SUCCESS;
367 }
368 
369 
370 static void
372  _In_ LIX_AGENT *Agent
373  )
383 {
384  INTSTATUS status;
385  BYTE *pSlack = NULL;
386 
387  if (Agent == NULL)
388  {
389  return;
390  }
391 
392  if (Agent->Data.Address == 0)
393  {
394  goto _exit;
395  }
396 
397  status = IntSlackFree(Agent->Data.Address);
398  if (status == INT_STATUS_NOT_FOUND)
399  {
400  goto _exit;
401  }
402  else if (!INT_SUCCESS(status))
403  {
404  ERROR("[ERROR] IntSlackFree failed with status: 0x%08x.", status);
405  }
406 
407  status = IntVirtMemMap(Agent->Data.Address, Agent->Data.Size, gGuest.Mm.SystemCr3, 0, &pSlack);
408  if (!INT_SUCCESS(status))
409  {
410  ERROR("[ERROR] IntVirtMemMap failed with status: 0x%08x. Cannot fill slack with NOPs...", status);
411  }
412  else
413  {
414  memset(pSlack, LIX_FIELD(Info, HasSlackInt3) ? 0xCC : 0x90, Agent->Data.Size);
415  IntVirtMemUnmap(&pSlack);
416  }
417 
418 _exit:
419  if (Agent->Thread)
420  {
421  IntLixAgentThreadFree(Agent->Thread);
422  Agent->Thread = NULL;
423  }
424 
425  if (Agent->Data.Code)
426  {
427  HpFreeAndNullWithTag(&Agent->Data.Code, IC_TAG_LAGE);
428  }
429 
431 }
432 
433 
434 static INTSTATUS
436  _Inout_ LIX_AGENT_DATA *Data,
437  _In_ LIX_AGENT_TAG Tag
438  )
453 {
454  QWORD crtAddress = gLixGuest->MmAlloc.Agent.Address;
455 
456  while (crtAddress <= gLixGuest->MmAlloc.Agent.Address + gLixGuest->MmAlloc.Agent.Length)
457  {
458  INTSTATUS status;
459  LIX_AGENT_HEADER header = { 0 };
460 
461  status = IntVirtMemRead(crtAddress,
462  sizeof(LIX_AGENT_HEADER),
464  &header,
465  NULL);
466  if (!INT_SUCCESS(status))
467  {
468  ERROR("[ERROR] IntVirtMemRead failed with status: 0x%08x.", status);
469  return status;
470  }
471 
472  if (header.Tag == (DWORD)(Tag))
473  {
474  Data->Code = HpAllocWithTag((size_t)header.CodeSize + header.DataSize, IC_TAG_LAGE);
475  if (Data->Code == NULL)
476  {
478  }
479 
480  memcpy(&Data->Header, &header, sizeof(LIX_AGENT_HEADER));
481 
482  status = IntVirtMemRead(crtAddress,
483  header.CodeSize + header.DataSize,
485  Data->Code,
486  NULL);
487  if (!INT_SUCCESS(status))
488  {
489  ERROR("[ERROR] IntVirtMemRead failed with status: 0x%08x.", status);
490  return status;
491  }
492 
493  Data->Address = crtAddress;
494  Data->Size = header.CodeSize + header.DataSize;
495 
496  return INT_STATUS_SUCCESS;
497  }
498 
499  crtAddress += (QWORD)header.CodeSize + header.DataSize;
500  }
501 
502  return INT_STATUS_NOT_FOUND;
503 }
504 
505 
506 static INTSTATUS
508  _Inout_ LIX_AGENT_DATA *Data,
509  _In_ LIX_AGENT_HANDLER *Handler
510  )
523 {
524  Data->Code = HpAllocWithTag(Handler->Code.Length, IC_TAG_LAGE);
525  if (Data->Code == NULL)
526  {
528  }
529 
530  memcpy(Data->Code, Handler->Code.Content, Handler->Code.Length);
531  memcpy(&Data->Header, Handler->Code.Content, sizeof(LIX_AGENT_HEADER));
532 
533  Data->Size = Handler->Code.Length;
534  Data->Address = 0;
535 
536  return INT_STATUS_SUCCESS;
537 }
538 
539 
540 static INTSTATUS
542  _Inout_ LIX_AGENT_DATA *Data,
543  _In_ LIX_AGENT_HANDLER *Handler
544  )
557 {
558  if (Handler->Code.Length != 0)
559  {
560  return IntLixAgentFillDataFromHandler(Data, Handler);
561  }
562  else
563  {
564  return IntLixAgentFillDataFromMemory(Data, Handler->Tag);
565  }
566 }
567 
568 
571  _In_ LIX_AGENT_FUNCTIONS *Function
572  )
580 {
581  return ((Function->Version.Version == gLixGuest->Version.Version ||
582  Function->Version.Version == BYTE_MAX) &&
583  (Function->Version.Patch == gLixGuest->Version.Patch ||
584  Function->Version.Patch == BYTE_MAX) &&
585  (Function->Version.Sublevel == gLixGuest->Version.Sublevel ||
586  Function->Version.Sublevel == WORD_MAX) &&
587  (Function->Version.Backport == gLixGuest->Version.Backport ||
588  Function->Version.Backport == WORD_MAX));
589 }
590 
591 
592 static INTSTATUS
594  _In_ LIX_AGENT_DATA *Data,
595  _In_ LIX_AGENT_HANDLER *Handler
596  )
623 {
624  LIX_AGENT_FUNCTIONS *pFunctions = NULL;
625  DWORD currentFunc = 0;
626 
627  memcpy(&Data->Code[sizeof(LIX_AGENT_HEADER)], &Data->Token, sizeof(LIX_AGENT_TOKEN));
628 
629  for (DWORD index = 0; index < Handler->Functions.Count; index++)
630  {
631  if (IntLixAgentMatchVersion(&Handler->Functions.Content[index]))
632  {
633  pFunctions = &Handler->Functions.Content[index];
634  break;
635  }
636  }
637 
638  if (pFunctions == NULL)
639  {
640  return INT_STATUS_NOT_FOUND;
641  }
642 
643  for (DWORD index = 0; index < pFunctions->Count; index++)
644  {
645  DWORD required = pFunctions->List[index].Required;
646  DWORD match = 0;
647  for (DWORD item = 0; item < pFunctions->List[index].Count; item++)
648  {
649  QWORD kallsymAddr = IntKsymFindByName(pFunctions->List[index].Name[item], NULL);
650  if (kallsymAddr)
651  {
652  TRACE("[LIX-AGENT] Found '%s' ksym @ 0x%16llx.", pFunctions->List[index].Name[item], kallsymAddr);
653  match++;
654  }
655  else
656  {
657  kallsymAddr = 0;
658  WARNING("[WARNING] IntLixGuestFindKsymByName failed for `%s`\n", pFunctions->List[index].Name[item]);
659  }
660 
661  *(QWORD *)(&Data->Code[sizeof(LIX_AGENT_HEADER) +
662  sizeof(LIX_AGENT_TOKEN) + sizeof(QWORD) * currentFunc]) = kallsymAddr;
663  currentFunc++;
664  }
665 
666  if (required > match)
667  {
668  ERROR("[ERROR] Failed to find required kallsyms for agent.\n");
669  return INT_STATUS_NOT_FOUND;
670  }
671  }
672 
673  memcpy(&Data->Code[sizeof(LIX_AGENT_HEADER) + sizeof(LIX_AGENT_TOKEN) + sizeof(QWORD) * currentFunc],
674  Handler->Args.Content, Handler->Args.Length);
675 
676  return INT_STATUS_SUCCESS;
677 }
678 
679 
680 static INTSTATUS
682  _In_ LIX_AGENT *Agent
683  )
696 {
697  if (Agent->Data.Address == 0)
698  {
699  INTSTATUS status = IntSlackAlloc(gGuest.KernelVa, FALSE, Agent->Data.Size, &Agent->Data.Address, 0);
700  if (!INT_SUCCESS(status))
701  {
702  ERROR("[ERROR] IntSlackAlloc failed with status: 0x%08x.", status);
703  return status;
704  }
705  }
706 
707  return INT_STATUS_SUCCESS;
708 }
709 
710 
711 __forceinline static DWORD
713  void
714  )
720 {
721  return gLixAgentState.CurrentId++;
722 }
723 
724 
725 static INTSTATUS
727  _In_ LIX_AGENT_TAG Tag,
728  _In_ DWORD TagEx,
729  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
730  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
731  _Out_ LIX_AGENT **Agent
732  )
753 {
754  INTSTATUS status = INT_STATUS_SUCCESS;
755  LIX_AGENT *pAgent = NULL;
756  LIX_AGENT_HANDLER *pHandler = NULL;
757 
758  TRACE("[LIX-AGENT] Create agent with tag %d ...", Tag);
759 
760  pHandler = IntLixAgentGetHandlerByTag(Tag);
761  if (pHandler == NULL)
762  {
763  return INT_STATUS_NOT_FOUND;
764  }
765 
766  pAgent = HpAllocWithTag(sizeof(LIX_AGENT), IC_TAG_LAGE);
767  if (pAgent == NULL)
768  {
770  }
771 
774  pAgent->Data.Token.Error = IntLixAgentGetToken();
775 
776  status = IntLixAgentFillData(&pAgent->Data, pHandler);
777  if (!INT_SUCCESS(status))
778  {
779  ERROR("[ERROR] IntLixAgentFillContent failed: 0x%x", status);
780  goto _free_and_exit;
781  }
782 
783  status = IntLixAgentResolveOffset(&pAgent->Data, pHandler);
784  if (!INT_SUCCESS(status))
785  {
786  ERROR("[ERROR] IntLixAgentResolveOffset failed: 0x%x", status);
787  goto _free_and_exit;
788  }
789 
790  pAgent->Tag = Tag;
791  pAgent->TagEx = TagEx;
792  pAgent->HypercallType = pHandler->HypercallType;
793  pAgent->Callback.Hypercall = HypercallCallback;
794  pAgent->Callback.Completion = CompletionCallback;
795  pAgent->Instruction.CloakHandle = NULL;
796  pAgent->Instruction.Address = 0;
797  pAgent->Instruction.Length = 0;
798  pAgent->Instruction.Restored = TRUE;
799  pAgent->Agid = IntLixAgentGetId();
800 
801  *Agent = pAgent;
802 
803  return INT_STATUS_SUCCESS;
804 
805 _free_and_exit:
807 
808  return status;
809 }
810 
811 
812 static INTSTATUS
814  _In_ LIX_AGENT_TAG Tag,
815  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
816  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
817  _In_opt_ BYTE *ContentAddress,
818  _In_opt_ DWORD ContentSize,
819  _Out_ LIX_AGENT_THREAD **Thread
820  )
842 {
843  INTSTATUS status = INT_STATUS_SUCCESS;
844  LIX_AGENT_THREAD *pThread = NULL;
845  LIX_AGENT_HANDLER *pHandler = NULL;
846 
848  if (pHandler == NULL)
849  {
850  return INT_STATUS_NOT_FOUND;
851  }
852 
853  pThread = HpAllocWithTag(sizeof(LIX_AGENT_THREAD), IC_TAG_LAGE);
854  if (pThread == NULL)
855  {
857  }
858 
861  pThread->Data.Token.Error = IntLixAgentGetToken();
862 
863  status = IntLixAgentFillData(&pThread->Data, pHandler);
864  if (!INT_SUCCESS(status))
865  {
866  ERROR("[ERROR] IntLixAgentFillContent failed: 0x%x", status);
867  goto _free_and_exit;
868  }
869 
870  status = IntLixAgentResolveOffset(&pThread->Data, pHandler);
871  if (!INT_SUCCESS(status))
872  {
873  ERROR("[ERROR] IntLixAgentResolveOffset failed: 0x%x", status);
874  goto _free_and_exit;
875  }
876 
877  pThread->Tag = Tag;
878  pThread->HypercallType = pHandler->HypercallType;
879  pThread->Callback.Hypercall = HypercallCallback;
880  pThread->Callback.Completion = CompletionCallback;
881  pThread->Content.Address = ContentAddress;
882  pThread->Content.Size = ContentSize;
883 
884  *Thread = pThread;
885 
886  return INT_STATUS_SUCCESS;
887 
888 _free_and_exit:
890 
891  return status;
892 }
893 
894 
895 INTSTATUS
897  _In_ LIX_AGENT_TAG Tag,
898  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
899  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback
900  )
916 {
917  INTSTATUS status = INT_STATUS_SUCCESS;
918  LIX_AGENT *pAgent = NULL;
919 
920  if (!gLixAgentState.Initialized)
921  {
922  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
924  }
925 
926  status = IntLixAgentCreate(Tag, 0, HypercallCallback, CompletionCallback, &pAgent);
927  if (!INT_SUCCESS(status))
928  {
929  ERROR("[ERROR] IntLixAgentCreateAgent failed with status: 0x%08x.", status);
930  goto _exit;
931  }
932 
933  InsertTailList(&gLixAgentState.PendingAgents, &pAgent->Link);
934 
935  TRACE("[AGENT] Linux agent allocated and initialized!\n");
936 
938  if (!INT_SUCCESS(status))
939  {
940  ERROR("[ERROR] IntLixAgentActivatePendingAgent failed with status: 0x%08x.", status);
941  return status;
942  }
943 
944  return INT_STATUS_SUCCESS;
945 
946 _exit:
947  IntLixAgentFree(pAgent);
948 
949  return status;
950 }
951 
952 
953 INTSTATUS
955  _In_ LIX_AGENT_TAG Tag,
956  _In_ DWORD TagEx,
957  _In_ AGENT_TYPE AgentType,
958  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
959  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
960  _In_opt_ const char *Name,
961  _In_opt_ BYTE *ContentAddress,
962  _In_ DWORD ContentSize
963  )
987 {
988  INTSTATUS status;
989  LIX_AGENT *pAgent = NULL;
990  LIX_AGENT_NAME *pName = NULL;
991 
992  if (!gLixAgentState.Initialized)
993  {
994  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
996  }
997 
998  if (!gLixGuest->MmAlloc.Agent.Initialized)
999  {
1001  }
1002 
1003 
1004  if (!gLixAgentState.SafeToInjectProcess)
1005  {
1006  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
1008  }
1009 
1010  if (Name != NULL && IntLixAgentNameIsRunning(Name))
1011  {
1013  }
1014 
1016  TagEx,
1019  &pAgent);
1020  if (!INT_SUCCESS(status))
1021  {
1022  ERROR("[ERROR] IntLixAgentCreateAgent failed with status: 0x%08x.", status);
1023  goto _exit;
1024  }
1025 
1026  status = IntLixAgentThreadCreate(Tag,
1027  HypercallCallback,
1028  CompletionCallback,
1029  ContentAddress,
1030  ContentSize,
1031  &pAgent->Thread);
1032  if (!INT_SUCCESS(status))
1033  {
1034  ERROR("[ERROR] IntLixAgentThreadCreate failed with status: 0x%08x.", status);
1035  goto _exit;
1036  }
1037 
1038  if (Name != NULL)
1039  {
1040  strlcpy(pAgent->Name, Name, sizeof(pAgent->Name));
1041 
1042  if (AgentType == AGENT_TYPE_PROCESS)
1043  {
1044  status = IntLixAgentNameCreate(Name, pAgent->TagEx, pAgent->Agid, &pName);
1045  if (!INT_SUCCESS(status))
1046  {
1047  ERROR("[ERROR] IntLixAgentNameCreate failed with status: 0x%08x.", status);
1048  goto _exit;
1049  }
1050  }
1051  }
1052 
1053  InsertTailList(&gLixAgentState.PendingAgents, &pAgent->Link);
1054 
1055  TRACE("[AGENT] Linux agent allocated and initialized!\n");
1056 
1058  if (!INT_SUCCESS(status))
1059  {
1060  ERROR("[ERROR] IntLixAgentActivatePendingAgent failed with status: 0x%08x.", status);
1061  return status;
1062  }
1063 
1064  return INT_STATUS_SUCCESS;
1065 
1066 _exit:
1067  if (pAgent != NULL)
1068  {
1069  IntLixAgentFree(pAgent);
1070  }
1071 
1072  if (pName != NULL)
1073  {
1074  IntLixAgentNameRemove(pName);
1075  }
1076 
1077  return status;
1078 }
1079 
1080 
1081 INTSTATUS
1083  void
1084  )
1100 {
1101  INTSTATUS status;
1102  LIX_AGENT *pAgent = NULL;
1103  BYTE instrux[ND_MAX_INSTRUCTION_LENGTH];
1104 
1105  if (!gLixAgentState.SafeToInjectProcess)
1106  {
1108  }
1109 
1110  if (gLixAgentState.CompletingAgentsCount != 0)
1111  {
1113  }
1114 
1115  if (IsListEmpty(&gLixAgentState.PendingAgents))
1116  {
1118  }
1119 
1120  pAgent = CONTAINING_RECORD(gLixAgentState.PendingAgents.Flink, LIX_AGENT, Link);
1121  memset(&instrux, 0x90, sizeof(instrux));
1122 
1123  TRACE("[LIX-AGENT] Found pending agent with tag %d.", pAgent->Tag);
1124 
1125  IntPauseVcpus();
1126 
1128  if (!INT_SUCCESS(status))
1129  {
1130  goto _exit;
1131  }
1132 
1133  status = IntLixAgentFindInstruction(1, &pAgent->Instruction.Address, &pAgent->Instruction.Length,
1134  pAgent->Instruction.Bytes);
1135  if (!INT_SUCCESS(status))
1136  {
1137  ERROR("[ERROR] IntAgentFindInstruction failed with status: 0x%08x\n", status);
1138  goto _exit;
1139  }
1140 
1141  status = IntLixAgentAllocate(pAgent);
1142  if (!INT_SUCCESS(status))
1143  {
1144  ERROR("[LIX-AGENT] IntLixAgentAllocate failed with status: 0x%08x.", status);
1145  goto _exit;
1146  }
1147 
1148  // The agent is Introcore allocated, so it's safe to use IntKernVirtMemWrite instead of IntVirtMemSafeWrite.
1149  status = IntKernVirtMemWrite(pAgent->Data.Address, pAgent->Data.Size, pAgent->Data.Code);
1150  if (!INT_SUCCESS(status))
1151  {
1152  ERROR("[ERROR] IntKernVirtMemWrite failed with status: 0x%x", status);
1153  goto _exit;
1154  }
1155 
1156  instrux[0] = 0xCC;
1157  status = IntMemClkCloakRegion(pAgent->Instruction.Address,
1158  0,
1159  pAgent->Instruction.Length,
1161  pAgent->Instruction.Bytes,
1162  instrux,
1163  NULL,
1164  &pAgent->Instruction.CloakHandle);
1165  if (!INT_SUCCESS(status))
1166  {
1167  ERROR("[ERROR] Failed cloaking region 0x%016llx: 0x%08x\n", pAgent->Instruction.Address, status);
1168  goto _exit;
1169  }
1170 
1171  pAgent->Instruction.Restored = FALSE;
1172 
1174 
1175  TRACE("[LIX-AGENT] Agent with tag %d deployed...", pAgent->Tag);
1176 
1177  RemoveEntryList(&pAgent->Link);
1178 
1179  gLixAgentState.CompletingAgentsCount++;
1180  gLixAgentState.ActiveAgent = pAgent;
1181 
1182  status = INT_STATUS_SUCCESS;
1183 
1184 _exit:
1185  IntResumeVcpus();
1186 
1187  return status;
1188 }
1189 
1190 
1191 static INTSTATUS
1193  _In_ LIX_AGENT *Agent
1194  )
1205 {
1206  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1207 #ifdef DEBUG
1208  INTSTATUS status = INT_STATUS_SUCCESS;
1209  char ksymbol[LIX_SYMBOL_NAME_LEN] = {0};
1210 
1211  ERROR("[ERROR] Error occurred while running the agent with tag '%d' (%d)...", Agent->Tag, Agent->TagEx);
1212 
1213  status = IntKsymFindByAddress(pRegs->R8, sizeof(ksymbol), ksymbol, NULL, NULL);
1214  if (INT_SUCCESS(status))
1215  {
1216  LOG("[LIX-AGENT] '%s' failed with status: %llx", ksymbol, pRegs->R9);
1217  }
1218 
1219  IntDumpArchRegs(pRegs);
1220 #endif
1221 
1222  IntLixAgentSendEvent(agentError, Agent->TagEx, (DWORD)(pRegs->R15));
1223 
1224  IntLixAgentNameRemoveByAgid(Agent->Agid);
1225 
1226  return INT_STATUS_SUCCESS;
1227 }
1228 
1229 
1230 static INTSTATUS
1232  _In_ LIX_AGENT *Agent
1233  )
1244 {
1245  INTSTATUS status = INT_STATUS_SUCCESS;
1246  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1247 
1248  status = IntMemClkUncloakRegion(Agent->Instruction.CloakHandle, MEMCLOAK_OPT_APPLY_PATCH);
1249  if (!INT_SUCCESS(status))
1250  {
1251  ERROR("[ERROR] IntMemClkUncloakRegion failed with status: 0x%08x\n", status);
1252  IntEnterDebugger();
1253  }
1254 
1255  Agent->Instruction.CloakHandle = NULL;
1256  Agent->Instruction.Restored = TRUE;
1257 
1258  pRegs->Rip = Agent->Data.Address + Agent->Data.Header.DataSize;
1259 
1260  TRACE("[LIX-AGENT] Deployed agent @ 0x%llx and entry point @ %llx", Agent->Data.Address, pRegs->Rip);
1261 
1262  status = IntSetGprs(gVcpu->Index, pRegs);
1263  if (!INT_SUCCESS(status))
1264  {
1265  ERROR("[ERROR] IntSetGprs failed with status: 0x%08x.\n", status);
1266  ERROR("[ERROR] Remove agent with tag '%d' (%d) ...", Agent->Tag, Agent->TagEx);
1267 
1268  IntLixAgentSendEvent(agentError, Agent->TagEx, 0);
1269  IntLixAgentFree(Agent);
1270 
1271  return INT_STATUS_NO_DETOUR_EMU;
1272  }
1273 
1274  LOG("[LIX-AGENT] Agent with tag '%d' (%d) start execution on VCPU %d at RIP %llx ...",
1275  Agent->Tag, Agent->TagEx, gVcpu->Index, pRegs->Rip);
1276 
1277  return INT_STATUS_NO_DETOUR_EMU;
1278 }
1279 
1280 
1281 static INTSTATUS
1283  _In_ LIX_AGENT *Agent
1284  )
1296 {
1297  INTSTATUS status = INT_STATUS_SUCCESS;
1298  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1299 
1300  if (!Agent->Instruction.Restored)
1301  {
1302  ERROR("[LIX-AGENT] Original instruction not restored at exit stage...");
1303  IntEnterDebugger();
1304  }
1305 
1306  pRegs->Rip = Agent->Instruction.Address;
1307 
1308  status = IntSetGprs(gVcpu->Index, pRegs);
1309  if (!INT_SUCCESS(status))
1310  {
1311  ERROR("[ERROR] IntSetGprs failed: 0x%08x\n", status);
1312  IntEnterDebugger();
1313  }
1314 
1315  if (Agent->Thread == NULL)
1316  {
1317  gLixAgentState.ActiveAgent = NULL;
1318  gLixAgentState.CompletingAgentsCount--;
1319 
1321 
1322  IntLixAgentFree(Agent);
1323 
1325  {
1326  ERROR("[ERROR] IntAgentActivatePendingAgent failed: 0x%08x\n", status);
1327  }
1328  }
1329 
1330  return INT_STATUS_NO_DETOUR_EMU;
1331 }
1332 
1333 
1334 static INTSTATUS
1336  _In_ LIX_AGENT *Agent,
1337  _In_ QWORD Rip
1338  )
1350 {
1351  INTSTATUS status;
1352  QWORD token = gVcpu->Regs.Rax;
1353 
1354  if (Agent->Data.Token.Hypercall == token)
1355  {
1356  if (Agent->Callback.Hypercall == NULL)
1357  {
1358  return INT_STATUS_SUCCESS;
1359  }
1360 
1361  status = Agent->Callback.Hypercall(Agent);
1362  if (!INT_SUCCESS(status))
1363  {
1364  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1365  }
1366 
1367  return status;
1368  }
1369 
1370  if (Agent->Data.Token.Completion == token)
1371  {
1372  if (Agent->Callback.Completion == NULL)
1373  {
1374  return INT_STATUS_SUCCESS;
1375  }
1376 
1377  status = Agent->Callback.Completion(Agent);
1378  if (!INT_SUCCESS(status))
1379  {
1380  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1381  }
1382 
1383  return status;
1384  }
1385 
1386  if (Agent->Data.Token.Error == token)
1387  {
1388  status = IntLixAgentError(Agent);
1389  if (!INT_SUCCESS(status))
1390  {
1391  ERROR("[LIX-AGENT] IntLixAgentError failed with status: 0x%08x.", status);
1392  }
1393 
1394  return status;
1395  }
1396 
1397  if (Rip == (Agent->Data.Address + Agent->Data.Header.ExitOffset))
1398  {
1399  status = IntLixAgentExit(Agent);
1400  if (!INT_SUCCESS(status))
1401  {
1402  ERROR("[LIX-AGENT] IntLixAgentExit failed with status: 0x%08x.", status);
1403  }
1404 
1405  return status;
1406  }
1407 
1408  ERROR("[ERROR] Breakpoint generated an exit from unrecognized rip ...");
1410 
1411  return INT_STATUS_NOT_FOUND;
1412 }
1413 
1414 
1415 static INTSTATUS
1417  _In_ LIX_AGENT *Agent
1418  )
1429 {
1430  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1431 #ifdef DEBUG
1432  INTSTATUS status = INT_STATUS_SUCCESS;
1433  char ksymbol[LIX_SYMBOL_NAME_LEN] = {0};
1434 
1435  ERROR("[ERROR] Error occurred while running the agent-thread with tag '%d' (%d)...",
1436  Agent->Thread->Tag, Agent->TagEx);
1437 
1438  status = IntKsymFindByAddress(pRegs->R8, sizeof(ksymbol), ksymbol, NULL, NULL);
1439  if (INT_SUCCESS(status))
1440  {
1441  LOG("[LIX-AGENT] '%s' failed with status: %llx", ksymbol, pRegs->R9);
1442  }
1443 
1444  IntDumpArchRegs(pRegs);
1445 #endif
1446 
1447  IntLixAgentSendEvent(agentError, Agent->TagEx, (DWORD)(pRegs->R9));
1448 
1449  IntLixAgentNameRemoveByAgid(Agent->Agid);
1450 
1451  return INT_STATUS_SUCCESS;
1452 }
1453 
1454 
1455 static INTSTATUS
1457  _In_ LIX_AGENT *Agent
1458  )
1470 {
1471  LOG("[LIX-AGENT] Agent-thread with tag '%d' (%d) completed ...", Agent->Thread->Tag, Agent->TagEx);
1472 
1473  gLixAgentState.ActiveAgent = NULL;
1474  gLixAgentState.CompletingAgentsCount--;
1475 
1476  IntLixAgentFree(Agent);
1477 
1479 
1481  {
1482  ERROR("[ERROR] IntAgentActivatePendingAgent failed");
1483  }
1484 
1485  return INT_STATUS_SUCCESS;
1486 }
1487 
1488 
1489 static INTSTATUS
1491  _In_ LIX_AGENT *Agent,
1492  _In_ QWORD Rip
1493  )
1505 {
1506  INTSTATUS status;
1507  LIX_AGENT_THREAD *pThread = Agent->Thread;
1508  QWORD token = gVcpu->Regs.Rax;
1509 
1510  if (pThread->Data.Token.Hypercall == token)
1511  {
1512  if (pThread->Callback.Hypercall == NULL)
1513  {
1514  return INT_STATUS_SUCCESS;
1515  }
1516 
1517  status = pThread->Callback.Hypercall(Agent);
1518  if (!INT_SUCCESS(status))
1519  {
1520  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1521  }
1522 
1523  return status;
1524  }
1525 
1526  if (pThread->Data.Token.Completion == token)
1527  {
1528  if (pThread->Callback.Completion == NULL)
1529  {
1530  return INT_STATUS_SUCCESS;
1531  }
1532 
1533  status = pThread->Callback.Completion(Agent);
1534  if (!INT_SUCCESS(status))
1535  {
1536  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1537  }
1538 
1539  return status;
1540  }
1541 
1542  if (pThread->Data.Token.Error == token)
1543  {
1544  status = IntLixAgentThreadError(Agent);
1545  if (!INT_SUCCESS(status))
1546  {
1547  ERROR("[LIX-AGENT] IntLixAgentThreadError failed with status %0x08x.", status);
1548  }
1549 
1550  return status;
1551  }
1552 
1553  if (Rip == (pThread->Data.Address + pThread->Data.Header.ExitOffset))
1554  {
1555  status = IntLixAgentThreadExit(Agent);
1556  if (!INT_SUCCESS(status))
1557  {
1558  ERROR("[ERROR] IntLixAgentThreadExit failed with status: 0x%08x.", status);
1559  }
1560 
1561  return status;
1562  }
1563 
1564  ERROR("[ERROR] Breakpoint generated an exit from unrecognized rip inside agent-thread '%d'...",
1565  pThread->Tag);
1567 
1568  return INT_STATUS_NOT_FOUND;
1569 }
1570 
1571 
1572 INTSTATUS
1574  _In_ QWORD Rip
1575  )
1589 {
1590  INTSTATUS status = INT_STATUS_SUCCESS;
1591  LIX_AGENT *pAgent = NULL;
1592  DWORD crtRing = 0;
1593 
1594  status = IntGetCurrentRing(gVcpu->Index, &crtRing);
1595  if (!INT_SUCCESS(status))
1596  {
1597  ERROR("[ERROR] IntGetCurrentRing failed: 0x%08x\n", status);
1598  return status;
1599  }
1600 
1601  if (crtRing != IG_CS_RING_0)
1602  {
1603  return INT_STATUS_NOT_FOUND;
1604  }
1605 
1606  pAgent = gLixAgentState.ActiveAgent;
1607  if (pAgent == NULL)
1608  {
1609  return INT_STATUS_NOT_FOUND;
1610  }
1611 
1612  if (pAgent->Instruction.Address == Rip)
1613  {
1614  if (pAgent->Instruction.Restored)
1615  {
1616  return INT_STATUS_NO_DETOUR_EMU;
1617  }
1618  else
1619  {
1620  status = IntLixAgentStart(pAgent);
1621  if (!INT_SUCCESS(status))
1622  {
1623  ERROR("[ERROR] IntLixAgentStart failed with status: 0x%08x.", status);
1624  }
1625 
1626  return status;
1627  }
1628  }
1629 
1630  if (IN_RANGE_LEN(Rip, pAgent->Data.Address, pAgent->Data.Size))
1631  {
1632  status = IntLixAgentHandleBreakpoint(pAgent, Rip);
1633  if (!INT_SUCCESS(status))
1634  {
1635  ERROR("[ERROR] IntLixAgentHandleBreakpoint failed with status: 0x%08x.", status);
1636  }
1637 
1638  return status;
1639  }
1640 
1641  if (pAgent->Thread != NULL &&
1642  IN_RANGE_LEN(Rip, pAgent->Thread->Data.Address, pAgent->Thread->Data.Size))
1643  {
1644  status = IntLixAgentThreadHandleBreakpoint(pAgent, Rip);
1645  if (!INT_SUCCESS(status))
1646  {
1647  ERROR("[ERROR] IntLixAgentThreadHandleBreakpoint failed with status: 0x%08x.", status);
1648  }
1649 
1650  return status;
1651  }
1652 
1653  return INT_STATUS_NOT_FOUND;
1654 }
1655 
1656 
1657 static INTSTATUS
1659  void
1660  )
1666 {
1667  ERROR("[ERROR] VMCALL executed from kernel mode. Rip 0x%016llx.", gVcpu->Regs.Rip);
1668 
1669  return INT_STATUS_NOT_SUPPORTED;
1670 }
1671 
1672 
1673 static INTSTATUS
1675  void
1676  )
1692 
1693 {
1694  INTSTATUS status = INT_STATUS_SUCCESS;
1695  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1696  QWORD arg1 = pRegs->Rcx;
1697  QWORD arg2 = pRegs->Rbx;
1698  QWORD op = pRegs->Rdx;
1699 
1700  if (AGENT_HCALL_INTERNAL == op)
1701  {
1702  EVENT_AGENT_EVENT *pEvent = &gAlert.Agent;
1703 
1704  pEvent->Event = agentError;
1705  pEvent->ErrorCode = (DWORD)(arg2);
1706  pEvent->AgentTag = IntLixAgentNameGetTagByAgid((DWORD)(arg1));
1707 
1709 
1710  LOG("[LIX-AGENT] User-mode stub reports error for agent with tag %d: 0x%08x\n",
1711  pEvent->AgentTag, pEvent->ErrorCode);
1712 
1713  status = IntNotifyIntroEvent(introEventAgentEvent, pEvent, sizeof(*pEvent));
1714  if (!INT_SUCCESS(status))
1715  {
1716  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
1717  }
1718  }
1719  else
1720  {
1721  LIX_TASK_OBJECT *pTask = IntLixTaskFindByCr3(pRegs->Cr3);
1722  if (pTask == NULL)
1723  {
1724  LOG("[WARNING] VMCALL coming from outside a process with CR3 %llx\n", pRegs->Cr3);
1725  return INT_STATUS_SUCCESS;
1726  }
1727 
1728  if (!pTask->AgentTag || pTask->IsPreviousAgent)
1729  {
1730  TRACE("[AGENT-LIX] VMCALL with op = %lld from `%s` (PID = %d) which is not an agent (previous = %d), "
1731  "will ignore\n", op, pTask->Comm, pTask->Pid, pTask->IsPreviousAgent);
1732  return INT_STATUS_SUCCESS;
1733  }
1734 
1735  if (AGENT_HCALL_REM_TOOL == op)
1736  {
1737  status = IntAgentHandleRemediationVmcall(NULL, pRegs);
1738  if (!INT_SUCCESS(status))
1739  {
1740  ERROR("[ERROR] IntAgentHandleRemediationVmcall failed: 0x%08x\n", status);
1741  return status;
1742  }
1743  }
1744  else if (AGENT_HCALL_GATHER_TOOL == op)
1745  {
1746  status = IntAgentHandleLogGatherVmcall(NULL, pRegs);
1747  if (!INT_SUCCESS(status))
1748  {
1749  ERROR("[ERROR] IntAgentHandleLogGatherVmcall failed: 0x%08x\n", status);
1750  return status;
1751  }
1752  }
1753  }
1754 
1755  return status;
1756 }
1757 
1758 
1759 INTSTATUS
1761  _In_ QWORD Rip
1762  )
1772 {
1773  INTSTATUS status;
1774  DWORD crtRing = 0;
1775 
1776  status = IntGetCurrentRing(gVcpu->Index, &crtRing);
1777  if (!INT_SUCCESS(status))
1778  {
1779  ERROR("[ERROR] IntGetCurrentRing failed: 0x%08x\n", status);
1780  return status;
1781  }
1782 
1783  if (crtRing == IG_CS_RING_0)
1784  {
1785  LIX_AGENT *pAgent = gLixAgentState.ActiveAgent;
1786  if (pAgent == NULL)
1787  {
1788  ERROR("[LIX-AGENT] VMCALL with no active agent from RIP 0x%016llx.", Rip);
1789  }
1790 
1791  status = IntLixAgentHandleKernelVmcall();
1792  }
1793  else
1794  {
1795  status = IntLixAgentHandleUserVmcall();
1796  }
1797 
1798  return status;
1799 }
1800 
1801 
1802 _Success_(return != agNone)
1805  _Out_opt_ DWORD *Tag
1806  )
1816 {
1817  if (gLixAgentState.ActiveAgent)
1818  {
1819  if (NULL != Tag)
1820  {
1821  LIX_AGENT *pAgent = gLixAgentState.ActiveAgent;
1822  *Tag = pAgent->Tag;
1823  }
1824 
1825  return agActive;
1826  }
1827 
1828  if (!IsListEmpty(&gLixAgentState.PendingAgents))
1829  {
1830  if (NULL != Tag)
1831  {
1832  LIX_AGENT *pAgent = CONTAINING_RECORD(gLixAgentState.PendingAgents.Flink, LIX_AGENT, Link);
1833  *Tag = pAgent->Tag;
1834  }
1835 
1836  return agWaiting;
1837  }
1838 
1839  return agNone;
1840 }
1841 
1842 
1843 void
1845  void
1846  )
1853 {
1854  if (!gLixAgentState.Initialized)
1855  {
1856  return;
1857  }
1858 
1859  list_for_each (gLixAgentState.PendingAgents, LIX_AGENT, pAgent)
1860  {
1861  RemoveEntryList(&pAgent->Link);
1862 
1863  IntLixAgentFree(pAgent);
1864  }
1865 }
1866 
1867 
1870  _In_ const char *Name
1871  )
1882 {
1883  SIZE_T length;
1884 
1885  if (IsListEmpty(&gLixAgentState.AgentNames))
1886  {
1887  return lixAgTagNone;
1888  }
1889 
1890  length = strlen(Name);
1891 
1892  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
1893  {
1894  if (0 == strncmp(Name, pName->Name, length))
1895  {
1896  pName->RefCount++;
1897 
1898  return pName->AgentTag;
1899  }
1900  }
1901 
1902  return lixAgTagNone;
1903 }
1904 
1905 
1908  _In_ const char *Name,
1909  _Out_ BOOLEAN *Removed
1910  )
1922 {
1923  SIZE_T length;
1924 
1925  *Removed = FALSE;
1926 
1927  if (IsListEmpty(&gLixAgentState.AgentNames))
1928  {
1929  return lixAgTagNone;
1930  }
1931 
1932  length = strlen(Name);
1933 
1934  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
1935  {
1936  if (memcmp_len(Name, pName->Name, length, pName->Length) == 0)
1937  {
1938  LIX_AGENT_TAG tag = pName->AgentTag;
1939 
1940  if (pName->RefCount > 0)
1941  {
1942  --pName->RefCount;
1943  }
1944  else
1945  {
1946  WARNING("[WARNING] Agent %s already done by our logic!\n", pName->Name);
1947  }
1948 
1949  if (pName->RefCount == 0)
1950  {
1951  IntLixAgentNameRemove(pName);
1952  *Removed = TRUE;
1953  }
1954 
1955  return tag;
1956  }
1957  }
1958 
1959  return lixAgTagNone;
1960 }
1961 
1962 
1963 void
1965  void
1966  )
1970 {
1971  gLixAgentState.SafeToInjectProcess = TRUE;
1972 
1974 }
1975 
1976 
1977 void
1979  void
1980  )
1984 {
1985  memzero(&gLixAgentState, sizeof(gLixAgentState));
1986 
1987  InitializeListHead(&gLixAgentState.PendingAgents);
1988  InitializeListHead(&gLixAgentState.AgentNames);
1989 
1990  gLixAgentState.Initialized = TRUE;
1991 
1992  LOG("[LIX-AGENT] Linux agent state initialized.\n");
1993 }
1994 
1995 
1996 INTSTATUS
1998  void
1999  )
2006 {
2007  if (gGuest.OSType != introGuestLinux)
2008  {
2010  }
2011 
2012  //
2013  // In case we inject our agent and the system is no longer running or it's hanged, the uninit agent may
2014  // remain allocated.
2015  //
2016  if (gLixAgentState.ActiveAgent)
2017  {
2018  IntLixAgentFree(gLixAgentState.ActiveAgent);
2019  }
2020 
2021  memzero(&gLixAgentState, sizeof(gLixAgentState));
2022 
2023  return INT_STATUS_SUCCESS;
2024 }
2025 
2026 
2027 static INTSTATUS
2029  _In_ LIX_AGENT *Agent
2030  )
2041 {
2042  INTSTATUS status = INT_STATUS_SUCCESS;
2043  LIX_AGENT_THREAD *pThread = Agent->Thread;
2044  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
2045 
2046  if (pRegs->R8 == 0)
2047  {
2048  goto _exit;
2049  }
2050 
2051  pThread->Data.Header.Address = pRegs->R8;
2052  pThread->Data.Address = pRegs->R8;
2053 
2054  memcpy(pThread->Data.Code, &pThread->Data.Header, sizeof(LIX_AGENT_HEADER));
2055 
2056  status = IntVirtMemWrite(pThread->Data.Address,
2057  pThread->Data.Size,
2059  pThread->Data.Code);
2060  if (!INT_SUCCESS(status))
2061  {
2062  ERROR("[ERROR] IntVirtMemWrite failed with status: 0x%08x.", status);
2063  goto _exit;
2064  }
2065 
2066  pRegs->Rax = pThread->Data.Address + pThread->Data.Header.DataSize;
2067  status = IntSetGprs(gVcpu->Index, pRegs);
2068  if (!INT_SUCCESS(status))
2069  {
2070  ERROR("[ERROR] IntSetGprs failed with status: 0x%08x.", status);
2071  goto _exit;
2072  }
2073 
2074  return INT_STATUS_SUCCESS;
2075 
2076 _exit:
2077  IntLixAgentSendEvent(agentError, Agent->TagEx, 0);
2078 
2079  IntLixAgentThreadFree(Agent->Thread);
2080  Agent->Thread = NULL;
2081 
2082  return INT_STATUS_SUCCESS;
2083 }
2084 
2085 
2086 static INTSTATUS
2088  _In_ LIX_AGENT *Agent
2089  )
2099 {
2100  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
2101  DWORD errorCode = 0;
2102 
2103  if (pRegs->Rax == 0)
2104  {
2105  errorCode = 1;
2106  goto _exit;
2107  }
2108 
2109  LOG("[DEPLOYER] Agent with tag %d has just been injected, error: 0x%08x.", Agent->TagEx, errorCode);
2110 
2111 _exit:
2112  IntLixAgentSendEvent(agentInjected, Agent->TagEx, errorCode);
2113 
2114  return INT_STATUS_SUCCESS;
2115 }
2116 
2117 
2118 void
2120  _In_ AGENT_EVENT_TYPE Event,
2122  _In_ DWORD ErrorCode
2123  )
2132 {
2133  INTSTATUS status;
2134  EVENT_AGENT_EVENT *pEvent = &gAlert.Agent;
2135 
2136  memzero(pEvent, sizeof(*pEvent));
2137 
2138  pEvent->Event = Event;
2139  pEvent->AgentTag = AgentTag;
2140  pEvent->ErrorCode = ErrorCode;
2141 
2142  status = IntNotifyIntroEvent(introEventAgentEvent, pEvent, sizeof(*pEvent));
2143  if (!INT_SUCCESS(status))
2144  {
2145  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
2146  }
2147 }
WORD DataSize
The size (bytes) of the data.
Definition: lixagent.h:82
INTSTATUS IntLixAgentUninit(void)
Uninit the agents state.
Definition: lixagent.c:1997
TIMER_FRIENDLY void IntDumpArchRegs(IG_ARCH_REGS const *Registers)
This function dumps the register values in a user friendly format.
Definition: dumper.c:20
#define _In_opt_
Definition: intro_sal.h:16
AG_WAITSTATE IntLixAgentGetState(DWORD *Tag)
Gets the global agents state.
Definition: lixagent.c:1804
static DWORD IntLixAgentGetId(void)
Generate a new ID.
Definition: lixagent.c:712
void IntLixAgentEnableInjection(void)
Enables agent injections.
Definition: lixagent.c:1964
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
LIX_AGENT_TAG Tag
The internal tag.
Definition: lixagent.h:153
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
static INTSTATUS IntLixAgentAllocate(LIX_AGENT *Agent)
Allocate a memory zone for the content of the agent.
Definition: lixagent.c:681
CHAR Name[IG_MAX_AGENT_NAME_LENGTH]
The name of the agent.
Definition: lixagent.h:162
INTSTATUS IntLixAgentHandleVmcall(QWORD Rip)
Handle a VMCALL that was executed inside the guest.
Definition: lixagent.c:1760
WORD CodeSize
The size (byes) of the code.
Definition: lixagent.h:84
Describes a handlers that contains the data required by the agent.
Definition: lixagent.h:217
struct _LINUX_GUEST::@128 MmAlloc
LIX_AGENT_DATA Data
The data used by the agent.
Definition: lixagent.h:124
struct _LINUX_GUEST::@128::@132 Agent
LIX_TASK_OBJECT * IntLixTaskFindByCr3(QWORD Cr3)
Finds the Linux process having the provided Cr3.
Definition: lixprocess.c:942
uint8_t BYTE
Definition: intro_types.h:47
QWORD Completion
The token used by completion callback.
Definition: lixagent.h:96
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
No active/pending agents.
Definition: agent.h:15
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
struct _LIX_AGENT_TOKEN LIX_AGENT_TOKEN
The tokens used by an agent.
static LIX_AGENT_STATE gLixAgentState
Definition: lixagent.c:69
DWORD Index
The VCPU number.
Definition: guests.h:172
LIX_AGENT_HANDLER * IntLixAgentGetHandlerByTag(LIX_AGENT_TAG AgentTag)
Iterates through all agent handlers and search the entry that has the provided tag.
Definition: lixaghnd.c:408
#define _In_
Definition: intro_sal.h:21
void IntLixAgentInit(void)
Initialize the agents state.
Definition: lixagent.c:1978
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
LIX_AGENT_HEADER Header
The header of the agent&#39;s data.
Definition: lixagent.h:106
DWORD Count
The number of function names.
Definition: lixagent.h:191
enum _LIX_AGENT_TAG LIX_AGENT_TAG
Tag used to identify an agent with a handler.
#define INT_STATUS_DISASM_ERROR
Indicates a decoder error.
Definition: introstatus.h:442
We have at least pending agent waiting to be injected inside the guest.
Definition: agent.h:17
#define _Out_writes_bytes_(expr)
Definition: intro_sal.h:38
DWORD Size
The size (bytes) of the injected agent.
Definition: lixagent.h:111
LIX_AGENT_HYPERCALL HypercallType
The hypercall type used.
Definition: lixagent.h:122
#define IntEnterDebugger()
Definition: introcore.h:373
Describes an agent-thread running inside the guest.
Definition: lixagent.h:119
void IntLixAgentDisablePendingAgents(void)
Disables all pending agents.
Definition: lixagent.c:1844
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
INTSTATUS(* PFUNC_AgentCallbackHypercall)(void *Context)
Hypercall callback prototype.
Definition: lixagent.h:26
#define IC_ANY_VAS
Definition: icache.h:86
#define AGENT_HCALL_INTERNAL
Reserved for internal use.
Definition: intro_types.h:2123
AGENT_EVENT_TYPE Event
The type of the agent.
Definition: intro_types.h:2347
The global agents state.
Definition: lixagent.c:54
#define _Success_(expr)
Definition: intro_sal.h:47
INTSTATUS IntLixAgentHandleInt3(QWORD Rip)
Called when a INT3 instruction from the current running agent is executed.
Definition: lixagent.c:1573
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
Definition: lixksym.c:1283
LIST_ENTRY Link
List entry element.
Definition: lixagent.h:151
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
static BOOLEAN IsListEmpty(const LIST_ENTRY *ListHead)
Definition: introlists.h:78
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
AGENT_EVENT_TYPE
The state of an agent.
Definition: intro_types.h:2097
DWORD TagEx
The tag provided by the integrator.
Definition: lixagent.h:154
INTSTATUS IntVirtMemWrite(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer)
Writes data to a guest virtual memory range.
Definition: introcore.c:652
Event structure for agent injection and termination.
Definition: intro_types.h:2345
QWORD Hypercall
The token used by hypercall callback.
Definition: lixagent.h:95
Describe an agent running inside the guest.
Definition: lixagent.h:149
void IntLixAgentNameRemoveByAgid(DWORD Agid)
Iterates through all agent names and removes the entry that contains the provided ID...
Definition: lixagent.c:285
INTSTATUS(* PFUNC_AgentCallbackCompletion)(void *Context)
Completion callback prototype.
Definition: lixagent.h:38
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
size_t Length
Name length.
Definition: lixagent.c:45
#define ERROR(fmt,...)
Definition: glue.h:62
Header with information about running code inside the guest.
Definition: lixagent.h:79
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
INTSTATUS IntAgentHandleRemediationVmcall(void *Reserved, PIG_ARCH_REGS Registers)
Handle a VMCALL issued by a remediation agent.
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
LIX_AGENT_TAG AgentTag
Agent tag.
Definition: lixagent.c:41
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
LIX_AGENT_THREAD * Thread
A pointer to a agent-thread, if any.
Definition: lixagent.h:160
DWORD IsPreviousAgent
TRUE if this process is an agent remaining from a previous session.
Definition: lixprocess.h:98
#define IMAGE_BASE_NAME_LEN
The maximum length of a process name.
Definition: winguest.h:15
static INTSTATUS IntLixAgentCreate(LIX_AGENT_TAG Tag, DWORD TagEx, PFUNC_AgentCallbackHypercall HypercallCallback, PFUNC_AgentCallbackCompletion CompletionCallback, LIX_AGENT **Agent)
Create an agent entry.
Definition: lixagent.c:726
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
LIST_HEAD PendingAgents
List of agents waiting to be injected.
Definition: lixagent.c:56
DWORD RefCount
Number of times this name has been used by agents.
Definition: lixagent.c:47
DWORD ErrorCode
The error code of the event. Success is 0.
Definition: intro_types.h:2349
#define MIN(a, b)
Definition: introdefs.h:146
Will write the contents of the patched data inside the guest.
Definition: memcloak.h:54
INTSTATUS IntSlackAlloc(QWORD ModuleBase, BOOLEAN Pageable, DWORD Size, QWORD *Buffer, QWORD SecHint)
Allocate slack inside the guest.
Definition: slack.c:437
#define LOG(fmt,...)
Definition: glue.h:61
static INTSTATUS IntLixAgentFillDataFromHandler(LIX_AGENT_DATA *Data, LIX_AGENT_HANDLER *Handler)
Fetch the content of the agent with the provided LIX_AGENT_TAG from the corresponding LIX_AGENT_HANDL...
Definition: lixagent.c:507
DWORD Count
The number of the functions list.
Definition: lixagent.h:209
INTSTATUS IntAgentHandleLogGatherVmcall(void *Reserved, PIG_ARCH_REGS Registers)
Handle a VMCALL issued by a log gather agent.
Definition: hnd_loggather.c:11
char Name[IMAGE_BASE_NAME_LEN]
Image base name.
Definition: lixagent.c:44
static INTSTATUS IntLixAgentCreateThreadHypercall(LIX_AGENT *Agent)
Called by the thread-agent to deploy the content of the kthread previously created.
Definition: lixagent.c:2028
enum _LIX_AGENT_HYPERCALL HypercallType
The hypercall type.
Definition: lixagent.h:220
static INTSTATUS IntLixAgentThreadCreate(LIX_AGENT_TAG Tag, PFUNC_AgentCallbackHypercall HypercallCallback, PFUNC_AgentCallbackCompletion CompletionCallback, BYTE *ContentAddress, DWORD ContentSize, LIX_AGENT_THREAD **Thread)
Create an agent-thread entry.
Definition: lixagent.c:813
BOOLEAN IntLixAgentMatchVersion(LIX_AGENT_FUNCTIONS *Function)
Checks if the provided LIX_AGENT_FUNCTIONS match the current guest version.
Definition: lixagent.c:570
The agent has been successfully injected.
Definition: intro_types.h:2099
DWORD CompletingAgentsCount
Number of agents that are yet to complete execution.
Definition: lixagent.c:61
char * Name[256]
The function name.
Definition: lixagent.h:192
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
LIX_AGENT_TAG IntLixAgentDecProcRef(const char *Name, BOOLEAN *Removed)
Checks if a process is an agent or not, and decrements the ref count of that name.
Definition: lixagent.c:1907
#define _Inout_
Definition: intro_sal.h:20
#define AGENT_HCALL_GATHER_TOOL
Log gathering tool.
Definition: intro_types.h:2119
DWORD Agid
Agent ID.
Definition: lixagent.c:42
LIST_ENTRY Link
List entry element.
Definition: lixagent.c:39
#define _Out_opt_
Definition: intro_sal.h:30
#define INT_STATUS_ALREADY_INITIALIZED
Definition: introstatus.h:263
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
BYTE * Address
A pointer to the content provided by the integrator.
Definition: lixagent.h:134
BYTE * Code
A buffer that contains the in-guest agent code/data.
Definition: lixagent.h:109
void * CloakHandle
Cloak handle used to hide the detoured instruction.
Definition: lixagent.h:177
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
LIX_AGENT_TAG IntLixAgentIncProcRef(const char *Name)
Checks if a process is an agent or not, and increments the ref count of that name.
Definition: lixagent.c:1869
BOOLEAN SafeToInjectProcess
Will be true the moment it&#39;s safe to inject agents (the OS has booted).
Definition: lixagent.c:64
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
#define memzero(a, s)
Definition: introcrt.h:35
LIX_AGENT_TAG Tag
The internal tag.
Definition: lixagent.h:121
unsigned long long QWORD
Definition: intro_types.h:53
DWORD Agid
The agent ID.
Definition: lixagent.h:156
Informational event sent when the remediation tool is injected or terminated. See EVENT_AGENT_EVENT...
Definition: intro_types.h:104
#define IN_RANGE_LEN(x, start, len)
Definition: introdefs.h:175
static INTSTATUS IntLixAgentHandleBreakpoint(LIX_AGENT *Agent, QWORD Rip)
Called when a INT3 instruction from the current running agent is hit.
Definition: lixagent.c:1335
#define TRUE
Definition: intro_types.h:30
static void IntLixAgentNameRemove(LIX_AGENT_NAME *Name)
Frees and removes from our list the provided LIX_AGENT_NAME.
Definition: lixagent.c:270
struct _LIX_AGENT_NAME LIX_AGENT_NAME
Describes the name of an injected process agent.
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:429
LIST_HEAD AgentNames
List of agent names.
Definition: lixagent.c:57
#define TRACE(fmt,...)
Definition: glue.h:58
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
INTSTATUS IntMemClkCloakRegion(QWORD VirtualAddress, QWORD Cr3, DWORD Size, DWORD Options, PBYTE OriginalData, PBYTE PatchedData, PFUNC_IntMemCloakWriteHandle WriteHandler, void **CloakHandle)
Hides a memory zone from the guest.
Definition: memcloak.c:548
DWORD AgentTag
Unique agent tag. See INTRO_DEP_AG_TAGS.
Definition: intro_types.h:2348
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
INTSTATUS IntIcFlushAddress(PINS_CACHE Cache, QWORD Gva, QWORD Cr3)
Flush entries cached from a given address.
Definition: icache.c:597
#define AGENT_HCALL_REM_TOOL
Used by the remediation tool.
Definition: intro_types.h:2117
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
#define INT_STATUS_NO_DETOUR_EMU
Signals that no emulation is needed for this event.
Definition: introstatus.h:378
static INTSTATUS IntLixAgentHandleKernelVmcall(void)
Called when a VMCALL instruction from the current running agent is executed.
Definition: lixagent.c:1658
size_t strlcpy(char *dst, const char *src, size_t dest_size)
Definition: introcrt.c:1093
#define WARNING(fmt,...)
Definition: glue.h:60
static INTSTATUS IntLixAgentFindInstruction(BYTE MinLen, QWORD *InstructionVa, BYTE *InstructionLen, BYTE *InstructionBytes)
Searches for a suitable instruction to replace with a INT3 instruction.
Definition: lixagent.c:92
BOOLEAN Initialized
True if the agents state has been initialized.
Definition: lixagent.c:65
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
Definition: lixguest.h:585
Describes the name of an injected process agent.
Definition: lixagent.c:37
#define PAGE_SIZE
Definition: common.h:70
enum _AGENT_TYPE AGENT_TYPE
INTSTATUS IntReleaseBuffer(void *Buffer, DWORD Size)
Definition: glue.c:1083
INTSTATUS IntSlackFree(QWORD Buffer)
Free slack space.
Definition: slack.c:499
static INTSTATUS IntLixAgentThreadError(LIX_AGENT *Agent)
Called when an error occurred while the running the current thread-agent.
Definition: lixagent.c:1416
void * InstructionCache
The currently used instructions cache.
Definition: guests.h:404
#define __forceinline
Definition: introtypes.h:61
QWORD Address
The address of the kthread.
Definition: lixagent.h:85
EVENT_AGENT_EVENT Agent
Definition: alerts.h:29
uint32_t DWORD
Definition: intro_types.h:49
void IntLixAgentSendEvent(AGENT_EVENT_TYPE Event, DWORD AgentTag, DWORD ErrorCode)
Send an event to the integrator that contains the AGENT_EVENT_TYPE, tag of the agent and the last err...
Definition: lixagent.c:2119
The tokens used by an agent.
Definition: lixagent.h:93
static uint64_t __rdtsc(void)
Definition: intrinsics.h:306
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
Definition: introcpu.c:905
static INTSTATUS IntLixAgentHandleUserVmcall(void)
Handles a VMCALL issued by a process that has been injected inside the guest.
Definition: lixagent.c:1674
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
QWORD Address
Address of the detoured instruction.
Definition: lixagent.h:172
DWORD IntLixAgentNameGetTagByAgid(DWORD Agid)
Iterates through all agent names and returns the tag of the agent that has the provided agent ID...
Definition: lixagent.c:312
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
static INTSTATUS IntLixAgentFillDataFromMemory(LIX_AGENT_DATA *Data, LIX_AGENT_TAG Tag)
Fetch the content of the agent with the provided LIX_AGENT_TAG from memory.
Definition: lixagent.c:435
char Comm[LIX_COMM_SIZE]
The short name of the executable.
Definition: lixprocess.h:44
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
PFUNC_AgentCallbackCompletion Completion
Completion callback.
Definition: lixagent.h:129
LIX_AGENT_HYPERCALL HypercallType
The hypercall type.
Definition: lixagent.h:158
INTSTATUS IntVirtMemRead(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength)
Reads data from a guest virtual memory range.
Definition: introcore.c:627
The functions required by the agent.
Definition: lixagent.h:199
static INTSTATUS IntEnableBreakpointNotifications(void)
Definition: callbacks.h:261
static INTSTATUS IntDisableBreakpointNotifications(void)
Definition: callbacks.h:278
#define IC_TAG_ALLOC
Memory allocation.
Definition: memtags.h:28
Describes the data of an agent.
Definition: lixagent.h:104
LIX_AGENT_FUNCTIONS_LIST List[20]
An array that contains LIX_AGENT_FUNCTIONS_LIST entries.
Definition: lixagent.h:210
LIX_AGENT_HANDLER * IntLixAgentThreadGetHandlerByTag(LIX_AGENT_TAG AgentTag, LIX_AGENT_TAG ThreadTag)
Iterates through all thread-agent handlers and search the entry that has the provided tag...
Definition: lixaghnd.c:432
DWORD Pid
The task PID.
Definition: lixprocess.h:72
struct _LIX_AGENT_STATE LIX_AGENT_STATE
The global agents state.
struct _LIX_AGENT_THREAD::@96 Callback
BYTE Bytes[16]
Detoured instruction bytes.
Definition: lixagent.h:174
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
The agent or the process stub reports an error.
Definition: intro_types.h:2104
static INTSTATUS IntLixAgentFillData(LIX_AGENT_DATA *Data, LIX_AGENT_HANDLER *Handler)
Fetch the content of the agent.
Definition: lixagent.c:541
static INTSTATUS IntLixAgentNameCreate(const char *Name, DWORD Tag, DWORD Agid, LIX_AGENT_NAME **AgentName)
Create an agent name and insert the newly create agent-name to linked list.
Definition: lixagent.c:231
#define LIST_HEAD_INIT(Name)
Definition: introlists.h:39
#define IC_TAG_AGNN
Agent name.
Definition: memtags.h:50
The create thread agent.
Definition: lixagent.h:64
static INTSTATUS IntLixAgentThreadFree(LIX_AGENT_THREAD *Thread)
Remove the provided agent-thread.
Definition: lixagent.c:341
DWORD Required
The number of required function addresses for the &#39;Name&#39; array.
Definition: lixagent.h:190
static INTSTATUS IntLixAgentResolveOffset(LIX_AGENT_DATA *Data, LIX_AGENT_HANDLER *Handler)
Search the functions and complete the args/tokens required by the agent.
Definition: lixagent.c:593
QWORD Error
The token used by error callback.
Definition: lixagent.h:97
QWORD SyscallAddress
The guest virtual address of the syscall.
Definition: lixguest.h:529
static QWORD IntLixAgentGetToken(void)
Randomly select a token to be used by the agent code when issuing hyper calls.
Definition: lixagent.c:78
DWORD CurrentId
Used to generate unique agent IDs.
Definition: lixagent.c:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTSTATUS IntLixAgentThreadInject(LIX_AGENT_TAG Tag, DWORD TagEx, AGENT_TYPE AgentType, PFUNC_AgentCallbackHypercall HypercallCallback, PFUNC_AgentCallbackCompletion CompletionCallback, const char *Name, BYTE *ContentAddress, DWORD ContentSize)
Schedule an thread-agent injection inside the guest.
Definition: lixagent.c:954
INTSTATUS IntMemClkUncloakRegion(void *CloakHandle, DWORD Options)
Removes a cloak region, making the original memory contents available again to the guest...
Definition: memcloak.c:970
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
static INTSTATUS IntLixAgentExit(LIX_AGENT *Agent)
Called when the agent is terminating.
Definition: lixagent.c:1282
static INTSTATUS IntLixAgentCreateThreadCompletion(LIX_AGENT *Agent)
Called by the thread-agent when the kthread started.
Definition: lixagent.c:2087
Process agent. A process will be injected & started inside the guest.
Definition: aghcall.h:47
QWORD Address
The guest virtual address of the injected agent.
Definition: lixagent.h:110
enum _AG_WAITSTATE AG_WAITSTATE
LIX_AGENT_DATA Data
The data used by the agent.
Definition: lixagent.h:159
Holds register state.
Definition: glueiface.h:30
INTSTATUS IntGetCurrentRing(DWORD CpuNumber, DWORD *Ring)
Read the current protection level.
Definition: introcpu.c:959
LIX_AGENT_TOKEN Token
The tokens of the agent.
Definition: lixagent.h:107
PFUNC_AgentCallbackHypercall Hypercall
Hypercall callback.
Definition: lixagent.h:128
#define UNREFERENCED_LOCAL_VARIABLE(V)
Definition: introdefs.h:30
BYTE Version
The version field of the version string.
Definition: lixguest.h:487
struct _LIX_AGENT_THREAD::@97 Content
BYTE Length
Detoured instruction length.
Definition: lixagent.h:175
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
#define WORD_MAX
Definition: introtypes.h:32
static INTSTATUS IntLixAgentError(LIX_AGENT *Agent)
Called when an error occurred while the running the current agent.
Definition: lixagent.c:1192
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
INTSTATUS IntLixAgentInject(LIX_AGENT_TAG Tag, PFUNC_AgentCallbackHypercall HypercallCallback, PFUNC_AgentCallbackCompletion CompletionCallback)
Schedule an agent injection inside the guest.
Definition: lixagent.c:896
We have an active agent, currently injected inside the guest.
Definition: agent.h:16
static INTSTATUS IntLixAgentThreadHandleBreakpoint(LIX_AGENT *Agent, QWORD Rip)
Called when a INT3 instruction from the current running thread-agent is hit.
Definition: lixagent.c:1490
static INTSTATUS IntLixAgentStart(LIX_AGENT *Agent)
Called when the INT3 instruction from SYSCALL is hit.
Definition: lixagent.c:1231
PFUNC_AgentCallbackCompletion Completion
Completion callback.
Definition: lixagent.h:167
DWORD Tag
The LIX_AGENT_TAG.
Definition: lixagent.h:81
INTSTATUS IntLixAgentActivatePendingAgent(void)
Activates a pending agent that waits to be injected.
Definition: lixagent.c:1082
static void IntLixAgentFree(LIX_AGENT *Agent)
Remove the provided agent.
Definition: lixagent.c:371
#define BYTE_MAX
Definition: introtypes.h:31
LIX_AGENT * ActiveAgent
The active agent at any given moment. This is the one.
Definition: lixagent.c:59
static BOOLEAN IntLixAgentNameIsRunning(const char *Name)
Iterates through all agent names to check if an agent with the provided name is running.
Definition: lixagent.c:204
struct _LIX_AGENT::@99 Instruction
QWORD PropperSyscallGva
The guest virtual address of the &#39;real&#39; syscall.
Definition: lixguest.h:530
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
PFUNC_AgentCallbackHypercall Hypercall
Hypercall callback.
Definition: lixagent.h:166
static INTSTATUS IntLixAgentThreadExit(LIX_AGENT *Agent)
Called when the thread-agent is terminating.
Definition: lixagent.c:1456
struct _LIX_AGENT::@98 Callback
size_t SIZE_T
Definition: intro_types.h:60
#define IC_TAG_LAGE
Linux agent entry.
Definition: memtags.h:48
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
DWORD Size
The size of the content provided by the integrator.
Definition: lixagent.h:135
WORD ExitOffset
The offset of the INT3 instruction that represent the exit point.
Definition: lixagent.h:83
BOOLEAN Restored
True if the detours instruction has been restored.
Definition: lixagent.h:179
LIX_AGENT_TAG AgentTag
The agent tag, if this process is an agent.
Definition: lixprocess.h:103