windows 驱动实例分析系列: wintun驱动分析-example篇(上)
Wintun Example 示例程序深度解析这部分作为演示如何使用wintun驱动进行二次开发的例子分为两部分。一、模块概述example文件夹是 Wintun 项目提供的一个完整的、可直接运行的示例程序用于演示如何使用wintun.dll的 API 来创建虚拟网络适配器、配置 IP 地址、收发数据包ICMP 回显请求/响应。它充当了一个最小化 VPN 客户端原型展示了从初始化到清理的完整生命周期。这个示例不仅是一个教学工具也是 Wintun 开发者进行集成测试的基准程序。其代码风格严谨、错误处理周全完全可以作为实际项目开发的参考模板。二、核心代码逐段分析2.1 函数指针与动态加载InitializeWintunstaticWINTUN_CREATE_ADAPTER_FUNC*WintunCreateAdapter;// ... 其余 13 个函数指针staticHMODULEInitializeWintun(void){HMODULE WintunLoadLibraryExW(Lwintun.dll,NULL,LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_SYSTEM32);if(!Wintun)returnNULL;#defineX(Name)((*(FARPROC*)NameGetProcAddress(Wintun,#Name))NULL)if(X(WintunCreateAdapter)||X(...)||/* ... */)#undefX{/* 错误处理并释放 */}returnWintun;}设计要点使用LoadLibraryEx并指定LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32确保优先从应用目录和系统目录加载wintun.dll防止 DLL 劫持。通过宏X批量获取所有导出函数的地址若任一失败则回滚并报错。返回的HMODULE在程序结束时释放确保资源正确清理。这种做法体现了延迟绑定的思想不静态链接wintun.lib而是运行时动态加载使得示例程序可以在未安装 Wintun 的系统上优雅地报错退出也方便替换不同版本的 DLL 进行测试。2.2 日志系统ConsoleLogger Log 辅助staticvoidCALLBACKConsoleLogger(WINTUN_LOGGER_LEVEL Level,DWORD64 Timestamp,constWCHAR*LogLine){SYSTEMTIME SystemTime;FileTimeToSystemTime((FILETIME*)Timestamp,SystemTime);WCHAR LevelMarker(LevelWINTUN_LOG_INFO)?L:(LevelWINTUN_LOG_WARN)?L-:L!;fwprintf(stderr,L%04u-%02u-%02u %02u:%02u:%02u.%04u [%c] %s\n,...);}亮点实现了 Wintun 要求的WINTUN_LOGGER_CALLBACK回调原型通过WintunSetLogger注册使 Wintun 内部日志也能输出到控制台。时间戳100 ns 间隔自 1601-01-01被正确转换为本地时间便于阅读。用、-、!分别代表 Info、Warn、Error 级别直观简洁。此外程序还提供了LogError、LogLastError、Log三个辅助函数LogError利用FormatMessage将 Win32 错误码转换为可读的字符串并自动添加前缀。LogLastError封装GetLastError()LogError简化调用。Log变参函数格式化输出到日志回调。这组日志工具使得程序在任何错误发生时都能输出详尽的诊断信息极大提升了调试效率。2.3 控制台信号处理优雅退出staticHANDLE QuitEvent;staticvolatileBOOL HaveQuit;staticBOOL WINAPICtrlHandler(DWORD CtrlType){switch(CtrlType){caseCTRL_C_EVENT:caseCTRL_BREAK_EVENT:caseCTRL_CLOSE_EVENT:caseCTRL_LOGOFF_EVENT:caseCTRL_SHUTDOWN_EVENT:Log(WINTUN_LOG_INFO,LCleaning up and shutting down...);HaveQuitTRUE;SetEvent(QuitEvent);returnTRUE;}returnFALSE;}机制HaveQuit是volatile全局标志供工作线程轮询。QuitEvent是一个手动重置事件用于唤醒阻塞在WaitForSingleObject上的线程。当用户按下 CtrlC 或关闭控制台时CtrlHandler被调用设置标志并触发事件所有线程收到信号后自行退出。这保证了示例程序在退出前能正确调用WintunEndSession和WintunCloseAdapter避免驱动资源泄漏。2.4 数据包处理逻辑PrintPacket MakeICMP2.4.1 收包解析PrintPacketstaticvoidPrintPacket(constBYTE*Packet,DWORD PacketSize){if(PacketSize20){/* 错误 */return;}BYTE IpVersionPacket[0]4,Proto;WCHAR Src[46],Dst[46];if(IpVersion4){RtlIpv4AddressToStringW((structin_addr*)Packet[12],Src);RtlIpv4AddressToStringW((structin_addr*)Packet[16],Dst);ProtoPacket[9];Packet20;PacketSize-20;}elseif(IpVersion6){// 检查最小长度 40 字节RtlIpv6AddressToStringW((structin6_addr*)Packet[8],Src);RtlIpv6AddressToStringW((structin6_addr*)Packet[24],Dst);ProtoPacket[6];Packet40;PacketSize-40;}else{Log(WINTUN_LOG_INFO,LReceived packet that was not IP);return;}// 如果协议是 ICMP (1) 且是回显应答 (type0)特殊标记if(Proto1PacketSize8Packet[0]0)Log(WINTUN_LOG_INFO,LReceived IPv%d ICMP echo reply from %s to %s,IpVersion,Src,Dst);elseLog(WINTUN_LOG_INFO,LReceived IPv%d proto 0x%x packet from %s to %s,IpVersion,Proto,Src,Dst);}解析要点通过 IPv4 首部第一个字节的高 4 位判断版本区分 IPv4 和 IPv6。使用RtlIpv4AddressToStringW/RtlIpv6AddressToStringW将二进制地址转换为字符串需链接ip2string.h和ntdll.lib。对于 ICMP 回显应答Echo Replytype0专门输出“ICMP echo reply”提示便于观察 ping 响应。2.4.2 发包构造MakeICMPstaticvoidMakeICMP(BYTE Packet[28]){memset(Packet,0,28);Packet[0]0x45;// IPv4, 首部长度 5*(USHORT*)Packet[2]htons(28);// 总长度 28Packet[8]255;// TTLPacket[9]1;// 协议 ICMP*(ULONG*)Packet[12]htonl((1024)|(616)|(78)|(80));// 源 10.6.7.8*(ULONG*)Packet[16]htonl((1024)|(616)|(78)|(70));// 目的 10.6.7.7*(USHORT*)Packet[10]IPChecksum(Packet,20);// IPv4 首部校验和Packet[20]8;// ICMP 类型: Echo Request*(USHORT*)Packet[22]IPChecksum(Packet[20],8);// ICMP 校验和Log(WINTUN_LOG_INFO,LSending IPv4 ICMP echo request to 10.6.7.8 from 10.6.7.7);}注意构造的是ICMP Echo Requestping 请求源地址为10.6.7.8目的地址为10.6.7.7。但示例程序在后续配置中将适配器的 IP 设为了10.6.7.7见后文这意味着它将 ping自身——实际上数据包会由操作系统路由回本机然后被ReceivePackets捕获并打印为“ICMP echo reply”不对因为源地址是 10.6.7.8而适配器是 10.6.7.7所以实际上是从 10.6.7.8 发往 10.6.7.7但源地址 10.6.7.8 并未分配给任何接口因此这个包会进入网络栈并被路由由于目标 10.6.7.7 是本机系统会响应 ICMP Echo Reply但源地址仍为 10.6.7.7目标为 10.6.7.8。所以最终接收到的包应该是 Echo ReplyPrintPacket 会识别出 type0输出“ICMP echo reply”。这个设计巧妙模拟了 ping 环回测试。IPv4 校验和计算函数IPChecksum实现了标准的一进制补码求和支持任意长度。

