Created
October 30, 2016 22:53
-
-
Save anonymous/b5024c25634fc36e699cd9d041224531 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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