windows PPTP协议通道分析
字数 2479 2025-08-22 12:22:36
Windows PPTP协议通道分析技术文档
1. PPTP协议概述
PPTP(Point-to-Point Tunneling Protocol)是Windows VPN中使用的协议,分为控制通道和数据通道两部分。Windows内核通过Winsock Kernel (WSK)实现PPTP协议栈。
2. Winsock Kernel (WSK)基础
WSK是Windows内核中的套接字实现,主要特点:
- 提供API形式服务
- 采用事件驱动的回调机制
- 每个套接字关联一个调度表(包含函数指针)
- 使用上下文结构跟踪连接状态
3. PPTP套接字生命周期
3.1 套接字创建
通过WskOpenSocket函数处理客户端套接字:
- 参数:客户端上下文、客户端调度表等
- 创建240字节标记为"wana"的内存池
- 将新客户端套接字写入内存池
初始化结构:
- 偏移0: 写入"WSKC"(0x434b5357)
- 偏移2QWORD:
raspptp!CtlReceiveCallback - 偏移3QWORD:
raspptp!CtlDisconnectCallback - 偏移4QWORD:
raspptp!CtlConnectQueryCallback - 偏移6QWORD:
raspptp!CtlLogWskLibActivity - 偏移8QWORD:
raspptp!CtlpSendMessageComplete - 最后设置sock释放函数
FreeSockHandle和引用计数(初始为1)
3.2 套接字释放
通过WskConnDisconnectEvent函数释放:
- 基于引用计数决定是否释放
- 引用计数操作:
_InterlockedIncrement((volatile signed __int32 *)(a1 + 512)); // 递增 _InterlockedDecrement((volatile signed __int32 *)(a1 + 512)); // 递减 - 当引用计数为0时调用释放函数
4. 控制连接生命周期
4.1 控制连接结构
通过CtlAlloc函数分配:
- 分配0x290大小,标记为"PTPT"
- 结构体布局:
- 偏移0h/8h: 自身指针地址
- 偏移20h: "PTPT"标记
- 偏移28h: NDIS句柄
- 偏移358h: NDIS定时器指针
- 创建NDIS定时器:
- 标签"PTMT"
- 定时器函数
CtlpEchoTimeout - NDIS对象头: 0x180197
4.2 新控制连接处理
由CtlConnectQueryCallback处理:
- 参数:
- a1: 未知
- a2: 未知
- a3: WSK类型套接字结构体对象
- 初始化:
- 设置状态为3(偏移30h)
- 偏移48h设置为1
- 偏移58h指向自旋锁
- 偏移80h指向套接字结构体
- 偏移60h存放IRQL(自旋锁释放用)
- 偏移248h指向NDIS计时器(30秒)
- 偏移238h指向Echo计时器(如有)
4.3 控制连接释放
通过引用计数管理:
- 递增操作:
_InterlockedIncrement((volatile signed __int32 *)(a1 + 16)); *(_BYTE *)(a1 + 104) = 1; - 递减操作:
*(_BYTE *)(a1 + 104) = 0; if (!_InterlockedDecrement((volatile signed __int32 *)(a1 + 16))) (*(void (__fastcall **)(__int64))(a1 + 24))(a1); - 引用计数为0时调用
CtlFree释放
5. 呼叫连接(Call)生命周期
5.1 Call结构体定义
通过CallAlloc分配:
- 大小0x2B8,标记"PTPC"
- 关键字段:
- 偏移30h: "PTPC"标记
- 偏移38h: NDIS_HANDLE对象
- 偏移c2h/248h: 设置为0
- 偏移60h/88h/a8h: 自旋锁指针(初始化)
- 偏移1E0h: 网络缓冲列表(
NdisAllocateNetBufferList) - 偏移258h/260h: IO工作项句柄(
NdisAllocateIoWorkItem) - 偏移1a0h: 定时器对象(
NdisAllocateTimerObject) - 偏移1c0h: Call Ack定时器
- 偏移200h:
CallpDialTimeout计时器
5.2 Call结构体初始化
- 设置NDIS定时器对象
TimerCharacteristics属性 - 上下文指向Call结构体
- NDIS对象头: 0x180197
- 标签"PTMT"(与控制连接相同)
- 定时器回调函数
CallpCloseTimeout
5.3 Call结构体释放
通过CallCleanup释放:
- 引用计数管理
- 初始化出错时直接调用
CallFree - 递减操作:
if (引用计数 == 1) { 调用偏移40处的释放函数 }
6. 关键回调函数
-
控制连接相关:
CtlConnectQueryCallback: 处理新控制连接CtlDisconnectCallback: 处理控制断开CtlReceiveCallback: 处理控制接收数据CtlpSendMessageComplete: 控制连接发送消息完成
-
定时器相关:
CtlpEchoTimeout: 控制连接Echo超时处理CallpCloseTimeout: Call关闭超时处理CallpDialTimeout: Call拨号超时处理
7. 内存管理特点
-
使用特定标记的内存池:
- "wana": 套接字内存池(240字节)
- "PTPT": 控制连接内存池(0x290字节)
- "PTPC": Call内存池(0x2B8字节)
-
引用计数机制:
- 套接字、控制连接和Call都使用引用计数
- 通过
InterlockedIncrement/InterlockedDecrement操作 - 计数为0时触发释放
8. NDIS集成
PPTP协议栈深度集成NDIS(Network Driver Interface Specification):
- 使用NDIS定时器对象
- 使用NDIS网络缓冲列表
- 使用NDIS IO工作项
- 遵循NDIS对象头标准(0x180197)
9. 同步机制
-
自旋锁使用:
- 控制连接偏移58h处
- Call结构体偏移60h/88h/a8h处
- 配合IRQL(偏移60h)使用
-
原子操作:
- 引用计数使用
Interlocked系列函数保证原子性
- 引用计数使用
10. 错误处理
-
初始化错误:
- Call结构体初始化失败直接调用
CallFree
- Call结构体初始化失败直接调用
-
超时处理:
- 通过多个定时器(
CtlpEchoTimeout,CallpCloseTimeout等)处理各种超时情况
- 通过多个定时器(
-
资源释放:
- 严格遵循引用计数机制确保资源正确释放