Skip to content

Instantly share code, notes, and snippets.

Created October 30, 2016 22:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/b5024c25634fc36e699cd9d041224531 to your computer and use it in GitHub Desktop.
Save anonymous/b5024c25634fc36e699cd9d041224531 to your computer and use it in GitHub Desktop.
static bool PatchKdCom()
{
KIRQL OldIrql = KeGetCurrentIrql();
KeLowerIrql(PASSIVE_LEVEL);
// Prevent suspend APCs
KeEnterCriticalRegion();
// Query the size to allocate
PVOID Buffer = NULL;
ULONG Size = 0;
NTSTATUS Status = Undocumented::NtQuerySystemInformation(SystemModuleInformation, Buffer, Size, &Size);
if (Status == STATUS_INFO_LENGTH_MISMATCH)
{
// Get the module info
Buffer = RtlAllocateMemory(false, Size);
Status = Undocumented::NtQuerySystemInformation(SystemModuleInformation, Buffer, Size, &Size);
}
SYSTEM_MODULE_INFORMATION* ModuleInfo = (SYSTEM_MODULE_INFORMATION*)Buffer;
if (!NT_SUCCESS(Status) || ModuleInfo == NULL || ModuleInfo->Count == 0)
{
RtlFreeMemory(Buffer);
return false;
}
SYSTEM_MODULE_ENTRY Entry = { 0 };
bool Found = false;
bool IsVirtualKD = false;
// Walk the loaded modules list
// NB: There are multiple ways to get this list - if using PsLoadedModuleList, the name is always kdcom.dll regardless of what is actually loaded
for (unsigned int i = 0; i < ModuleInfo->Count; ++i)
{
Entry = ModuleInfo->Modules[i];
char* DllName = (char*)(Entry.ImageName + Entry.ModuleNameOffset);
if (_stricmp(DllName, "kdcom.dll") == 0)
{
Log("[TITANHIDE] Found kdcom.dll at 0x%p\r\n", Entry.ImageBase);
Found = true;
break;
}
if (_stricmp(DllName, "kdbazis.dll") == 0)
{
Log("[TITANHIDE] Found kdbazis.dll at 0x%p\r\n", Entry.ImageBase);
Found = true;
IsVirtualKD = true;
break;
}
}
if (!Found)
{
Log("[TITANHIDE] Couldn't find any kdcom module to patch...\r\n");
RtlFreeMemory(Buffer);
return false;
}
// Opcodes to search and patches for various kdcom DLLs
#ifdef _WIN64
UCHAR SearchXPA[] = { 0x0C, 0x02, // or al,2
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR SearchXPB[] = { 0x24, 0xFD, // and al,0FDh
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR Search7_10A[] = { 0x40, 0x0A, 0xC6, // or al,sil
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR Search7_10B[] = { 0x24, 0xFD, // and al,0FDh
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR SearchVboxA[] = { 0x41, 0x0F, 0xB6, 0xC4, // movzx eax,r12b
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR SearchVboxB[] = { 0x41, 0x0F, 0xB6, 0xC6, // movzx eax,r14b
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR SearchVmwareA[] = { 0x0F, 0xB6, 0xC3, // movzx eax,bl
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR SearchVmwareB[] = { 0x0F, 0xB6, 0xC3, // movzx eax,bl
0xA2, 0xD4, 0x02, 0x00, 0x00, 0x80, 0xF7, 0xFF, 0xFF }; // movabs ds:0FFFFF780000002D4h,al
UCHAR PatchXPA[] = { 0x33, 0xC0 }; // xor eax,eax
UCHAR PatchXPB[] = { 0x33, 0xC0 }; // xor eax,eax
UCHAR Patch7_10A[] = { 0x90, 0x33, 0xC0 }; // nop, xor eax,eax
UCHAR Patch7_10B[] = { 0x33, 0xC0 }; // xor eax,eax
UCHAR PatchVboxA[] = { 0x90, 0x90, 0x33, 0xC0 }; // nop, nop, xor eax,eax
UCHAR PatchVboxB[] = { 0x90, 0x90, 0x33, 0xC0 }; // nop, nop, xor eax,eax
UCHAR PatchVmwareA[] = { 0x90, 0x33, 0xC0 }; // nop, xor eax,eax
UCHAR PatchVmwareB[] = { 0x90, 0x33, 0xC0 }; // nop, xor eax,eax
#else // x86
UCHAR SearchXPA[] = { 0x80, 0x0D, 0xD4, 0x02, 0xDF, 0xFF, 0x02, // or byte ptr ds:0FFDF02D4h,2
0x66, 0x33, 0xC0 }; // xor ax,ax
UCHAR SearchXPB[] = { 0x80, 0x25, 0xD4, 0x02, 0xDF, 0xFF, 0xFD }; // and byte ptr ds:0FFDF02D4h,0FDh
UCHAR Search7_10A[] = { 0x80, 0x0D, 0xD4, 0x02, 0xDF, 0xFF, 0x02, // or byte ptr ds:0FFDF02D4h,2
0x33, 0xC0 }; // xor eax,eax
UCHAR Search7_10B[] = { 0x80, 0x25, 0xD4, 0x02, 0xDF, 0xFF, 0xFD }; // and byte ptr ds:0FFDF02D4h,0FDh
UCHAR SearchVboxA[] = { 0xC1, 0xE8, 0x08, // shr eax,8
0xA2, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,al
UCHAR SearchVboxB[] = { 0xC1, 0xEB, 0x08, // shr ebx,8
0x88, 0x1D, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,bl
UCHAR SearchVmwareA[] = { 0xC1, 0xE8, 0x08, // shr eax,8
0xA2, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,al
UCHAR SearchVmwareB[] = { 0xC1, 0xEA, 0x08, // shr edx,8
0x88, 0x15, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,dl
UCHAR PatchXPA[] = { 0x90, 0x90, 0x90, 0x33, 0xC0, // nop, nop, nop, xor eax,eax
0xA2, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,al
UCHAR PatchXPB[] = { 0xC6, 0x05, 0xD4, 0x02, 0xDF, 0xFF, 0x00 }; // mov byte ptr ds:0FFDF02D4h,0
UCHAR Patch7_10A[] = { 0x90, 0x90, 0x33, 0xC0, // nop, nop, xor eax,eax
0xA2, 0xD4, 0x02, 0xDF, 0xFF }; // mov ds:0FFDF02D4h,al
UCHAR Patch7_10B[] = { 0xC6, 0x05, 0xD4, 0x02, 0xDF, 0xFF, 0x00 }; // mov byte ptr ds:0FFDF02D4h,0
UCHAR PatchVboxA[] = { 0x90, 0x33, 0xC0 }; // nop, xor eax,eax
UCHAR PatchVboxB[] = { 0x90, 0x31, 0xDB }; // nop, xor ebx,ebx
UCHAR PatchVmwareA[] = { 0x90, 0x33, 0xC0 }; // nop, xor eax,eax
UCHAR PatchVmwareB[] = { 0x90, 0x31, 0xD2 }; // nop, xor edx,edx
#endif
// Get a safeish address range to search
UINT_PTR Base = (UINT_PTR)Entry.ImageBase;
ULONG FirstSectionVA;
Size = PE::GetMaxVABeforeDirectory((PVOID)Base, IMAGE_DIRECTORY_ENTRY_EXPORT, &FirstSectionVA); // Patch area always precedes export dir
UINT_PTR Start = Base + (UINT_PTR)FirstSectionVA;
UINT_PTR End = Base + (UINT_PTR)Size;
unsigned int NumPatched = 0;
for (UINT_PTR Address = Start; Address < End; ++Address)
{
if (NumPatched >= 2)
break; // Done
__try
{
if (!IsVirtualKD) // kdcom.dll
{
if (memcmp((PVOID)Address, SearchXPA, sizeof(SearchXPA)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchXPA, sizeof(PatchXPA));
NumPatched++;
}
else if (memcmp((PVOID)Address, SearchXPB, sizeof(SearchXPB)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchXPB, sizeof(PatchXPB));
NumPatched++;
}
else if (memcmp((PVOID)Address, Search7_10A, sizeof(Search7_10A)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, Patch7_10A, sizeof(Patch7_10A));
NumPatched++;
}
else if (memcmp((PVOID)Address, Search7_10B, sizeof(Search7_10B)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, Patch7_10B, sizeof(Patch7_10B));
NumPatched++;
}
}
else // kdbazis.dll
{
if (memcmp((PVOID)Address, SearchVboxA, sizeof(SearchVboxA)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchVboxA, sizeof(PatchVboxA));
NumPatched++;
}
else if (memcmp((PVOID)Address, SearchVboxB, sizeof(SearchVboxB)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchVboxB, sizeof(PatchVboxB));
NumPatched++;
}
else if (memcmp((PVOID)Address, SearchVmwareA, sizeof(SearchVmwareA)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchVmwareA, sizeof(PatchVmwareA));
NumPatched++;
}
else if (memcmp((PVOID)Address, SearchVmwareB, sizeof(SearchVmwareB)) == 0)
{
RtlSuperCopyMemory((PVOID)Address, PatchVmwareB, sizeof(PatchVmwareB));
NumPatched++;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Log("[TITANHIDE] Exception %08X while trying to patch kdcom.dll at 0x%p\r\n...", GetExceptionCode(), (PVOID)Address);
break; // No point continuing
}
}
// No need to write to SharedUserData. The kernel debugger interface has already done that for us by now
RtlFreeMemory(Buffer);
KeLeaveCriticalRegion();
if (OldIrql > KeGetCurrentIrql())
KfRaiseIrql(OldIrql);
return NumPatched == 2;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment