碎碎念
买了书要看完呀==毕竟书很贵,网速慢真的很痛苦==软件装了好久都没装上。
环境准备
- Visual studio
- WDK
- windows虚拟机
内核入口函数
NTSTATUS DriverEntry{
PDRIVER_OBJECT DriverObject; // 当前驱动所对应的驱动对象指针
PUNICODE_STRING RegistryPath; // 当前驱动所对应的注册表位置
}
typedef struct _UNICODE_STRING{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer; // 不要求以'\0'结束
} UNICODE_STRING, *PUNICODE_STRING;
// RegistryPath表示注册表的位置,但是表示方式是内核级别的表示方式,而不是用户态的表示方式
typedef LONG NTSTATUS; // 返回值实际上为LONG类型
# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) //返回STATUS_SUCCESS则表示成功
内核驱动作为windows服务运行,在执行具体代码之前,驱动SYS文件首先会被映射到内核地址空间,作为内核的一个驱动模块,接着系统对这个驱动模块执行导入表初始化、修正重定位表中对应的数据偏移等操作,最后系统会调用该驱动模式的DriverEntry
入口函数,如果这个入口函数返回STATUS_SUCCESS
,系统认为这个驱动初始化成功;如果这个入口函数返回其他值,系统认为驱动初始化失败,系统执行一系列的清理工作,并把驱动模块从内核空间中移除。
helloworld
#include "ntddk.h"
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
if(DriverObject != NULL)
{
DbgPrint("[%ws]Driver Upload, Driver Object Address:%p", __FUNCTIONW__, DriverObject);
}
return;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint("[%ws]Hello Kernel World\n", __FUNCTIONW__);
if(RegistryPath != NULL)
{
// Register不是'\0'结尾,所以不能直接使用%ws打印
DbgPrint("[%ws]Driver RegistryPath:%wZ\n", __FUNCTIONW__, RegistryPath);
}
if(DriverObject != NULL)
{
DbgPrint("[%ws]Driver Object Address:%p\n", __FUNCTIONW__, DriverObject);
DriverObject->DriverUnload = DriverUnload;
}
return STATUS_SUCCESS;
}
当一个内核驱动被要求停止时,DriverObject->DriverUnload
指向的函数就会被调用,在这个函数里面可以执行一些清理相关的工作。但是DriverUnload
也不是必须的,如果开发者没有提供DriverUnload
函数则该驱动不支持停止,这个特性会被很多安全软件利用,刻意不提供DriverUnload
函数,防止服务被恶意中止。
一些概念
上下文Context
上下文泛指CPU在执行代码时,该代码所处的环境与状态,通俗来讲,这些环境状态包含(不仅限):当前代码所属线程、中断请求级别、CPU寄存器各状态等。
网友评论