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

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

最近在学习windwos下的驱动编程

开个贴记录一下一些相关的知识点,以及遇到的问题(各种蓝屏的姿势)

配置好VS、WDK以及双机调试环境后,开始学习

首先,从最简单的驱动程序开始,写个Hello World

[C] 纯文本查看 复制代码#include

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文件的格式

55fd2b2273b5a8b4531f72773c469d6e.gif

N~HN`ZT904B`WK`XCV7GD_G.png (19.56 KB, 下载次数: 0)

驱动_hello world

2020-3-8 22:10 上传

此时进入我们的虚拟机,我这里用的是win xp sp3环境进行驱动开发学习的,将.sys驱动复制进去,使用驱动装载器将我们的驱动装载

驱动装载器可以去github上下载,搜索关键词"DriverLoader"即可搜索到结果,在后续弄明白驱动装载的原理后,也打算实现一个自己的驱动装载工具

55fd2b2273b5a8b4531f72773c469d6e.gif

(D3MSUFOEIO)3HV33V(G.png (22.37 KB, 下载次数: 0)

2020-3-8 22:18 上传

点击Load即为装载驱动,Unload即为卸载驱动

可以使用DbgView来查看我们的结果,需要在使用的时候按Ctrl+K或者是勾选图中的Capture Kernel选项。

55fd2b2273b5a8b4531f72773c469d6e.gif

JU~UAK81AU7USJYSX7RYY.png (13.47 KB, 下载次数: 0)

2020-3-8 22:19 上传

当然,这时候踩到了第一个坑,驱动装载后,直接蓝屏了!

原来是由于实验环境是win xp环境,而vs2019默认的目标环境是win10,我们需要在设置里修改目标平台属性

55fd2b2273b5a8b4531f72773c469d6e.gif

9Z_8ZE6PG{2KYK`2DE`V89D.png (41.6 KB, 下载次数: 0)

2020-3-9 09:16 上传

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

55fd2b2273b5a8b4531f72773c469d6e.gif

ABX[GBQ13K7{3YC3(UR3GN8.png (1.18 KB, 下载次数: 0)

2020-3-9 09:19 上传

再次装载驱动,即可在DbgView中看到打印出的Hello World字符

第一个程序所包含的知识点

DriverEntry:

该函数就相当于C语言中的main函数,相当于驱动模块的入口点,在装载驱动的时候执行其中的代码。该函数有两个参数,一个是驱动对象的指针pDriver,该结构会在后续为大家介绍,还有一个参数是指向UNICODE字符串的指针,储存了驱动注册到的注册表目录,可以使用DbgPrint函数以%zW参数输出

DbgPrint:

相当于写3环c程序中的printf程序

DriverUnload:

驱动卸载时所执行的函数,定义后需要在入口函数中将卸载函数的地址赋值给pdriver->DriverUnload

点击驱动装载器的Unload,即可在DbgView中看到结果

55fd2b2273b5a8b4531f72773c469d6e.gif

}4RCT5V1}9UT)]FZFN(QG.png (9.46 KB, 下载次数: 0)

2020-3-9 09:31 上传

此时,我们的第一个驱动程序的执行周期算是结束了,从装载的时候执行DriverEntry到卸载的时候执行DriverUnload函数,接下来,就是对pDriver对象进行研究

我们可以使用DbgPrint("%X",pdriver);将指针的值打印出来

55fd2b2273b5a8b4531f72773c469d6e.gif

_27FM[1E{`5PM]RXI8VVIU4.png (6.2 KB, 下载次数: 0)

2020-3-9 09:40 上传

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

55fd2b2273b5a8b4531f72773c469d6e.gif

2]G00Z_K1XTC([I5MSNAXLC.png (17.64 KB, 下载次数: 0)

2020-3-9 09:43 上传

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

55fd2b2273b5a8b4531f72773c469d6e.gif

7{0SXNTYX_17H_)@M_8JV_3.png (13.01 KB, 下载次数: 0)

2020-3-9 09:49 上传

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

这里我们对DriverSection进行着重研究

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

55fd2b2273b5a8b4531f72773c469d6e.gif

2013OB8~`~S{E0@%%O25$A4.png (18.5 KB, 下载次数: 0)

2020-3-9 09:55 上传

可以看到在DriverSection结构体的首部是一个链表,查阅资料得知,这是一个指向系统中已经加载驱动的双向链表,我们可以通过遍历这个列表得到系统中已经加载的所有驱动模块,读者可以自己使用dt指令对双向链表的节点进行观察

看到这个,可以进行下拓展,写个驱动模块以遍历出系统中已经安装的驱动名称等信息,或者将自己的驱动节点从该链表中断链以达到隐藏的目的(听说断链技术已经不适用于win 10,会导致蓝屏)

遍历的代码如下

首先需要自己定义一个DriverSection结构体,这个结构体windows未导出

[C] 纯文本查看 复制代码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;

}

55fd2b2273b5a8b4531f72773c469d6e.gif

6S`2BDA2NTHC_FFO`M60F)2.png (27.83 KB, 下载次数: 0)

2020-3-9 10:15 上传

遍历的结果如图所示,就不截全了

驱动断链的代码如下

[C] 纯文本查看 复制代码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;

}

实验时,先将断链的驱动装载至其中,然后再重新装载遍历驱动对象的模块

实验结果如下

55fd2b2273b5a8b4531f72773c469d6e.gif

06SW5@K[_QG_%]2A8MXJS18.png (334.03 KB, 下载次数: 0)

2020-3-9 10:20 上传

可以看到无法寻找到我们的HideMyself.sys模块,隐藏成功

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值