网络编程之Winsock2 服务提供者接口(SPI)

zz from: http://blog.csdn.net/aaron133/article/details/78005779


【1】全称Winsock2 服务提供者接口(SPI):

[描述]
1、一般用于提供给操作系统开发商、传输堆栈商在基础协议的基础上,开发更高级的服务.
2、因为[Winsock服务体系]符合[Windows开放服务体系],所以,它支持[第三方服务提供者]插入到其中.
3、只要上层和下层的边缘支持Winsock2 SPI,即可向他们中间安装[提供者程序].

4、普通开发者一般都是开发SPI的LSP(分层服务提供者),即第三方提供者,可用于监控Winsock API执行,HOOK Winsock API,甚至利用LSP技术注入DLL.

5、基础协议(TCP、UDP、原始)的提供者其实就是DLL,编写分层协议提供者就是在编写DLL,然后安装在Winsock目录上,让系统上的网络程序调用.


【须知】网络程序是如何调用Winsock2 服务提供者进行网络通讯


1、当网络程序使用WSAStartup加载库时,系统并不做什么,而是当程序真正创建套接字时,会先调用WSCEnumProtocols函数,遍历系统内安装的所有提供者(分层、基础、协议链),当先找到一个与要求使用的协议符合的,那么导出此提供者的DLL,调用提供者的WSPStartup初始化函数,才能使用send,recv(TCP协议提供者的DLL)或sendto,recvfrom(UDP协议提供者的DLL)等函数的功能.



【1.1】SPI由两个部分组成:
  1)传输服务提供者:1)提供建立连接、传输数据、流控制、出错控制.
                                 2)共两种类型:

                                         1)基础服务提供者:实现传输协议的细节,导出Winsock接口(此接口直接实现协议). //TCP、UDP、原始

                                                                        一般都有与之关联的内核模式协议驱动,TCP、UDP由系统内的Tcpip.sys驱动


                                         2)分层服务提供者:     //我们自己写的提供者(就是Dll)
                                                        1)将自己安装到[Winsock目录]中[基础提供者]的上一层,可能安装在其他[提供者]之间,可截获程序的Winsock API.
                                                        2)依靠[基础服务提供者]作为通信基础,实现更高层的通信函数.
        
  2)命名空间服务提供者:1)与[传输服务提供者]相似,可截获[名称解析API](gethostbyname、WSALookupServiceBegin)的调用.
                                         2)需在[命名空间目录]安装自己.


【2】SPI函数集合类型:                               //头文件:ws2spi.h


SPI函数类型总数:4种类型.


[开头]                      [描述]
 WSC                        安装、移除、修改[分层服务提供者]和[命名空间提供者程序].
 WSP                        [分层服务提供者]的API.
 WPU                        [分层服务提供者]使用的支持函数.
 NSP                         [命名空间服务提供者]的API.


【3】[Winsock协议目录]的概念:



1、SPI提供3种协议:1)分层协议:处在[基础协议]的上一层,依靠[基础协议]作为通信基础.
                                  2)基础协议:能够独立、安全、远程端点实现数据通信的协议.

                                  3)协议链:将一系列[基础协议]和[分层协议]按特定顺序连接在一起.


2、注意:只有管理员用户组能够安装、移除Winsock目录入口!



[WSAPROTOCOL_INFO结构体]

说明:描述某个[协议]的完整信息,一个WSAPROTOCOL_INFO结构体称为[一个Winsock目录入口].

typedef struct _WSAPROTOCOL_INFOW {
    DWORD dwServiceFlags1;       //描述[协议]提供的服务的位掩码
    DWORD dwServiceFlags2;       //保留
    DWORD dwServiceFlags3;       //保留
    DWORD dwServiceFlags4;       //保留
    DWORD dwProviderFlags;       //此[协议]在[Winsock目录]中的[表示方式]
    GUID ProviderId;                      //由[服务提供商]安排的GUID唯一标示符
    DWORD dwCatalogEntryId;      //WS2_32.DLL为每一个WSAPROTOCOL_INFOW结构安排的唯一标示符(目录入口ID)


    WSAPROTOCOLCHAIN ProtocolChain; /*1)与[此协议]相关联的WSAPROTOCOLCHAIN结构.
                                                                     2)说明了[此协议]在[分层协议]中所处的位置.*/

    int iVersion;                       //[协议]版本标示符
    int iAddressFamily;            //传递给socket/WSASocket函数的[地址加载参数]   
    int iMaxSockAddr;              //地址的最大长度(以字节为单位)
    int iMinSockAddr;               //地址的最小长度(以字节为单位)
    int iSocketType;                 //传递给socket函数的[套接字类型参数]
    int iProtocol;                       //传递给socket函数的[协议参数]
    int iProtocolMaxOffset;       //添加到iProtocol的最大值
    int iNetworkByteOrder;       //顺序类型:大尾顺序(BIGENDIAN),小尾顺序(LITTLEENDIAN)
    int iSecurityScheme;          //安全方案

    DWORD dwMessageSize;         /*[此协议]支持的最大消息长度(以字节为单位)
                                   1)0为基于流协议(如TCP),没有最大长度的概念.
                                   2)1为发送消息的最大长度依赖于下层网络的MTU(最大传输单元),在套接字绑定后,应使用SO_MAX_MSG_SIZE套接字选项.
                                     获取发送消息的最大长度.
                                   3)-1为此协议是基于消息的,但是对发送的消息没有最大长度的限制.
                                 */  

    DWORD dwProviderReserved;                            //保留给服务提供者使用.
    WCHAR  szProtocol[WSAPROTOCOL_LEN+1];  //随意编辑的,此协议的可读字符串.一般用于说明是什么协议
} WSAPROTOCOL_INFOW, FAR * LPWSAPROTOCOL_INFOW;


