分层服务提供者(LSP)(1)
开发过滤数据包的LSP程序可以定义过滤规则,恩,先看看
LSP本身是DLL,可以将它安装至Winsock目录,创建套接字的应用程序不必知道此LSP的任何信息就能调用它
1. 运行原理
用户创建套接字
1) 套接字创建函数(如socket)在Winsock目录寻合适的协议
2) 此协议的提供者导出的函数完成各种功能
我们的目的:
1) 将自己编写的提供者安装到Winsock目录中,让用户调用我们的服务提供者
2) 由我们的提供者调用下层提供者
就可以截获所有的Winsock调用
服务提供者本身是DLL,导出与Windows API相对应的函数,如WSPStartup,WSPSocket,WSPSendTo等.
这里的LSP向上导出所有的SPI函数供Ws2_32.dll调用,在内部又通过基础服务提供者实现这些SPI
2. 安装LSP
实现LSP之前,将分层提供者安装到Winsock目录,安装一个LSP包括安装一个WSAPROTOCOL_INFOW结构(协议的入口),让创建套接字的应用程序可以枚举到它.
WSAPROTOCOL_INFOW结构:定义了分层提供者的特性和LSP是如何填写"链"的.
(1) 协议链
LSP和基础提供者连在一起形成了协议链,协议链描述了分层提供者加入Winsock目录的顺序.
SPI提供三中协议:分层协议,基础协议,协议链
协议类型由WSAPROTOCOL_INFOW结构内的WSAPROTOCOLCHAIN结构中数据指定,如下:
typedef struct _WSAPROTOCOLCHAIN {
int ChainLen; // 链的大小,也就是下面数组的大小
DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; // 协议链入口数组,数组成员为链中协议的目录ID号
} WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
ChainLen暗示了入口的提供者类型
∙ 0, 分层协议
∙ 1, 基础协议(基础提供者,如TCP和UDP提供者,有与之关联的内核模式协议驱动TCPIP.SYS)
∙ 2, 协议链(目录ID-WSAPROTOCOL_INFOW结构中的dwCatalogEntryId域)
LSP在协议链中位置的影响:
顶层:被Ws2_32.dll加载
非顶层:被链中位于它上层的LSP加载
LSP被加载后的动作:
1) 首先调用LSP导出的函数WSPStartup
2) 将包含协议链的WSAPROTOCOL_INFOW结构传递给这个函数
3) LSP再到协议链中位于自己下方的提供者,进而加载它
安装LSP
1) 安装一个分层协议,用系统分配给此协议的目录ID和下层提供者的目录ID构建一个ChainEntries数组,进而构建一个WSAPROTOCOL_INFOW结构
2) 安装协议链
(2)安装函数
该函数只需提供LSP的GUID,DLL位置,描述它支持的协议的一个或多个WSAPROTOCOL_INFOW结构即可
int WSCInstallProvider(
const LPGUID lpProviderId, // 要安装的提供者的GUID
const LPWSTR lpszProviderDllPath, // 指向提供者DLL的路径
const LPWSAPROTOCOL_INFO lpProtocolInfoList, // 指向一个WSAPROTOCOL_INFOW结构数组
DWORD dwNumberOfEntries, // lpProtocolInfoList数组中入口的数量,即数组大小
LPINT lpErrno // 返回可能的失败代码
)
; // 只有UNICODE版本,失败则返回SOCKET_ERROR
lpProviderId: GUID可以通过命令行工具UUIDGEN或者编程中是用UuidCreate函数生成.
lpszProviderDllPath: UNICODE字符串,包含环境变量.如 %SYSTEMROOT%
lpProtocolInfoList: WSAPROTOCOL_INFOW结构的数组,每个数组成员是一个要安装的单独的入口,即可一次安装多个服务提供者
通常从它要分层的下层提供者拷贝,两种情况例外:
第一,szProtocol域要修改,以包含新提供者的名称
第二,如有XP1_IFS_HANDLES标志,从dwServiceFlags1域中移除
XP1_IFS_HANDLES标志表示此提供者返回的句柄是真正地操作系统句柄,可能会被传递到内部API.此提供者必须关联内核模式组件,创建TCPIP.SYS一样的句柄.
(3) 重新为目录排序
int WSCWriteProviderOrder(
LPDWORD lpwdCatalogEntryId, // WSAPROTOCOL_INFOW结构中的CatalogEntryId元素数组
DWORD dwNumberOfEntries // 上面数组的大小
);
lpwdCatalogEntryId: DWORD类型数组,以新的顺序包含了目录中每个提供者的目录入口.
这个函数定义在SPORDER.H和SPORDER.LIB库中,新的SDK中,定义转移到WS2_32.LIB中
总结:
1) 安装分层协议入口,获取系统分配的目录ID号
2) 安装一个或多个协议链,安装数量根据要分层的下层协议数量决定,如要把LSP安装在TCP,UDP和Raw之上,就要安装3个协议链.
(4) 示例代码
// 函数名 InstallProvider
// 参数:WCHAR* wszDllPath,为安装的LSP DLL路径地址
// 功能:将LSP安装到UDP协议之上
// 返回值: 错误值
// 步骤
// 1. 枚举所有的服务程序提供者,当发现其iAddressFamily == AF_INET和iProtocol == IPPROTO_UDP停止
// 2. 得到该协议信息,为WSAPROTOCOL_INFOW结构
// 3. 安装分层协议,根据上面得到的结构修改szProtocol,ChainLen,dwProviderFlags
// 5. WSCInstallProvider安装
// 6. 获取分层协议的目录ID号,根据ProviderId成员的判断得到该ID号
// 7. 安装协议链,原UDP的协议放在分层协议下层,协议链取新名,注意协议链与分层协议是两者不相关的
// 8. 重新排序Winsock目录,将我们的协议链提前
// 首先先查协议链,到ChainEntries[0]=该分层协议的协议链,放在第一个位置
// 而后添加其他基本协议(包括分层协议)或ChainEntries[0]不等于该分层协议的协议链
3. 移除LSP
传递要移除的提供者的GUID即可
int WSCDeinstallProvider(
LPGUID lpProviderId,
recv函数 LPINT lpErrno
);
首先根据分层协议的GUID号到其目录ID号,然后逐个移除各协议链,最后再移除分层协议的提供者.
// 函数名: InstallProvider
// 功能: 移除该LSP
// 到协议链和协议,移除
// 1. 根据协议的GUID到dwCatalogEntryId,然后根据这个到ChainEntries[0]等于该ID的协议链
// 2. 移除协议和协议链
4. 编写LSP
Winsock2 LSP实现在标准的Windows DLL中, 每个LSP必须实现和导出WSPStartup函数,函数原型如下:
int WSPStartup(
WORD wVersionRequested, // 调用者可以使用的Winsock SPI的最高版本号, 高字节是小版本号
LPWSPDATA lpWSPData, // 指向一个WSPDATA结构, 用于取得Winsock服务提供者的详细信息
LPWSAPROTOCOL_INFO lpProtocolInfo, // 指向一个WSAPROTOCOL_INFO结构,用来指定想得到的协议特征
WSPUPCALLTABLE UpcallTable, // Ws2_32.dll提供的向上调用转发的函数表结构
LPWSPPROC_TABLE lpProcTable // 指向SPI函数表结构的指针, 用来返回30个SPI服务函数
);
其他的SPI函数都经由LSP的分派表----pProcTable参数导出,描述分派表的WSPPROC_TABLE结构定义了必须在LSP实现的函数,原型如下
typedef struct _WSPPROC_TABLE {
LPWSPACCEPT lpWSPAccept;
LPWSPADDRESSTOSTRING lpWSPAddressToString;
LPWSPASYNCSELECT lpWSPAsyncSelect;
LPWSPBIND lpWSPBind;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论