[英]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);
現在,我不想每次需要從此內存中進行寫入/讀取時都發出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;
這將用於將虛擬地址從內核空間返回到用戶空間。
在我使用的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中,我們將找到由內核空間創建和共享的內存區域,內核和用戶程序可以直接訪問該區域。
我沒有寫過,但是我們需要記住將整個MmGetSystemAddressForMdlSafe(...)-----> RtlCopyMemory(...)包裝在Try ... Except塊中,因為我們在這里可能會遇到各種問題,最終會導致BugCheck,因此比后悔更安全。 無論如何,如果您在檢查的環境中編譯此類代碼,Microsoft AutocodeReview將指出這一點。
如果有人需要更多說明,或者我寫錯了,請告訴我,我很樂意修改此帖子。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.