【4】遍历系统所安装的协议


[说明]
1、此函数仅能够遍历[基础协议]、[协议链],不能遍历[分层协议].

函数:WSAEnumProtocols(3个参数)

返回值:系统中安装的协议数量,失败为SOCKET_ERROR.

参数1:一个数组
1、NULL为函数将返回所有协议.
2、否则只检索数组中列出的那些协议.

参数2:取信息的缓冲区

参数3:参数2缓冲区的长度

1、如果参数2为NULL,参数3为0,执行后,WSAENOBUFS错误,参数3包含了所需的缓冲区长度.


【4.1】支持遍历[分层协议]的函数,功能与上面相同:


[说明]
1、因为SPI是用于开发系统组件的函数,所以他只使用Unicode字符串,与Windows系统相对应.

函数:WSCEnumProtocols(4个参数)   //SPI提供的函数,参数4:相当于WSAGetLastError()执行的结果

                                             //前3个参数与上面的函数相同


【5】遍历系统内安装的所有协议例子:

头文件:

#pragma once
#include <iostream>
#include <winsock2.h>     
#include <ws2tcpip.h>
#include <mstcpip.h>
#include <string.h>
#include <tchar.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(lib, "Ws2_32.lib")
//系统安装协议遍历实验
class ProtocolTraversestheExperiment
{
public:
ProtocolTraversestheExperiment()
{
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
}
~ProtocolTraversestheExperiment()
{
WSACleanup();
}
LPWSAPROTOCOL_INFO GetProvider(LPINT lpnTotalProtocols)
{
DWORD dwSize = 0;
LPWSAPROTOCOL_INFO pProtoInfo = NULL;
if (WSAEnumProtocols(NULL, pProtoInfo, &dwSize) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAENOBUFS)
return NULL;
}
pProtoInfo = (LPWSAPROTOCOL_INFO)new WSAPROTOCOL_INFO[dwSize / sizeof(WSAPROTOCOL_INFO)];
if (!pProtoInfo)
return NULL;
ZeroMemory(pProtoInfo, dwSize);
*lpnTotalProtocols = WSAEnumProtocols(NULL, pProtoInfo, &dwSize);
return pProtoInfo;
}
void FreeProvider(LPWSAPROTOCOL_INFO pProtoInfo,int i)
{
if(i == 1)
delete pProtoInfo;
else
   delete[] pProtoInfo;
}
};

源文件:

#include "Hello.h"
int main(int argc,char** argv)
{
system("color 4e");
ProtocolTraversestheExperiment s;
int ProtocolsCount = 0;
LPWSAPROTOCOL_INFO info = s.GetProvider(&ProtocolsCount);
if (ProtocolsCount != 0)
{
for (int i = 0; i < ProtocolsCount; i++)
{
wprintf(_T("Protocol:%s \r\n"), info[i].szProtocol);
wprintf(_T("CatalogEntryId:%d         ChainLen:%d \n\n"), info[i].dwCatalogEntryId, info[i].ProtocolChain.ChainLen);
}
s.FreeProvider(info, ProtocolsCount);
}
getchar();
return 0;
}

执行:



下一篇文章讲解安装LSP(分层服务提供者): //SPI的使用

1、由于基础传输提供者和命名空间提供者一般仅对操作系统开发商、传输堆栈商有效

      一般开发者只能开发分层服务提供者(所谓的第三方系统组件)

2、黑客通常安装LSP,拦截Winsock API,对用户进行浏览器劫持、监控使用者信息等等.

3、地址:http://blog.csdn.net/aaron133/article/details/78028942


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值