驱动基础
01Hello World
驱动基础知识
驱动不是进程,本质上和DLL一样是模块
NT驱动:如果绑定设备,不能卸载
WDM驱动:热拔插,可以更新卸载
WDF驱动:简化开发,相当于事件驱动机制,依赖环境
KWDF驱动:内核驱动框架
UWDF驱动:用户驱动框架(支持在用户下运行的)
学的主要是NF和WDM驱动
驱动内存不共享
驱动文件按照0x200
对齐,内存按照0x1000
对齐
驱动加载方法
- 服务加载(官方提供)
- 本地加载
服务加载
加载过程
OpenSrcManager->CreateService->StartService->StopService->DeleteService
服务加载是调用Windows所提供的服务,并不是本进程加载,能不能启动是Windows说的算,在R3就可以拦截
例如当用户设置什么策略的时候,就会导致驱动无法加载,可能让注册表都写不了
杀软在拦截模块加载的时候,使用服务加载可以让杀软获取不到启动进程
本地加载
加载过程
Zw/NtLoadDriver->Zw/NtUnloadDriver
需要自己实现创建服务也就是写注册表的过程
本地加载只能在R0拦截
杀软在拦截模块加载的时候,使用本地加载杀软拦截的时候可以直接获得对应的启动进程
代码
#include <ntifs.h>
VOID Unload(PDRIVER_OBJECT pDriver)
{
DbgPrint("unload\r\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
pDriver->DriverUnload = Unload;
DbgBreakPoint();//断点进去windbg
DbgPrint("TEST_Entry\r\n");
return STATUS_SUCCESS;
}
介绍
入口点在这,在这里JMP到我们的DriverEntry
函数里面
可以看到程序在DbgBreakPoint()
的地方自动断下
使用dt pDriver
命令查看pDriver结构体
kd> dt pDriver
Local var @ 0x807ee9d8 Type _DRIVER_OBJECT*
0x872925c8
+0x000 Type : 0n4//格式
+0x002 Size : 0n168
+0x004 DeviceObject : (null)
+0x008 Flags : 2
+0x00c DriverStart : 0xac600000 Void//PE头
+0x010 DriverSize : 0x6000//驱动的大小(被拉伸后)
+0x014 DriverSection : 0x88b567f0 Void
+0x018 DriverExtension : 0x87292670 _DRIVER_EXTENSION//驱动拓展
+0x01c DriverName : _UNICODE_STRING "\Driver\MyDriver8"//驱动名
+0x024 HardwareDatabase : 0x843c7270 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"//注册表路径(和pReg不一样)
+0x028 FastIoDispatch : (null)
+0x02c DriverInit : 0xac604000 long MyDriver8!GsDriverEntry+0//驱动入口点
+0x030 DriverStartIo : (null)
+0x034 DriverUnload : 0xac601030 void MyDriver8!Unload+0
+0x038 MajorFunction : [28] 0x84101c0d long nt!IopInvalidDeviceRequest+0
查看一下驱动的PE头
+0x00c DriverStart : 0xac600000 Void//PE头
查看驱动拓展
+0x018 DriverExtension : 0x87292670 _DRIVER_EXTENSION//驱动拓展
kd> dt _DRIVER_EXTENSION 0x87292670
ntdll!_DRIVER_EXTENSION
+0x000 DriverObject : 0x872925c8 _DRIVER_OBJECT//指向一个驱动对象
+0x004 AddDevice : (null)
+0x008 Count : 0
+0x00c ServiceKeyName : _UNICODE_STRING "MyDriver8"//服务名字
+0x014 ClientDriverExtension : (null)
+0x018 FsFilterCallbacks : (null)
DriverObject
可以发现我们的驱动对象(DriverObject)
和我们的驱动的pDriver
指向的是一致的
是一个链式结构(A->B->A
)
ServiceKeyName
根据驱动的ServiceKeyName
可以找到驱动在注册表的路径
在services
中的MyDriver8
中
DisplayName:显示名字
ErrorControl:错误控制,当驱动加载失败的时候会有个错误描述
ImagePath:驱动路径
Start:驱动启动类型
Start的值设置为0,则驱动由启动引导器加载,应该跟“随着开机,最先启动”是同一回事;
Start的值设置为1,则驱动由操作系统的I/O子系统加载,即在系统内核初始化时加载;
Start的值设置为2,则驱动/服务在启动后自动加载;
Start的值设置为3,则驱动/服务就是按需手动加载;
Start的值设置为4,驱动/服务就是被禁用的状态
Type:驱动必为1
PUNICODE_STRING
PUNICODE_STRING
是一个结构体
typedef struct _UNICODE_STRING {
USHORT Length;//当前字符串长度
USHORT MaximumLength;//申请出来的大小,最大长度
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
打印PUNICODE_STRING
类型的字符串的时候要使用%wZ
来打印
小技巧
当驱动注册后可以通过cmd命令行运行
net start 驱动服务名
停止时使用net stop 驱动服务名
停止
驱动卸载的时候可以使用sc delete 驱动服务名
将驱动卸载
课后题
火哥要证明驱动内存不共享,要求是用A驱动读B驱动的值,看看能否成功
B驱动代码,打印出了x的地址
#include <ntifs.h>
int x = 100;
VOID Unload(PDRIVER_OBJECT pDriver)
{
DbgPrint("unload\r\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
pDriver->DriverUnload = Unload;
DbgBreakPoint();
DbgPrint("----%x------\r\n",&x);
return STATUS_SUCCESS;
}
A驱动代码,读出了B驱动内的x的值
#include <ntifs.h>
int *x = 0xb42cb000;
VOID Unload(PDRIVER_OBJECT pDriver)
{
DbgPrint("unload\r\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
pDriver->DriverUnload = Unload;
DbgBreakPoint();
DbgPrint("----%i------\r\n", *x);
return STATUS_SUCCESS;
}
VS-工具-代码片段
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>DriverMain</Title>
<Shortcut>DriverMain</Shortcut>
<Description>DriverMain</Description>
<Author>MuRKuo</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>expression</ID>
<ToolTip>要计算的表达式</ToolTip>
<Default>true</Default>
</Literal>
</Declarations>
<Code Language="cpp"><![CDATA[#include <ntifs.h>
VOID Unload(PDRIVER_OBJECT pDriver)
{
DbgPrint("unload\r\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
pDriver->DriverUnload = Unload;
//DbgBreakPoint();
DbgPrint("TEST_Entry\r\n");
return STATUS_SUCCESS;
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
C:\Users\MuRKuo\Documents\Visual Studio 2019\Code Snippets\Visual C++\My Code Snippets\DriverMain.snippet