简体   繁体   English

从用户模式访问内核内存(Windows)

[英]Accessing kernel memory from user mode (Windows)

I'm writing a driver that needs to allocate a Non Paged pool of memory and this memory, for performance sake, must be directly accessible from a usermode program. 我正在编写一个驱动程序,该驱动程序需要分配一个非分页的内存池,出于性能考虑,必须可以直接从用户模式程序访问该内存。

In the driver entry I've allocated some memory with these two type of methods: 在驱动程序条目中,我使用以下两种类型的方法分配了一些内存:

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);

and

userMemory = ExAllocatePoolWithTag(
                NonPagedPool,
                4096,
                POOL_TAG);

Now I don't want to issue a DeviceIoControl every time I need to write/read from this memory, but instead I want to do something like this: 现在,我不想每次需要从此内存中进行写入/读取时都发出DeviceIoControl,而是我想要执行以下操作:

char* sharedMem;
.....
transactionResult = DeviceIoControl ( hDevice,
                        (DWORD) IOCTL_MMAP,
                        NULL,
                        0,
                        sharedMem,
                        sizeof(int),
                        &bRetur,
                        NULL
                        );
.....
sharedMem[0]='c';

Using a DeviceIoControl to get the address in kernel memory and then using it directly, like it were an mmap under Linux. 使用DeviceIoControl在内核内存中获取地址,然后直接使用它,就像在Linux下是mmap一样。

Is there some kind of way to do this in Windows? 在Windows中有某种方法可以做到这一点吗?

I've done this: 我已经做到了:

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);

And I've created the view in Kernel like this: 我在内核中创建了这样的视图:

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);

But in the kernel when I read the memory it's empty: how can it be? 但是在内核中,当我读取内存时,它是空的:怎么可能呢?

I finally understood how this needs to work. 我终于明白了这是如何工作的。

First I've created a structure like the following. 首先,我创建了如下结构。

typedef struct _MEMORY_ENTRY
{
    PVOID pBuffer;
} MEMORY_ENTRY, *PMEMORY_ENTRY;

This will be used to return the virtual address from the kernel space to the user space. 这将用于将虚拟地址从内核空间返回到用户空间。

In the DriverEntry I used 在我使用的DriverEntry中

userMem = ExAllocatePoolWithTag(NonPagedPool,
                                MEM_WIDTH,
                                POOL_TAG );

to set up the NonPaged memory. 设置非分页内存。

Then I've created an IOCTL working in DIRECT_OUT mode that does the following snippet: 然后,我创建了一个在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

In the user mode program I just needed to to this 在用户模式程序中,我只需要这样做

transactionResult = DeviceIoControl(
                        hDevice,
                        (DWORD) IOCTL_MMAP,
                        NULL,
                        0,
                        sharedMem,
                        sizeof(void*),
                        &bRetur,
                        NULL
                        );

In (MEMORY_ENTRY*)sharedMem->pBuffer we will find the memory area created and shared by the kernel space directly accessible by the kernel and by the user program. 在(MEMORY_ENTRY *)sharedMem-> pBuffer中,我们将找到由内核空间创建和共享的内存区域,内核和用户程序可以直接访问该区域。

I haven't wrote it but we need to remember to wrap the entire MmGetSystemAddressForMdlSafe(...)----->RtlCopyMemory(...) in a Try...Except block because we can encounter various problems here that may eventually cause a BugCheck so better be safe than sorry. 我没有写过,但是我们需要记住将整个MmGetSystemAddressForMdlSafe(...)-----> RtlCopyMemory(...)包装在Try ... Except块中,因为我们在这里可能会遇到各种问题,最终会导致BugCheck,因此比后悔更安全。 Anyway, if you're compiling this kind of code in a checked environment the Microsoft AutocodeReview will be pointing this out. 无论如何,如果您在检查的环境中编译此类代码,Microsoft AutocodeReview将指出这一点。

If someone needs more clarifications, or if I wrote something wrong just let me know and I will be happy to modify this post. 如果有人需要更多说明,或者我写错了,请告诉我,我很乐意修改此帖子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM