从用户模式访问内核内存 (Windows)
Accessing kernel memory from user mode (Windows)
我正在编写一个需要分配非分页内存池的驱动程序,为了性能起见,该内存必须可以直接从用户模式程序访问。
在驱动程序条目中,我使用以下两种方法分配了一些内存:
pMdl = IoAllocateMdl(NULL,
4096,
FALSE,
FALSE,
NULL);
if(!pMdl) {
DbgPrintEx(DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "Error on IoAllocateMdl. Returning from driver early.\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool(pMdl);
userMemory = (void *)MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmWriteCombined, NULL, FALSE, LowPagePriority);
和
userMemory = ExAllocatePoolWithTag(
NonPagedPool,
4096,
POOL_TAG);
现在我不想每次需要从这个内存中 write/read 时发出 DeviceIoControl,而是我想做这样的事情:
char* sharedMem;
.....
transactionResult = DeviceIoControl ( hDevice,
(DWORD) IOCTL_MMAP,
NULL,
0,
sharedMem,
sizeof(int),
&bRetur,
NULL
);
.....
sharedMem[0]='c';
使用DeviceIoControl获取内核内存中的地址然后直接使用,就像Linux下的mmap一样。
在 Windows 中有什么方法可以做到这一点吗?
我已经这样做了:
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // Read/write access
TRUE,
"Global\SharedMemory"); // Name of mapping object
lastError = GetLastError();
if (hMapFile == NULL)
{
printf("Could not create file mapping object (%d).\n" ,GetLastError());
return 1;
}
pBuf = (char*)MapViewOfFile(hMapFile, // Handle to map object
FILE_MAP_ALL_ACCESS, // Read/write permission
0,
0,
4096);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
pBuf[0] = 'c';
pBuf[1] = '\n';
CloseHandle(hMapFile);
我在内核中创建了这样的视图:
RtlInitUnicodeString(&name, L"\BaseNamedObjects\SharedMemory");
InitializeObjectAttributes(&oa, &name, 0, 0, NULL);
ZwCreateSection(&hsection, SECTION_ALL_ACCESS, &oa, &Li, PAGE_READWRITE, SEC_COMMIT, NULL);
ZwMapViewOfSection(hsection, NtCurrentProcess(),
&userMem, 0, MEM_WIDTH, NULL,
&j, ViewShare, 0, PAGE_READWRITE);
但是在内核中,当我读取内存时它是空的:怎么可能?
我终于明白这需要如何工作了。
首先,我创建了如下结构。
typedef struct _MEMORY_ENTRY
{
PVOID pBuffer;
} MEMORY_ENTRY, *PMEMORY_ENTRY;
这将用于return从内核space到用户space的虚拟地址。
在我使用的DriverEntry中
userMem = ExAllocatePoolWithTag(NonPagedPool,
MEM_WIDTH,
POOL_TAG );
设置非分页内存。
然后我创建了一个在 DIRECT_OUT 模式下工作的 IOCTL,它执行以下代码片段:
...
PMDL mdl = NULL;
PVOID buffer = NULL;
MEMORY_ENTRY returnedValue;
void* UserVirtualAddress = NULL;
...
buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); // Gets safely the pointer for the output in the IRP
mdl = IoAllocateMdl(userMem, MEM_WIDTH, FALSE, FALSE, NULL); // Allocate the memory descriptor list
MmBuildMdlForNonPagedPool(mdl); // This is needed when we're managing NonPaged memory
UserVirtualAddress = MmMapLockedPagesSpecifyCache(
mdl,
UserMode,
MmNonCached,
NULL,
FALSE,
NormalPagePriority); // Return the virtual address in the context of
// the user space program who called the IOCTL
returnedValue.pBuffer = UserVirtualAddress;
RtlCopyMemory(buffer,
&returnedValue,
sizeof(PVOID)); // I copy the virtual address in the structure that will
// be returned to the user mode program by the IRP
在用户态程序中我只需要这样做
transactionResult = DeviceIoControl(
hDevice,
(DWORD) IOCTL_MMAP,
NULL,
0,
sharedMem,
sizeof(void*),
&bRetur,
NULL
);
在(MEMORY_ENTRY*)sharedMem->pBuffer中我们会发现内核创建和共享的内存区域space可以直接被内核和用户程序访问
我还没有写,但我们需要记住将整个 MmGetSystemAddressForMdlSafe(...)----->RtlCopyMemory(...) 包装在一个 Try...Except 块中,因为我们可能会遇到这里的各种问题最终可能会导致 BugCheck,所以安全总比后悔好。
无论如何,如果您在经过检查的环境中编译此类代码,Microsoft AutocodeReview 会指出这一点。
如果有人需要更多说明,或者我写错了什么,请告诉我,我很乐意修改 post。
我正在编写一个需要分配非分页内存池的驱动程序,为了性能起见,该内存必须可以直接从用户模式程序访问。
在驱动程序条目中,我使用以下两种方法分配了一些内存:
pMdl = IoAllocateMdl(NULL,
4096,
FALSE,
FALSE,
NULL);
if(!pMdl) {
DbgPrintEx(DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "Error on IoAllocateMdl. Returning from driver early.\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool(pMdl);
userMemory = (void *)MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmWriteCombined, NULL, FALSE, LowPagePriority);
和
userMemory = ExAllocatePoolWithTag(
NonPagedPool,
4096,
POOL_TAG);
现在我不想每次需要从这个内存中 write/read 时发出 DeviceIoControl,而是我想做这样的事情:
char* sharedMem;
.....
transactionResult = DeviceIoControl ( hDevice,
(DWORD) IOCTL_MMAP,
NULL,
0,
sharedMem,
sizeof(int),
&bRetur,
NULL
);
.....
sharedMem[0]='c';
使用DeviceIoControl获取内核内存中的地址然后直接使用,就像Linux下的mmap一样。
在 Windows 中有什么方法可以做到这一点吗?
我已经这样做了:
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // Read/write access
TRUE,
"Global\SharedMemory"); // Name of mapping object
lastError = GetLastError();
if (hMapFile == NULL)
{
printf("Could not create file mapping object (%d).\n" ,GetLastError());
return 1;
}
pBuf = (char*)MapViewOfFile(hMapFile, // Handle to map object
FILE_MAP_ALL_ACCESS, // Read/write permission
0,
0,
4096);
if (pBuf == NULL)
{
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
pBuf[0] = 'c';
pBuf[1] = '\n';
CloseHandle(hMapFile);
我在内核中创建了这样的视图:
RtlInitUnicodeString(&name, L"\BaseNamedObjects\SharedMemory");
InitializeObjectAttributes(&oa, &name, 0, 0, NULL);
ZwCreateSection(&hsection, SECTION_ALL_ACCESS, &oa, &Li, PAGE_READWRITE, SEC_COMMIT, NULL);
ZwMapViewOfSection(hsection, NtCurrentProcess(),
&userMem, 0, MEM_WIDTH, NULL,
&j, ViewShare, 0, PAGE_READWRITE);
但是在内核中,当我读取内存时它是空的:怎么可能?
我终于明白这需要如何工作了。
首先,我创建了如下结构。
typedef struct _MEMORY_ENTRY
{
PVOID pBuffer;
} MEMORY_ENTRY, *PMEMORY_ENTRY;
这将用于return从内核space到用户space的虚拟地址。
在我使用的DriverEntry中
userMem = ExAllocatePoolWithTag(NonPagedPool,
MEM_WIDTH,
POOL_TAG );
设置非分页内存。
然后我创建了一个在 DIRECT_OUT 模式下工作的 IOCTL,它执行以下代码片段:
...
PMDL mdl = NULL;
PVOID buffer = NULL;
MEMORY_ENTRY returnedValue;
void* UserVirtualAddress = NULL;
...
buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); // Gets safely the pointer for the output in the IRP
mdl = IoAllocateMdl(userMem, MEM_WIDTH, FALSE, FALSE, NULL); // Allocate the memory descriptor list
MmBuildMdlForNonPagedPool(mdl); // This is needed when we're managing NonPaged memory
UserVirtualAddress = MmMapLockedPagesSpecifyCache(
mdl,
UserMode,
MmNonCached,
NULL,
FALSE,
NormalPagePriority); // Return the virtual address in the context of
// the user space program who called the IOCTL
returnedValue.pBuffer = UserVirtualAddress;
RtlCopyMemory(buffer,
&returnedValue,
sizeof(PVOID)); // I copy the virtual address in the structure that will
// be returned to the user mode program by the IRP
在用户态程序中我只需要这样做
transactionResult = DeviceIoControl(
hDevice,
(DWORD) IOCTL_MMAP,
NULL,
0,
sharedMem,
sizeof(void*),
&bRetur,
NULL
);
在(MEMORY_ENTRY*)sharedMem->pBuffer中我们会发现内核创建和共享的内存区域space可以直接被内核和用户程序访问
我还没有写,但我们需要记住将整个 MmGetSystemAddressForMdlSafe(...)----->RtlCopyMemory(...) 包装在一个 Try...Except 块中,因为我们可能会遇到这里的各种问题最终可能会导致 BugCheck,所以安全总比后悔好。 无论如何,如果您在经过检查的环境中编译此类代码,Microsoft AutocodeReview 会指出这一点。
如果有人需要更多说明,或者我写错了什么,请告诉我,我很乐意修改 post。