Windows NT Driver >> C/C++

Share Memory


參考資訊:
1. Source Code
2. Sharing Memory Between Drivers and Applications

Viking大師有天突然詢問司徒,為何在教學網站上面,沒有任何關於Share Memory的教學呢?這...,大師擺明就是來踢館的,不過,既然Viking大師都開口了,司徒小弟只能趕緊寫一篇關於Device Driver和User Application共享記憶體的使用教學,於是,誕生了這一篇教學。

需求如下:
驅動程式在DriverEntry()時,配置一塊記憶體,接著,User Application可以讀寫這塊記憶體(Device Driver也可以讀寫),User Application的數量不限定,所以,代表多個User Application都可以共享到這一塊記憶體,大家看到的內容都是一樣的。

步驟如下:
1. MmAllocatePagesForMdl()
2. MmMapLockedPagesSpecifyCache()
3. MmUnmapLockedPages()
4. MmFreePagesFromMdl()
5. IoFreeMdl()

這邊有一個東西,值得注意一下,Map Memory的地方,需要在該Process執行的空間上,所以,在DriverEntry()做Map Memory時,User Application是無法存取的,因為DriverEntry()是由系統調度,所以司徒使用兩個IOCTL做Map、Unmap,每個User Application啟動後,就會執行Map Memory的動作,而被Map的Memory則是在DriverEntry()做配置,這樣大家就可以Map到同一塊Memory,達到共享的目的。

main.c

#include <wdm.h>

#define IOCTL_MAP_PTR   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_UNMAP_PTR CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define DEV_NAME L"\\Device\\MyDriver"
#define SYM_NAME L"\\DosDevices\\MyDriver"

PMDL Mdl = NULL;

void Unload(PDRIVER_OBJECT pOurDriver)
{
    UNICODE_STRING usSymboName;

    RtlInitUnicodeString(&usSymboName, L"\\DosDevices\\MyDriver");
    IoDeleteSymbolicLink(&usSymboName);
    IoDeleteDevice(pOurDriver->DeviceObject);
    if(Mdl) {
        MmFreePagesFromMdl(Mdl);
        IoFreeMdl(Mdl);
    }
}

NTSTATUS IrpIOCTL(PDEVICE_OBJECT pOurDevice, PIRP pIrp)
{
    ULONG Len = 0;
    ULONG dwTmp = 0;
    PIO_STACK_LOCATION psk = IoGetCurrentIrpStackLocation(pIrp);

    switch(psk->Parameters.DeviceIoControl.IoControlCode) {
    case IOCTL_UNMAP_PTR:
        DbgPrint("IOCTL_UNMAP_PTR");
        Len = psk->Parameters.DeviceIoControl.InputBufferLength;
        memcpy(&dwTmp, pIrp->AssociatedIrp.SystemBuffer, Len);
        if(dwTmp && Mdl) {
            MmUnmapLockedPages(dwTmp, Mdl);
            DbgPrint("UnmapPtr=0x%x", dwTmp);
        }
        break;
    case IOCTL_MAP_PTR:
        DbgPrint("IOCTL_MAP_PTR");
        if(Mdl) {
            unsigned char *Ptr = NULL;

            dwTmp = Ptr = MmMapLockedPagesSpecifyCache(Mdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
            DbgPrint("Mdl=0x%x, MapPtr=0x%x", Mdl, Ptr);
            Ptr[0] += 1;
        }
        Len = sizeof(PVOID);
        memcpy(pIrp->AssociatedIrp.SystemBuffer, &dwTmp, Len);
        break;
    }
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    pIrp->IoStatus.Information = Len;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS IrpFile(PDEVICE_OBJECT pOurDevice, PIRP pIrp)
{
    PIO_STACK_LOCATION psk = IoGetCurrentIrpStackLocation(pIrp);

    switch(psk->MajorFunction) {
    case IRP_MJ_CREATE:
        DbgPrint("IRP_MJ_CREATE");
        break;
    case IRP_MJ_CLOSE:
        DbgPrint("IRP_MJ_CLOSE");
        break;
    }
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pOurDriver, PUNICODE_STRING pOurRegistry)
{
    SIZE_T TotalBytes;
    PHYSICAL_ADDRESS LowAddress;
    PHYSICAL_ADDRESS HighAddress;

    PDEVICE_OBJECT pOurDevice = NULL;
    UNICODE_STRING usDeviceName;
    UNICODE_STRING usSymboName;

    pOurDriver->MajorFunction[IRP_MJ_CREATE] = IrpFile;
    pOurDriver->MajorFunction[IRP_MJ_CLOSE] = IrpFile;
    pOurDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpIOCTL;
    pOurDriver->DriverUnload = Unload;

    RtlInitUnicodeString(&usDeviceName, L"\\Device\\MyDriver");
    IoCreateDevice(pOurDriver, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pOurDevice);
    RtlInitUnicodeString(&usSymboName, L"\\DosDevices\\MyDriver");
    IoCreateSymbolicLink(&usSymboName, &usDeviceName);
    pOurDevice->Flags &= ~DO_DEVICE_INITIALIZING;
    pOurDevice->Flags |= DO_BUFFERED_IO;

    LowAddress.QuadPart = 0;
    HighAddress.QuadPart = -1;
    TotalBytes = 4096;
    Mdl = MmAllocatePagesForMdl(LowAddress, HighAddress, LowAddress, TotalBytes);
    DbgPrint("Mdl=0x%x", Mdl);
    return STATUS_SUCCESS;
}

app.cpp

#define INITGUID
#include <windows.h>
#include <winioctl.h>
#include <strsafe.h>
#include <setupapi.h>
#include <stdio.h>
#include <stdlib.h>

#define IOCTL_MAP_PTR   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_UNMAP_PTR CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)

int __cdecl main(int argc, char *argv[])
{
    DWORD dwRet = 0;
    HANDLE hFile = NULL;
    unsigned long dwTmp = 0;
    unsigned char *u8Ptr = NULL;

    hFile = CreateFile("\\\\.\\MyDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if(hFile == INVALID_HANDLE_VALUE) {
        printf("failed to open mydriver");
        return 1;
    }
    DeviceIoControl(hFile, IOCTL_MAP_PTR, NULL, 0, &dwTmp, sizeof(dwTmp), &dwRet, NULL);
    u8Ptr = (unsigned char *)dwTmp;
    printf("u8Ptr:0x%x, value:%d\n", u8Ptr, u8Ptr[0]);
    Sleep(10000);
    DeviceIoControl(hFile, IOCTL_UNMAP_PTR, &dwTmp, sizeof(dwTmp), NULL, 0, &dwRet, NULL);
    CloseHandle(hFile);
    return 0;
}

開啟多個User Application後,可以發現Map後的Memory Address都是一樣的,但是,卻不會有問題(即使在不同時間點做Unmap),這是因為在各自Process空間上的緣故


返回上一頁