拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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 高效收发的核心——环形缓冲区与无锁设计。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门