您的位置:首页 > 编程语言 > PHP开发

SetMode、SetProcPrimissions函数运用(full kernel mode)

2009-10-23 12:00 274 查看
如果在定制内核的时候选择了“Full Kernel Mode”,那么在这个内核上运行的所有线程都处于内核模式,即使调用SetKMode(FALSE)后
线程仍然具有内核模式的特点,能够访问任何有效的虚拟地址。假设现有一个64MB RAM 的WINCE 产品,RAM 映射从0x80000000 到
0x84000000,如果线程处于内核模式,它就直接可以访问这个范围的虚拟地址:
在OnButton1()中编写
DWORD oldMode = SetKMode(FALSE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
*piTemp = 12345;
在OnButton2()中编写
DWORD oldMode = SetKMode(FALSE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
int iTemp = *piTemp;
先只执行OnButton1()然后关闭程序,再重启程序然后执行OnButton2(),iTemp 仍然等于12345。结果说明了两点:内核模式线程可以直接
访问0x80000000 以上的有效虚拟地址;我们写到RAM 中的数据没有丢失,说明虚拟地址有效。
如果在定制内核的时候没有选择“Full Kernel Mode”,那么在这个内核上运行的所有线程都处于用户模式。可以调用SetKMode(TRUE)使调
用线程暂时处于内核模式,还是原来的假设环境,我再举个例子:
在OnButton1()中编写
DWORD oldMode = SetKMode(TRUE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
*piTemp = 12345;
在用户模式下,如果不调用SetKMode(TRUE),那么执行*piTemp = 12345 一定会弹出对话框,提示地址访问非法,如果调用
SetKMode(TRUE)就不会提示地址访问非法,而且在OnButton2()中仍然能得到12345 这个值。
通过这两个例子我相信读者能够完全了解两种模式的区别了。
4、WINCE 提供了两个函数SetKMode 和SetProcPermissions,其中SetKMode 能够把调用线程切换到内核模式,还可以切换回用户模式。
SetProcPermissions + GetCurrentPermissions 添加当前进程访问权限给调用线程,SetProcPermissions (0xFFFFFFFF)能让调用线程访问所有进程
空间,但是调用线程仍然处于用户模式。SetKMode 和SetProcPermissions 函数使得用户模式的特点不那么明晰。
如上所说一个应用程序的线程可能转移到其它两个进程地址空间中读写数据,而每一个线程在被创建的时候只有访问创建它的进程地址空间
的权限,所以驱动程序开发者必须在驱动程序读写数据前调用SetKMode 或者SetProcPermissions 增加调用此函数的线程访问其它进程空间
的权限。如果一个应用程序的线程只转移到一个进程地址空间,一般为设备管理器进程device.exe,这种情况下不必增加线程访问其它进程
空间的权限,但如果驱动程序本身创建了一个线程,那还是要调用SetKMode 或者SetProcPermissions 增加新的线程访问其它进程的权限的,
因为驱动程序创建线程时,当前进程为设备管理器,所以新线程只具有访问设备管理器进程空间的权限,而不具备访问应用程序进程空间的
权限。
5、可能一个编写过简单的流驱动的初学者会很疑惑,因为开发一个简单的流驱动程序根本不需要调用这些函数,也没有调用过
MapPtrToProcess,那是因为如果标准流驱动接口函数的参数为指针(ReadFile、WriteFile、DeviceIoControl 参数都有指针),WINCE 内核会
自动映射指针包含的地址,但仅此而已,其余任何情况都要求开发者自行处理,比如流接口函数的参数是一个指向结构体的指针PA,而结
构体中包括指针PB,PB 指针就必须在流接口函数中映射,映射后才能访问,否则就会造成地址访问非法。所以结构体中每个指针都要映射。
为了让读者能了解其中的原因,我举个例子:
假设设备管理器被加载到Slot4,应用程序A 被加载到Slot 8,A 只有一个主线程T,T 开始执行,按照WINCE 的规定,正获得CPU 的进程
作者:付林林 windowsce@tom.com 天极论坛嵌入式开发版http://378.bbs.yesky.com
14
必须映射到Slot0,那么在执行代码的时候A 的所有虚拟地址都被减去一个偏移值,也就是8×0x02000000,A 调用DeviceIoControl,传递
一个指向一个结构体的指针B,而这个结构体中包含一个指针C,指针C 包含的地址假设为0x00030000,当执行DeviceIoControl 时WINCE
把设备管理器的进程地址空间映射到Slot0,因为放在注册表[HKLM/Drivers/BuiltIn]下的驱动程序是由设备管理器加载的,自然驱动程序的
代码段被加载到设备管理器进程空间,但是线程仍然是T,此时T 的当前所在进程为设备管理器(CurrentProcess),A 变成了T 的调用者进
程(CallerProcess),T 自动具有了访问调用者进程空间的权限。这时访问Slot0 中的虚拟地址其实质就是访问设备管理器的进程地址空间,
要把地址加上一个偏移值,也就是4×0x02000000,所以DeviceIoControl 访问指针C 包含的地址时本应该加上8×0x02000000,却加上4×
0x02000000,结果地址并不是设备管理器的合法区域,系统就会提示地址访问非法。而如果做了一个映射,指针C 包含的地址就会被加一
个正确的偏移值,使地址处于A 的地址空间Slot 8 中,T 此时具有访问A 进程空间的权限,访问到正确的虚拟地址当然会得到正确的数据
了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: