65.9K
CodeProject 正在变化。 阅读更多。
Home

WDF 驱动程序开发的简单演示

2010 年 4 月 26 日

CPOL

2分钟阅读

viewsIcon

50301

downloadIcon

4371

在用户模式下访问物理内存和I/O端口

引言

WINFO是一款互联网上广为人知的工具,可以直接访问I/O和内存。它应用了微软未公开的函数(NATIVE API)来获取I/O数据。PCI View的设计结构基于WDF,旨在模拟WINFO的功能,以访问I/O和内存。

背景

需要具备Win32 SDK的知识。

程序结构

PCI View可以通过IOMEM.DLLDeviceIoControlReadFile/WriteFile函数访问I/O端口和内存。

应用程序介绍

在Windows NT环境下,可以使用READ_PORT_UCHAR(USHORT/ULONG)WRITE_PORT_UCHAR(USHORT/ULONG) API函数访问I/O端口。这些API函数的使用方式类似于C语言运行时库提供的函数,例如_outp_inp

case 1: //UCHAR 
   if (pvInputBuffer->Command == 0) //decide to write or read 
        WRITE_PORT_UCHAR((PUCHAR)pvInputBuffer->PortBase, (UCHAR)pvInputBuffer->Data); 
   else 
        *(PUCHAR)pvOutputBuffer = READ_PORT_UCHAR((PUCHAR)pvInputBuffer->PortBase); 
break; 

case 2: // USHORT 
   if (pvInputBuffer->Command == 0) 
       WRITE_PORT_USHORT((PUSHORT)pvInputBuffer->PortBase, (USHORT)pvInputBuffer->Data); 
   else 
       *(PUSHORT)pvOutputBuffer = READ_PORT_USHORT((PUSHORT)pvInputBuffer->PortBase); 
break; 

case 4: //ULONG 
   if (pvInputBuffer->Command == 0) 
       WRITE_PORT_ULONG((PULONG)pvInputBuffer->PortBase, (ULONG)pvInputBuffer->Data); 
   else 
       *(PULONG)pvOutputBuffer = READ_PORT_ULONG((PULONG)pvInputBuffer->PortBase); 
break;

内存处理比I/O处理更复杂,而I/O处理可以通过API函数轻松完成。

  1. 首先,我们需要获取用户想要访问内存的地址和长度。然后,MmMapIoSpace函数可以将地址和长度映射到非分页系统空间。
  2. 如果之前的过程成功,那么分配IoAllocateMdland MmBuildMdlForNonPagedPool就足以缓冲以映射实际内存。
  3. MmMapLockedPagesSpecifyCache函数可以将虚拟内存映射到调用者。因此,RING 3应用程序可以直接获取内存。
//Step 1.
memReq.MapIo = MmMapIoSpace(Address, memReq.Length, MmNonCached);
if (memReq.MapIo == NULL)
{
    status = STATUS_INSUFFICIENT_RESOURCES;
    __leave;
};

// Step 2.
memReq.Mdl = IoAllocateMdl(memReq.MapIo, memReq.Length, FALSE, FALSE, NULL);
if (memReq.Mdl == NULL)
{
    status = STATUS_INSUFFICIENT_RESOURCES;
    __leave;
};
MmBuildMdlForNonPagedPool(memReq.Mdl);

// Step 3.
memReq.Buffer = (PUCHAR)MmMapLockedPagesSpecifyCache(memReq.Mdl,
                      UserMode, //set value as UserMode
                      MmNonCached,
                      NULL,
                      FALSE,
                      NormalPagePriority);
if (memReq.Buffer == NULL)
{
     status = STATUS_INSUFFICIENT_RESOURCES;
     __leave;
};

实模式下的动态函数提供了outp_outpw_outpd_inp_inpw_inpd来访问I/O端口。有四个函数,例如MapMemoryUnmapMemoryReadPhyicalMemoryWritePhyicalMemory,可用于获取内存。

函数:设计用于访问内存的地址和长度

PUCHAR MapMemory(__in ULONG Address, __in ULONG Length);
Address : To access the beginning address of memory.
Length : To get the length of memory

The function will return the beginning address mapping in memory 
when executed successfully. 
Function: Release the assigned memory.
BOOLEAN UnmapMemory(VOID);

示例程序

该应用程序提供了一个访问IO-MEM的示例。在不包含DLL包的情况下,该应用程序在直接调用IOMEM.DLL时显示分配的内存或I/O端口的信息。可以从http://bbs.codeheaven.com.tw/下载源代码。

示例

历史

  • 2010年4月26日:初始发布
© . All rights reserved.