尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
windows 驱动实例分析系列: wintun驱动分析-api篇(二)
Wintun API 模块深度解析文档二适配器生命周期与驱动管理一、概述本文档深入分析api模块中的适配器管理和驱动安装逻辑主要涉及文件adapter.c/adapter.hadapter_win7.hdriver.c/driver.hregistry.c/registry.h辅助读取注册表resource.c/resource.h提取嵌入式文件适配器管理是 Wintun 最核心的功能之一涵盖了从创建、打开、关闭、删除到孤儿设备清理的全过程。驱动安装则负责在首次使用或版本更新时将 Wintun 内核驱动wintun.sys和配套 INF/CAT 文件部署到系统。二、驱动安装与版本管理driver.c2.1 驱动版本检测WintunGetRunningDriverVersion通过NtQuerySystemInformation枚举已加载的内核模块查找名为wintun.sys的驱动然后读取其文件版本通过GetFileVersionInfo。若未加载返回 0 并设置ERROR_FILE_NOT_FOUND。内部辅助函数MaybeGetRunningDriverVersion(ReturnOneIfRunningInsteadOfVersion)支持仅检测是否存在返回 1用于等待驱动卸载。2.2 驱动安装流程DriverInstall此函数在WintunCreateAdapter中被调用首次创建适配器时。流程如下获取互斥锁通过NamespaceTakeDriverInstallationMutex()确保同一时刻只有一个进程执行安装避免竞争。创建设备信息使用SetupDiCreateDeviceInfoListExW创建网络设备类的一个临时设备信息元素设置硬件 ID 为Wintun。枚举已安装的兼容驱动通过SetupDiBuildDriverInfoList获取系统中所有匹配Wintun硬件 ID 的驱动。版本比较遍历每个驱动信息与 Wintun 内置驱动版本从 INF 提取的WINTUN_INF_VERSION和WINTUN_INF_FILETIME比较。如果现有驱动更新则直接使用如果内置驱动更新则禁用所有使用当前驱动创建的 Wintun 适配器调用DisableAllOurAdapters等待驱动卸载EnsureWintunUnloaded。调用SetupUninstallOEMInfW卸载旧驱动SUOI_FORCEDELETE强制删除。继续寻找下一个驱动。若没有找到可用驱动则执行全新安装使用ResourceCreateTemporaryDirectory在%WINDIR%\Temp下创建随机临时目录。根据本机架构NativeMachine从 DLL 资源中提取对应的wintun.sys、wintun.cat、wintun.inf到临时目录。调用SetupCopyOEMInfW将 INF 复制到系统驱动存储%SystemRoot%\INF完成安装。删除临时文件并移除目录。保存上下文将之前禁用的适配器列表通过输出参数DevInfoExistingAdaptersForCleanup和ExistingAdaptersForCleanup返回由调用方在适配器创建完成后重新启用它们通过DriverInstallDeferredCleanup。2.3 驱动卸载WintunDeleteDriver首先调用AdapterCleanupOrphanedDevices清理所有孤儿适配器无所有者进程。再次枚举匹配Wintun硬件 ID 的驱动对每个驱动调用SetupUninstallOEMInfW移除。此操作需获取驱动安装互斥锁且仅在无适配器使用时成功。2.4 版本比较逻辑IsNewer函数通过比较FILETIME和 64 位版本号高 16 位为主版本其次为次版本其次为构建号低 16 位为修订决定新旧。优先比较日期再比较版本号。三、适配器创建WintunCreateAdapter这是最复杂的函数需要处理 Windows 7/8/10 的不同 API并支持 WOW64 代理。3.1 前期准备获取设备安装互斥锁NamespaceTakeDeviceInstallationMutex。调用DriverInstall确保驱动已安装。分配并初始化WINTUN_ADAPTER结构。3.2 Windows 8 的软件设备创建路径步骤生成实例 ID若调用方提供了RequestedGUID则直接使用否则调用CoCreateGuid生成随机 GUID。将 GUID 转换为字符串作为设备实例 ID。创建存根设备Stub在 Windows 10 上先通过SwDeviceCreate创建一个临时的存根设备仅设置硬件 ID 为空字符串并在其软件注册表项中写入SuggestedInstanceId用于影响 NLA GUID。然后立即关闭该存根。此步骤的目的是为系统网络位置感知NLA提供确定的 GUID避免每次创建新适配器都生成新的 NLA 条目。创建主设备再次调用SwDeviceCreate传入实际的硬件 IDWINTUN_HWID和设备属性DEVPKEY_Wintun_Name用户指定的适配器名称如 “Demo”。DEVPKEY_Device_FriendlyName隧道类型名称 Tunnel。DEVPKEY_Device_DeviceDesc同上。设置标志SWDeviceCapabilitiesSilentInstall静默安装和SWDeviceCapabilitiesDriverRequired需要驱动。等待设备创建完成通过回调DeviceCreateCallback设置事件然后等待。等待接口可用调用WaitForInterface使用DevCreateObjectQuery查询设备接口GUID_DEVINTERFACE_NET是否已启用超时 15 秒。这确保了驱动已正确加载并注册了设备接口。打开设备信息通过SetupDiOpenDeviceInfo打开该设备然后调用PopulateAdapterData从注册表读取NetCfgInstanceId、NetLuidIndex、*IfType等关键信息。设置网络连接名称调用NciSetAdapterName内部使用NciSetConnectionName将网络连接显示名设置为用户指定的名称若冲突则自动添加序号后缀。Windows 7 特殊处理若系统为 Windows 7则路径不同见下文。3.3 Windows 7 的专用创建路径Windows 7 不支持SwDeviceCreate因此 Wintun 使用传统的 Setup API 进行设备创建参考adapter_win7.h中的CreateAdapterWin7函数创建设备信息元素设置硬件 ID 为Wintun。构建兼容驱动列表选中第一个匹配的驱动。依次调用DIF_REGISTERDEVICE、DIF_REGISTER_COINSTALLERS、DIF_INSTALLINTERFACES、DIF_INSTALLDEVICE。设置自定义属性DEVPKEY_Wintun_OwningProcess包含进程 ID 和创建时间用于孤儿设备清理。等待设备接口可用通过轮询检查注册表值和设备状态。返回设备实例 ID。3.4 WOW64 代理调用在 32 位进程运行于 64 位系统上时直接调用 Setup API 会失败。因此adapter.c中的AdapterRemoveInstance、AdapterEnableInstance、AdapterDisableInstance等函数会检查全局NativeMachine和IMAGE_FILE_PROCESS若不同则通过rundll32.c中的辅助函数启动 64 位代理进程setupapihost.dll来执行操作。代理调用的实现细节已在之前《setupapihost 深度解析》中详细说明此处不再重复。3.5 适配器打开WintunOpenAdapter枚举所有网络设备过滤枚举器为SWD\WintunWin8或ROOT\WintunWin7查找DEVPKEY_Wintun_Name与给定名称匹配的设备。获取设备实例 ID打开设备信息填充WINTUN_ADAPTER结构。同样等待接口可用并填充数据。3.6 适配器关闭WintunCloseAdapter若适配器由CreateAdapter创建具有SwDevice或通过 Windows 7 路径则调用AdapterRemoveInstance删除设备。否则只释放句柄不删除打开模式。释放内存后触发异步孤儿设备清理QueueUpOrphanedDeviceCleanupRoutine。3.7 孤儿设备清理AdapterCleanupOrphanedDevices孤儿设备是指那些没有关联进程或关联进程已退出的 Wintun 适配器。这类设备可能因进程崩溃或未正确调用CloseAdapter而遗留。清理逻辑Win8枚举所有网络设备检查设备状态是否有问题CM_Get_DevNode_Status的DN_HAS_PROBLEM。对于有问题的设备尝试通过DEVPKEY_Wintun_Name获取名称并调用AdapterRemoveInstance删除。Windows 7 特殊版本AdapterCleanupOrphanedDevicesWin7检查自定义属性DEVPKEY_Wintun_OwningProcess若进程不存在或进程创建时间不匹配则判定为孤儿并删除。此外AdapterCleanupLegacyDevices用于清理早期 Wintun 版本在ROOT\NET枚举器下遗留的设备。四、辅助函数与注册表操作4.1PopulateAdapterData从设备驱动注册表项DIREG_DRV读取NetCfgInstanceId转换为 GUID 存入CfgInstanceID。NetLuidIndex用于构造NET_LUID。*IfType接口类型。4.2AdapterGetDeviceObjectFileName通过CM_Get_Device_Interface_ListW获取设备接口的符号链接名如\\.\Wintun_{GUID}用于后续CreateFile打开设备对象。4.3WaitForInterface使用 Windows 8 引入的DevCreateObjectQuery创建设备查询等待设备接口启用超时 15 秒。若超时或失败记录详细错误信息包括问题代码和 NTSTATUS。4.4 名称冲突解决NciSetAdapterName调用NciSetConnectionName尝试设置网络连接名若返回ERROR_DUP_NAME则自动在名称后添加空格加数字序号最多尝试 1000 次并尝试重命名冲突的现有连接。五、总结本文详细剖析了 Wintun 适配器的创建、打开、关闭、删除流程以及驱动安装/卸载的完整机制。关键亮点包括跨版本兼容性为 Windows 7 保留传统 Setup API 路径同时为 Windows 8 使用更现代的软件设备模型。WOW64 透明代理自动检测进程位数通过rundll32启动代理 DLL 执行需要本机架构的 Setup API 调用。驱动版本管理智能比较现有驱动与内置驱动版本必要时升级并禁用/重新启用现有适配器。孤儿设备清理确保崩溃进程留下的适配器能被自动回收保持系统整洁。下一篇文章将转向会话管理与数据路径揭示 Wintun 高效收发的核心——环形缓冲区与无锁设计。
RELATED