相关新闻

北邻京网站茵建设:小站深耕长尾流量的逆袭之路

北邻京网站茵建设:小站深耕长尾流量的逆袭之路

在这个流量为王、大V横行的互联网时代,很多人一听到“建站”这两个字,脑子里蹦出来的全是高大上的电商平台、炫酷的3A级门户或者动辄百万预算的定制化开发。大家总觉得,只有那些拥有庞大服务器集群、顶尖UI设计团队和海量资金支撑的项目,才配叫“做网站”。然而,现实往往是…

2026/9/12 20:35:38 阅读更多 →
OpenGeos/GeoLibre开源GIS工具实测:从环境搭建到核心功能验证

OpenGeos/GeoLibre开源GIS工具实测:从环境搭建到核心功能验证

这类开源地理空间工具最值得先看的不是功能列表,而是它到底解决了数据处理、发布还是协作中的哪个具体问题。OpenGeos / GeoLibre 这个名字听起来像是一个平台或工具集,对于需要处理地图、矢量数据、栅格影像或者搭建简单 GIS 服务器的开发者、数据分析师…

2026/9/11 17:27:42 阅读更多 →
管理系统通过邮箱自动备份数据思路|阿雪技术观-东方仙盟

管理系统通过邮箱自动备份数据思路|阿雪技术观-东方仙盟

