分享

关于用户态和内核态的初步理解

 JP_Morgen 2014-05-18

今天在测试socket的内核缓冲区大小的时候,初步了解了内核态与用户态的切换过程。

我的测试是这样的:首先建立c/s模型,建立socket连接,然后让服务器端不断的发送消息,每次发送1024个字节,而客户端不接收数据。这样当服务器端发送了24K左右以后,就会阻塞在send处,无法再发送数据了。

同理,客户端发送消息的时候也是一样的。测试结果显示缓冲区大小也是25K左右。

这样我们就初步证明了内核缓冲区的存在性。

也就是说,如果我们只是发送数据而没有接收数据的话,那么我们使用send函数发送数据的时候,最终会调用内核态ring0级的send函数(究竟是哪个内核API自己现在还不是很清楚)。在内核态应该有一块缓冲区专门用来存放发送的数据,而且类似管道机制,如果数据没有存满,那么允许一直存放,直到到达缓冲区最大容许存放的大小。

从应用层转换到内核层这整个过程是很繁琐的,中间会调用很多API。

关于应用层到内核层的切换问题,下面这个链接举了一个最常见的fork函数的例子。以及在哪些情况下会使操作系统运行在ring0级别上。

http://rf./article/09-12/1628861261320722.html?sort=899_939_950_0

用户态切换到内核态的3种方式

a. 系统调用

   这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int80h中断。

b. 异常

    当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

c. 外围设备的中断

    当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

 

这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。


那么看了上面的概念之后,自然而然就产生了这样一个疑惑:我们怎么样可以主动进入到ring0呢?


今天初步看了《寒江独钓 windows内核安全编程》这本书,自己只是想把基础概念了解一下。

简单的说,我们自己写一个内核模块,或者说是驱动程序,当然不是说我们真正开发驱动,而是我们通过这种方法可以进入ring0层。可以任意修改内核。

我们知道,用户空间是各个进程隔离的,但是内核空间是共享的。编写的内核模块运行在内核空间,成为操作系统的一个模块,最终被所有需要该模块提供功能的应用程序调用。

那么这个内核模块是被哪个进程拥有的呢?实际上,内核模块位于任何一个进程空间中。这取决于请求的来源、处理的过程等。

还有几个基本概念需要我们了解的:

http://blog.csdn.net/vangoals/article/details/4359612

http://blog.csdn.net/yangbostar/article/details/5774774

驱动对象       设备对象    请求(IRP)  分发函数

    首先,谈谈驱动对象(DRIVER_OBJECT),可以说驱动对象代表的是一个驱动程序(或者叫内核模块)。在写内核程序时,必须要填写这样一种结构,来告诉Windows程序提供的功能。内核程序并不生成进程,它们有系统的System进程加载,可以存在于任何的进程。

      设备对象(DEVICE_OBJECT)可以是一个具体的物理设备,如:键盘、硬盘等;也可以是一个虚拟的“设备”,如:用于进程间通信的管道。设备对象由驱动对象创建,一个驱动对象可以创建很多个设备对象。这些设备对象储存在一个设备栈中,这些设备对象是用链表连接在一起的,当新的设备对象产生时应该是用的尾插入(和人理解)。

      对于请求,我们可以理解为Windows SDK程序设计里的消息。一般都是以IRP方式传递的。而设备对象是唯一可以接受请求的实体。然而一个驱动对象中可能会有很多个设备对象,那么是由哪一个设备对象来处理呢?

我的理解是:就像MFC中的消息传递机制一样,会有一个消息的接收顺序;IRP请求也是这样,它先发送到设备栈中最上面的一个设备(最新加入),没有被处理就继续向下发送,如果到最后都还是没有被处理,我认为会有一个默认的处理。

    请求是有各种各样的类型,有的要求读,有的要求写,那么它们就要被分类后,分发到对应的自己编写的处理函数,这些函数叫做“分发函数”,也有翻译为“派遣函数”


以上内容只是自己初步学习的笔迹总结,可能有很多错误的地方,还请大家指正。谢谢

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多