今天在测试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. 系统调用 b. 异常 c. 外围设备的中断 这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请求也是这样,它先发送到设备栈中最上面的一个设备(最新加入),没有被处理就继续向下发送,如果到最后都还是没有被处理,我认为会有一个默认的处理。 请求是有各种各样的类型,有的要求读,有的要求写,那么它们就要被分类后,分发到对应的自己编写的处理函数,这些函数叫做“分发函数”,也有翻译为“派遣函数”
以上内容只是自己初步学习的笔迹总结,可能有很多错误的地方,还请大家指正。谢谢 |
|