驱动蓝屏

在驱动中操作注册表的时候在函数前面加了如下

#pragma INITCODE

void ZwTestNum()
{
ULONG dwNum = 0;

        ....................................

}

结果出现蓝屏,蓝屏代码出现在这个函数中,去掉就不蓝屏了,暂时也不是太明白原因,下面是一些相关资料可以看下:


资料1:

#pragma INITCODE specifies that the code following this is
initialization code to be used only at the time when the driver is
initializing. This means that the system can page this code out once
the driver initialization is over since this code will never be used again.

#pragma PAGEDCODE means that the code following this can be paged out.

资料2:

#pragma INITCODE //将driverEntry设在分页内存中,当驱动加载成功,此函数在内存中移除。 
PAGED_CODE();//当例程所在的中断请求级超过APC_LEVEL时,会产生一个断言,断言会使程序终止


资料3:

DeviceExtension:
8207fea8 8207fdf0 00280026 f8a77150 001a0018
8207feb8 f8a77130 00000000 0000000d 8207fdf0

DriverEntry结束后8207feb8空间被释放,驱动卸载时调用IoDeleteSymbolicLink函数蓝屏,如果将code_seg("INIT")去掉可正常,启动/停止。

驱动源码来自《windows驱动开发技术详解》,诧异的是在网上查询没找到该问题的答案然道都能正常运行?

better

呵呵,我早就遇到过了,原因好像是字符串放在INIT节中,卸载时却被换出内存了。不过现在好像无法重现了

gmay

的确是这样,要把CreateDevice函数的#pragma INITCODE改为#pragma PAGEDCODE,我问过作者,也没有给明确的答复

资料4:

分类: WINDOWS

Windows规定有些虚拟内存可以交换到文件中,这类内存被称为分页内存

有些虚拟内存 永远不会交换到文件中,这些内存叫非分页内存

#define PAGEDCODE  code_seg(“PAGE”);//分页内存

#define LOCKEDCODE  code_seg();//非分页的

#define INITCODE  code_seg(“INIT”);

 

#define PAGEDDATA  data_seg(“PAGE”);

#define LOCKEDDATA  data_seg();

#define INITDATA  data_seg(“INIT”);

 

例:

如果将某个函数载入到分页内存中,可用下列的函数

#pragma PAGEDCODE

VOID Fun()

{

  PAGED_CODE(); //do something

}

注意:   PAGED_CODE()DDK提供的宏,只在check版本中生效,它会检查这个函                数是否运行在低于DISPATCH_LEVAL的中断请求,如果等于或高于这个中断                请求级,则产生一个断言。当程序运行在DISPATCH_LEVEL之上时(包括本                层),程序只能使用非分页内存,否则将导致蓝屏死机

 

如果将某个函数载入到非分页内存中,可用下列的函数

#pragma LOCKEDCODE

VOID Fun()

{

}

某个例程需要在初始化的时候载入内存,然后可以从内存中卸载掉,比如DriverEntry            情况下,DriverEntry会很大,占据很大的空间,为了节省内存,需要及时地从内存中         卸载

#pragma INITCODE

NTSTATUS DriverEntry(

   IN PDRIVER_OBJECT pDriverObject,

   IN PUNICODE_STRING RegisterPath)

