4d61726b / VirtualKD-Redux

VirtualKD-Redux - A revival and modernization of VirtualKD
GNU Lesser General Public License v2.1
777 stars 136 forks source link

KD cannot connect to the virtual machine on the latest 22621 #45

Closed AppleSky6 closed 1 year ago

AppleSky6 commented 2 years ago

The reason may be Microsoft( https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/ )As a result of the randomization of SharedUserData , the content on SharedUserData does not have the write attribute, and the content with the write attribute is mapped to the MmWriteableSharedUserData address (they all point to the same physical memory at the same time, and the address is randomized with the MiProtectSharedUserPage function. Therefore, the kdreceivepacket function should not be used directly.This is my suggestion for change. I'm sorry my English is very poor.

static PKUSER_SHARED_DATA NtSharedUserData = SharedUserData; static PKUSER_SHARED_DATA *KdvmSharedUserData = &NtSharedUserData;

NTSTATUS SearchPattern(IN const UCHAR pattern, IN UCHAR wildcard, IN ULONG_PTR len, IN const VOID base, IN ULONG_PTR size, OUT PVOID *ppFound) { ASSERT(ppFound != NULL && pattern != NULL && base != NULL); if (ppFound == NULL || pattern == NULL || base == NULL) return STATUS_INVALID_PARAMETER;

for (ULONG_PTR i = 0; i < size - len; i++)
{
    BOOLEAN found = TRUE;
    for (ULONG_PTR j = 0; j < len; j++)
    {
        if (pattern[j] != wildcard && pattern[j] != ((const UCHAR *)base)[i + j])
        {
            found = FALSE;
            break;
        }
    }

    if (found != FALSE)
    {
        *ppFound = (PUCHAR)base + i;
        return STATUS_SUCCESS;
    }
}

return STATUS_NOT_FOUND;

}

NTSTATUS GetMmWriteableSharedUserData() { NTSTATUS status = STATUS_SUCCESS; PCHAR resultPtr = NULL; UNICODE_STRING routineName; PVOID FsRtlDismountComplete = NULL;

RtlUnicodeStringInit(&routineName, L"FsRtlDismountComplete");
FsRtlDismountComplete = MmGetSystemRoutineAddress(&routineName);
if(FsRtlDismountComplete == NULL)
    return STATUS_SUCCESS;

status = SearchPattern((const UCHAR*) "\x48\x8B\x05", 0xff, 3, FsRtlDismountComplete, 0x16, (PVOID*)&resultPtr);
if (NT_SUCCESS(status) == TRUE)
{
    // MmWriteableSharedUserData
    KdvmSharedUserData = (PKUSER_SHARED_DATA *)(resultPtr + (ULONG_PTR)(*(PULONG)(resultPtr + 3)) + 7);
}
return STATUS_SUCCESS;

}

4d61726b commented 1 year ago

Thanks for reporting this bug!

I had some free time last weekend and triaged the issue. I appreciate you posting your implementation of finding the writable KUSER_SHARED_DATA page.

I reversed the kdcom dll that ships with 22621 and discovered an easier way to modify that page of memory. Instead of searching for the page, VirtualKD-Redux can use RtlSetSystemGlobalData, a new function that is exported from ntoskrnl. Take a look at commit 1a2babfd4d3df1ea574d41d9f733c21d5b330c7c to see how I did this.

I went ahead and released VirtualKD-Redux 2022.1 which adds support for build 22621 and beyond.