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 "guests.h"
9 #include "hnd_remediation.h"
10 #include "hnd_loggather.h"
11 #include "icache.h"
12 #include "memcloak.h"
13 #include "slack.h"
14 #include "lixksym.h"
15 
16 
17 static INTSTATUS
19  _In_ LIX_AGENT *Agent
20  );
21 
22 static INTSTATUS
24  _In_ LIX_AGENT *Agent
25  );
26 
27 
36 typedef struct _LIX_AGENT_NAME
37 {
39 
42 
44  size_t Length;
45 
48 
49 
53 typedef struct _LIX_AGENT_STATE
54 {
57 
59 
62 
66 
67 
69 {
70  .PendingAgents = LIST_HEAD_INIT(gLixAgentState.PendingAgents),
71  .AgentNames = LIST_HEAD_INIT(gLixAgentState.AgentNames)
72 };
73 
74 
75 
76 static QWORD
78  void
79  )
85 {
86  return __rdtsc();
87 }
88 
89 
90 static INTSTATUS
92  _In_ BYTE MinLen,
93  _Out_ QWORD *InstructionVa,
94  _Out_ BYTE *InstructionLen,
95  _Out_writes_bytes_(ND_MAX_INSTRUCTION_LENGTH) BYTE *InstructionBytes
96  )
112 {
113  INTSTATUS status;
114  BYTE *pSyscallCode = NULL;
115  QWORD syscallGva = 0;
116  size_t parsed = 0;
117  BYTE stiCount, neededStiCount;
118  BOOLEAN bFound, bStiFound;
119 
121 
122  bFound = bStiFound = FALSE;
123  neededStiCount = 1;
124  stiCount = 0;
125 
126  pSyscallCode = HpAllocWithTag(PAGE_SIZE, IC_TAG_ALLOC);
127  if (NULL == pSyscallCode)
128  {
130  }
131 
132  if (LIX_FIELD(Info, HasAlternateSyscall))
133  {
134  syscallGva = gLixGuest->PropperSyscallGva;
135  }
136  else
137  {
138  syscallGva = gLixGuest->SyscallAddress;
139  }
140 
141  status = IntKernVirtMemRead(syscallGva, PAGE_SIZE, pSyscallCode, NULL);
142  if (!INT_SUCCESS(status))
143  {
144  ERROR("[ERROR] IntKernVirtMemRead failed for syscall 0x%016llx: 0x%08x\n", syscallGva, status);
145  goto _exit;
146  }
147 
148  while (parsed + 16 < PAGE_SIZE)
149  {
150  INSTRUX instrux;
151 
152  NDSTATUS ndstatus = NdDecodeEx(&instrux, pSyscallCode + parsed, PAGE_SIZE - parsed, ND_CODE_64, ND_DATA_64);
153  if (!ND_SUCCESS(ndstatus))
154  {
155  ERROR("[ERROR] NdDecodeEx failed at 0x%016llx: 0x%08x\n", syscallGva + parsed, ndstatus);
156 
157  status = INT_STATUS_DISASM_ERROR;
158  goto _exit;
159  }
160 
161  if (!bStiFound)
162  {
163  if (ND_INS_STI == instrux.Instruction)
164  {
165  if (++stiCount == neededStiCount)
166  {
167  bStiFound = TRUE;
168  }
169  }
170  }
171  else if ((instrux.Length >= MinLen) && !ND_HAS_PREDICATE(&instrux)) // Avoid conditional instructions.
172  {
173  bFound = TRUE;
174 
175  *InstructionVa = syscallGva + parsed;
176  *InstructionLen = instrux.Length;
177 
178  memcpy(InstructionBytes, instrux.InstructionBytes, ND_MAX_INSTRUCTION_LENGTH);
179 
180  break;
181  }
182 
183  parsed += instrux.Length;
184  }
185 
186  if (bFound)
187  {
188  status = INT_STATUS_SUCCESS;
189  }
190  else
191  {
192  status = INT_STATUS_NOT_FOUND;
193  }
194 
195 _exit:
196  HpFreeAndNullWithTag(&pSyscallCode, IC_TAG_ALLOC);
197 
198  return status;
199 }
200 
201 
202 static BOOLEAN
204  _In_ const char *Name
205  )
213 {
214  size_t nameLength = MIN(strlen(Name), IMAGE_BASE_NAME_LEN - 1);
215 
216  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
217  {
218  if (memcmp_len(pName->Name, Name, pName->Length, nameLength) == 0)
219  {
220  ERROR("[ERROR] An agent with the name '%s' is already injected!\n", Name);
221  return TRUE;
222  }
223  }
224 
225  return FALSE;
226 }
227 
228 
229 static INTSTATUS
231  _In_ const char *Name,
232  _In_ DWORD Tag,
233  _In_ DWORD Agid,
234  _Out_ LIX_AGENT_NAME **AgentName
235  )
247 {
249  if (pName == NULL)
250  {
252  }
253 
254  strlcpy(pName->Name, Name, sizeof(pName->Name));
255  pName->Length = strlen(pName->Name);
256  pName->Agid = Agid;
257  pName->AgentTag = Tag;
258  pName->RefCount = 0;
259 
260  *AgentName = pName;
261 
262  InsertTailList(&gLixAgentState.AgentNames, &pName->Link);
263 
264  return INT_STATUS_SUCCESS;
265 }
266 
267 
268 static void
271  )
277 {
278  RemoveEntryList(&Name->Link);
280 }
281 
282 
283 void
285  _In_ DWORD Agid
286  )
292 {
293  if (IsListEmpty(&gLixAgentState.AgentNames))
294  {
295  return;
296  }
297 
298  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
299  {
300  if (Agid == pName->Agid)
301  {
302  IntLixAgentNameRemove(pName);
303 
304  return;
305  }
306  }
307 }
308 
309 
310 DWORD
312  _In_ DWORD Agid
313  )
321 {
322  if (IsListEmpty(&gLixAgentState.AgentNames))
323  {
324  return lixAgTagNone;
325  }
326 
327  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
328  {
329  if (Agid == pName->Agid)
330  {
331  return pName->AgentTag;
332  }
333  }
334 
335  return lixAgTagNone;
336 }
337 
338 
339 static INTSTATUS
341  _In_ LIX_AGENT_THREAD *Thread
342  )
352 {
353  if (Thread->Data.Code != NULL)
354  {
355  HpFreeAndNullWithTag(&Thread->Data.Code, IC_TAG_LAGE);
356  }
357 
359 
360  return INT_STATUS_SUCCESS;
361 }
362 
363 
364 static void
366  _In_ LIX_AGENT *Agent
367  )
377 {
378  INTSTATUS status;
379  BYTE *pSlack = NULL;
380 
381  if (Agent == NULL)
382  {
383  return;
384  }
385 
386  if (Agent->Data.Address == 0)
387  {
388  goto _exit;
389  }
390 
391  status = IntSlackFree(Agent->Data.Address);
392  if (status == INT_STATUS_NOT_FOUND)
393  {
394  goto _exit;
395  }
396  else if (!INT_SUCCESS(status))
397  {
398  ERROR("[ERROR] IntSlackFree failed with status: 0x%08x.", status);
399  }
400 
401  status = IntVirtMemMap(Agent->Data.Address, Agent->Data.Size, gGuest.Mm.SystemCr3, 0, &pSlack);
402  if (!INT_SUCCESS(status))
403  {
404  ERROR("[ERROR] IntVirtMemMap failed with status: 0x%08x. Cannot fill slack with NOPs...", status);
405  }
406  else
407  {
408  memset(pSlack, 0x90, Agent->Data.Size);
409  IntVirtMemUnmap(&pSlack);
410  }
411 
412 _exit:
413  if (Agent->Thread)
414  {
415  IntLixAgentThreadFree(Agent->Thread);
416  Agent->Thread = NULL;
417  }
418 
419  if (Agent->Data.Code)
420  {
421  HpFreeAndNullWithTag(&Agent->Data.Code, IC_TAG_LAGE);
422  }
423 
425 }
426 
427 
428 static INTSTATUS
430  _Inout_ LIX_AGENT_DATA *Data,
431  _In_ LIX_AGENT_TAG Tag
432  )
447 {
448  QWORD crtAddress = gLixGuest->MmAlloc.Agent.Address;
449 
450  while (crtAddress <= gLixGuest->MmAlloc.Agent.Address + gLixGuest->MmAlloc.Agent.Length)
451  {
452  INTSTATUS status;
453  LIX_AGENT_HEADER header = { 0 };
454 
455  status = IntVirtMemRead(crtAddress,
456  sizeof(LIX_AGENT_HEADER),
458  &header,
459  NULL);
460  if (!INT_SUCCESS(status))
461  {
462  ERROR("[ERROR] IntVirtMemRead failed with status: 0x%08x.", status);
463  return status;
464  }
465 
466  if (header.Tag == (DWORD)(Tag))
467  {
468  Data->Code = HpAllocWithTag((size_t)header.CodeSize + header.DataSize, IC_TAG_LAGE);
469  if (Data->Code == NULL)
470  {
472  }
473 
474  memcpy(&Data->Header, &header, sizeof(LIX_AGENT_HEADER));
475 
476  status = IntVirtMemRead(crtAddress,
477  header.CodeSize + header.DataSize,
479  Data->Code,
480  NULL);
481  if (!INT_SUCCESS(status))
482  {
483  ERROR("[ERROR] IntVirtMemRead failed with status: 0x%08x.", status);
484  return status;
485  }
486 
487  Data->Address = crtAddress;
488  Data->Size = header.CodeSize + header.DataSize;
489 
490  return INT_STATUS_SUCCESS;
491  }
492 
493  crtAddress += (QWORD)header.CodeSize + header.DataSize;
494  }
495 
496  return INT_STATUS_NOT_FOUND;
497 }
498 
499 
500 static INTSTATUS
502  _Inout_ LIX_AGENT_DATA *Data,
503  _In_ LIX_AGENT_HANDLER *Handler
504  )
517 {
518  Data->Code = HpAllocWithTag(Handler->Code.Length, IC_TAG_LAGE);
519  if (Data->Code == NULL)
520  {
522  }
523 
524  memcpy(Data->Code, Handler->Code.Content, Handler->Code.Length);
525  memcpy(&Data->Header, Handler->Code.Content, sizeof(LIX_AGENT_HEADER));
526 
527  Data->Size = Handler->Code.Length;
528  Data->Address = 0;
529 
530  return INT_STATUS_SUCCESS;
531 }
532 
533 
534 static INTSTATUS
536  _Inout_ LIX_AGENT_DATA *Data,
537  _In_ LIX_AGENT_HANDLER *Handler
538  )
551 {
552  if (Handler->Code.Length != 0)
553  {
554  return IntLixAgentFillDataFromHandler(Data, Handler);
555  }
556  else
557  {
558  return IntLixAgentFillDataFromMemory(Data, Handler->Tag);
559  }
560 }
561 
562 
565  _In_ LIX_AGENT_FUNCTIONS *Function
566  )
574 {
575  return ((Function->Version.Version == gLixGuest->Version.Version ||
576  Function->Version.Version == BYTE_MAX) &&
577  (Function->Version.Patch == gLixGuest->Version.Patch ||
578  Function->Version.Patch == BYTE_MAX) &&
579  (Function->Version.Sublevel == gLixGuest->Version.Sublevel ||
580  Function->Version.Sublevel == WORD_MAX) &&
581  (Function->Version.Backport == gLixGuest->Version.Backport ||
582  Function->Version.Backport == WORD_MAX));
583 }
584 
585 
586 static INTSTATUS
588  _In_ LIX_AGENT_DATA *Data,
589  _In_ LIX_AGENT_HANDLER *Handler
590  )
617 {
618  LIX_AGENT_FUNCTIONS *pFunctions = NULL;
619  DWORD currentFunc = 0;
620 
621  memcpy(&Data->Code[sizeof(LIX_AGENT_HEADER)], &Data->Token, sizeof(LIX_AGENT_TOKEN));
622 
623  for (DWORD index = 0; index < Handler->Functions.Count; index++)
624  {
625  if (IntLixAgentMatchVersion(&Handler->Functions.Content[index]))
626  {
627  pFunctions = &Handler->Functions.Content[index];
628  break;
629  }
630  }
631 
632  if (pFunctions == NULL)
633  {
634  return INT_STATUS_NOT_FOUND;
635  }
636 
637  for (DWORD index = 0; index < pFunctions->Count; index++)
638  {
639  DWORD required = pFunctions->List[index].Required;
640  DWORD match = 0;
641  for (DWORD item = 0; item < pFunctions->List[index].Count; item++)
642  {
643  QWORD kallsymAddr = IntKsymFindByName(pFunctions->List[index].Name[item], NULL);
644  if (kallsymAddr)
645  {
646  TRACE("[LIX-AGENT] Found '%s' ksym @ 0x%16llx.", pFunctions->List[index].Name[item], kallsymAddr);
647  match++;
648  }
649  else
650  {
651  kallsymAddr = 0;
652  WARNING("[WARNING] IntLixGuestFindKsymByName failed for `%s`\n", pFunctions->List[index].Name[item]);
653  }
654 
655  *(QWORD *)(&Data->Code[sizeof(LIX_AGENT_HEADER) +
656  sizeof(LIX_AGENT_TOKEN) + sizeof(QWORD) * currentFunc]) = kallsymAddr;
657  currentFunc++;
658  }
659 
660  if (required > match)
661  {
662  ERROR("[ERROR] Failed to find required kallsyms for agent.\n");
663  return INT_STATUS_NOT_FOUND;
664  }
665  }
666 
667  memcpy(&Data->Code[sizeof(LIX_AGENT_HEADER) + sizeof(LIX_AGENT_TOKEN) + sizeof(QWORD) * currentFunc],
668  Handler->Args.Content, Handler->Args.Length);
669 
670  return INT_STATUS_SUCCESS;
671 }
672 
673 
674 static INTSTATUS
676  _In_ LIX_AGENT *Agent
677  )
690 {
691  if (Agent->Data.Address == 0)
692  {
693  INTSTATUS status = IntSlackAlloc(gGuest.KernelVa, FALSE, Agent->Data.Size, &Agent->Data.Address, 0);
694  if (!INT_SUCCESS(status))
695  {
696  ERROR("[ERROR] IntSlackAlloc failed with status: 0x%08x.", status);
697  return status;
698  }
699  }
700 
701  return INT_STATUS_SUCCESS;
702 }
703 
704 
705 __forceinline static DWORD
707  void
708  )
714 {
715  return gLixAgentState.CurrentId++;
716 }
717 
718 
719 static INTSTATUS
721  _In_ LIX_AGENT_TAG Tag,
722  _In_ DWORD TagEx,
723  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
724  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
725  _Out_ LIX_AGENT **Agent
726  )
747 {
748  INTSTATUS status = INT_STATUS_SUCCESS;
749  LIX_AGENT *pAgent = NULL;
750  LIX_AGENT_HANDLER *pHandler = NULL;
751 
752  TRACE("[LIX-AGENT] Create agent with tag %d ...", Tag);
753 
754  pHandler = IntLixAgentGetHandlerByTag(Tag);
755  if (pHandler == NULL)
756  {
757  return INT_STATUS_NOT_FOUND;
758  }
759 
760  pAgent = HpAllocWithTag(sizeof(LIX_AGENT), IC_TAG_LAGE);
761  if (pAgent == NULL)
762  {
764  }
765 
768  pAgent->Data.Token.Error = IntLixAgentGetToken();
769 
770  status = IntLixAgentFillData(&pAgent->Data, pHandler);
771  if (!INT_SUCCESS(status))
772  {
773  ERROR("[ERROR] IntLixAgentFillContent failed: 0x%x", status);
774  goto _free_and_exit;
775  }
776 
777  status = IntLixAgentResolveOffset(&pAgent->Data, pHandler);
778  if (!INT_SUCCESS(status))
779  {
780  ERROR("[ERROR] IntLixAgentResolveOffset failed: 0x%x", status);
781  goto _free_and_exit;
782  }
783 
784  pAgent->Tag = Tag;
785  pAgent->TagEx = TagEx;
786  pAgent->HypercallType = pHandler->HypercallType;
787  pAgent->Callback.Hypercall = HypercallCallback;
788  pAgent->Callback.Completion = CompletionCallback;
789  pAgent->Instruction.CloakHandle = NULL;
790  pAgent->Instruction.Address = 0;
791  pAgent->Instruction.Length = 0;
792  pAgent->Instruction.Restored = TRUE;
793  pAgent->Agid = IntLixAgentGetId();
794 
795  *Agent = pAgent;
796 
797  return INT_STATUS_SUCCESS;
798 
799 _free_and_exit:
801 
802  return status;
803 }
804 
805 
806 static INTSTATUS
808  _In_ LIX_AGENT_TAG Tag,
809  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
810  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
811  _In_opt_ BYTE *ContentAddress,
812  _In_opt_ DWORD ContentSize,
813  _Out_ LIX_AGENT_THREAD **Thread
814  )
836 {
837  INTSTATUS status = INT_STATUS_SUCCESS;
838  LIX_AGENT_THREAD *pThread = NULL;
839  LIX_AGENT_HANDLER *pHandler = NULL;
840 
842  if (pHandler == NULL)
843  {
844  return INT_STATUS_NOT_FOUND;
845  }
846 
847  pThread = HpAllocWithTag(sizeof(LIX_AGENT_THREAD), IC_TAG_LAGE);
848  if (pThread == NULL)
849  {
851  }
852 
855  pThread->Data.Token.Error = IntLixAgentGetToken();
856 
857  status = IntLixAgentFillData(&pThread->Data, pHandler);
858  if (!INT_SUCCESS(status))
859  {
860  ERROR("[ERROR] IntLixAgentFillContent failed: 0x%x", status);
861  goto _free_and_exit;
862  }
863 
864  status = IntLixAgentResolveOffset(&pThread->Data, pHandler);
865  if (!INT_SUCCESS(status))
866  {
867  ERROR("[ERROR] IntLixAgentResolveOffset failed: 0x%x", status);
868  goto _free_and_exit;
869  }
870 
871  pThread->Tag = Tag;
872  pThread->HypercallType = pHandler->HypercallType;
873  pThread->Callback.Hypercall = HypercallCallback;
874  pThread->Callback.Completion = CompletionCallback;
875  pThread->Content.Address = ContentAddress;
876  pThread->Content.Size = ContentSize;
877 
878  *Thread = pThread;
879 
880  return INT_STATUS_SUCCESS;
881 
882 _free_and_exit:
884 
885  return status;
886 }
887 
888 
889 INTSTATUS
891  _In_ LIX_AGENT_TAG Tag,
892  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
893  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback
894  )
910 {
911  INTSTATUS status = INT_STATUS_SUCCESS;
912  LIX_AGENT *pAgent = NULL;
913 
914  if (!gLixAgentState.Initialized)
915  {
916  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
918  }
919 
920  status = IntLixAgentCreate(Tag, 0, HypercallCallback, CompletionCallback, &pAgent);
921  if (!INT_SUCCESS(status))
922  {
923  ERROR("[ERROR] IntLixAgentCreateAgent failed with status: 0x%08x.", status);
924  goto _exit;
925  }
926 
927  InsertTailList(&gLixAgentState.PendingAgents, &pAgent->Link);
928 
929  TRACE("[AGENT] Linux agent allocated and initialized!\n");
930 
932  if (!INT_SUCCESS(status))
933  {
934  ERROR("[ERROR] IntLixAgentActivatePendingAgent failed with status: 0x%08x.", status);
935  return status;
936  }
937 
938  return INT_STATUS_SUCCESS;
939 
940 _exit:
941  IntLixAgentFree(pAgent);
942 
943  return status;
944 }
945 
946 
947 INTSTATUS
949  _In_ LIX_AGENT_TAG Tag,
950  _In_ DWORD TagEx,
951  _In_ AGENT_TYPE AgentType,
952  _In_opt_ PFUNC_AgentCallbackHypercall HypercallCallback,
953  _In_opt_ PFUNC_AgentCallbackCompletion CompletionCallback,
954  _In_opt_ const char *Name,
955  _In_opt_ BYTE *ContentAddress,
956  _In_ DWORD ContentSize
957  )
981 {
982  INTSTATUS status;
983  LIX_AGENT *pAgent = NULL;
984  LIX_AGENT_NAME *pName = NULL;
985 
986  if (!gLixAgentState.Initialized)
987  {
988  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
990  }
991 
992  if (!gLixGuest->MmAlloc.Agent.Initialized)
993  {
995  }
996 
997 
998  if (!gLixAgentState.SafeToInjectProcess)
999  {
1000  WARNING("[WARNING] Tried to create an agent but the agent state not initialized.");
1002  }
1003 
1004  if (Name != NULL && IntLixAgentNameIsRunning(Name))
1005  {
1007  }
1008 
1010  TagEx,
1013  &pAgent);
1014  if (!INT_SUCCESS(status))
1015  {
1016  ERROR("[ERROR] IntLixAgentCreateAgent failed with status: 0x%08x.", status);
1017  goto _exit;
1018  }
1019 
1020  status = IntLixAgentThreadCreate(Tag,
1021  HypercallCallback,
1022  CompletionCallback,
1023  ContentAddress,
1024  ContentSize,
1025  &pAgent->Thread);
1026  if (!INT_SUCCESS(status))
1027  {
1028  ERROR("[ERROR] IntLixAgentThreadCreate failed with status: 0x%08x.", status);
1029  goto _exit;
1030  }
1031 
1032  if (Name != NULL)
1033  {
1034  strlcpy(pAgent->Name, Name, sizeof(pAgent->Name));
1035 
1036  if (AgentType == AGENT_TYPE_PROCESS)
1037  {
1038  status = IntLixAgentNameCreate(Name, pAgent->TagEx, pAgent->Agid, &pName);
1039  if (!INT_SUCCESS(status))
1040  {
1041  ERROR("[ERROR] IntLixAgentNameCreate failed with status: 0x%08x.", status);
1042  goto _exit;
1043  }
1044  }
1045  }
1046 
1047  InsertTailList(&gLixAgentState.PendingAgents, &pAgent->Link);
1048 
1049  TRACE("[AGENT] Linux agent allocated and initialized!\n");
1050 
1052  if (!INT_SUCCESS(status))
1053  {
1054  ERROR("[ERROR] IntLixAgentActivatePendingAgent failed with status: 0x%08x.", status);
1055  return status;
1056  }
1057 
1058  return INT_STATUS_SUCCESS;
1059 
1060 _exit:
1061  if (pAgent != NULL)
1062  {
1063  IntLixAgentFree(pAgent);
1064  }
1065 
1066  if (pName != NULL)
1067  {
1068  IntLixAgentNameRemove(pName);
1069  }
1070 
1071  return status;
1072 }
1073 
1074 
1075 INTSTATUS
1077  void
1078  )
1094 {
1095  INTSTATUS status;
1096  LIX_AGENT *pAgent = NULL;
1097  BYTE instrux[ND_MAX_INSTRUCTION_LENGTH];
1098 
1099  if (!gLixAgentState.SafeToInjectProcess)
1100  {
1102  }
1103 
1104  if (gLixAgentState.CompletingAgentsCount != 0)
1105  {
1107  }
1108 
1109  if (IsListEmpty(&gLixAgentState.PendingAgents))
1110  {
1112  }
1113 
1114  pAgent = CONTAINING_RECORD(gLixAgentState.PendingAgents.Flink, LIX_AGENT, Link);
1115  memset(&instrux, 0x90, sizeof(instrux));
1116 
1117  TRACE("[LIX-AGENT] Found pending agent with tag %d.", pAgent->Tag);
1118 
1119  IntPauseVcpus();
1120 
1122  if (!INT_SUCCESS(status))
1123  {
1124  goto _exit;
1125  }
1126 
1127  status = IntLixAgentFindInstruction(1, &pAgent->Instruction.Address, &pAgent->Instruction.Length,
1128  pAgent->Instruction.Bytes);
1129  if (!INT_SUCCESS(status))
1130  {
1131  ERROR("[ERROR] IntAgentFindInstruction failed with status: 0x%08x\n", status);
1132  goto _exit;
1133  }
1134 
1135  status = IntLixAgentAllocate(pAgent);
1136  if (!INT_SUCCESS(status))
1137  {
1138  ERROR("[LIX-AGENT] IntLixAgentAllocate failed with status: 0x%08x.", status);
1139  goto _exit;
1140  }
1141 
1142  // The agent is Introcore allocated, so it's safe to use IntKernVirtMemWrite instead of IntVirtMemSafeWrite.
1143  status = IntKernVirtMemWrite(pAgent->Data.Address, pAgent->Data.Size, pAgent->Data.Code);
1144  if (!INT_SUCCESS(status))
1145  {
1146  ERROR("[ERROR] IntKernVirtMemWrite failed with status: 0x%x", status);
1147  goto _exit;
1148  }
1149 
1150  instrux[0] = 0xCC;
1151  status = IntMemClkCloakRegion(pAgent->Instruction.Address,
1152  0,
1153  pAgent->Instruction.Length,
1155  pAgent->Instruction.Bytes,
1156  instrux,
1157  NULL,
1158  &pAgent->Instruction.CloakHandle);
1159  if (!INT_SUCCESS(status))
1160  {
1161  ERROR("[ERROR] Failed cloaking region 0x%016llx: 0x%08x\n", pAgent->Instruction.Address, status);
1162  goto _exit;
1163  }
1164 
1165  pAgent->Instruction.Restored = FALSE;
1166 
1168 
1169  TRACE("[LIX-AGENT] Agent with tag %d deployed...", pAgent->Tag);
1170 
1171  RemoveEntryList(&pAgent->Link);
1172 
1173  gLixAgentState.CompletingAgentsCount++;
1174  gLixAgentState.ActiveAgent = pAgent;
1175 
1176  status = INT_STATUS_SUCCESS;
1177 
1178 _exit:
1179  IntResumeVcpus();
1180 
1181  return status;
1182 }
1183 
1184 
1185 static INTSTATUS
1187  _In_ LIX_AGENT *Agent
1188  )
1199 {
1200  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1201 #ifdef DEBUG
1202  INTSTATUS status = INT_STATUS_SUCCESS;
1203  char ksymbol[LIX_SYMBOL_NAME_LEN] = {0};
1204 
1205  ERROR("[ERROR] Error occurred while running the agent with tag '%d' (%d)...", Agent->Tag, Agent->TagEx);
1206 
1207  status = IntKsymFindByAddress(pRegs->R8, sizeof(ksymbol), ksymbol, NULL, NULL);
1208  if (INT_SUCCESS(status))
1209  {
1210  LOG("[LIX-AGENT] '%s' failed with status: %llx", ksymbol, pRegs->R9);
1211  }
1212 
1213  IntDumpArchRegs(pRegs);
1214 #endif
1215 
1216  IntLixAgentSendEvent(agentError, Agent->TagEx, (DWORD)(pRegs->R15));
1217 
1218  IntLixAgentNameRemoveByAgid(Agent->Agid);
1219 
1220  return INT_STATUS_SUCCESS;
1221 }
1222 
1223 
1224 static INTSTATUS
1226  _In_ LIX_AGENT *Agent
1227  )
1238 {
1239  INTSTATUS status = INT_STATUS_SUCCESS;
1240  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1241 
1242  status = IntMemClkUncloakRegion(Agent->Instruction.CloakHandle, MEMCLOAK_OPT_APPLY_PATCH);
1243  if (!INT_SUCCESS(status))
1244  {
1245  ERROR("[ERROR] IntMemClkUncloakRegion failed with status: 0x%08x\n", status);
1246  IntEnterDebugger();
1247  }
1248 
1249  Agent->Instruction.CloakHandle = NULL;
1250  Agent->Instruction.Restored = TRUE;
1251 
1252  pRegs->Rip = Agent->Data.Address + Agent->Data.Header.DataSize;
1253 
1254  TRACE("[LIX-AGENT] Deployed agent @ 0x%llx and entry point @ %llx", Agent->Data.Address, pRegs->Rip);
1255 
1256  status = IntSetGprs(gVcpu->Index, pRegs);
1257  if (!INT_SUCCESS(status))
1258  {
1259  ERROR("[ERROR] IntSetGprs failed with status: 0x%08x.\n", status);
1260  ERROR("[ERROR] Remove agent with tag '%d' (%d) ...", Agent->Tag, Agent->TagEx);
1261 
1262  IntLixAgentSendEvent(agentError, Agent->TagEx, 0);
1263  IntLixAgentFree(Agent);
1264 
1265  return INT_STATUS_NO_DETOUR_EMU;
1266  }
1267 
1268  LOG("[LIX-AGENT] Agent with tag '%d' (%d) start execution on VCPU %d at RIP %llx ...",
1269  Agent->Tag, Agent->TagEx, gVcpu->Index, pRegs->Rip);
1270 
1271  return INT_STATUS_NO_DETOUR_EMU;
1272 }
1273 
1274 
1275 static INTSTATUS
1277  _In_ LIX_AGENT *Agent
1278  )
1290 {
1291  INTSTATUS status = INT_STATUS_SUCCESS;
1292  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1293 
1294  if (!Agent->Instruction.Restored)
1295  {
1296  ERROR("[LIX-AGENT] Original instruction not restored at exit stage...");
1297  IntEnterDebugger();
1298  }
1299 
1300  pRegs->Rip = Agent->Instruction.Address;
1301 
1302  status = IntSetGprs(gVcpu->Index, pRegs);
1303  if (!INT_SUCCESS(status))
1304  {
1305  ERROR("[ERROR] IntSetGprs failed: 0x%08x\n", status);
1306  IntEnterDebugger();
1307  }
1308 
1309  if (Agent->Thread == NULL)
1310  {
1311  gLixAgentState.ActiveAgent = NULL;
1312  gLixAgentState.CompletingAgentsCount--;
1313 
1315 
1316  IntLixAgentFree(Agent);
1317 
1319  {
1320  ERROR("[ERROR] IntAgentActivatePendingAgent failed: 0x%08x\n", status);
1321  }
1322  }
1323 
1324  return INT_STATUS_NO_DETOUR_EMU;
1325 }
1326 
1327 
1328 static INTSTATUS
1330  _In_ LIX_AGENT *Agent,
1331  _In_ QWORD Rip
1332  )
1344 {
1345  INTSTATUS status;
1346  QWORD token = gVcpu->Regs.Rax;
1347 
1348  if (Agent->Data.Token.Hypercall == token)
1349  {
1350  if (Agent->Callback.Hypercall == NULL)
1351  {
1352  return INT_STATUS_SUCCESS;
1353  }
1354 
1355  status = Agent->Callback.Hypercall(Agent);
1356  if (!INT_SUCCESS(status))
1357  {
1358  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1359  }
1360 
1361  return status;
1362  }
1363 
1364  if (Agent->Data.Token.Completion == token)
1365  {
1366  if (Agent->Callback.Completion == NULL)
1367  {
1368  return INT_STATUS_SUCCESS;
1369  }
1370 
1371  status = Agent->Callback.Completion(Agent);
1372  if (!INT_SUCCESS(status))
1373  {
1374  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1375  }
1376 
1377  return status;
1378  }
1379 
1380  if (Agent->Data.Token.Error == token)
1381  {
1382  status = IntLixAgentError(Agent);
1383  if (!INT_SUCCESS(status))
1384  {
1385  ERROR("[LIX-AGENT] IntLixAgentError failed with status: 0x%08x.", status);
1386  }
1387 
1388  return status;
1389  }
1390 
1391  if (Rip == (Agent->Data.Address + Agent->Data.Header.ExitOffset))
1392  {
1393  status = IntLixAgentExit(Agent);
1394  if (!INT_SUCCESS(status))
1395  {
1396  ERROR("[LIX-AGENT] IntLixAgentExit failed with status: 0x%08x.", status);
1397  }
1398 
1399  return status;
1400  }
1401 
1402  ERROR("[ERROR] Breakpoint generated an exit from unrecognized rip ...");
1404 
1405  return INT_STATUS_NOT_FOUND;
1406 }
1407 
1408 
1409 static INTSTATUS
1411  _In_ LIX_AGENT *Agent
1412  )
1423 {
1424  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1425 #ifdef DEBUG
1426  INTSTATUS status = INT_STATUS_SUCCESS;
1427  char ksymbol[LIX_SYMBOL_NAME_LEN] = {0};
1428 
1429  ERROR("[ERROR] Error occurred while running the agent-thread with tag '%d' (%d)...",
1430  Agent->Thread->Tag, Agent->TagEx);
1431 
1432  status = IntKsymFindByAddress(pRegs->R8, sizeof(ksymbol), ksymbol, NULL, NULL);
1433  if (INT_SUCCESS(status))
1434  {
1435  LOG("[LIX-AGENT] '%s' failed with status: %llx", ksymbol, pRegs->R9);
1436  }
1437 
1438  IntDumpArchRegs(pRegs);
1439 #endif
1440 
1441  IntLixAgentSendEvent(agentError, Agent->TagEx, (DWORD)(pRegs->R9));
1442 
1443  IntLixAgentNameRemoveByAgid(Agent->Agid);
1444 
1445  return INT_STATUS_SUCCESS;
1446 }
1447 
1448 
1449 static INTSTATUS
1451  _In_ LIX_AGENT *Agent
1452  )
1464 {
1465  LOG("[LIX-AGENT] Agent-thread with tag '%d' (%d) completed ...", Agent->Thread->Tag, Agent->TagEx);
1466 
1467  gLixAgentState.ActiveAgent = NULL;
1468  gLixAgentState.CompletingAgentsCount--;
1469 
1470  IntLixAgentFree(Agent);
1471 
1473 
1475  {
1476  ERROR("[ERROR] IntAgentActivatePendingAgent failed");
1477  }
1478 
1479  return INT_STATUS_SUCCESS;
1480 }
1481 
1482 
1483 static INTSTATUS
1485  _In_ LIX_AGENT *Agent,
1486  _In_ QWORD Rip
1487  )
1499 {
1500  INTSTATUS status;
1501  LIX_AGENT_THREAD *pThread = Agent->Thread;
1502  QWORD token = gVcpu->Regs.Rax;
1503 
1504  if (pThread->Data.Token.Hypercall == token)
1505  {
1506  if (pThread->Callback.Hypercall == NULL)
1507  {
1508  return INT_STATUS_SUCCESS;
1509  }
1510 
1511  status = pThread->Callback.Hypercall(Agent);
1512  if (!INT_SUCCESS(status))
1513  {
1514  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1515  }
1516 
1517  return status;
1518  }
1519 
1520  if (pThread->Data.Token.Completion == token)
1521  {
1522  if (pThread->Callback.Completion == NULL)
1523  {
1524  return INT_STATUS_SUCCESS;
1525  }
1526 
1527  status = pThread->Callback.Completion(Agent);
1528  if (!INT_SUCCESS(status))
1529  {
1530  ERROR("[LIX-AGENT] Agent callback failed with status %0x08x.", status);
1531  }
1532 
1533  return status;
1534  }
1535 
1536  if (pThread->Data.Token.Error == token)
1537  {
1538  status = IntLixAgentThreadError(Agent);
1539  if (!INT_SUCCESS(status))
1540  {
1541  ERROR("[LIX-AGENT] IntLixAgentThreadError failed with status %0x08x.", status);
1542  }
1543 
1544  return status;
1545  }
1546 
1547  if (Rip == (pThread->Data.Address + pThread->Data.Header.ExitOffset))
1548  {
1549  status = IntLixAgentThreadExit(Agent);
1550  if (!INT_SUCCESS(status))
1551  {
1552  ERROR("[ERROR] IntLixAgentThreadExit failed with status: 0x%08x.", status);
1553  }
1554 
1555  return status;
1556  }
1557 
1558  ERROR("[ERROR] Breakpoint generated an exit from unrecognized rip inside agent-thread '%d'...",
1559  pThread->Tag);
1561 
1562  return INT_STATUS_NOT_FOUND;
1563 }
1564 
1565 
1566 INTSTATUS
1568  _In_ QWORD Rip
1569  )
1583 {
1584  INTSTATUS status = INT_STATUS_SUCCESS;
1585  LIX_AGENT *pAgent = NULL;
1586  DWORD crtRing = 0;
1587 
1588  status = IntGetCurrentRing(gVcpu->Index, &crtRing);
1589  if (!INT_SUCCESS(status))
1590  {
1591  ERROR("[ERROR] IntGetCurrentRing failed: 0x%08x\n", status);
1592  return status;
1593  }
1594 
1595  if (crtRing != IG_CS_RING_0)
1596  {
1597  return INT_STATUS_NOT_FOUND;
1598  }
1599 
1600  pAgent = gLixAgentState.ActiveAgent;
1601  if (pAgent == NULL)
1602  {
1603  return INT_STATUS_NOT_FOUND;
1604  }
1605 
1606  if (pAgent->Instruction.Address == Rip)
1607  {
1608  if (pAgent->Instruction.Restored)
1609  {
1610  return INT_STATUS_NO_DETOUR_EMU;
1611  }
1612  else
1613  {
1614  status = IntLixAgentStart(pAgent);
1615  if (!INT_SUCCESS(status))
1616  {
1617  ERROR("[ERROR] IntLixAgentStart failed with status: 0x%08x.", status);
1618  }
1619 
1620  return status;
1621  }
1622  }
1623 
1624  if (IN_RANGE_LEN(Rip, pAgent->Data.Address, pAgent->Data.Size))
1625  {
1626  status = IntLixAgentHandleBreakpoint(pAgent, Rip);
1627  if (!INT_SUCCESS(status))
1628  {
1629  ERROR("[ERROR] IntLixAgentHandleBreakpoint failed with status: 0x%08x.", status);
1630  }
1631 
1632  return status;
1633  }
1634 
1635  if (pAgent->Thread != NULL &&
1636  IN_RANGE_LEN(Rip, pAgent->Thread->Data.Address, pAgent->Thread->Data.Size))
1637  {
1638  status = IntLixAgentThreadHandleBreakpoint(pAgent, Rip);
1639  if (!INT_SUCCESS(status))
1640  {
1641  ERROR("[ERROR] IntLixAgentThreadHandleBreakpoint failed with status: 0x%08x.", status);
1642  }
1643 
1644  return status;
1645  }
1646 
1647  return INT_STATUS_NOT_FOUND;
1648 }
1649 
1650 
1651 static INTSTATUS
1653  void
1654  )
1660 {
1661  ERROR("[ERROR] VMCALL executed from kernel mode. Rip 0x%016llx.", gVcpu->Regs.Rip);
1662 
1663  return INT_STATUS_NOT_SUPPORTED;
1664 }
1665 
1666 
1667 static INTSTATUS
1669  void
1670  )
1686 
1687 {
1688  INTSTATUS status = INT_STATUS_SUCCESS;
1689  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
1690  QWORD arg1 = pRegs->Rcx;
1691  QWORD arg2 = pRegs->Rbx;
1692  QWORD op = pRegs->Rdx;
1693 
1694  if (AGENT_HCALL_INTERNAL == op)
1695  {
1696  EVENT_AGENT_EVENT *pEvent = &gAlert.Agent;
1697 
1698  pEvent->Event = agentError;
1699  pEvent->ErrorCode = (DWORD)(arg2);
1700  pEvent->AgentTag = IntLixAgentNameGetTagByAgid((DWORD)(arg1));
1701 
1703 
1704  LOG("[LIX-AGENT] User-mode stub reports error for agent with tag %d: 0x%08x\n",
1705  pEvent->AgentTag, pEvent->ErrorCode);
1706 
1707  status = IntNotifyIntroEvent(introEventAgentEvent, pEvent, sizeof(*pEvent));
1708  if (!INT_SUCCESS(status))
1709  {
1710  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
1711  }
1712  }
1713  else
1714  {
1715  LIX_TASK_OBJECT *pTask = IntLixTaskFindByCr3(pRegs->Cr3);
1716  if (pTask == NULL)
1717  {
1718  LOG("[WARNING] VMCALL coming from outside a process with CR3 %llx\n", pRegs->Cr3);
1719  return INT_STATUS_SUCCESS;
1720  }
1721 
1722  if (!pTask->AgentTag || pTask->IsPreviousAgent)
1723  {
1724  TRACE("[AGENT-LIX] VMCALL with op = %lld from `%s` (PID = %d) which is not an agent (previous = %d), "
1725  "will ignore\n", op, pTask->Comm, pTask->Pid, pTask->IsPreviousAgent);
1726  return INT_STATUS_SUCCESS;
1727  }
1728 
1729  if (AGENT_HCALL_REM_TOOL == op)
1730  {
1731  status = IntAgentHandleRemediationVmcall(NULL, pRegs);
1732  if (!INT_SUCCESS(status))
1733  {
1734  ERROR("[ERROR] IntAgentHandleRemediationVmcall failed: 0x%08x\n", status);
1735  return status;
1736  }
1737  }
1738  else if (AGENT_HCALL_GATHER_TOOL == op)
1739  {
1740  status = IntAgentHandleLogGatherVmcall(NULL, pRegs);
1741  if (!INT_SUCCESS(status))
1742  {
1743  ERROR("[ERROR] IntAgentHandleLogGatherVmcall failed: 0x%08x\n", status);
1744  return status;
1745  }
1746  }
1747  }
1748 
1749  return status;
1750 }
1751 
1752 
1753 INTSTATUS
1755  _In_ QWORD Rip
1756  )
1766 {
1767  INTSTATUS status;
1768  DWORD crtRing = 0;
1769 
1770  status = IntGetCurrentRing(gVcpu->Index, &crtRing);
1771  if (!INT_SUCCESS(status))
1772  {
1773  ERROR("[ERROR] IntGetCurrentRing failed: 0x%08x\n", status);
1774  return status;
1775  }
1776 
1777  if (crtRing == IG_CS_RING_0)
1778  {
1779  LIX_AGENT *pAgent = gLixAgentState.ActiveAgent;
1780  if (pAgent == NULL)
1781  {
1782  ERROR("[LIX-AGENT] VMCALL with no active agent from RIP 0x%016llx.", Rip);
1783  }
1784 
1785  status = IntLixAgentHandleKernelVmcall();
1786  }
1787  else
1788  {
1789  status = IntLixAgentHandleUserVmcall();
1790  }
1791 
1792  return status;
1793 }
1794 
1795 
1796 _Success_(return != agNone)
1799  _Out_opt_ DWORD *Tag
1800  )
1810 {
1811  if (gLixAgentState.ActiveAgent)
1812  {
1813  if (NULL != Tag)
1814  {
1815  LIX_AGENT *pAgent = gLixAgentState.ActiveAgent;
1816  *Tag = pAgent->Tag;
1817  }
1818 
1819  return agActive;
1820  }
1821 
1822  if (!IsListEmpty(&gLixAgentState.PendingAgents))
1823  {
1824  if (NULL != Tag)
1825  {
1826  LIX_AGENT *pAgent = CONTAINING_RECORD(gLixAgentState.PendingAgents.Flink, LIX_AGENT, Link);
1827  *Tag = pAgent->Tag;
1828  }
1829 
1830  return agWaiting;
1831  }
1832 
1833  return agNone;
1834 }
1835 
1836 
1837 void
1839  void
1840  )
1847 {
1848  if (!gLixAgentState.Initialized)
1849  {
1850  return;
1851  }
1852 
1853  list_for_each (gLixAgentState.PendingAgents, LIX_AGENT, pAgent)
1854  {
1855  RemoveEntryList(&pAgent->Link);
1856 
1857  IntLixAgentFree(pAgent);
1858  }
1859 }
1860 
1861 
1864  _In_ const char *Name
1865  )
1876 {
1877  SIZE_T length;
1878 
1879  if (IsListEmpty(&gLixAgentState.AgentNames))
1880  {
1881  return lixAgTagNone;
1882  }
1883 
1884  length = strlen(Name);
1885 
1886  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
1887  {
1888  if (0 == strncmp(Name, pName->Name, length))
1889  {
1890  pName->RefCount++;
1891 
1892  return pName->AgentTag;
1893  }
1894  }
1895 
1896  return lixAgTagNone;
1897 }
1898 
1899 
1902  _In_ const char *Name,
1903  _Out_ BOOLEAN *Removed
1904  )
1916 {
1917  SIZE_T length;
1918 
1919  *Removed = FALSE;
1920 
1921  if (IsListEmpty(&gLixAgentState.AgentNames))
1922  {
1923  return lixAgTagNone;
1924  }
1925 
1926  length = strlen(Name);
1927 
1928  list_for_each (gLixAgentState.AgentNames, LIX_AGENT_NAME, pName)
1929  {
1930  if (memcmp_len(Name, pName->Name, length, pName->Length) == 0)
1931  {
1932  LIX_AGENT_TAG tag = pName->AgentTag;
1933 
1934  if (pName->RefCount > 0)
1935  {
1936  --pName->RefCount;
1937  }
1938  else
1939  {
1940  WARNING("[WARNING] Agent %s already done by our logic!\n", pName->Name);
1941  }
1942 
1943  if (pName->RefCount == 0)
1944  {
1945  IntLixAgentNameRemove(pName);
1946  *Removed = TRUE;
1947  }
1948 
1949  return tag;
1950  }
1951  }
1952 
1953  return lixAgTagNone;
1954 }
1955 
1956 
1957 void
1959  void
1960  )
1964 {
1965  gLixAgentState.SafeToInjectProcess = TRUE;
1966 
1968 }
1969 
1970 
1971 void
1973  void
1974  )
1978 {
1979  memzero(&gLixAgentState, sizeof(gLixAgentState));
1980 
1981  InitializeListHead(&gLixAgentState.PendingAgents);
1982  InitializeListHead(&gLixAgentState.AgentNames);
1983 
1984  gLixAgentState.Initialized = TRUE;
1985 
1986  LOG("[LIX-AGENT] Linux agent state initialized.\n");
1987 }
1988 
1989 
1990 INTSTATUS
1992  void
1993  )
2000 {
2001  if (gGuest.OSType != introGuestLinux)
2002  {
2004  }
2005 
2006  //
2007  // In case we inject our agent and the system is no longer running or it's hanged, the uninit agent may
2008  // remain allocated.
2009  //
2010  if (gLixAgentState.ActiveAgent)
2011  {
2012  IntLixAgentFree(gLixAgentState.ActiveAgent);
2013  }
2014 
2015  memzero(&gLixAgentState, sizeof(gLixAgentState));
2016 
2017  return INT_STATUS_SUCCESS;
2018 }
2019 
2020 
2021 static INTSTATUS
2023  _In_ LIX_AGENT *Agent
2024  )
2035 {
2036  INTSTATUS status = INT_STATUS_SUCCESS;
2037  LIX_AGENT_THREAD *pThread = Agent->Thread;
2038  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
2039 
2040  if (pRegs->R8 == 0)
2041  {
2042  goto _exit;
2043  }
2044 
2045  pThread->Data.Header.Address = pRegs->R8;
2046  pThread->Data.Address = pRegs->R8;
2047 
2048  memcpy(pThread->Data.Code, &pThread->Data.Header, sizeof(LIX_AGENT_HEADER));
2049 
2050  status = IntVirtMemWrite(pThread->Data.Address,
2051  pThread->Data.Size,
2053  pThread->Data.Code);
2054  if (!INT_SUCCESS(status))
2055  {
2056  ERROR("[ERROR] IntVirtMemWrite failed with status: 0x%08x.", status);
2057  goto _exit;
2058  }
2059 
2060  pRegs->Rax = pThread->Data.Address + pThread->Data.Header.DataSize;
2061  status = IntSetGprs(gVcpu->Index, pRegs);
2062  if (!INT_SUCCESS(status))
2063  {
2064  ERROR("[ERROR] IntSetGprs failed with status: 0x%08x.", status);
2065  goto _exit;
2066  }
2067 
2068  return INT_STATUS_SUCCESS;
2069 
2070 _exit:
2071  IntLixAgentSendEvent(agentError, Agent->TagEx, 0);
2072 
2073  IntLixAgentThreadFree(Agent->Thread);
2074  Agent->Thread = NULL;
2075 
2076  return INT_STATUS_SUCCESS;
2077 }
2078 
2079 
2080 static INTSTATUS
2082  _In_ LIX_AGENT *Agent
2083  )
2093 {
2094  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
2095  DWORD errorCode = 0;
2096 
2097  if (pRegs->Rax == 0)
2098  {
2099  errorCode = 1;
2100  goto _exit;
2101  }
2102 
2103  LOG("[DEPLOYER] Agent with tag %d has just been injected, error: 0x%08x.", Agent->TagEx, errorCode);
2104 
2105 _exit:
2106  IntLixAgentSendEvent(agentInjected, Agent->TagEx, errorCode);
2107 
2108  return INT_STATUS_SUCCESS;
2109 }
2110 
2111 
2112 void
2114  _In_ AGENT_EVENT_TYPE Event,
2116  _In_ DWORD ErrorCode
2117  )
2126 {
2127  INTSTATUS status;
2128  EVENT_AGENT_EVENT *pEvent = &gAlert.Agent;
2129 
2130  memzero(pEvent, sizeof(*pEvent));
2131 
2132  pEvent->Event = Event;
2133  pEvent->AgentTag = AgentTag;
2134  pEvent->ErrorCode = ErrorCode;
2135 
2136  status = IntNotifyIntroEvent(introEventAgentEvent, pEvent, sizeof(*pEvent));
2137  if (!INT_SUCCESS(status))
2138  {
2139  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%x\n", status);
2140  }
2141 }
WORD DataSize
The size (bytes) of the data.
Definition: lixagent.h:82
INTSTATUS IntLixAgentUninit(void)
Uninit the agents state.
Definition: lixagent.c:1991
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:1798
static DWORD IntLixAgentGetId(void)
Generate a new ID.
Definition: lixagent.c:706
void IntLixAgentEnableInjection(void)
Enables agent injections.
Definition: lixagent.c:1958
#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:675
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:1754
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
LIX_AGENT_DATA Data
The data used by the agent.
Definition: lixagent.h:124
LIX_TASK_OBJECT * IntLixTaskFindByCr3(QWORD Cr3)
Finds the Linux process having the provided Cr3.
Definition: lixprocess.c:940
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:68
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:1972
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:207
#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
struct _LIX_AGENT_THREAD::@93 Callback
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:1838
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:1960
AGENT_EVENT_TYPE Event
The type of the agent.
Definition: intro_types.h:2184
The global agents state.
Definition: lixagent.c:53
#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:1567
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:1245
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:1934
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:2182
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:284
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:44
#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:40
#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
struct _LIX_AGENT::@96 Instruction
#define IMAGE_BASE_NAME_LEN
The maximum length of a process name.
Definition: winguest.h:14
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:720
struct _LINUX_GUEST::@125::@129 Agent
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:274
LIST_HEAD PendingAgents
List of agents waiting to be injected.
Definition: lixagent.c:55
DWORD RefCount
Number of times this name has been used by agents.
Definition: lixagent.c:46
DWORD ErrorCode
The error code of the event. Success is 0.
Definition: intro_types.h:2186
#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:367
#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:501
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:43
static INTSTATUS IntLixAgentCreateThreadHypercall(LIX_AGENT *Agent)
Called by the thread-agent to deploy the content of the kthread previously created.
Definition: lixagent.c:2022
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:807
BOOLEAN IntLixAgentMatchVersion(LIX_AGENT_FUNCTIONS *Function)
Checks if the provided LIX_AGENT_FUNCTIONS match the current guest version.
Definition: lixagent.c:564
The agent has been successfully injected.
Definition: intro_types.h:1936
DWORD CompletingAgentsCount
Number of agents that are yet to complete execution.
Definition: lixagent.c:60
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:1901
#define _Inout_
Definition: intro_sal.h:20
#define AGENT_HCALL_GATHER_TOOL
Log gathering tool.
Definition: intro_types.h:1956
DWORD Agid
Agent ID.
Definition: lixagent.c:41
LIST_ENTRY Link
List entry element.
Definition: lixagent.c:38
#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
struct _LIX_AGENT::@95 Callback
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:1863
BOOLEAN SafeToInjectProcess
Will be true the moment it&#39;s safe to inject agents (the OS has booted).
Definition: lixagent.c:63
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:1329
#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:269
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:426
LIST_HEAD AgentNames
List of agent names.
Definition: lixagent.c:56
#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:2185
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:279
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:1954
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:1652
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:91
BOOLEAN Initialized
True if the agents state has been initialized.
Definition: lixagent.c:64
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:582
Describes the name of an injected process agent.
Definition: lixagent.c:36
#define PAGE_SIZE
Definition: common.h:53
enum _AGENT_TYPE AGENT_TYPE
INTSTATUS IntSlackFree(QWORD Buffer)
Free slack space.
Definition: slack.c:429
static INTSTATUS IntLixAgentThreadError(LIX_AGENT *Agent)
Called when an error occurred while the running the current thread-agent.
Definition: lixagent.c:1410
void * InstructionCache
The currently used instructions cache.
Definition: guests.h:400
#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:2113
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:1668
__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:311
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:370
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:429
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:48
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.
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:1941
static INTSTATUS IntLixAgentFillData(LIX_AGENT_DATA *Data, LIX_AGENT_HANDLER *Handler)
Fetch the content of the agent.
Definition: lixagent.c:535
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:230
#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:340
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:587
QWORD Error
The token used by error callback.
Definition: lixagent.h:97
QWORD SyscallAddress
The guest virtual address of the syscall.
Definition: lixguest.h:526
static QWORD IntLixAgentGetToken(void)
Randomly select a token to be used by the agent code when issuing hyper calls.
Definition: lixagent.c:77
DWORD CurrentId
Used to generate unique agent IDs.
Definition: lixagent.c:61
#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:948
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:57
static INTSTATUS IntLixAgentExit(LIX_AGENT *Agent)
Called when the agent is terminating.
Definition: lixagent.c:1276
static INTSTATUS IntLixAgentCreateThreadCompletion(LIX_AGENT *Agent)
Called by the thread-agent when the kthread started.
Definition: lixagent.c:2081
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:484
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:1361
#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:1186
#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:890
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:1484
static INTSTATUS IntLixAgentStart(LIX_AGENT *Agent)
Called when the INT3 instruction from SYSCALL is hit.
Definition: lixagent.c:1225
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:1076
struct _LINUX_GUEST::@125 MmAlloc
static void IntLixAgentFree(LIX_AGENT *Agent)
Remove the provided agent.
Definition: lixagent.c:365
#define BYTE_MAX
Definition: introtypes.h:31
LIX_AGENT * ActiveAgent
The active agent at any given moment. This is the one.
Definition: lixagent.c:58
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:203
QWORD PropperSyscallGva
The guest virtual address of the &#39;real&#39; syscall.
Definition: lixguest.h:527
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:29
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:1450
struct _LIX_AGENT_THREAD::@94 Content
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