`

《Windows内核编程》---内存管理基本概念

 
阅读更多

内存管理概念:

1)物理内存

PC上有三条总线:数据总线、地址总线和控制总线。32CPU的寻址能力是4GB个字节,用户最多可以使用4GB的真实物理内存。PC中很多设备都提供了自己的设备内存,例如显卡就提供了自己的显存。这部分内存会映射到PC的物理内存上,也就是读写这段物理地址,其实会读写的设备内存地址,而不会读写物理内存地址。

2)虚拟内存地址

Windows所有程序(包括Ring0层和Ring3层的程序)可以操作的都是虚拟内存。之所以称为虚拟内存,是因为对它的所有操作最终都会变成一系列对真实物理内存的操作。

CPU中有一个重要的寄存器CR0,它是32位的寄存器,其中的一个位(PG位)是负责告诉系统是否分页的。Windows在启动前会将它的PG位设为1,即允许分页。DDK中有个宏PAGE_SIZE记录着分页大小,一般为4KB4GB的虚拟内存会被分割成1M个分页单元。

其中,有一部分单元会和物理内存对应起来,即虚拟内存中第N个分页单元对应着物理内存第M个分页单元,这是一种多对一的映射,多个虚拟内存页可以映射到同一个物理内存页。还有一部分单元会被映射成磁盘上的文件,并标记为脏的(Dirty)。当读取这段虚拟内存时,系统会发出一个异常,此时会触发异常处理函数,异常处理函数会将这个页的磁盘文件读入内存,并标记为不脏。

Windows使用虚拟内存是基于以下原因:

1、虚拟的增加了内存的大小;

2、使不同进程的虚拟内存互不干扰,为了让系统可以同时运行不同的进程,Windows让每个进程看到的虚拟内存都不相同。

3)用户模式地址和内核模式地址

虚拟地址0~0x7FFFFFFF范围内的虚拟内存,即低2GB的虚拟地址被称为用户模式地址;而0x80000000~0xFFFFFFFF范围内的虚拟内存,即高2GB的虚拟内存被称为内核模式地址。Windows规定运行在用户态(Ring3层)的程序只能访问用户模式地址,而运行在核心态(Ring0层)的程序可以访问整个4GB的虚拟内存。

Windows的核心代码和Windows的驱动程序加载的位置都在高2GB的内核地址里。Windows在进程切换时,保持内核模式地址是完全相同的,只改变用户模式地址的映射。

4Windows驱动程序和进程的关系

驱动程序可以看成是一个特殊的DLL文件被应用程序加载到虚拟内存中,只不过加载地址是内核模式地址而不是用户模式地址。Windows驱动程序里的不同例程运行在不同的进程中,DriverEntry例程和AddDevice例程是运行在系统进程System中的。System进程是Windows第一个运行的进程。当需要加载驱动程序时,System进程中会有一个线程将驱动程序加载到内核模式地址空间中,并调用DriverEntry例程。而其他一些例程,如IRP_MJ_READ的派遣函数会运行于应用程序的上下文中。所谓运行在进程的上下文,指的是运行于某个进程的环境中,所能访问的虚拟地址是这个进程的虚拟地址。

下面的函数可以显示出当前进程的进程名:

VOID DisplayProcessName()

{

//得到当前进程

PEPROCESS process = PsGetCurrentProcess();

//得到当前进程名称

PTSTR ProcessName = (PTSTR)((ULONG)process + 0x174);

KdPrint(("%s/n", processName));

}

5)分页与非分页内存

Windows规定有些虚拟内存页面可以交换到文件中,这类内存被称为分页内存;而有些虚拟内存永远不会交换到文件中,这些内存被称为非分页内存。

当程序的中断请求级在DISPATCH_LEVEL之上时(包括DISPATCH_LEVEL层),程序只能使用非分页内存,否则将导致蓝屏死机。在编译DDK提供的例程时,可以指定某个例程和某个全局变量是载入分页内存还是非分页内存:

#define PAGEDCODE code_seg("PAGE")

#define LOCKEDCODE code_seg()

#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")

#define LOCKEDCODE code_seg()

#define INITDATA data_seg("INIT")

如果将某个函数载入到分页内存,我们这样使用:

#pragma PAGEDCODE

VOID ASCEFunction()

{

PAGED_CODE();

//do something

}

其中,PAGED_CODE()DDK提供的宏,只在Checked版本中生效。它检验这个函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。

如果让函数加载到非分页内存中,我们这样使用:

#pragma LOCKEDCODE

VOID ASCEFunction()

{

//do something

}

如果某个例程需要在初始化时载入内存,然后就可以从内存中卸载掉(这种情况指出现在DriverEntry情况下,尤其是NT式驱动,DriverEntry会很长,占据很大的空间,为了节省内存,需要及时地从内存中卸载掉),我们这样使用:

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,

IN PUNICODE_STRING RegistryPath)

{

//do something

}

6)分配内核内存

Windows驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约。和应用程序一样,局部变量存放在栈空间中,但栈空间不像应用程序那么大,所以驱动程序不适合递归调用或这局部变量是大型结构体。若需要大型结构体,应该在堆上申请。

堆中申请内存的函数如下:

PVOID ExAllocatePoolWithTag(

__in POOL_TYPE PoolType,

__in SIZE_T NumberOfBytes,

__in ULONG Tag

);

PVOID ExAllocatePoolWithQuotaTag(

__in POOL_TYPE PoolType,

__in SIZE_T NumberOfBytes,

__in ULONG Tag

);

其中,PoolType是个枚举变量:

NonPagedPool //指定要求分配非分页内存

PagedPool //指定要求分配分页内存

NonPagedPoolMustSucceed //指定分配非分页内存,必须成功

DontUseThisType //未指定

NonPagedPoolCacheAligned //指定要求分配非分页内存,而且必须内存对齐

PagedPoolCacheAligned //指定分配分页内存,且必须内存对齐

NonPagedPoolCacheAlignedMustS //指定分配非分页内存,且必须内存对齐,且必须成功

NumberOfBytes是分配内存的大小,最好是4的倍数;

返回值分配的内存地址,一定是内核模式地址;如果返回0,表示分配失败。

函数以WithQuota结尾代表分配时按配额分配;以WithTag结尾的,多出的Tag参数,用在调试时,可以找出是否有标有这个Tag的内存没有被释放。

将分配的内存进行回收的函数是ExFreePoolExFreePoolWithTag

VOID ExFreePool(

__in PVOID P

);

VOID ExFreePoolWithTag(

__in PVOID P,

__in ULONG Tag

);

分享到:
评论

相关推荐

    寒江独钓-Windows内核安全编程(高清完整版).part7

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part1

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part4

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part5

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part6

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    精通Windows.API-函数、接口、编程实例.pdf

    5.6.1 标准C内存管理函数与Windows内存管理API的关系 149 5.6.2 功能性区别 149 5.6.3 效率的区别 149 第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序与...

    寒江独钓-Windows内核安全编程(高清完整版).part3

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    寒江独钓-Windows内核安全编程(高清完整版).part2

     本书从Windows内核编程出发,全面系统地介绍了串口、键盘、磁盘、文件系统、网络等相关的Windows内核模块的编程技术,以及基于这些技术实现的密码保护、防毒引擎、文件加密、网络嗅探、网络防火墙等信息安全软件的...

    Windows内核安全与驱动开发光盘源码

    1.3.5 设置Windows内核符号表 12 1.3.6 实战调试first 13 第2章 内核编程环境及其特殊性 16 2.1 内核编程的环境 16 2.1.1 隔离的应用程序 16 2.1.2 共享的内核空间 17 2.1.3 无处不在的内核模块 18 2.2 数据...

    Android高级编程--源代码

    1.5.8 优化的内存和进程管理 8 1.6 开放手机联盟简介 8 1.7 运行Android的环境 8 1.8 从事Android开发的原因 9 1.8.1 推动Android普及的因素 9 1.8.2 Android的独到之处 10 1.8.3 改变移动开发格局 10 1.9 ...

    精通WindowsAPI 函数 接口 编程实例

    5.6.1 标准C内存管理函数与Windows内存管理API的关系 149 5.6.2 功能性区别 149 5.6.3 效率的区别 149 第6章 进程、线程和模块 150 6.1 基本概念 150 6.1.1 应用程序与进程 150 6.1.2 控制台应用程序...

    新版Android开发教程.rar

    ----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...

    操作系统(内存管理)

    本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上进行汇编语言编程的时代,那时内存管理还不是个大问题。您实际上在运行整个系统。系统有多少内存,您就有多少内存。您甚至...

    Windows内核安全驱动开发(随书光盘)

    1.3.5 设置Windows内核符号表 12 1.3.6 实战调试first 13 第2章 内核编程环境及其特殊性 16 2.1 内核编程的环境 16 2.1.1 隔离的应用程序 16 2.1.2 共享的内核空间 17 2.1.3 无处不在的内核模块 18 2.2 数据...

    windows驱动开发技术详解-part2

     5.1.1 物理内存概念(Physical Memory Address)  5.1.2 虚拟内存地址概念(Virtual Memory Address)  5.1.3 用户模式地址和内核模式地址  5.1.4 Windows驱动程序和进程的关系  5.1.5 分页与非分页内存 ...

    用C语言开发手机软件 -Windows+CE+6.0开发者参考

    11.2 基本概念 11.3 数据库.API 第12章 通知 12.1 用户通知 12.2 计时器事件通知 12.3 系统事件通知 12.4 NoteDemo示例程序 12.5 查询已设定的通知 12.6 气泡通知 12.6.1 添加气泡通知 12.6.2 修改气泡通知 12.6.3 ...

    用C语言开发手机软件-Windows CE 6.0开发者参考

    11.2 基本概念 11.3 数据库.API 第12章 通知 12.1 用户通知 12.2 计时器事件通知 12.3 系统事件通知 12.4 NoteDemo示例程序 12.5 查询已设定的通知 12.6 气泡通知 12.6.1 添加气泡通知 12.6.2 修改气泡通知 12.6.3 ...

    《Windows核心编程系列》谈谈内核对象及句柄的本质

    本章讨论的是相对抽象的概念,不涉及任何具体的内核对象的细节而是讨论所有内核对象的共有特性。  首先让我们来了解一下什么是内核对象。内核对象通过API来创建,每个内核对象是一个数据结构,它对应一块内存,由...

    Windows驱动开发技术详解的光盘-part1

     5.1.1 物理内存概念(Physical Memory Address)  5.1.2 虚拟内存地址概念(Virtual Memory Address)  5.1.3 用户模式地址和内核模式地址  5.1.4 Windows驱动程序和进程的关系  5.1.5 分页与非分页内存 ...

Global site tag (gtag.js) - Google Analytics