{//do something  }

资料5:

分页内存是低中断级别的例程可以访问的。

而非分页内存则是各个中断级别的例程都可以使用的。

区别在于:
分页内存是虚拟内存,在物理上未必总是能得到。

操作系统实现虚拟内存的主要方法就是通过分页机制。在Win32中,物理地址空间,二维虚拟地址空间和实际内存地址是三个不同的概念。操作系统通过段选择子构成二维虚拟地址空间,每个进程有一个4G的地址空间,然后操作系统的内存管理器件把每个进程映射到一维物理地址空间的不同部分,但是因为我们实际机器上大都没有4G内存,所以,实际内存空间是物理地址空间的子集。

分页管理器把地址空间划分成4K大小的页面(非Intel X86体系与之不同),当进程访问某个页面时,操作系统首先在Cache中查找页面,如果该页面不在内存中,则产生一个缺页中断(Page Fault),进程就会被阻塞,直至要访问的页面从外存调入内存中。
我们知道,在处理低优先级的中断时,仍可以发生高优先级的中断。既然缺页过程也是一个中断过程,那么就产生一个问题,即,缺页中断和其他中断的优先级的问题。如果在高于缺页中断的中断优先级上再发生缺页中断,内核就会崩溃。所以在DISPATCH_LEVEL级别以上,绝对不能使用分页内存,一旦使用分页内存,就有发生缺页中断的可能,前面说过,这样会导致内核崩溃。

 

 

 

另一种解释:

 

虽然可以寻址4GB的内存,而在PC里往往没有如此多的真实物理内存。操作系统和硬件(这里指的是CPU中的内存管理单元MMU)为使用者提供了虚拟内存的概念。Windows的所有程序(包括Ring0层和Ring3层的程序)可以操作的都是虚拟内存。之所以称为虚拟内存,是因为对它的所有操作,最终会变成一系列对真实物理内存的操作。在CPU中有一个重要的寄存器CR0,它是32位的寄存器,其中的一个位(PG位)是负责告诉系统是否分页的。Windows在启动前会将它的PG位置1,即允许分页。宏PAGE_SIZE记录分页大小4KB,4GB的虚拟内存会被分割成1M个分页单元。

         有一部分单元会和物理内存对应起来,这种对应不是一一对应,而是多对一的映射,多个虚拟内存页可以映射同一个物理内存页。还有一部分单元会被映射成磁盘上的文件,并标记为脏的(Dirty)。0~0X7FFFFFFF范围内的虚拟内存,即低于2GB的虚拟地址为用户内核模式地址,而0X80000000~0XFFFFFFFF范围内的虚拟内存,即高2GB的虚拟内存,为内核模式地址。Windows的核心代码和Windows的驱动程序加载的位置都是在高2GB的内核地址里,所以一般的应用程序是不能访问到这些核心代码和重要数据的。同时Windows操作系统在进程切换时,保持内核模式地址是完全相同的。也就是说,所有进程的内核地址映射完全一致,进程切换的时候,只改变用户模式地址的映射。

      Windows规定有些虚拟内存页面是可以交换到文件中的,这类内存被称为分页内存。而有些虚拟内存永远不会交换到文件中,这些内存被称为非分页内存。当程序的中断请求级在DISPATCH_LEVEL之上(包括DISPATCH_LEVEL层),程序只能使用非分页内存,否则将导致蓝屏死机。


资料6

  前一段时间参加了学校的网络安全竞赛。其中有一道题目是“拦截注册表”,使用SSDT HOOK ZwSetKeyValue函数。在自己的ZwSetKeyValue函数中,需要对传递进来的注册表路径与设定好的注册表路径进行匹配(ANSII 比较),如果一样,则被拦截。否则,则放行。

  虽然在Windows内核中并不推荐使用C语言的字符串操作的库函数,但又没有其他好的办法的时候仍然需要使用。我在程序中使用了strcpy()与strcmp()函数。可以成功生成驱动,但加载之后,系统会蓝屏。开始始终搞不清楚,多次尝试之后,发现取消DriverEntry开头的#define INITCODE code_seg("INIT")即可。具体的原因到现在依然不太清楚,后来百度了一下,在pediy论坛上发现了别人也在进行这个问题的讨论。链接是:

  http://bbs.pediy.com/showthread.php?p=808708

  两条可能有用的回复摘下来:

  2.呵呵,我早就遇到过了,原因好像是字符串放在INIT节中,卸载时却被换出内存了。不过现在好像无法重现了。

  4.的确是这样,要把CreateDevice函数的#pragma INITCODE改为#pragma PAGEDCODE,我问过作者,也没有给明确的答复。




posted @ 2013-10-12 17:14  vcerror  阅读(891)  评论(0编辑  收藏  举报