jy40 发表于 2020-3-9 10:26

【笔记】windows驱动编程学习-从hello world出发

本帖最后由 jy40 于 2020-3-9 10:36 编辑

最近在学习windwos下的驱动编程
============
开个贴记录一下一些相关的知识点,以及遇到的问题(各种蓝屏的姿势)
---------
配置好VS、WDK以及双机调试环境后,开始学习
首先,从最简单的驱动程序开始,写个Hello World
#include<ntddk.h>

VOID DriverUnload(PDRIVER_OBJECT pdriver) {
      DbgPrint("Unload Success\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg) {
      DbgPrint("Hello World\n");
      pdriver->DriverUnload = DriverUnload;
      return STATUS_SUCCESS;
}
按f7编译生成以后,即可在自己的目录下寻找到 .sys后缀的文件,这就是我们生成的驱动文件了,同样是pe文件的格式

此时进入我们的虚拟机,我这里用的是win xp sp3环境进行驱动开发学习的,将.sys驱动复制进去,使用驱动装载器将我们的驱动装载
驱动装载器可以去github上下载,搜索关键词"DriverLoader"即可搜索到结果,在后续弄明白驱动装载的原理后,也打算实现一个自己的驱动装载工具

点击Load即为装载驱动,Unload即为卸载驱动
可以使用DbgView来查看我们的结果,需要在使用的时候按Ctrl+K或者是勾选图中的Capture Kernel选项。

当然,这时候踩到了第一个坑,驱动装载后,直接蓝屏了!
原来是由于实验环境是win xp环境,而vs2019默认的目标环境是win10,我们需要在设置里修改目标平台属性

经过测试,指定目标平台版本为windows 7也可以在win xp系统中运行

再次装载驱动,即可在DbgView中看到打印出的Hello World字符
第一个程序所包含的知识点
---------------------
**DriverEntry:**
   该函数就相当于C语言中的main函数,相当于驱动模块的入口点,在装载驱动的时候执行其中的代码。该函数有两个参数,一个是驱动对象的指针pDriver,该结构会在后续为大家介绍,还有一个参数是指向UNICODE字符串的指针,储存了驱动注册到的注册表目录,可以使用DbgPrint函数以%zW参数输出
**DbgPrint:**
    相当于写3环c程序中的printf程序
**DriverUnload:**
    驱动卸载时所执行的函数,定义后需要在入口函数中将卸载函数的地址赋值给pdriver->DriverUnload
    点击驱动装载器的Unload,即可在DbgView中看到结果

此时,我们的第一个驱动程序的执行周期算是结束了,从装载的时候执行DriverEntry到卸载的时候执行DriverUnload函数,接下来,就是对pDriver对象进行研究
我们可以使用DbgPrint("%X",pdriver);将指针的值打印出来

81240DA0就是pDriver对象的地址,在windbg中中断下来,使用dt _DRIVER_OBJECT 81240DA0指令查看该结构的内容,结果如下

可以看到驱动名等一些驱动的参数,比如驱动名,比如驱动的卸载函数的地址,我们反编译一下他

可以很清晰的看到调用了一个DbgPrint函数,而push的则是我们的字符串参数,感兴趣的可以自己尝试跟进一下查看字符串的值是否为"Unload Success“
这里我们对DriverSection进行着重研究

DriverSection是个结构体,指向了 _LDR_DATA_TABLE_ENTRY结构,使用dt _LDR_DATA_TABLE_ENTRY 0x8129d4a8 查看结构内容

可以看到在DriverSection结构体的首部是一个链表,查阅资料得知,这是一个指向系统中已经加载驱动的双向链表,我们可以通过遍历这个列表得到系统中已经加载的所有驱动模块,读者可以自己使用dt指令对双向链表的节点进行观察
看到这个,可以进行下拓展,写个驱动模块以遍历出系统中已经安装的驱动名称等信息,或者将自己的驱动节点从该链表中断链以达到隐藏的目的(听说断链技术已经不适用于win 10,会导致蓝屏)
遍历的代码如下
首先需要自己定义一个DriverSection结构体,这个结构体windows未导出
typedef struct _DRIVER_SECTION {
      LIST_ENTRY InLoadOrderLinks;
      LIST_ENTRY InMemoryOrderLinks;
      LIST_ENTRY InInitializationOrderLinks;
      PVOID DllBase;
      PVOID EntryPoint;
      ULONG SizeOfImage;
      UNICODE_STRING FullDllName;
      UNICODE_STRING BaseDllName;
      ULONG Flags;
      USHORT LoadCount;
      USHORT TlsIndex;
      union {
                LIST_ENTRY HashLinks;
                struct {
                        PVOID SectionPointer;
                        ULONG CheckSum;
                };
      };
      ULONG TimeDateStamp;
      PVOID LoadedImports;
      PVOID EntryPointActivationContext;
      PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {
      pDriver->DriverUnload = DriverUnload;
      PLDR_DATA_TABLE_ENTRY MyDriverList = (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;

      while (1) {
                DbgPrint("%wZ", &MyDriverList->BaseDllName);
                MyDriverList = MyDriverList->InLoadOrderLinks.Flink;
                if (MyDriverList == (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection) {
                        DbgPrint("end\n");
                        break;
                }
      }
      return STATUS_SUCCESS;
}
遍历的结果如图所示,就不截全了


驱动断链的代码如下

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {
      pDriver->DriverUnload = DriverUnload;
      PLDR_DATA_TABLE_ENTRY MyDriverList = (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
      MyDriverList->InLoadOrderLinks.Blink->Flink = MyDriverList->InLoadOrderLinks.Flink;
      MyDriverList->InLoadOrderLinks.Flink->Blink = MyDriverList->InLoadOrderLinks.Blink;
      return STATUS_SUCCESS;
}
实验时,先将断链的驱动装载至其中,然后再重新装载遍历驱动对象的模块
实验结果如下

可以看到无法寻找到我们的HideMyself.sys模块,隐藏成功
然而这种隐藏并不是非常实用的,首先前面提到过的,无法在win10 x64下使用;其次驱动对象pDriver头4个成员的值是固定的,会被内存搜索的方式暴力定位到驱动对象,只能对抗一些API的检索,为了防止被这种方式搜索到,可以考虑将pDriver的头4个成员置零;最后,系统注册一个驱动的时候,除了向该链表添加节点外,还有对注册表进行写入的操作,所以注册表也会暴露驱动模块的存在,要想实现真正的隐藏必须要注意这一点


萌新第一次发帖,如有不足希望大佬提出意见以补足
--------------

ldw471427015 发表于 2020-3-9 11:21

贼强啊

simon6902 发表于 2020-3-9 20:38

谢谢分享,驱动开发挺难的,学习

wingking 发表于 2020-3-14 02:48

满满的干货啊,收藏了!

ewfa 发表于 2020-3-14 09:05

谢谢分享,大佬nb

ciker_li 发表于 2020-3-14 09:32

厉害,厉害

内心xi 发表于 2020-3-17 16:08

小白可以学这东西?

无法撤销 发表于 2020-6-17 13:36

如果用这种方式。后期不优化,那么必须神机才能装载。占用资源过高。

sunxugood 发表于 2020-6-23 12:23


谢谢分享,大佬

阳光下的少年 发表于 2020-7-3 12:11

有点意思, 看上去挺复杂的
页: [1] 2
查看完整版本: 【笔记】windows驱动编程学习-从hello world出发