作者:xiaoshujun
转自:http://blog.csdn.net/xiaoshujun/article/details/5862452
CE6.0中驱动分为内核态驱动和用户态驱动,用户态驱动有不少的限制,有不少特权API函数都不能直接使用,比如映射地址很常用的VirtualCopy函数等会返回失败,但并不是说不能使用这些函数。CE6.0的用户态驱动通过Reflector服务可以使用某些特权API函数的。
既然是驱动,就不可避免需要直接跟硬件打交道,在用户态驱动中想要使用VirtualAlloc和VirtualCopy函数来映射物理地址,需要在驱动程序的注册表信息中加上所需要映射的地址的基址和长度。
先来看看通常使用VirtualAlloc和VirtualCopy来进行地址映射的方法:
//-----------------------------------------------------------------------------------
//内存映射
//-----------------------------------------------------------------------------------
pBase->dwVirBuf= (DWORD)VirtualAlloc(NULL,pBase->BuffSize, MEM_RESERVE, PAGE_NOACCESS);
if(NULL == pBase->dwVirBuf)
{
returnFALSE;
}
if(!VirtualCopy((PVOID)pBase->dwVirBuf,(LPVOID)(pBase->dwPhyBuf >> 8), pBase->BuffSize,
PAGE_PHYSICAL| PAGE_READWRITE | PAGE_NOCACHE))
{
VirtualFree((PVOID)pBase->dwVirBuf,0, MEM_RELEASE);
pBase->dwVirBuf= NULL;
returnFALSE;
}
CE6.0以前这样映射不会有任何问题,CE6.0中内核态驱动这样映射也可以,但是用户态驱动中VirtualCopy调用会失败。下面介绍解决办法:
看看如下示例(*.reg文件):
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/testDrv]
"Dll"="testDrv.dll"
"Prefix"="TST"
"Index"=dword:1
"Order"=dword:0
"Flags"=dword:10 ;10 for use mode
"MemBase"=dword:"00A00000"
"MemBase"=dword:"00100000"
上例中"Flags"为10时表明是用户态,其实这个10是十六进制的0X00000010,但是这里不能加上0X,否则会报错;
"MemBase"和 "MemBase"分别表示需要映射的物理基址和长度
若有多片非连续的物理空间,则只需要将"MemBase"和 "MemBase"的数据类型改为multi_sz,后面的数据用”,”隔开即可。
这样子在用户态驱动中就可以按上面的方法成功映射物理空间。
在某些场合,应用程序也需要直接操作物理空间,但在CE6.0中应用程序调用VirtualCopy必定会失败,那么该如何解决呢?
办法是有的,在CE6.0中出现了一个新的API函数:VirtualAllocCopyEx,它可以将一个进程中的地址转换到另一个进程中的地址空间中,首先看看这个函数的原型:
LPVOID VirtualAllocCopyEx (
HANDLE hSrcProc,
HANDLE hDstProc,
LPVOID pAddr,
DWORD cbSize,
DWORDdwProtect
);
其中有两个HANDLE句柄参数,为hSrcProc为源进程的ID号,hDstProc为目的进程的ID号,VirtualAllocCopyEx就是将hSrcProc中的地址转换到hDstProc中,这样就可以通过在内核态映射物理空间,然后应用程序通过IOCONTROL调用VirtualAllocCopyEx来将映射好的虚拟地址转换到应用程序进程中,并通过IOCONTROL返回给应用程序,这样应用程序就可以直接操作内核态驱动映射好的物理空间。
注意:VirtualAllocCopyEx函数只能在内核态中使用。