驱动基础

01Hello World

驱动基础知识

驱动不是进程,本质上和DLL一样是模块

NT驱动:如果绑定设备,不能卸载

WDM驱动:热拔插,可以更新卸载

WDF驱动:简化开发,相当于事件驱动机制,依赖环境

KWDF驱动:内核驱动框架

UWDF驱动:用户驱动框架(支持在用户下运行的)

学的主要是NF和WDM驱动

驱动内存不共享

驱动文件按照0x200对齐,内存按照0x1000对齐

驱动加载方法

  1. 服务加载(官方提供)
  2. 本地加载

服务加载

加载过程

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
posted @ 2024-05-18 17:14  MuRKuo  阅读(27)  评论(0编辑  收藏  举报