数字化经营环境下,企业各类管理系统沉淀的业务单据、台账资料、流程记录,是支撑经营追溯、业务持续运转的核心信息资产。在日常运维管理中,多数企业更加关注系统能否稳定对外提供服务,却常常忽视数据留存体系的建设。一旦出现存储…

2026/9/4 20:21:58 阅读更多 →

最新新闻

C语言核心基础:彻底搞懂分支与循环语句

C语言核心基础:彻底搞懂分支与循环语句

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:05:13 阅读更多 →
Dozzle MCP 集成指南:让 AI 编程助手直接读写你的 Docker 容器日志

Dozzle MCP 集成指南:让 AI 编程助手直接读写你的 Docker 容器日志

Dozzle MCP 集成指南:让 AI 编程助手直接读写你的 Docker 容器日志 【免费下载链接】dozzle Realtime log viewer for containers. Supports Docker, Swarm and K8s. 项目地址: https://gitcode.com/GitHub_Trending/do/dozzle Dozzle 通过内置的 Model Con…

2026/9/15 2:05:13 阅读更多 →
为什么Java仍是国内开发者最稳妥的选择?从生态到面试全解析

为什么Java仍是国内开发者最稳妥的选择?从生态到面试全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 2:05:13 阅读更多 →
微网两阶段鲁棒容量配置:CCG算法与YALMIP/CPLEX实现

微网两阶段鲁棒容量配置:CCG算法与YALMIP/CPLEX实现

简介:这套代码面向微电网规划与电气工程研究者,解决含风电、光伏、储能及燃气轮机的多电源容量配置问题。程序基于两阶段鲁棒优化方法,一阶段决策储能、风电和光伏的安装容量,二阶段在不确定性场景下优化各机组实际出力&#xff0…

2026/9/15 2:05:13 阅读更多 →
YOLOv5果蔬识别系统实战:从数据集标注到模型训练与部署

YOLOv5果蔬识别系统实战:从数据集标注到模型训练与部署

简介:YOLOv5果蔬识别系统是一套面向计算机专业毕业设计、期末大作业与深度学习实战的完整项目资料,包含可供模型训练与评估的果蔬数据集、可本地编译运行的源代码,以及配套教程,适合需要快速落地目标检测实践的高校学生和开发者。…

2026/9/15 2:05:13 阅读更多 →
视频元数据管理工具与批量处理实战指南

视频元数据管理工具与批量处理实战指南

1. 视频元数据管理的重要性与痛点在数字媒体爆炸式增长的今天,视频文件已成为我们日常工作和娱乐的重要组成部分。每个视频文件都携带了大量元数据(Metadata),这些隐藏在文件内部的信息记录了视频的标题、作者、创建日期、版权信息…

2026/9/15 2:04:12 阅读更多 →

日新闻

Java高级技术:从语言特性到性能优化全解析

Java高级技术:从语言特性到性能优化全解析

1. Java高级技术概述Java作为一门成熟的编程语言,经过二十多年的发展已经形成了完整的生态系统。在企业级应用开发、大数据处理、移动开发等领域,Java都占据着重要地位。掌握Java高级技术不仅意味着能够编写更高效的代码,更代表着开发者能够解…

2026/9/15 0:00:23 阅读更多 →
C#与Halcon结合的工业视觉处理实战指南

C#与Halcon结合的工业视觉处理实战指南

1. 项目概述:C#与Halcon强强联合的视觉处理利器这个基于C#和Halcon的视觉处理Demo项目,是我在工业质检领域摸爬滚打多年后提炼出的实战精华。它完美融合了C#的界面开发优势与Halcon强大的图像处理能力,就像给视觉工程师配上了一把瑞士军刀。项…

2026/9/15 0:00:23 阅读更多 →
32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

1. 为什么“32路复合型”不是营销话术,而是工业现场真实痛点的硬解你有没有遇到过这样的场景:在某大型能源站的PLC机柜里,十几台不同年代、不同品牌的温控仪、电表、气体分析仪、阀门控制器,全靠RS-485总线挂在一根线上&#xff0…

2026/9/15 0:00:23 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/14 5:45:49 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/15 1:32:25 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/15 1:32:21 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/14 17:35:10 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/14 16:59:29 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/14 5:45:14 阅读更多 →