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. 关键回调函数

  1. 控制连接相关:

    • CtlConnectQueryCallback: 处理新控制连接
    • CtlDisconnectCallback: 处理控制断开
    • CtlReceiveCallback: 处理控制接收数据
    • CtlpSendMessageComplete: 控制连接发送消息完成
  2. 定时器相关:

    • CtlpEchoTimeout: 控制连接Echo超时处理
    • CallpCloseTimeout: Call关闭超时处理
    • CallpDialTimeout: Call拨号超时处理

7. 内存管理特点

  1. 使用特定标记的内存池:

    • "wana": 套接字内存池(240字节)
    • "PTPT": 控制连接内存池(0x290字节)
    • "PTPC": Call内存池(0x2B8字节)
  2. 引用计数机制:

    • 套接字、控制连接和Call都使用引用计数
    • 通过InterlockedIncrement/InterlockedDecrement操作
    • 计数为0时触发释放

8. NDIS集成

PPTP协议栈深度集成NDIS(Network Driver Interface Specification):

  • 使用NDIS定时器对象
  • 使用NDIS网络缓冲列表
  • 使用NDIS IO工作项
  • 遵循NDIS对象头标准(0x180197)

9. 同步机制

  1. 自旋锁使用:

    • 控制连接偏移58h处
    • Call结构体偏移60h/88h/a8h处
    • 配合IRQL(偏移60h)使用
  2. 原子操作:

    • 引用计数使用Interlocked系列函数保证原子性

10. 错误处理

  1. 初始化错误:

    • Call结构体初始化失败直接调用CallFree
  2. 超时处理:

    • 通过多个定时器(CtlpEchoTimeout, CallpCloseTimeout等)处理各种超时情况
  3. 资源释放:

    • 严格遵循引用计数机制确保资源正确释放
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 函数释放: 基于引用计数决定是否释放 引用计数操作: 当引用计数为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 控制连接释放 通过引用计数管理: 递增操作: 递减操作: 引用计数为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 递减操作: 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 超时处理: 通过多个定时器( CtlpEchoTimeout , CallpCloseTimeout 等)处理各种超时情况 资源释放: 严格遵循引用计数机制确保资源正确释放