22 #define DETOUR_MAX_FUNCTION_SIZE 24 52 #define for_each_detour(_var_name) list_for_each (gDetours.DetoursList, DETOUR, _var_name) 74 if (!Detour->LixFnDetour)
79 TRACE(
"[DETOUR] Disabling detour - Function name : %s, Hijack function name: %s\n", Detour->LixFnDetour->FunctionName,
80 Detour->LixFnDetour->HijackFunctionName != NULL ? Detour->LixFnDetour->HijackFunctionName :
"none");
82 Detour->Disabled =
TRUE;
87 ERROR(
"[ERROR] IntKernVirtMemWrite failed for GVA 0x%016llx with status: 0x%08x\n", Detour->LixGuestDetour, status);
116 BYTE atomic_nop_3[3] = {0x66, 0x66, 0x90};
118 if (NULL == Detour->HandlerCloakHandle)
123 Detour->Disabled =
TRUE;
130 switch (Detour->HypercallType)
134 Detour->HypercallOffset,
140 Detour->HypercallOffset,
141 sizeof(atomic_nop_3),
175 if (NULL == Detour->HandlerCloakHandle)
180 Detour->Disabled =
FALSE;
187 switch (Detour->HypercallType)
191 Detour->HypercallOffset,
197 Detour->HypercallOffset,
224 if (NULL == Detour->FunctionCloakHandle)
231 Detour->FunctionCloakHandle = NULL;
252 if (NULL != Detour->HandlerCloakHandle)
257 Detour->HandlerCloakHandle = NULL;
259 if (0 != Detour->HandlerAddress)
264 Detour->HandlerAddress = 0;
424 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
434 pDetour->
Callback = FnDetour->Callback;
477 BYTE prologueSize = 0;
479 QWORD handlerAddress = Detour->HandlerAddress;
490 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
494 while (prologueSize < 5)
499 FunctionSize - prologueSize,
512 relInstr = NdIsInstruxRipRelative(&instrux);
516 if ((instrux.PrimaryOpCode != 0xe8) &&
517 (instrux.PrimaryOpCode != 0xe9) &&
518 (instrux.PrimaryOpCode != 0x89) &&
519 (instrux.PrimaryOpCode != 0x8b) &&
520 (instrux.PrimaryOpCode != 0x80) &&
521 (instrux.Instruction != ND_INS_Jcc || instrux.Length != 6))
523 WARNING(
"[WARNING] RIP relative found at GVA 0x%016llx, can't continue!\n",
524 Detour->FunctionAddress + prologueSize);
531 if (instrux.PrimaryOpCode == 0xe8 || instrux.PrimaryOpCode == 0xe9)
536 calledFunc = Detour->FunctionAddress + prologueSize +
537 SIGN_EX(instrux.RelOffsLength, instrux.RelativeOffset);
539 patched = (
DWORD)(calledFunc - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
540 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.PrimaryOpCode;
542 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 1, &patched, 4);
544 else if (relInstr && (instrux.PrimaryOpCode == 0x8b || instrux.PrimaryOpCode == 0x89))
546 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
548 QWORD movGva = Detour->FunctionAddress + prologueSize +
549 SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
551 DWORD patched = (
DWORD)(movGva - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
553 if (instrux.Rex.Rex != 0)
555 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
556 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
557 handler[Detour->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
559 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 3, &patched, 4);
563 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
564 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
566 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
569 else if (relInstr && instrux.PrimaryOpCode == 0x80)
571 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
573 QWORD cmpGva = Detour->FunctionAddress + prologueSize +
574 SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
576 DWORD patched = (
DWORD)(cmpGva - (handlerAddress + Detour->RelocatedCodeOffset + prologueSize));
578 handler[Detour->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
579 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
581 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
583 handler[Detour->RelocatedCodeOffset + prologueSize + 6] = instrux.InstructionBytes[6];
585 else if (relInstr && instrux.Instruction == ND_INS_Jcc)
587 QWORD target = Detour->FunctionAddress + instrux.Operands[0].Info.RelativeOffset.Rel;
588 DWORD newRel = (
DWORD)(target - (handlerAddress + Detour->RelocatedCodeOffset));
593 handler[Detour->RelocatedCodeOffset + prologueSize] = 0x0F;
594 handler[Detour->RelocatedCodeOffset + prologueSize + 1] = 0x80 | instrux.Predicate;
596 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize + 2, &newRel, 4);
601 memcpy(handler + Detour->RelocatedCodeOffset + prologueSize, FunctionCode + prologueSize, instrux.Length);
604 prologueSize += instrux.Length;
610 ERROR(
"[ERROR] IntVirtMemWrite failed with status: 0x%x.", status);
614 Detour->RelocatedCodeLength = prologueSize;
646 _In_ void *CloakHandle,
672 BYTE *memcloakData = NULL;
673 DWORD memcloakDataSize;
681 if (NULL == CloakHandle)
697 ERROR(
"[ERROR] Detour writes are not being handled on this OS!");
713 WARNING(
"[WARNING] IntLixDrvIsLegitimateTextPoke failed for address 0x%llx. Status: 0x%08x\n",
714 PhysicalAddress, status);
720 ERROR(
"[ERROR] The guest attempted to perform a write inside detour %d with a non-legitimate " 721 "text poke. Will deny!", pActivePatch->
DetourTag);
727 ERROR(
"[ERROR] Detour write handler called, but the ActivePatch is not inside a detour! 0x%llx (+%d)\n",
728 pActivePatch->
Gva, pActivePatch->
Length);
737 ERROR(
"[ERROR] IntMemClkGetOriginalData failed: 0x%08x\n", status);
741 regionOffset = (
DWORD)(pActivePatch->
Gva - RegionVirtualAddress);
743 WARNING(
"[WARNING] The guest is applying a patch with size %d at 0x%llx (+ %d).\n",
744 pActivePatch->
Length, RegionVirtualAddress, regionOffset);
748 relocateAfter = (pActivePatch->
Length == 1);
749 relocateAfter = relocateAfter && (RegionVirtualAddress == pActivePatch->
Gva);
750 relocateAfter = relocateAfter && (memcloakData[regionOffset] == 0xCC);
754 relocateAfter = relocateAfter && (pActivePatch->
Data[0] != 0xCC);
763 ERROR(
"[ERROR] IntMemClkModifyPatchedData failed with status 0x%08x\n", status);
767 TRACE(
"[INFO] Updated memcloak original buffer at 0x%llx. Size: %d\n. ",
768 pActivePatch->
Gva, pActivePatch->
Length);
778 ERROR(
"[ERROR] IntMemClkGetOriginalData failed: 0x%08x\n", status);
782 if (memcloakDataSize < pDet->RelocatedCodeLength)
787 ERROR(
"[ERROR] Cloaked region size for detour %d is smaller than the relocated code length (%d vs %d)!\n",
799 ERROR(
"[ERROR] Failed to relocate patch for detour %d. Status: 0x%08x\n\n",
838 QWORD handlerAddress = 0;
842 handlerAddress = Detour->HandlerAddress;
844 functionDetour[0] = 0xE9;
845 *(
DWORD *)(functionDetour + 1) = (
DWORD)(handlerAddress - (Detour->FunctionAddress + 5));
847 for (
DWORD i = 5; i < Detour->RelocatedCodeLength; i++)
849 functionDetour[i] = 0x90;
854 Detour->RelocatedCodeLength,
859 &Detour->FunctionCloakHandle);
862 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
906 DWORD relInstrCount = 0;
909 if (FunctionAddress == 0)
914 if (FnDetour == NULL)
919 status =
IntKernVirtMemRead(FunctionAddress,
sizeof(functionCode), functionCode, NULL);
922 ERROR(
"[ERROR] IntKernVirtMemRead failed with status: 0x%08x\n", status);
929 ERROR(
"[ERROR] IntDetCreateObjectLix failed with status: 0x%08x.", status);
934 status =
IntDetRelocate(pDetour, functionCode,
sizeof(functionCode), &relInstrCount);
937 ERROR(
"[WARNING] IntDetRelocate failed with status: 0x%08x.", status);
941 *MultipleInstructions =
FALSE;
942 if (relInstrCount > 1)
944 *MultipleInstructions =
TRUE;
950 ERROR(
"[ERROR] IntDetPatchFunction failed with status: 0x%08x.", status);
961 ERROR(
"[ERROR] IntKernVirtMemWrite failed with status: 0x%08x\n", status);
969 LOG(
"[DETOUR] %llx: handler @ %llx (%s)\n",
1046 DWORD prologueSize, newJumpBackOffset, totalHandlerSize, i;
1050 if (NULL == Descriptor)
1060 if (NULL == Handler)
1065 if (0 == ModuleBase)
1070 if (FunctionAddress)
1077 DWORD funOffset = (
DWORD)(FunctionAddress - ModuleBase);
1081 ERROR(
"[ERROR] Function not inside kernel buffer. Offset: 0x%08x, size: 0x%08zx, buffer size: 0x%08x\n",
1093 ERROR(
"[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
1099 if (origFn[0] == 0xE9)
1101 WARNING(
"[INFO] API function already detoured (0x%016llx), don't know by who! Aborting!\n",
1108 while (prologueSize < 5)
1111 sizeof(origFn) - prologueSize,
1119 prologueSize += instrux.Length;
1123 totalHandlerSize = Handler->CodeLength + prologueSize;
1125 if (
sizeof(newHnd) < totalHandlerSize)
1127 ERROR(
"[ERROR] The size of the handler exceeds %zu bytes: %d!\n",
sizeof(newHnd), totalHandlerSize);
1132 if (NULL == pDetour)
1140 ERROR(
"[ERROR] IntSlackAlloc failed: 0x%08x\n", status);
1141 goto cleanup_and_exit;
1144 if (NULL != Descriptor->PreCallback)
1146 status = Descriptor->PreCallback(FunctionAddress, Handler, pDetour->
HandlerAddress);
1149 ERROR(
"[ERROR] PreCallback for hook %d (`%s!%s`) failed: 0x%08x\n",
1150 Descriptor->Tag,
utf16_for_log(Descriptor->ModuleName), Descriptor->FunctionName, status);
1151 goto cleanup_and_exit;
1155 LOG(
"[INFO] PreCallback for hook %d (`%s!%s`) returned NOT NEEDED. Will skip the hook (critical: %d)\n",
1158 Descriptor->FunctionName,
1159 !Descriptor->NotCritical);
1161 goto cleanup_and_exit;
1168 ERROR(
"[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
1169 goto cleanup_and_exit;
1172 memcpy(newHnd, Handler->Code, totalHandlerSize - prologueSize);
1174 if (0 == FunctionAddress)
1181 while (prologueSize < 5)
1186 sizeof(origFn) - prologueSize,
1191 goto cleanup_and_exit;
1194 relInstr = NdIsInstruxRipRelative(&instrux);
1198 if ((instrux.PrimaryOpCode != 0xe8) &&
1199 (instrux.PrimaryOpCode != 0x89) &&
1200 (instrux.PrimaryOpCode != 0x8b) &&
1201 (instrux.PrimaryOpCode != 0x80) &&
1202 (instrux.PrimaryOpCode != 0x63) &&
1203 (instrux.Instruction != ND_INS_Jcc || instrux.Length != 6))
1205 CHAR insText[ND_MIN_BUF_SIZE] = {0};
1207 NdToText(&instrux, FunctionAddress + prologueSize,
sizeof(insText), insText);
1209 WARNING(
"[WARNING] RIP relative instruction '%s' found at GVA 0x%016llx, can't continue!\n",
1210 insText, FunctionAddress + prologueSize);
1214 goto cleanup_and_exit;
1218 if (instrux.PrimaryOpCode == 0xe8)
1220 QWORD calledFunc = FunctionAddress + prologueSize +
SIGN_EX(instrux.RelOffsLength, instrux.RelativeOffset);
1223 (pDetour->
HandlerAddress + Handler->RelocatedCodeOffset + prologueSize));
1225 newHnd[Handler->RelocatedCodeOffset + prologueSize] = 0xe8;
1226 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 1, &patched, 4);
1228 else if (relInstr && (instrux.PrimaryOpCode == 0x8b || instrux.PrimaryOpCode == 0x89))
1230 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1232 QWORD movGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1235 if (instrux.Rex.Rex != 0)
1237 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1238 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1239 newHnd[Handler->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
1241 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 3, &patched, 4);
1245 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1246 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1248 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
1251 else if (relInstr && instrux.PrimaryOpCode == 0x80)
1253 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1255 QWORD cmpGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1258 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1259 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1261 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &patched, 4);
1263 newHnd[Handler->RelocatedCodeOffset + prologueSize + 6] = instrux.InstructionBytes[6];
1265 else if (relInstr && instrux.Instruction == ND_INS_Jcc)
1267 QWORD target = FunctionAddress + instrux.Operands[0].Info.RelativeOffset.Rel;
1273 newHnd[Handler->RelocatedCodeOffset + prologueSize] = 0x0F;
1274 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = 0x80 | instrux.Predicate;
1276 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &newRel, 4);
1278 else if (relInstr && instrux.PrimaryOpCode == 0x63)
1280 DWORD relOp = (instrux.Operands[0].Type == ND_OP_MEM) ? 0 : 1;
1281 QWORD crtInstruxGva = FunctionAddress + prologueSize +
SIGN_EX(4, instrux.Operands[relOp].Info.Memory.Disp);
1285 if (instrux.Rex.Rex != 0)
1287 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1288 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1289 newHnd[Handler->RelocatedCodeOffset + prologueSize + 2] = instrux.InstructionBytes[2];
1292 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 3, &crtInstruxPatch, 4);
1296 newHnd[Handler->RelocatedCodeOffset + prologueSize] = instrux.InstructionBytes[0];
1297 newHnd[Handler->RelocatedCodeOffset + prologueSize + 1] = instrux.InstructionBytes[1];
1299 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize + 2, &crtInstruxPatch, 4);
1305 memcpy(newHnd + Handler->RelocatedCodeOffset + prologueSize, origFn + prologueSize, instrux.Length);
1308 prologueSize += instrux.Length;
1315 newJumpBackOffset = Handler->RelocatedCodeOffset + prologueSize;
1318 *(newHnd + newJumpBackOffset) = 0xE9;
1321 newJumpBackOffset + 5));
1324 *(
DWORD *)(newHnd + newJumpBackOffset + 1) += prologueSize - 5;
1330 for (i = 5; i < prologueSize; i++)
1337 pDetour->
Tag = Descriptor->Tag;
1339 pDetour->
Callback = Descriptor->Callback;
1344 Handler->HypercallOffset;
1368 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
1369 goto cleanup_and_exit;
1372 if (FunctionAddress)
1384 ERROR(
"[ERROR] IntMemClkCloackRegion failed: 0x%08x\n", status);
1385 goto cleanup_and_exit;
1394 TRACE(
"[DETOUR] Hooked function @ 0x%016llx, handler @ 0x%016llx, hypercall @ 0x%016llx\n",
1407 TRACE(
"[INFO] Will ensure that SSDT isn't in our detours!\n");
1412 WARNING(
"[WARNING] SSDT 0x%016llx (%d services) is in the same page (function) as detour %d \n",
1419 WARNING(
"[WARNING] SSDT 0x%016llx (%d services) is in the same page (handler) as detour %d \n",
1431 if (NULL != Descriptor->PostCallback)
1433 status = Descriptor->PostCallback(Handler);
1436 WARNING(
"[ERROR] PostCallback for hook %d (`%s!%s`) failed: 0x%08x\n",
1437 Descriptor->Tag,
utf16_for_log(Descriptor->ModuleName), Descriptor->FunctionName, status);
1476 if (NULL == Registers)
1481 ERROR(
"[ERROR] IntGetGprs failed: 0x%08x\n", status);
1488 switch (Detour->HypercallType)
1491 Registers->Rax = ReturnValue;
1495 Registers->Rsi = ReturnValue;
1500 ERROR(
"[DETOUR] Invalid hypercall type %d ...", Detour->HypercallType);
1508 ERROR(
"[ERROR] IntSetGprs failed: 0x%08x\n", status);
1577 pDet->HypercallAddress == 0 ||
1579 pDet->Callback == NULL)
1584 if (!pDet->Disabled)
1589 status = pDet->Callback(pDet);
1608 LOG(
"[DETOUR] Removing detour with tag %d\n", pDetour->
Tag);
1615 WARNING(
"[WARNING] The detour uses vmcall as a hypercall. Cannot remove and set RIP ...");
1621 LOG(
"[DETOUR] Removing detour with tag %d and setting RIP[%d] on 0x%016llx\n",
1647 _In_ void const *Data,
1649 _In_ char const *PublicDataName
1693 if (NULL == PublicDataName)
1718 if (NULL == pPublicData)
1728 LOG(
"[DETOUR] Will modify patched data for public data %s at offset %d with size %u\n",
1734 ERROR(
"[ERROR] IntMemClkModifyPatchedData failed: 0x%08x\n", status);
1783 memzero(&gDetours,
sizeof(gDetours));
1796 LOG(
"[DBGINTRO] Introspection detours:\n");
1800 char *pFnName = NULL;
1803 if (pDetour->LixFnDetour != NULL)
1805 pFnName = pDetour->LixFnDetour->FunctionName;
1807 else if (pDetour->Descriptor != NULL)
1809 pFnName = pDetour->Descriptor->FunctionName;
1814 pFnName = pDetour->Descriptor != NULL ? pDetour->Descriptor->FunctionName : NULL;
1817 LOG(
" ## %-32s Hits: %12llu, RIP: %llx, Tag: %02d, Handler RIP: %llx (+ %02x), Hooked RIP: %llx\n",
1818 pFnName != NULL ? pFnName :
"unknown",
1820 pDetour->HypercallAddress,
1822 pDetour->HandlerAddress,
1823 pDetour->HandlerSize,
1824 pDetour->FunctionAddress);
1828 LOG(
" Module: %llx\n",
1829 pDetour->ModuleBase);
1852 if (Ptr >= pDet->FunctionAddress &&
1853 Ptr < pDet->FunctionAddress + pDet->RelocatedCodeLength)
1905 if ((Ptr >= pDet->HandlerAddress) && (Ptr < pDet->HandlerAddress + pDet->HandlerSize))
1907 WARNING(
"[WARNING] Found %s ptr 0x%016llx in detours: handler RIP 0x%016llx, hook RIP 0x%016llx\n",
1908 Type ==
ptrLiveRip ?
"live RIP" :
"stack value", Ptr, pDet->HandlerAddress, pDet->FunctionAddress);
1917 if (Ptr < pDet->HandlerAddress + pDet->RelocatedCodeOffset)
1919 gRipInsideRtlpVirtualUnwindReloc =
TRUE;
1955 if ((Ptr > pDetour->FunctionAddress) &&
1956 (Ptr < pDetour->FunctionAddress + pDetour->RelocatedCodeLength))
1958 return pDetour->HandlerAddress + pDetour->RelocatedCodeOffset + (Ptr - pDetour->FunctionAddress);
1988 if ((Ptr > pDetour->HandlerAddress) &&
1989 (Ptr < pDetour->HandlerAddress + pDetour->HandlerSize))
1991 *Address = pDetour->HandlerAddress;
1992 *Size = pDetour->HandlerSize;
1993 *Tag = pDetour->Tag;
2059 BOOLEAN haveStackBuffer = StackBuffer && StackBufferSize;
2067 if (haveStackBuffer && stackOffset +
gGuest.
WordSize <= StackBufferSize)
2071 *Value = *(
DWORD const *)(StackBuffer + stackOffset);
2075 *Value = *(
QWORD const *)(StackBuffer + stackOffset);
2085 ERROR(
"[ERROR] IntKernVirtMemRead failed for %llx: 0x%08x\n", pRegs->
Rsp + stackOffset, status);
2092 *Value = ((
QWORD const *)pRegs)[Arg];
2096 ERROR(
"[ERROR] Invalid argument type: 0x%08x\n", Arg);
2106 _In_ void const *Detour,
2165 _In_ void const *Detour,
2190 BYTE stackBuffer[256];
2194 DWORD stackBufferSize = 0;
2195 BYTE const *pStackBuffer = NULL;
2224 ERROR(
"[ERROR] Requested to read %u arguments for for detour %d, but only %u exist.\n",
2229 for (
DWORD i = 0; i < argc; i++)
2237 if (stackBufferSize)
2245 stackBufferSize =
MIN(stackBufferSize,
sizeof(stackBuffer));
2250 WARNING(
"[WARNING] IntKernVirtMemRead failed for [0x%016llx, 0x%016llx]: 0x%08x\n",
2251 rsp, rsp + stackBufferSize, status);
2252 stackBufferSize = 0;
2257 pStackBuffer = stackBuffer;
2261 for (
DWORD i = 0; i < argc; i++)
2268 ERROR(
"[ERROR] IntDetGetArgument failed for %u: 0x%08x\n", i, status);
2279 _In_ void const *Detour,
2332 ERROR(
"[ERROR] IntVirtMemSafeWrite failed: 0x%08x\n", status);
2338 ((
QWORD *)pRegs)[arg] = Value;
2343 ERROR(
"[ERROR] IntSetGprs failed: 0x%08x\n", status);
2349 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.
BYTE NrPublicDataOffsets
The number of valid entries inside the PublicDataOffsets array.
DWORD Argc
The number of valid entries inside the Argv array.
#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
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
#define INT_STATUS_REMOVE_DETOUR_AND_SET_RIP
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.
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.
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.
INTSTATUS IntVirtMemWrite(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer)
Writes data to a guest virtual memory range.
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)
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 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.
#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.
static __default_fn_attr size_t vmcall(DETOUR_ID id)
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.
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.
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.
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.
#define INT_STATUS_NOT_INITIALIZED
DWORD Argv[DET_ARGS_MAX]
Argument encoding. See DET_ARG_REGS and DET_ARG_ON_STACK.
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.
#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.
#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.
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.
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.
#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.
#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.
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.
struct _LINUX_GUEST::@125::@128 Detour
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...
BYTE RelocatedCodeLength
The size of the relocated code.
void * HandlerCloakHandle
The memory cloak handle used to hide the detour handler. See Memory cloaking.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
static void IntDetRemoveDetour(DETOUR *Detour)
Removes and frees a detour.
const LIX_FN_DETOUR * LixFnDetour
#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.
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.
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
struct _LINUX_GUEST::@125 MmAlloc
#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.
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