阶段六:驱动开发
📅 创建日期: 2025-01-XX
⏱️ 预计学时: 10-12 周
🎯 学习目标: 掌握 Windows 内核编程、驱动开发、VT 虚拟化技术
📋 前置要求: [[阶段五:核心逆向技术]]
🔗 返回: [[逆向与驱动开发学习路径(详细版)]]
📚 本阶段内容概览
- [[#6.1 WDK环境搭建|6.1 WDK环境搭建]]
- [[#6.2 驱动基础|6.2 驱动基础]]
- [[#6.2.1 驱动入口与卸载|驱动入口与卸载]]
- [[#6.2.2 设备对象与符号链接|设备对象与符号链接]]
- [[#6.2.3 IRP请求处理|IRP请求处理]]
- [[#6.2.4 驱动与应用通信|驱动与应用通信]]
- [[#6.3 内核编程|6.3 内核编程]]
- [[#6.3.1 内核内存操作|内核内存操作]]
- [[#6.3.2 进程线程操作|进程线程操作]]
- [[#6.3.3 内核回调|内核回调]]
- [[#6.4 VT虚拟化技术|6.4 VT虚拟化技术]]
6.1 WDK环境搭建
📝 学习笔记
安装步骤
- 安装 Visual Studio 2019/2022 (带C++桌面开发)
- 安装 Windows SDK (与系统版本匹配)
- 安装 Windows Driver Kit (WDK)
- 安装 Spectre缓解库(可选)
测试环境配置
推荐配置:
- 主机: Windows 10/11
- 虚拟机: VMware/VirtualBox + Windows 10
- 调试: WinDbg + 内核调试
开启测试签名模式
# 以管理员运行
bcdedit /set testsigning on
bcdedit /set nointegritychecks on
bcdedit /debug on
# 重启生效
shutdown /r /t 0
内核调试设置(虚拟机)
# 被调试机 (虚拟机)
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
# VMware: 添加串口 -> Named Pipe -> \\.\pipe\com_1
# WinDbg: File -> Kernel Debug -> COM -> Pipe: \\.\pipe\com_1
6.2 驱动基础
6.2.1 驱动入口与卸载
📝 学习笔记
最简驱动框架
#include <ntddk.h>
// 驱动卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("[MyDriver] Driver unloaded\n");
}
// 驱动入口点
extern "C" NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
) {
UNREFERENCED_PARAMETER(RegistryPath);
DbgPrint("[MyDriver] Driver loaded\n");
// 设置卸载函数
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
DRIVER_OBJECT 关键字段
| 字段 | 类型 | 说明 |
|---|---|---|
| DriverUnload | PDRIVER_UNLOAD | 卸载回调 |
| DeviceObject | PDEVICE_OBJECT | 设备对象链表 |
| MajorFunction | PDRIVER_DISPATCH[] | IRP处理函数表 |
| DriverName | UNICODE_STRING | 驱动名称 |
6.2.2 设备对象与符号链接
📝 学习笔记
#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMLINK_NAME L"\\??\\MyDevice"
PDEVICE_OBJECT g_DeviceObject = NULL;
NTSTATUS CreateDevice(PDRIVER_OBJECT DriverObject) {
NTSTATUS status;
UNICODE_STRING deviceName, symlinkName;
RtlInitUnicodeString(&deviceName, DEVICE_NAME);
RtlInitUnicodeString(&symlinkName, SYMLINK_NAME);
// 创建设备对象
status = IoCreateDevice(
DriverObject,
0, // DeviceExtension大小
&deviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE, // 非独占
&g_DeviceObject
);
if (!NT_SUCCESS(status)) {
DbgPrint("IoCreateDevice failed: 0x%X\n", status);
return status;
}
// 创建符号链接(用户态可访问)
status = IoCreateSymbolicLink(&symlinkName, &deviceName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(g_DeviceObject);
return status;
}
// 设置通信方式
g_DeviceObject->Flags |= DO_BUFFERED_IO;
g_DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
VOID DeleteDevice() {
UNICODE_STRING symlinkName;
RtlInitUnicodeString(&symlinkName, SYMLINK_NAME);
IoDeleteSymbolicLink(&symlinkName);
if (g_DeviceObject) {
IoDeleteDevice(g_DeviceObject);
}
}
[!important] 符号链接路径
\Device\xxx- 内核设备名\??\xxx或\DosDevices\xxx- 用户态符号链接- 用户态访问:
\\.\xxx(如\\.\MyDevice)
6.2.3 IRP请求处理
📝 学习笔记
IRP 分发函数
// 通用IRP处理
NTSTATUS DefaultDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// DeviceIoControl处理
NTSTATUS DeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
PVOID inputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG bytesReturned = 0;
switch (controlCode) {
case IOCTL_MY_COMMAND:
// 处理自定义命令
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = bytesReturned;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
// 注册分发函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
// ... 创建设备 ...
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = DefaultDispatch;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = DefaultDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DefaultDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
return STATUS_SUCCESS;
}
常用 IRP 主功能码
| 功能码 | 触发条件 |
|---|---|
| IRP_MJ_CREATE | CreateFile |
| IRP_MJ_CLOSE | CloseHandle |
| IRP_MJ_READ | ReadFile |
| IRP_MJ_WRITE | WriteFile |
| IRP_MJ_DEVICE_CONTROL | DeviceIoControl |
6.2.4 驱动与应用通信
📝 学习笔记
定义 IOCTL 码
// 驱动和应用共享的头文件
#define MY_DEVICE_TYPE 0x8000
#define IOCTL_READ_MEMORY CTL_CODE(MY_DEVICE_TYPE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_WRITE_MEMORY CTL_CODE(MY_DEVICE_TYPE, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
// 通信结构
typedef struct _MEMORY_REQUEST {
ULONG ProcessId;
PVOID Address;
SIZE_T Size;
PVOID Buffer;
} MEMORY_REQUEST, *PMEMORY_REQUEST;
应用层代码
#include <Windows.h>
#include "shared.h" // 包含IOCTL定义
int main() {
// 打开设备
HANDLE hDevice = CreateFile(
L"\\\\.\\MyDevice",
GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("Failed to open device: %d\n", GetLastError());
return 1;
}
// 发送请求
MEMORY_REQUEST req = {};
req.ProcessId = 1234;
req.Address = (PVOID)0x12345678;
req.Size = 4;
BYTE buffer[4];
DWORD bytesReturned;
BOOL success = DeviceIoControl(
hDevice,
IOCTL_READ_MEMORY,
&req, sizeof(req), // 输入
buffer, sizeof(buffer), // 输出
&bytesReturned,
NULL
);
if (success) {
printf("Read successful: %02X %02X %02X %02X\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
}
CloseHandle(hDevice);
return 0;
}
6.3 内核编程
6.3.1 内核内存操作
📝 学习笔记
内存分配
// 分页内存(可换出)
PVOID paged = ExAllocatePoolWithTag(PagedPool, 1024, 'tseT');
// 非分页内存(常驻物理内存)
PVOID nonPaged = ExAllocatePoolWithTag(NonPagedPool, 1024, 'tseT');
// 释放
ExFreePoolWithTag(paged, 'tseT');
// Windows 10+ 新API
PVOID mem = ExAllocatePool2(POOL_FLAG_NON_PAGED, 1024, 'tseT');
ExFreePool(mem);
跨进程内存读写
NTSTATUS ReadProcessMemory(HANDLE ProcessId, PVOID Address, PVOID Buffer, SIZE_T Size) {
PEPROCESS process;
NTSTATUS status;
// 通过PID获取EPROCESS
status = PsLookupProcessByProcessId(ProcessId, &process);
if (!NT_SUCCESS(status)) return status;
SIZE_T bytes = 0;
// 复制内存
status = MmCopyVirtualMemory(
process, // 源进程
Address, // 源地址
PsGetCurrentProcess(), // 目标进程(当前驱动上下文)
Buffer, // 目标缓冲区
Size,
KernelMode,
&bytes
);
ObDereferenceObject(process);
return status;
}
MDL 映射物理内存
PVOID MapPhysicalMemory(PHYSICAL_ADDRESS PhysAddr, SIZE_T Size) {
PMDL mdl = IoAllocateMdl(NULL, (ULONG)Size, FALSE, FALSE, NULL);
if (!mdl) return NULL;
MmBuildMdlForNonPagedPool(mdl);
// 映射物理地址
PVOID mapped = MmMapLockedPagesSpecifyCache(
mdl,
KernelMode,
MmNonCached,
NULL,
FALSE,
NormalPagePriority
);
return mapped;
}
6.3.2 进程线程操作
📝 学习笔记
进程枚举
VOID EnumerateProcesses() {
PEPROCESS process = PsGetCurrentProcess();
PLIST_ENTRY listHead = (PLIST_ENTRY)((ULONG_PTR)process + ActiveProcessLinksOffset);
PLIST_ENTRY current = listHead->Flink;
while (current != listHead) {
PEPROCESS proc = (PEPROCESS)((ULONG_PTR)current - ActiveProcessLinksOffset);
// 获取进程信息
HANDLE pid = PsGetProcessId(proc);
PUCHAR name = PsGetProcessImageFileName(proc);
DbgPrint("PID: %d, Name: %s\n", (ULONG)(ULONG_PTR)pid, name);
current = current->Flink;
}
}
进程操作 API
| API | 功能 |
|---|---|
| PsLookupProcessByProcessId | 通过PID获取EPROCESS |
| PsGetProcessId | 获取进程PID |
| PsGetProcessImageFileName | 获取进程名 |
| PsGetProcessPeb | 获取PEB指针 |
| KeAttachProcess | 切换到目标进程上下文 |
| KeStackAttachProcess | 安全版进程切换 |
进程上下文切换
NTSTATUS ReadInProcessContext(PEPROCESS Process, PVOID Address, PVOID Buffer, SIZE_T Size) {
KAPC_STATE apcState;
// 切换到目标进程
KeStackAttachProcess(Process, &apcState);
__try {
// 验证地址可读
ProbeForRead(Address, Size, 1);
RtlCopyMemory(Buffer, Address, Size);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
KeUnstackDetachProcess(&apcState);
return GetExceptionCode();
}
KeUnstackDetachProcess(&apcState);
return STATUS_SUCCESS;
}
6.3.3 内核回调
📝 学习笔记
进程创建回调
VOID ProcessNotifyCallback(
PEPROCESS Process,
HANDLE ProcessId,
PPS_CREATE_NOTIFY_INFO CreateInfo
) {
if (CreateInfo) {
// 进程创建
DbgPrint("Process created: PID=%d, Image=%wZ\n",
(ULONG)(ULONG_PTR)ProcessId,
CreateInfo->ImageFileName);
// 可以阻止进程创建
// CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
} else {
// 进程退出
DbgPrint("Process exited: PID=%d\n", (ULONG)(ULONG_PTR)ProcessId);
}
}
// 注册回调
NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, FALSE);
// 卸载时移除
PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, TRUE);
线程创建回调
VOID ThreadNotifyCallback(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN Create) {
if (Create) {
DbgPrint("Thread created: PID=%d, TID=%d\n",
(ULONG)(ULONG_PTR)ProcessId,
(ULONG)(ULONG_PTR)ThreadId);
}
}
PsSetCreateThreadNotifyRoutine(ThreadNotifyCallback);
PsRemoveCreateThreadNotifyRoutine(ThreadNotifyCallback);
模块加载回调
VOID LoadImageCallback(
PUNICODE_STRING FullImageName,
HANDLE ProcessId,
PIMAGE_INFO ImageInfo
) {
DbgPrint("Image loaded: PID=%d, Base=%p, Name=%wZ\n",
(ULONG)(ULONG_PTR)ProcessId,
ImageInfo->ImageBase,
FullImageName);
}
PsSetLoadImageNotifyRoutine(LoadImageCallback);
PsRemoveLoadImageNotifyRoutine(LoadImageCallback);
对象操作回调 (ObRegisterCallbacks)
OB_PREOP_CALLBACK_STATUS PreOperationCallback(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
) {
// 可以修改访问权限
if (OperationInformation->ObjectType == *PsProcessType) {
// 移除某些权限
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &=
~PROCESS_TERMINATE;
}
return OB_PREOP_SUCCESS;
}
// 注册
OB_OPERATION_REGISTRATION opReg = {};
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opReg.PreOperation = PreOperationCallback;
OB_CALLBACK_REGISTRATION cbReg = {};
cbReg.Version = OB_FLT_REGISTRATION_VERSION;
cbReg.OperationRegistrationCount = 1;
cbReg.OperationRegistration = &opReg;
RtlInitUnicodeString(&cbReg.Altitude, L"12345");
PVOID regHandle;
ObRegisterCallbacks(&cbReg, ®Handle);
6.4 VT虚拟化技术
📝 学习笔记
VT-x 基础概念
| 术语 | 说明 |
|---|---|
| VMX Root | 主机模式(Hypervisor运行) |
| VMX Non-Root | 客户机模式(Guest运行) |
| VMCS | 虚拟机控制结构 |
| VM-Exit | Guest退出到Host |
| VM-Entry | Host进入Guest |
检测 VT 支持
BOOLEAN CheckVTSupport() {
int cpuInfo[4];
// 检查CPUID
__cpuid(cpuInfo, 1);
if (!(cpuInfo[2] & (1 << 5))) { // ECX.VMX
return FALSE;
}
// 检查MSR
ULONG64 featureControl = __readmsr(0x3A); // IA32_FEATURE_CONTROL
if (!(featureControl & 1)) { // Lock bit
// 可以启用
}
if (!(featureControl & 4)) { // VMXON outside SMX
return FALSE;
}
return TRUE;
}
简化的 VT 框架结构
// VMCS区域
typedef struct _VMCS_REGION {
ULONG RevisionId;
ULONG AbortIndicator;
UCHAR Data[4088];
} VMCS_REGION, *PVMCS_REGION;
// 每个处理器的虚拟化状态
typedef struct _VCPU {
PVOID VmxonRegion;
PHYSICAL_ADDRESS VmxonRegionPA;
PVMCS_REGION VmcsRegion;
PHYSICAL_ADDRESS VmcsRegionPA;
BOOLEAN VmxEnabled;
} VCPU, *PVCPU;
// 初始化VT
NTSTATUS InitializeVT() {
// 1. 分配VMXON区域
// 2. 执行VMXON
// 3. 分配VMCS
// 4. VMCLEAR + VMPTRLD
// 5. 设置VMCS字段
// 6. VMLAUNCH
}
// VM-Exit处理
VOID VmExitHandler(PGUEST_CONTEXT Context) {
ULONG exitReason = __vmx_vmread(VMCS_EXIT_REASON);
switch (exitReason) {
case EXIT_REASON_CPUID:
HandleCpuid(Context);
break;
case EXIT_REASON_MSR_READ:
HandleMsrRead(Context);
break;
// ... 其他退出原因
}
}
[!tip] VT 学习资源
- Intel SDM Volume 3C: VMX章节
- SimpleVisor: 开源轻量级Hypervisor
- HyperPlatform: 功能完整的示例
✅ 阶段检查点
环境搭建检查
- [ ] 安装配置WDK开发环境
- [ ] 配置内核调试环境
- [ ] 能加载和卸载测试驱动
驱动基础检查
- [ ] 编写基本的驱动框架
- [ ] 创建设备对象和符号链接
- [ ] 实现驱动与应用的通信
内核编程检查
- [ ] 掌握内核内存分配和释放
- [ ] 实现跨进程内存读写
- [ ] 使用内核回调监控系统事件
VT技术检查
- [ ] 理解VT-x基本概念
- [ ] 了解VMCS结构
- [ ] 学习开源Hypervisor代码
📖 学习资料
| 资源类型 | 名称 | 说明 |
|---|---|---|
| 📕 书籍 | Windows内核原理与实现 | 潘爱民著,深入内核 |
| 📕 书籍 | 寒江独钓:Windows内核安全编程 | 经典驱动开发 |
| 📕 文档 | Intel SDM | VT-x官方文档 |
| 🔧 项目 | HyperPlatform | VT研究项目 |
| 🔧 项目 | SimpleVisor | 轻量级Hypervisor |
| 🌐 网站 | OSR Online | 驱动开发社区 |
🔗 导航
← [[阶段五:核心逆向技术]] | [[逆向与驱动开发学习路径(详细版)| 返回主目录]] | [[阶段七:图形渲染]] →