24 #define DETOUR_MAX_FUNCTION_SIZE 24 54 #define for_each_detour(_var_name) list_for_each (gDetours.DetoursList, DETOUR, _var_name) 76 if (!Detour->LixFnDetour)
81 TRACE(
"[DETOUR] Disabling detour - Function name : %s, Hijack function name: %s\n", Detour->LixFnDetour->FunctionName,
82 Detour->LixFnDetour->HijackFunctionName != NULL ? Detour->LixFnDetour->HijackFunctionName :
"none");
84 Detour->Disabled =
TRUE;
89 ERROR(
"[ERROR] IntKernVirtMemWrite failed for GVA 0x%016llx with status: 0x%08x\n", Detour->LixGuestDetour, status);
118 BYTE atomic_nop_3[3] = {0x66, 0x66, 0x90};
120 if (NULL == Detour->HandlerCloakHandle)
125 Detour->Disabled =
TRUE;
132 switch (Detour->HypercallType)
136 Detour->HypercallOffset,
142 Detour->HypercallOffset,
143 sizeof(atomic_nop_3),
177 if (NULL == Detour->HandlerCloakHandle)
182 Detour->Disabled =
FALSE;
189 switch (Detour->HypercallType)
193 Detour->HypercallOffset,
199 Detour->HypercallOffset,
226 if (NULL == Detour->FunctionCloakHandle)
233 Detour->FunctionCloakHandle = NULL;
254 if (NULL != Detour->HandlerCloakHandle)
259 Detour->HandlerCloakHandle = NULL;
261 if (0 != Detour->HandlerAddress)
266 Detour->HandlerAddress = 0;
426 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
436 pDetour->
Callback = FnDetour->Callback;
479 BYTE prologueSize = 0;
481 QWORD handlerAddress = Detour->HandlerAddress;
492 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
496 while (prologueSize < 5)
501 FunctionSize - prologueSize,
514 relInstr = NdIsInstruxRipRelative(&instrux);
518 if ((instrux.PrimaryOpCode != 0xe8) &&
519 (instrux.PrimaryOpCode != 0xe9) &&
520 (instrux.PrimaryOpCode != 0x89) &&
521 (instrux.PrimaryOpCode != 0x8b) &&
522 (instrux.PrimaryOpCode != 0x80) &&
523 (instrux.Instruction != ND_INS_Jcc || instrux.Length != 6))
525 WARNING(
"[WARNING] RIP relative found at GVA 0x%016llx, can't continue!\n",
526 Detour->FunctionAddress + prologueSize);
533 if (instrux.PrimaryOpCode == 0xe8 || instrux.PrimaryOpCode == 0xe9)
538 calledFunc = Detour->FunctionAddress + prologueSize +
539 SIGN_EX(instrux.RelOffsLength, instrux.RelativeOffset);
541 patched = (
DWORD)(calledFunc - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
542 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.PrimaryOpCode;
544 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 1, &patched, 4);
546 else if (relInstr && (instrux.PrimaryOpCode == 0x8b || instrux.PrimaryOpCode == 0x89))
548 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
550 QWORD movGva = Detour->FunctionAddress + prologueSize +
551 SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
553 DWORD patched = (
DWORD)(movGva - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
555 if (instrux.Rex.Rex != 0)
557 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
558 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
559 handler[Detour->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
561 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 3, &patched, 4);
565 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
566 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
568 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
571 else if (relInstr && instrux.PrimaryOpCode == 0x80)
573 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
575 QWORD cmpGva = Detour->FunctionAddress + prologueSize +
576 SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
578 DWORD patched = (
DWORD)(cmpGva - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
580 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
581 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
583 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
585 handler[Detour->RelocatedCodeOffset + prologueSize + 6] = instrux.InstructionBytes[6];
587 else if (relInstr && instrux.Instruction == ND_INS_Jcc)
589 QWORD target = Detour->FunctionAddress + instrux.Operands[0].Info.RelativeOffset.Rel;
590 DWORD newRel = (
DWORD)(target - (handlerAddress + Detour->RelocatedCodeOffset));
595 handler[Detour->RelocatedCodeOffset + prologueSize] = 0x0F;
596 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = 0x80 | instrux.Predicate;
598 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &newRel, 4);
603 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize, FunctionCode + prologueSize, instrux.Length);
606 prologueSize += instrux.Length;
612 ERROR(
"[ERROR] IntVirtMemWrite failed with status: 0x%x.", status);
616 Detour->RelocatedCodeLength = prologueSize;
648 _In_ void *CloakHandle,
674 BYTE *memcloakData = NULL;
675 DWORD memcloakDataSize;
683 if (NULL == CloakHandle)
699 ERROR(
"[ERROR] Detour writes are not being handled on this OS!");
715 WARNING(
"[WARNING] IntLixDrvIsLegitimateTextPoke failed for address 0x%llx. Status: 0x%08x\n",
716 PhysicalAddress, status);
722 ERROR(
"[ERROR] The guest attempted to perform a write inside detour %d with a non-legitimate " 723 "text poke. Will deny!", pActivePatch->
DetourTag);
729 ERROR(
"[ERROR] Detour write handler called, but the ActivePatch is not inside a detour! 0x%llx (+%d)\n",
730 pActivePatch->
Gva, pActivePatch->
Length);
739 ERROR(
"[ERROR] IntMemClkGetOriginalData failed: 0x%08x\n", status);
743 regionOffset = (
DWORD)(pActivePatch->
Gva - RegionVirtualAddress);
745 WARNING(
"[WARNING] The guest is applying a patch with size %d at 0x%llx (+ %d).\n",
746 pActivePatch->
Length, RegionVirtualAddress, regionOffset);
750 relocateAfter = (pActivePatch->
Length == 1);
751 relocateAfter = relocateAfter && (RegionVirtualAddress == pActivePatch->
Gva);
752 relocateAfter = relocateAfter && (memcloakData[regionOffset] == 0xCC);
756 relocateAfter = relocateAfter && (pActivePatch->
Data[0] != 0xCC);
765 ERROR(
"[ERROR] IntMemClkModifyPatchedData failed with status 0x%08x\n", status);
769 TRACE(
"[INFO] Updated memcloak original buffer at 0x%llx. Size: %d\n. ",
770 pActivePatch->
Gva, pActivePatch->
Length);
780 ERROR(
"[ERROR] IntMemClkGetOriginalData failed: 0x%08x\n", status);
784 if (memcloakDataSize < pDet->RelocatedCodeLength)
789 ERROR(
"[ERROR] Cloaked region size for detour %d is smaller than the relocated code length (%d vs %d)!\n",
801 ERROR(
"[ERROR] Failed to relocate patch for detour %d. Status: 0x%08x\n\n",
840 QWORD handlerAddress = 0;
844 handlerAddress = Detour->HandlerAddress;
846 functionDetour[0] = 0xE9;
847 *(
DWORD *)(functionDetour + 1) = (
DWORD)(handlerAddress - (Detour->FunctionAddress + 5));
849 for (
DWORD i = 5; i < Detour->RelocatedCodeLength; i++)
851 functionDetour[i] = 0x90;
856 Detour->RelocatedCodeLength,
861 &Detour->FunctionCloakHandle);
864 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
877 _In_ char *FunctionName,
895 memzero(pEvent,
sizeof(*pEvent));
934 WARNING(
"[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
974 DWORD relInstrCount = 0;
977 if (FunctionAddress == 0)
982 if (FnDetour == NULL)
987 status =
IntKernVirtMemRead(FunctionAddress,
sizeof(functionCode), functionCode, NULL);
990 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
994 if (functionCode[0] == 0xE9 || functionCode[0] == 0xE8)
1000 WARNING(
"[WARNING] API function already detoured (0x%016llx) by kprobe/live-patch!\n", addr);
1006 ERROR(
"[ERROR] IntDetCreateObjectLix failed with status: 0x%08x.", status);
1010 status =
IntDetRelocate(pDetour, functionCode,
sizeof(functionCode), &relInstrCount);
1013 ERROR(
"[WARNING] IntDetRelocate failed with status: 0x%08x.", status);
1017 *MultipleInstructions =
FALSE;
1018 if (relInstrCount > 1)
1020 *MultipleInstructions =
TRUE;
1026 ERROR(
"[ERROR] IntDetPatchFunction failed with status: 0x%08x.", status);
1037 ERROR(
"[ERROR] IntKernVirtMemWrite failed with status: 0x%08x\n", status);
1045 LOG(
"[DETOUR] %llx: handler @ %llx (%s)\n",
1122 DWORD prologueSize, newJumpBackOffset, totalHandlerSize, i;
1126 if (NULL == Descriptor)
1136 if (NULL == Handler)
1141 if (0 == ModuleBase)
1146 if (FunctionAddress)
1153 DWORD funOffset = (
DWORD)(FunctionAddress - ModuleBase);
1157 ERROR(
"[ERROR] Function not inside kernel buffer. Offset: 0x%08x, size: 0x%08zx, buffer size: 0x%08x\n",
1169 ERROR(
"[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
1175 if (origFn[0] == 0xE9)
1181 WARNING(
"[INFO] API function already detoured (0x%016llx), don't know by who! Aborting!\n", addr);
1187 while (prologueSize < 5)
1190 sizeof(origFn) - prologueSize,
1198 prologueSize += instrux.Length;
1202 totalHandlerSize = Handler->CodeLength + prologueSize;
1204 if (
sizeof(newHnd) < totalHandlerSize)
1206 ERROR(
"[ERROR] The size of the handler exceeds %zu bytes: %d!\n",
sizeof(newHnd), totalHandlerSize);
1211 if (NULL == pDetour)
1219 ERROR(
"[ERROR] IntSlackAlloc failed: 0x%08x\n", status);
1220 goto cleanup_and_exit;
1223 if (NULL != Descriptor->PreCallback)
1225 status = Descriptor->PreCallback(FunctionAddress, Handler, Descriptor);
1228 ERROR(
"[ERROR] PreCallback for hook %d (`%s!%s`) failed: 0x%08x\n",
1229 Descriptor->Tag,
utf16_for_log(Descriptor->ModuleName), Descriptor->FunctionName, status);
1230 goto cleanup_and_exit;
1234 LOG(
"[INFO] PreCallback for hook %d (`%s!%s`) returned NOT NEEDED. Will skip the hook (critical: %d)\n",
1237 Descriptor->FunctionName,
1238 !Descriptor->NotCritical);
1240 goto cleanup_and_exit;
1247 ERROR(
"[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
1248 goto cleanup_and_exit;
1251 memcpy(newHnd, Handler->Code, totalHandlerSize - prologueSize);
1253 if (0 == FunctionAddress)
1260 while (prologueSize < 5)
1265 sizeof(origFn) - prologueSize,
1270 goto cleanup_and_exit;
1273 relInstr = NdIsInstruxRipRelative(&instrux);
1277 if ((instrux.PrimaryOpCode != 0xe8) &&
1278 (instrux.PrimaryOpCode != 0x89) &&
1279 (instrux.PrimaryOpCode != 0x8b) &&
1280 (instrux.PrimaryOpCode != 0x80) &&
1281 (instrux.PrimaryOpCode != 0x63) &&
1282 (instrux.Instruction != ND_INS_Jcc || instrux.Length != 6))
1284 CHAR insText[ND_MIN_BUF_SIZE] = {0};
1286 NdToText(&instrux, FunctionAddress + prologueSize,
sizeof(insText), insText);
1288 WARNING(
"[WARNING] RIP relative instruction '%s' found at GVA 0x%016llx, can't continue!\n",
1289 insText, FunctionAddress + prologueSize);
1293 goto cleanup_and_exit;
1297 if (instrux.PrimaryOpCode == 0xe8)
1299 QWORD calledFunc = FunctionAddress + prologueSize +
SIGN_EX(instrux.RelOffsLength, instrux.RelativeOffset);
1302 (pDetour->
HandlerAddress + Handler->RelocatedCodeOffset + prologueSize));
1304 newHnd[Handler->RelocatedCodeOffset + prologueSize] = 0xe8;
1305 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 1, &patched, 4);
1307 else if (relInstr && (instrux.PrimaryOpCode == 0x8b || instrux.PrimaryOpCode == 0x89))
1309 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1311 QWORD movGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1314 if (instrux.Rex.Rex != 0)
1316 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1317 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1318 newHnd[Handler->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
1320 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 3, &patched, 4);
1324 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1325 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1327 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
1330 else if (relInstr && instrux.PrimaryOpCode == 0x80)
1332 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1334 QWORD cmpGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1337 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1338 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1340 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
1342 newHnd[Handler->RelocatedCodeOffset + prologueSize + 6] = instrux.InstructionBytes[6];
1344 else if (relInstr && instrux.Instruction == ND_INS_Jcc)
1346 QWORD target = FunctionAddress + instrux.Operands[0].Info.RelativeOffset.Rel;
1352 newHnd[Handler->RelocatedCodeOffset + prologueSize] = 0x0F;
1353 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = 0x80 | instrux.Predicate;
1355 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &newRel, 4);
1357 else if (relInstr && instrux.PrimaryOpCode == 0x63)
1359 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1360 QWORD crtInstruxGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1364 if (instrux.Rex.Rex != 0)
1366 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1367 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1368 newHnd[Handler->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
1371 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 3, &crtInstruxPatch, 4);
1375 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1376 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1378 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &crtInstruxPatch, 4);
1384 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize, origFn + prologueSize, instrux.Length);
1387 prologueSize += instrux.Length;
1394 newJumpBackOffset = Handler->RelocatedCodeOffset + prologueSize;
1397 *(newHnd + newJumpBackOffset) = 0xE9;
1400 newJumpBackOffset + 5));
1403 *(
DWORD *)(newHnd + newJumpBackOffset + 1) += prologueSize - 5;
1409 for (i = 5; i < prologueSize; i++)
1416 pDetour->
Tag = Descriptor->Tag;
1418 pDetour->
Callback = Descriptor->Callback;
1423 Handler->HypercallOffset;
1447 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
1448 goto cleanup_and_exit;
1451 if (FunctionAddress)
1463 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
1464 goto cleanup_and_exit;
1473 TRACE(
"[DETOUR] Hooked function @ 0x%016llx, handler @ 0x%016llx, hypercall @ 0x%016llx\n",
1486 TRACE(
"[INFO] Will ensure that SSDT isn't in our detours!\n");
1491 WARNING(
"[WARNING] SSDT 0x%016llx (%d services) is in the same page (function) as detour %d \n",
1498 WARNING(
"[WARNING] SSDT 0x%016llx (%d services) is in the same page (handler) as detour %d \n",
1510 if (NULL != Descriptor->PostCallback)
1512 status = Descriptor->PostCallback(Handler);
1515 WARNING(
"[ERROR] PostCallback for hook %d (`%s!%s`) failed: 0x%08x\n",
1516 Descriptor->Tag,
utf16_for_log(Descriptor->ModuleName), Descriptor->FunctionName, status);
1555 if (NULL == Registers)
1560 ERROR(
"[ERROR] IntGetGprs failed: 0x%08x\n", status);
1567 switch (Detour->HypercallType)
1570 Registers->Rax = ReturnValue;
1574 Registers->Rsi = ReturnValue;
1579 ERROR(
"[DETOUR] Invalid hypercall type %d ...", Detour->HypercallType);
1587 ERROR(
"[ERROR] IntSetGprs failed: 0x%08x\n", status);
1656 pDet->HypercallAddress == 0 ||
1658 pDet->Callback == NULL)
1663 if (!pDet->Disabled)
1668 status = pDet->Callback(pDet);
1687 LOG(
"[DETOUR] Removing detour with tag %d\n", pDetour->
Tag);
1696 WARNING(
"[WARNING] The detour uses vmcall as a hypercall. Cannot remove and set RIP ...");
1703 LOG(
"[DETOUR] Removing detour with tag %d and setting RIP[%d] to 0x%016llx\n",
1711 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n",
1727 LOG(
"[DETOUR] Removing detour with tag %d and setting RIP[%d] to 0x%016llx\n",
1753 _In_ void const *Data,
1755 _In_ char const *PublicDataName
1799 if (NULL == PublicDataName)
1824 if (NULL == pPublicData)
1834 LOG(
"[DETOUR] Will modify patched data for public data %s at offset %d with size %u\n",
1840 ERROR(
"[ERROR] IntMemClkModifyPatchedData failed: 0x%08x\n", status);
1889 memzero(&gDetours,
sizeof(gDetours));
1902 LOG(
"[DBGINTRO] Introspection detours:\n");
1906 char *pFnName = NULL;
1909 if (pDetour->LixFnDetour != NULL)
1911 pFnName = pDetour->LixFnDetour->FunctionName;
1913 else if (pDetour->Descriptor != NULL)
1915 pFnName = pDetour->Descriptor->FunctionName;
1920 pFnName = pDetour->Descriptor != NULL ? pDetour->Descriptor->FunctionName : NULL;
1923 LOG(
" ## %-32s Hits: %12llu, RIP: %llx, Tag: %02d, Handler RIP: %llx (+ %02x), Hooked RIP: %llx\n",
1924 pFnName != NULL ? pFnName :
"unknown",
1926 pDetour->HypercallAddress,
1928 pDetour->HandlerAddress,
1929 pDetour->HandlerSize,
1930 pDetour->FunctionAddress);
1934 LOG(
" Module: %llx\n",
1935 pDetour->ModuleBase);
1958 if (Ptr >= pDet->FunctionAddress &&
1959 Ptr < pDet->FunctionAddress + pDet->RelocatedCodeLength)
2011 if ((Ptr >= pDet->HandlerAddress) && (Ptr < pDet->HandlerAddress + pDet->HandlerSize))
2013 WARNING(
"[WARNING] Found %s ptr 0x%016llx in detours: handler RIP 0x%016llx, hook RIP 0x%016llx\n",
2014 Type ==
ptrLiveRip ?
"live RIP" :
"stack value", Ptr, pDet->HandlerAddress, pDet->FunctionAddress);
2023 if (Ptr < pDet->HandlerAddress + pDet->RelocatedCodeOffset)
2025 gRipInsideRtlpVirtualUnwindReloc =
TRUE;
2061 if ((Ptr > pDetour->FunctionAddress) &&
2062 (Ptr < pDetour->FunctionAddress + pDetour->RelocatedCodeLength))
2064 return pDetour->HandlerAddress + pDetour->RelocatedCodeOffset + (Ptr - pDetour->FunctionAddress);
2094 if ((Ptr > pDetour->HandlerAddress) &&
2095 (Ptr < pDetour->HandlerAddress + pDetour->HandlerSize))
2097 *Address = pDetour->HandlerAddress;
2098 *Size = pDetour->HandlerSize;
2099 *Tag = pDetour->Tag;
2191 BOOLEAN haveStackBuffer = StackBuffer && StackBufferSize;
2199 if (haveStackBuffer && stackOffset +
gGuest.
WordSize <= StackBufferSize)
2203 *Value = *(
DWORD const *)(StackBuffer + stackOffset);
2207 *Value = *(
QWORD const *)(StackBuffer + stackOffset);
2217 ERROR(
"[ERROR] IntKernVirtMemRead failed for %llx: 0x%08x\n", pRegs->
Rsp + stackOffset, status);
2224 *Value = ((
QWORD const *)pRegs)[Arg];
2228 ERROR(
"[ERROR] Invalid argument type: 0x%08x\n", Arg);
2238 _In_ void const *Detour,
2297 _In_ void const *Detour,
2322 BYTE stackBuffer[256];
2326 DWORD stackBufferSize = 0;
2327 BYTE const *pStackBuffer = NULL;
2356 ERROR(
"[ERROR] Requested to read %u arguments for for detour %d, but only %u exist.\n",
2361 for (
DWORD i = 0; i < argc; i++)
2369 if (stackBufferSize)
2377 stackBufferSize =
MIN(stackBufferSize,
sizeof(stackBuffer));
2382 WARNING(
"[WARNING] IntKernVirtMemRead failed for [0x%016llx, 0x%016llx]: 0x%08x\n",
2383 rsp, rsp + stackBufferSize, status);
2384 stackBufferSize = 0;
2389 pStackBuffer = stackBuffer;
2393 for (
DWORD i = 0; i < argc; i++)
2400 ERROR(
"[ERROR] IntDetGetArgument failed for %u: 0x%08x\n", i, status);
2411 _In_ void const *Detour,
2464 ERROR(
"[ERROR] IntVirtMemSafeWrite failed: 0x%08x\n", status);
2470 ((
QWORD *)pRegs)[arg] = Value;
2475 ERROR(
"[ERROR] IntSetGprs failed: 0x%08x\n", status);
2481 ERROR(
"[ERROR] Invalid argument type: 0x%016llx\n", arg);
static DETOUR * IntDetFindByTag(DETOUR_TAG Tag)
Searches a detour by its tag.
INTSTATUS IntDetSetLixHook(QWORD FunctionAddress, const LIX_FN_DETOUR *FnDetour, BOOLEAN *MultipleInstructions)
Detours a function from guest.
QWORD LixGuestDetour
The address of the linux-detour header.
API_HOOK_PUBLIC_DATA PublicDataOffsets[PUBLIC_DATA_MAX_DESCRIPTORS]
Public data that can be used to modify the detour handler.
QWORD HandlerAddress
The guest virtual address of the detour handler.
static INTSTATUS IntDetEnableHypercall(DETOUR *Detour)
Enables a detour hypercall.
Describes the information about a Linux active-patch.
static void IntDetRemoveBranch(DETOUR *Detour)
Restores the original instructions of a hooked function.
PDETOUR DetoursTable[detTagMax]
Table of detours, indexed by DETOUR_TAG.
struct _LINUX_GUEST::@128 MmAlloc
static INTSTATUS IntDetSendIntegrityAlert(char *FunctionName, QWORD FunctionAddress, QWORD DetourAddress)
Sends an integrity alert if the provieded function is already hooked.
DWORD Size
The size of the access.
BYTE NrPublicDataOffsets
The number of valid entries inside the PublicDataOffsets array.
DWORD Argc
The number of valid entries inside the Argv array.
struct _LINUX_GUEST::@128::@133 PerCpuData
#define OFFSET_OF(Type, Member)
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
IG_ARCH_REGS Regs
The current state of the guest registers.
DWORD Index
The VCPU number.
LIX_ACTIVE_PATCH ActivePatch[lixActivePatchCount]
An array that contains information about the active-patches.
struct _LIX_GUEST_DETOUR LIX_GUEST_DETOUR
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
#define INT_STATUS_REMOVE_DETOUR_AND_SET_RIP
QWORD NewValue[8]
The written value. Only the first Size bytes are valid.
Holds information about the currently set detours.
INTSTATUS IntGetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Get the current guest GPR state.
INTSTATUS IntMemClkModifyPatchedData(void *CloakHandle, DWORD Offset, DWORD Size, const void *Data)
Modifies the patched data inside the guest memory.
Event structure for integrity violations on monitored structures.
Described a detour handler.
QWORD HitCount
The number of times this detour issued a hypercall.
Describes a detour set inside the guest memory.
#define INT_SUCCESS(Status)
QWORD HypercallAddress
The guest virtual address at which the hypercall is placed.
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
INTSTATUS IntDetGetArgument(void const *Detour, DWORD Index, BYTE const *StackBuffer, DWORD StackBufferSize, QWORD *Value)
Reads the specified argument for a detour.
The action was not allowed because there was no reason to allow it.
INTSTATUS IntVirtMemWrite(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer)
Writes data to a guest virtual memory range.
struct _EVENT_INTEGRITY_VIOLATION::@304 Victim
WORD Length
The patch length.
struct _DETOURS_STATE * PDETOURS_STATE
static DETOURS_STATE gDetours
The global detour state.
#define INT_STATUS_NOT_NEEDED_HINT
#define DET_ARG_STACK_OFFSET(Arg)
Gets the stack offset at which a stack argument is found.
INTSTATUS IntDetModifyPublicData(DETOUR_TAG Tag, void const *Data, DWORD DataSize, char const *PublicDataName)
Modifies public parts of a detour handler.
#define HpAllocWithTag(Len, Tag)
The function is already hooked.
int INTSTATUS
The status data type.
INTSTATUS IntDetEnableDetour(DETOUR_TAG Tag)
Enables a detour based on its tag.
#define INT_STATUS_DISABLE_DETOUR_ON_RET
Can be used by detour callbacks to signal that the detour should be disabled.
#define INT_STATUS_NOT_FOUND
DWORD NumberOfServices
The number of entries in the SSDT.
unsigned long long EnableOptions
INTSTATUS IntDetGetFunctionAddressByTag(DETOUR_TAG Tag, QWORD *FunctionAddress)
Get a detour function address by its tag.
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
static INTSTATUS IntDetDisableLixHypercall(DETOUR *Detour)
Disables a Linux detour hypercall.
INTRO_GUEST_TYPE OSType
The type of the guest.
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
#define INT_STATUS_BUFFER_OVERFLOW
#define _Out_writes_(expr)
void IntDetDisableAllHooks(void)
Removes all detours from the guest.
Will write the contents of the patched data inside the guest.
DETOUR_TAG DetourTag
If the guest attempts to patch the jump label for our detour, contains the tag of the detour...
The detour will use a INT3 instruction in order to notify introcore about an event.
INTSTATUS IntSlackAlloc(QWORD ModuleBase, BOOLEAN Pageable, DWORD Size, QWORD *Buffer, QWORD SecHint)
Allocate slack inside the guest.
PFUNC_DetourCallback Callback
Callback to be invoked when the detour issues a hypercall. May be NULL.
INTSTATUS IntDetGetByTag(DETOUR_TAG Tag, QWORD *Address, DWORD *Size)
Get a detour handler address and size by its tag.
void * FunctionCloakHandle
The memory cloak handle used to hide the modified function start. See Memory cloaking.
No hypercall. This detour does not generate events.
Describes a kernel driver.
static __default_fn_attr size_t vmcall(DETOUR_ID id)
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
CHAR PublicDataName[PUBLIC_DATA_MAX_NAME_SIZE]
Name used to identify the data.
static INTSTATUS IntDetDisableWinHypercall(DETOUR *Detour)
Disables a Windows detour hypercall.
INTSTATUS IntDetCallCallback(void)
Calls the appropriate detour handler for hypercall.
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
static INTSTATUS IntDetGetArgumentInternal(DWORD Arg, BYTE const *StackBuffer, DWORD StackBufferSize, QWORD *Value)
Reads the value of an argument passed from a detour.
INTSTATUS IntDetSetReturnValue(DETOUR const *Detour, IG_ARCH_REGS *Registers, QWORD ReturnValue)
Sets the return value for a hooked guest function.
struct _LINUX_GUEST::@128::@131 Detour
GENERIC_ALERT gAlert
Global alert buffer.
BYTE HypercallOffset
Offset, relative to HandlerAddress, where the hypercall instruction is found.
INTSTATUS IntDetPatchArgument(void const *Detour, DWORD Index, QWORD Value)
Modifies the value of a detour argument.
void IntAlertFillLixKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves information about a kernel module inside an alert.
TIMER_FRIENDLY void IntDumpInstruction(INSTRUX *Instruction, QWORD Rip)
This function dumps a given instruction (textual disassembly).
INTSTATUS IntDetDisableDetour(DETOUR_TAG Tag)
Disables a detour based on its tag.
DETOUR_ARGS Arguments
Encoding of the arguments needed by introcore from the hooked function.
DWORD Size
The size of the modified memory area.
#define INT_STATUS_NOT_INITIALIZED
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
DWORD Argv[DET_ARGS_MAX]
Argument encoding. See DET_ARG_REGS and DET_ARG_ON_STACK.
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Public data which allows for external modification to a in-guest hook handler.
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
#define IN_RANGE(x, start, end)
INTSTATUS IntMemClkGetOriginalData(void *CloakHandle, BYTE **OriginalData, DWORD *Length)
Returns the original data of a cloaked region.
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
#define for_each_detour(_var_name)
Iterates the linked list in gDetours.
PAPI_HOOK_DESCRIPTOR Descriptor
The hook descriptor for which this hook was set.
static INTSTATUS IntDetCreateObjectLix(QWORD FunctionAddress, const LIX_FN_DETOUR *FnDetour, LIX_GUEST_DETOUR *DetourStruct, DETOUR **Detour)
Create a DETOUR structure using the information from LIX_FN_DETOUR.
HYPERCALL_TYPE HypercallType
The type of the hypercall that this detour uses.
INTRO_MODULE Module
The module that modified the monitored region.
#define IN_RANGE_LEN(x, start, len)
Must always be the last one.
struct _DETOURS_STATE DETOURS_STATE
Holds information about the currently set detours.
QWORD VirtualAddress
The guest virtual address which was modified.
#define INT_STATUS_INVALID_PARAMETER_4
QWORD Ssdt
Guest virtual address of the SSDT structure inside the kernel.
INTSTATUS IntDecDecodeInstructionFromBuffer(PBYTE Buffer, size_t BufferSize, IG_CS_TYPE CsType, void *Instrux)
Decode an instruction from the provided buffer.
INTRO_VIOLATION_HEADER Header
The alert header.
INTSTATUS IntMemClkModifyOriginalData(void *CloakHandle, DWORD Offset, DWORD Size, void *Data)
Modifies the internal copy of the original data buffer held by a cloak region.
#define HpFreeAndNullWithTag(Add, Tag)
#define INT_STATUS_INVALID_INTERNAL_STATE
#define DETOUR_MAX_HANDLER_SIZE
The maximum size of a in-guest detour handler.
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.
QWORD KernelVa
The guest virtual address at which the kernel image.
const LIX_FN_DETOUR gLixHookHandlersx64[]
An array that contains the descriptors about the function that will be hooked (see lixapi...
void IntDetUninit(void)
Uninitializes the detour module.
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
BOOLEAN gRipInsideRtlpVirtualUnwindReloc
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
#define INT_STATUS_NO_DETOUR_EMU
Signals that no emulation is needed for this event.
BOOLEAN IntDetIsPtrInRelocatedCode(QWORD Ptr, DETOUR_TAG *Tag)
Checks if a guest pointer is inside the modified prologue of a function.
QWORD FunctionAddress
The guest virtual address of the hooked function.
#define ALERT_FLAG_NOT_RING0
If set, the alert was triggered in ring 1, 2 or 3.
static void InitializeListHead(LIST_ENTRY *ListHead)
INTSTATUS IntVirtMemSafeWrite(QWORD Cr3, QWORD VirtualAddress, DWORD Size, void *Buffer, DWORD Ring)
Safely modify guest memory.
static void IntDetRemoveHandler(DETOUR *Detour)
Removes a detour handler from the guest.
QWORD IntDetRelocatePtrIfNeeded(QWORD Ptr)
Returns the new value Ptr should have if it is currently pointing inside a relocated prologue...
#define UNREFERENCED_PARAMETER(P)
INTSTATUS IntSlackFree(QWORD Buffer)
Free slack space.
DWORD HandlerSize
The size of the detour handler.
WCHAR Name[ALERT_PATH_MAX_LEN]
NULL-terminated string with a human readable description of the modified object.
#define DETOUR_MAX_FUNCTION_SIZE
The maximum size of the original function code we will replace.
DWORD KernelBufferSize
The size of the KernelBuffer.
PDETOUR LixDetourTable[det_max_id]
Table of detours, indexed by DETOUR_TAG (linux).
LIST_ENTRY Link
The link inside the DETOURS_STATE.DetoursList list.
BOOLEAN Valid
Set to True if the information in the structure is valid, False otherwise.
#define INT_STATUS_INVALID_PARAMETER_6
BYTE JumpBackOffset
Offset, relative to HandlerAddress, where the jump that returns control to the hooked function is fou...
enum _INTRO_ACTION INTRO_ACTION
Event actions.
INTSTATUS IntDetGetAddrAndTag(QWORD Ptr, QWORD *Address, DWORD *Size, DETOUR_TAG *Tag)
Checks if Ptr is inside a detour handler and returns the detour's handler address, size and tag.
INTRO_WRITE_INFO WriteInfo
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
BYTE Data[32]
The replacement data which follows to be written.
INTSTATUS IntLixDrvIsLegitimateTextPoke(void *Hook, QWORD Address, LIX_ACTIVE_PATCH *ActivePatch, INTRO_ACTION *Action)
This function checks if the modified zone by the current instruction is a 'text_poke'.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
GUEST_STATE gGuest
The current guest state.
THS_PTR_TYPE
The type of pointer to be checked.
LIST_HEAD DetoursList
List of detours. Each entry is a DETOUR structure.
QWORD ModuleBase
The guest virtual address of the base of the kernel module that owns the hooked function.
BYTE PublicDataOffset
The offset at which the data is available inside the detour handler.
#define DETOUR_INVALID_HYPERCALL
Used to specify that no hypercall is present in the detour handler so the HypercallOffset field insid...
EVENT_INTEGRITY_VIOLATION Integrity
BYTE RelocatedCodeLength
The size of the relocated code.
void * HandlerCloakHandle
The memory cloak handle used to hide the detour handler. See Memory cloaking.
struct _EVENT_INTEGRITY_VIOLATION::@302 Originator
INTRO_ACTION Action
The action that was taken as the result of this alert.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
KERNEL_DRIVER * IntDriverFindByAddress(QWORD Gva)
Returns the driver in which Gva resides.
static void IntDetRemoveDetour(DETOUR *Detour)
Removes and frees a detour.
const LIX_FN_DETOUR * LixFnDetour
QWORD BaseAddress
The guest virtual address at which the monitored integrity region starts.
#define LIST_HEAD_INIT(Name)
INTSTATUS IntKernVirtMemPatchQword(QWORD GuestVirtualAddress, QWORD Data)
Writes 8 bytes in the guest kernel memory.
static void IntDetPermanentlyDisableDetour(DETOUR *Detour)
Removes a detour from the guest.
#define INT_STATUS_NOT_INITIALIZED_HINT
BYTE * KernelBuffer
A buffer containing the entire kernel image.
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
#define INT_STATUS_INVALID_PARAMETER_1
#define INT_STATUS_NOT_SUPPORTED
INTSTATUS IntMemClkUncloakRegion(void *CloakHandle, DWORD Options)
Removes a cloak region, making the original memory contents available again to the guest...
VCPU_STATE * gVcpu
The state of the current VCPU.
PFUNC_LixDetourCallback Callback
Callback to be invoked when the detour issues a hypercall.
Sent for integrity violation alerts. See EVENT_INTEGRITY_VIOLATION.
static INTSTATUS IntDetHandleWrite(void *Hook, QWORD PhysicalAddress, QWORD RegionVirtualAddress, void *CloakHandle, INTRO_ACTION *Action)
Handle the writes over bytes modified from detoured function.
BYTE PublicDataSize
The size of the data.
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
INTSTATUS IntDetGetArguments(void const *Detour, DWORD Argc, QWORD *Argv)
Reads multiple arguments from a detour.
DETOUR_TAG
Unique tag used to identify a detour.
QWORD Gva
The start of the region which follows to be patched.
static INTSTATUS IntDetPatchFunction(DETOUR *Detour, BYTE *FunctionCode, DWORD FunctionSize)
Patch the first instruction of the function with a 'JMP' to our handler.
#define DET_ARG_ON_STACK(Arg)
Checks if the argument should be taken from the guest stack.
void IntAlertFillWinKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves kernel module information inside an alert.
BOOLEAN Disabled
True if this detour has been disabled.
void IntDetDumpDetours(void)
Prints all the detours in the gDetours list of detours.
unsigned long long JumpBack
#define INT_STATUS_INVALID_PARAMETER_2
INTSTATUS IntDetSetHook(QWORD FunctionAddress, QWORD ModuleBase, API_HOOK_DESCRIPTOR *Descriptor, API_HOOK_HANDLER *Handler)
Will inject code inside the guest.
WCHAR * utf8toutf16(WCHAR *Destination, const char *Source, DWORD DestinationMaxLength)
BYTE RelocatedCodeOffset
Offset, relative to HandlerAddress, where the prologue that has been replaced by our jump at the begi...
#define DET_ARGS_MAX
The maximum number of arguments passed from the guest to introcore.
Describes a function to be hooked.
void IntDisasmBuffer(void *Buffer, DWORD Length, QWORD Rip)
This function disassembles a given code buffer and then dumps the instructions (textual disassembly)...
The detour will use a VMCALL instruction in order to notify introcore about an event.
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
#define INT_STATUS_INVALID_DATA_SIZE
BOOLEAN IntDetIsPtrInHandler(QWORD Ptr, THS_PTR_TYPE Type, DETOUR_TAG *Tag)
Checks if a guest pointer is inside a detour handler.
DETOUR_TAG Tag
Detour tag.
static INTSTATUS IntDetRelocate(DETOUR *Detour, BYTE *FunctionCode, DWORD FunctionSize, DWORD *InstrCount)
Relocate the over-written instruction from detoured function.
#define INT_STATUS_INSUFFICIENT_RESOURCES
#define DET_ARG_REGS(Arg)
Checks if the argument should be taken from the guest general purpose registers.
Describes a Linux-function to be hooked.
#define INT_STATUS_INVALID_PARAMETER_3