相关推荐

重磅数据——GEDI L4D 数据(GEDI L4D Imputed Waveforms, Version 2):将激光点云变为连续性30米栅格图像(高度和生物量)

重磅数据——GEDI L4D 数据(GEDI L4D Imputed Waveforms, Version 2):将激光点云变为连续性30米栅格图像(高度和生物量)

GEDI L4D 插补波形数据 v2:将激光雷达足迹扩展为30米连续栅格 引言 森林是地球碳循环的关键组成部分,但精确量化全球森林的结构与碳储量一直是个巨大挑战。GEDI(全球生态系统动力学调查,Global Ecosystem Dynamics Investigatio…

📅 2026/10/6 14:14:44
CentOS6.5 虚拟机部署 iSCSI 存储 + multipath 多路径完整实操

CentOS6.5 虚拟机部署 iSCSI 存储 + multipath 多路径完整实操

背景 业务使用仅兼容 CentOS6.5 的老旧程序,虚拟机本地磁盘空间不足,需通过 iSCSI 挂载外部集中存储存放数据库、日志等数据。 单条存储链路易因网口、线路故障造成业务中断,还存在带宽上限;部署 multipath 多路径可实现链路故障…

📅 2026/10/5 5:40:00
一文讲透 Spring AOP、Bean 作用域与事务:从代理机制到事务失效

一文讲透 Spring AOP、Bean 作用域与事务:从代理机制到事务失效

Spring AOP、Bean 作用域和事务看似是三个知识点,实际上都与 Spring 容器和代理机制密切相关:容器管理 Bean 的生命周期,AOP 为 Bean 创建代理,声明式事务则是 AOP 的典型应用。 一、Spring AOP 是什么 AOP,即面向切…

📅 2026/9/4 6:16:24
MORE NEWS

更多资讯

📰

二叉树递归遍历四连刷:翻转、对称、最大/最小深度全攻略

今天是我算法复健的第12天,照例刷了四道 LeetCode 二叉树题:226 翻转二叉树、101 对称二叉树、104 二叉树的最大深度、111 二叉树的最小深度。这四道题不是随手点的,它们摆在一起恰好能把二叉树最核心的递归遍历吃透——前序、后序、层序都覆…

📰

Windows 下 Claude Code 安装配置与 VSCode 集成避坑指南

1. 为什么要在 Windows 上认真折腾 Claude Code很多人第一次听说 Claude Code,以为它只是个"命令行版的 AI 聊天框",装完随便敲两句就完事了。真上手才发现,这东西在 Windows 上的落地体验和 macOS、Linux 完全不是一回事——路径分…

📰

Xcelium混合仿真三大生死线:语言边界、时序契约与数据类型映射

1. 为什么混合仿真不是“把代码扔进工具就能跑”——Xcelium里Verilog、VHDL、SystemC共存的真实水深你手头有一块SoC,顶层是SystemC写的事务级模型(TLM),控制逻辑用VHDL写成,而数据通路模块全是Verilog RTL。老板说&a…

📰

二叉树算法复健:翻转、对称、最大/最小深度一次吃透

算法复健 Day12 - 二叉树 LC 226,101,104,111最近在重刷算法题,拿二叉树开刀算是比较舒服的复健路径。今天集中做掉四道 LeetCode 上的经典树题:翻转二叉树(LC 226)、对称二叉树(LC …

📰

SSA麻雀搜索算法优化随机森林回归与SHAP分析的MATLAB实现

开头直接进入主题,不寒暄。这篇是分享一个我自己跑通的完整方案:SSA(麻雀搜索算法)优化随机森林回归,配 SHAP 可解释性分析,做优化前后对比,再拿新数据做预测,整套流程在 MATLAB 里实…

📰

LLM工程化实战:从API调用到可控AI系统的构建

1. 这不是“笔记”,而是一份LLM工程实践的活体日志“LLM 学习笔记”这六个字,乍看像学生时代的课堂记录,实则藏着当前AI落地最硬核的一线战场。我从2023年初开始系统性地把大模型拉进真实业务流——不是调API玩demo,而是让LLM在生…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