内核空间与内核模块

Posted onetrainee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核空间与内核模块相关的知识,希望对你有一定的参考价值。

Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

一、内核空间分布:

  在4GB内存的操作系统中,高2G的给内存空间操作系统使用,这部分内存空间所有进程共享。

  低2G的内存给各个进程使用,每个进程占有独立的内存空间,相互进程其内存之间并不影响。

  技术图片

 

二、内核模块

  内核模块与一般应用层的模块并没有太大区别,其文件结构都遵守Windows的可执行文件结构规范(PE),本质是一样的。

  技术图片

 

 三、DRIVER_OBJECT 结构体介绍

  每一个内核模块中都有一个DRIVER_OBJECT结构体,用来描述这个模块在内核中的位置、大小、名称等。

  使用 windbg 来查看该结构体

        kd > dt _DRIVER_OBJECT
        nt!_DRIVER_OBJECT
        + 0x000 Type             : Int2B
        + 0x002 Size : Int2B
        + 0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
        + 0x008 Flags : Uint4B
        + 0x00c DriverStart : Ptr32 Void    // 驱动程序开始的位置
        + 0x010 DriverSize : Uint4B       // 驱动的大小
        + 0x014 DriverSection : Ptr32 Void       // 指向 _LDR_DATA_TABLE_ENTRY,实验二有介绍,我们之前了解过。
        + 0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
        + 0x01c DriverName : _UNICODE_STRING    // 在内核中名字是什么
        + 0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
        + 0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
        + 0x02c DriverInit : Ptr32     long
        + 0x030 DriverStartIo : Ptr32     void
        + 0x034 DriverUnload : Ptr32     void
        + 0x038 MajorFunction : [28] Ptr32   long

  我们在进行驱动开发时,其DriverEntry驱动入口程序第一个参数就是传入这个结构体的指针,我们可以打印出这个地址,然后在windbg中查看对应的数据结构(实验一)

  NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path){
        // 驱动代码
   }

  注意:我们看很多内核结构体,有Driver,其可以认为内核模块,两者并无太大区别,Driver是负责协调操作系统与硬件的。

 

 

实验一:编写驱动程序,输出该驱动 DRIVER_OBJECT结构体指针,并在windbg中查看验证。

  1)编写驱动代码,打印出diver地址,并生成 .sys 驱动文件,放入虚拟机驱动。

 1 #include <ntifs.h>
 2 
 3 //提供一个卸载函数,让程序能卸载,如果没有这个函数,驱动将不能卸载。
 4 VOID UnDriver(PDRIVER_OBJECT driver)
 5 {
 6     KdPrint(("卸载驱动成功"));
 7 }
 8 //入口函数,相当于main。
 9 NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
10 {
11     __asm {
12         int 3
13         xor eax,eax
14         xor eax,eax
15     }
16     KdPrint(("%x..
",driver));
17     driver->DriverUnload = UnDriver;
18     return STATUS_SUCCESS;
19 }

  2)利用 DebugView 工具查看驱动输出的 driver 指针地址。

    技术图片

 

  3) 使用Windbg,“dt 结构体 地址” 指令,可以将内存空间中的数据与结构体完美映射。            

 

    技术图片

  

 

 实验二:通过DriverSection来遍历其他模块地址

  DriverSection成员指向 _LDR_DATA_TABLE_ENTRY结构体,其表示一个进程模块加载的入口地址,前三个成员是一个双向链表。

  利用实验一中介绍的 "dt 结构体 内存地址"的指令可以将内存映射到结构体中查看详细信息。

  更详细的信息可以参考以前的一篇博客:利用C++进行模块隐藏(R3层断链) https://www.cnblogs.com/onetrainee/p/11674211.html

   技术图片

 

以上是关于内核空间与内核模块的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法从linux内核模块调用用户空间函数?

《linux内核设计与分析》内核模块编程

《linux内核设计与分析》内核模块编程

将 ioctl 代码从内核模块传递到用户空间程序

Linux 内核Linux 内核体系架构 ( 硬件层面 | 内核空间 | 用户空间 | 内核态与用户态切换 | 系统调用 | 体系结构抽象层 )

Linux 内核进程管理 ( 进程与操作系统 | 进程与程序 | 进程与线程 | 虚拟地址空间 )