/ Windows / 172浏览

Windows 驱动入门

前置知识

R3 和 R0

API 从 R3 到 R0

#include <iostream>
#include <windows.h>

void testThread() {
    while (true)
    {
        Sleep(1000);
    }
}

HANDLE thread = 0;
int main()
{
    thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)testThread, 0, 0, 0);
    if (thread == 0) {
        printf("CreateThread failed. GetLastError()=%dn", GetLastError());
        system("pause");
        return 0;
    }
    DebugBreak();
    SuspendThread(thread);

    system("pause");
}
# Child-SP          RetAddr               Call Site
00 ffff9f8473a21998 fffff80782aec1d8     nt!KiInsertQueueApc
01 ffff9f8473a219a0 fffff80782aec104     nt!KiSuspendThread+0x88
02 ffff9f8473a219f0 fffff80782edc197     nt!KeSuspendThread+0x78
03 ffff9f8473a21a40 fffff80782edc0f3     nt!PsSuspendThread+0x67
04 ffff9f8473a21aa0 fffff80782c0f3f5     nt!NtSuspendThread+0x93
05 ffff9f8473a21b00 00007ffa111907f4     nt!KiSystemServiceCopyEnd+0x25
06 000000fe5a72fbc8 00007ffa0e994a90     ntdll!NtSuspendThread+0x14
07 000000fe5a72fbd0 00007ff7b13d1a29     KERNELBASE!SuspendThread+0x10
08 000000fe5a72fc00 00007ff7b13d2459     SuspendDemo!main+0x89 [C:UsersfrendguosourcereposSuspendDemoSuspendDemoSuspendDemo.cpp @ 37] 
09 000000fe5a72fd10 00007ff7b13d22fe     SuspendDemo!invoke_main+0x39 [D:a_work1ssrcvctoolscrtvcstartupsrcstartupexe_common.inl @ 79] 
0a 000000fe5a72fd60 00007ff7b13d21be     SuspendDemo!__scrt_common_main_seh+0x12e [D:a_work1ssrcvctoolscrtvcstartupsrcstartupexe_common.inl @ 288] 
0b 000000fe5a72fdd0 00007ff7b13d24ee     SuspendDemo!__scrt_common_main+0xe [D:a_work1ssrcvctoolscrtvcstartupsrcstartupexe_common.inl @ 331] 
0c 000000fe5a72fe00 00007ffa0f477604     SuspendDemo!mainCRTStartup+0xe [D:a_work1ssrcvctoolscrtvcstartupsrcstartupexe_main.cpp @ 17] 
0d 000000fe5a72fe30 00007ffa111426a1     KERNEL32!BaseThreadInitThunk+0x14
0e 000000fe5a72fe60 0000000000000000     ntdll!RtlUserThreadStart+0x21
Nt* 和 Zw* 的区别参考:

SSDT(System Service Descriptor Table)

SSDT表中存放在一组服务函数, 通过该表找到该API在执行体 (Executive)(ntoskrnl.exe)中导出函数的位置,最终调用系统功能。

Windows IO 模型

参考自:处理 IRP - Windows drivers | Microsoft Learn

内核模式驱动程序通过一个保护子系统对最终用户进行隐藏,该子系统实现了一个已经熟悉的编程接口,例如Windows或POSIX。设备仅对用户模式代码可见,包括受保护的子系统,但只作为由I/O管理器控制的具名文件对象。具体关系可以看下图:

下面官方有个图,来描述从 subsystem 中打开一个文件的过程:

来自:Example I/O Request - An Overview - Windows drivers | Microsoft Learn

具体到 IO 是怎么做的,可以看下面这个图:

可以看到,整个过程都是使用 IRP 来传输信息的。简化下:

模型中我们需要关注三个概念:

  1. I/O 请求使用 IRP 从用户空间发送到驱动程序
  2. I/O 管理器(I/O manager)为所有内核模式驱动程序提供一致的接口。
  3. 此 I/O 管理器为每个已安装和加载的驱动程序创建一个驱动程序对象( driver object)。

IRP

IRP 在驱动开发过程中不可避免的,除了 DriverEntry,还有我们的 R0 和 R3 通信,也是利用 IRP 来进行的。具体可以参考:

驱动类型

具体分类可以看:

主要开发框架

框架名称解释使用场景
Windows Driver Model (WDM)用于Windows 98到XP的统一驱动模型通用硬件驱动开发
Kernel-Mode Driver Framework (KMDF)WDF的一部分,用于内核模式驱动开发需要直接与硬件交互的驱动程序
User-Mode Driver Framework (UMDF)WDF的一部分,用于用户模式驱动开发需要在用户模式下运行的驱动程序
Network Driver Interface Specification (NDIS)网络驱动开发框架网络适配器和相关硬件的驱动开发
Windows Display Driver Model (WDDM)图形显示驱动模型显示和图形卡驱动开发
Miniport Drivers与通用端口驱动程序一起用于特定类型的硬件接口特定硬件如SCSI、网络设备的驱动开发
Class Drivers and Function Drivers类驱动程序用于控制一类设备,功能驱动程序针对特定设备例如,USB类驱动程序可控制所有USB设备,功能驱动程序可针对特定USB摄像头

上个手

0. 准备工作

1. 写代码

2. 调试

  • 安装驱动
  • Windbg 附加
  • 符号配置、源配置
  • 断点

3. 签名

参考文档

  1. 通过驱动接触win内核-编程技术-看雪-安全社区|安全招聘|kanxue.com
  2. https://bbs.kanxue.com/thread-275999.htm
  3. https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/handling-irps
Windows是如何区分互联网下载文件和本地文件的
Windows是如何区分互联网下载文件和本地文件的
如何低成本的获取到应用卡顿情况
如何低成本的获取到应用卡顿情况
【译】ETW 堆跟踪 – 每个分配都被记录
【译】ETW 堆跟踪 – 每个分配都被记录
【译】Wait Analysis – 寻找空闲时间
【译】Wait Analysis – 寻找空闲时间
如何通过 ETW Provider 来记录应用日志
如何通过 ETW Provider 来记录应用日志
如何通过 C++ 实时监听 ETW 事件
如何通过 C++ 实时监听 ETW 事件

0

  1. This post has no comment yet

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注