• LSP(分层服务提供者)


    LSP本身是DLL,可以将它安装到winsock目录,以便创建套接字的应用程序不必知道此LSP的任何信息就能调用它。

    运行原理:

      套接字创建函数会在winsock目录中寻找合适的协议

      调用此协议,的提供者导出的函数 完成各种功能。

    编写目的:

      让用户调用自定义的服务提供者,有自定义的服务提供者调用下层提供者。这样便截获所有的winsock调用了。

    服务提供者本身是DLL,导出一些与winsock API相对应的SPI函数。winsock库加载服务提供者时,便依靠这些函数来实现winsockAPI。

    LSP也是如此,它向上导出所有的SPI函数供 Ws2_32.dll调用,在内部通过调用基础提供者实现这些SPI


    安装LSP:

    实现LSP之前,要先将分层提供者安装到winsock目录,安装包括一个WSAPPROTOCOL_INFOW结构,定义了分层提供者的特性和LSP填写链的方式。(也叫做协议入口)


    协议链:

      协议链描述了 分层提供者 加入winsock的目录的顺序。

    typedef struct _WSAPROTOCOLCHAIN{
      int ChainLen;
      DWORD ChainEntries[Max_PROTOCOL_CHAN];
    }WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN;

    ChainLen为0:分层协议  为1 基础协议   大于1 协议链

    当ChainLen为0或者1时,ChainEntries数组无意义

    大于1时,各个服务提供者的目录ID就包含在数组中。

     

    实现LSP的DLL要么被另一个LSP加载,要么直接被WS2_32.DLL加载。取决于它的位置。

    如果LSP没有在协议链的顶端,就会被链中位于它上层的LSP加载,否则的话,将被WS2_32.DLL加载。

    安装LSP时,必须在winsock目录中安装两种协议:一个分层协议,一个协议链

    安装分层协议视为了获取winsock库分配的目录ID号,一边在协议链中标识自己的位置。

    协议链才是winsock目录中LSP的真正入口,连中包含了自己分层协议的目录ID号和下层提供者的目录ID号。

    在安装时,要先安装一个分层协议,用系统分配给此分层协议的目录ID下层提供者的目录ID构建一个 ChainEntries数组,进而构建一个WSAPROTOCOL_INFOW结构,然后再安装这个协议链


    安装函数:

    提供LSP GUID DLL WSAPROTOCOL_INFOW结构便可。

    int WSCInstallProvider(
    const LPGUID lpProviderId,
    const LPWSTR lpszProviderDllPath,
    const LPWSAPROTOCOL_INFOW lpProtocolInfoList,
    DWORD dwNumberOfEntries,
    LPINT lpErrno
    );

    每一个安装提供者需要一个GUID来标识它的入口,GUID可以通过命令行工具UUIDGEN或者在编程使用UuidCreate函数来生成。

    LSP的WSAPROTOCOL_INFOW结构通常从它要分层的下层提供者拷贝

    1 szProtocol域要修改,以包含新提供者的名称

    2 如果包含XP1_IFS_HANDLES标识,要从dwServiceFlags1域移除。


    重新目录排序  WSCWriteProviderOrder

    新安装的LSP会默认安装到winsock目录的结尾,这样系统调用的时候,还是会调用原先调用的LSP,因此只有进行重新的排序才能让系统调用到新安装的LSP。


    总结:

      1 安装分层协议入口,以便获取系统分配的目录ID号。

      2 安装一个或者多个协议链,安装的数量取决于要分层的下层协议的数量。

      3 在结尾进行目录排序


    示例代码:

    ////////////////////////////////////////////////////////
    // InstDemo.cpp
    
    #include <Ws2spi.h>
    #include <Sporder.h>                // 定义了WSCWriteProviderOrder函数
    
    #include <windows.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Ws2_32.lib")
    #pragma comment(lib, "Rpcrt4.lib")    // 实现了UuidCreate函数
    
    
    // 要安装的LSP的硬编码,在移除的时候还要使用它
    GUID  ProviderGuid = {0xd3c21122, 0x85e1, 0x48f3, {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};
    
    
    LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)
    {
        DWORD dwSize = 0;
        int nError;
        LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
        
        // 取得需要的长度
        if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)
        {
            if(nError != WSAENOBUFS)
                return NULL;
        }
        
        pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);
        *lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
        return pProtoInfo;
    }
    
    void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)
    {
        ::GlobalFree(pProtoInfo);
    }
    
    
    // 将LSP安装到UDP协议提供者之上
    int InstallProvider(WCHAR *wszDllPath)
    {
        WCHAR wszLSPName[] = L"TinyLSP";    // 我们的LSP的名称
        int nError = NO_ERROR;
    
        LPWSAPROTOCOL_INFOW pProtoInfo;
        int nProtocols;
        WSAPROTOCOL_INFOW UDPLayeredInfo, UDPChainInfo; // 我们要安装的UDP分层协议和协议链
        DWORD dwUdpOrigCatalogId, dwLayeredCatalogId;
    
            // 在Winsock目录中找到原来的UDP协议服务提供者,我们的LSP要安装在它之上
        // 枚举所有服务程序提供者
        pProtoInfo = GetProvider(&nProtocols);
        for(int i=0; i<nProtocols; i++)
        {
            if(pProtoInfo[i].iAddressFamily == AF_INET && pProtoInfo[i].iProtocol == IPPROTO_UDP)
            {
                memcpy(&UDPChainInfo, &pProtoInfo[i], sizeof(UDPLayeredInfo));
                // 
                UDPChainInfo.dwServiceFlags1 = UDPChainInfo.dwServiceFlags1 & ~XP1_IFS_HANDLES;  
                // 保存原来的入口ID
                dwUdpOrigCatalogId = pProtoInfo[i].dwCatalogEntryId;
                break;
            }
        }  
    
            // 首先安装分层协议,获取一个Winsock库安排的目录ID号,即dwLayeredCatalogId
        // 直接使用下层协议的WSAPROTOCOL_INFOW结构即可
        memcpy(&UDPLayeredInfo, &UDPChainInfo, sizeof(UDPLayeredInfo));
        // 修改协议名称,类型,设置PFL_HIDDEN标志
        wcscpy(UDPLayeredInfo.szProtocol, wszLSPName);
        UDPLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL;        // LAYERED_PROTOCOL即0
        UDPLayeredInfo.dwProviderFlags |= PFL_HIDDEN;
        // 安装
        if(::WSCInstallProvider(&ProviderGuid, 
                        wszDllPath, &UDPLayeredInfo, 1, &nError) == SOCKET_ERROR)
            return nError;
        // 重新枚举协议,获取分层协议的目录ID号
        FreeProvider(pProtoInfo);
        pProtoInfo = GetProvider(&nProtocols);
        for(i=0; i<nProtocols; i++)
        {
            if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0)
            {
                dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
                break;
            }
        }
    
            // 安装协议链
        // 修改协议名称,类型
        WCHAR wszChainName[WSAPROTOCOL_LEN + 1];
        swprintf(wszChainName, L"%ws over %ws", wszLSPName, UDPChainInfo.szProtocol);
        wcscpy(UDPChainInfo.szProtocol, wszChainName);
        if(UDPChainInfo.ProtocolChain.ChainLen == 1)
        {
            UDPChainInfo.ProtocolChain.ChainEntries[1] = dwUdpOrigCatalogId;
        }
        else
        {
            for(i=UDPChainInfo.ProtocolChain.ChainLen; i>0 ; i--)
            {
                UDPChainInfo.ProtocolChain.ChainEntries[i] = UDPChainInfo.ProtocolChain.ChainEntries[i-1];
            }
        }
        UDPChainInfo.ProtocolChain.ChainLen ++;
        // 将我们的分层协议置于此协议链的顶层
        UDPChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; 
        // 获取一个Guid,安装之
        GUID ProviderChainGuid;
        if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK)
        {
            if(::WSCInstallProvider(&ProviderChainGuid, 
                        wszDllPath, &UDPChainInfo, 1, &nError) == SOCKET_ERROR)
                        return nError;
        }
        else
            return GetLastError();
    
    
    
            // 重新排序Winsock目录,将我们的协议链提前
        // 重新枚举安装的协议
        FreeProvider(pProtoInfo);
        pProtoInfo = GetProvider(&nProtocols);
    
        DWORD dwIds[20];
        int nIndex = 0;
        // 添加我们的协议链
        for(i=0; i<nProtocols; i++)
        {
            if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
                        (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
                dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
        }
        // 添加其它协议
        for(i=0; i<nProtocols; i++)
        {
            if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||
                    (pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))
                dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
        }
        // 重新排序Winsock目录
        nError = ::WSCWriteProviderOrder(dwIds, nIndex);
    
        FreeProvider(pProtoInfo);
        return nError;
    }
    
    void RemoveProvider()
    {    
        LPWSAPROTOCOL_INFOW pProtoInfo;
        int nProtocols;
        DWORD dwLayeredCatalogId;
    
        // 根据Guid取得分层协议的目录ID号
        pProtoInfo = GetProvider(&nProtocols);
        int nError;
        for(int i=0; i<nProtocols; i++)
        {
            if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0)
            {
                dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
                break;
            }
        }
    
        if(i < nProtocols)
        {
            // 移除协议链
            for(i=0; i<nProtocols; i++)
            {
                if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
                        (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
                {
                    ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
                }
            }
            // 移除分层协议
            ::WSCDeinstallProvider(&ProviderGuid, &nError);
        }
    }
    
    
    
    ////////////////////////////////////////////////////
    
    int binstall = 0;
    void main()
    {
        if(binstall)
        {
            if(InstallProvider(L"lsp.dll") == ERROR_SUCCESS)
            {
                printf(" Install successully \n");
            }
            else
            {
                printf(" Install failed \n");
            }
        }
        else
            RemoveProvider();
    }
  • 相关阅读:
    QT解决方案中新建动态链接库工程,且继承于QObject,解决无法生成moc_XXX.cpp文件的问题,解决工程之间的引用问题
    MATLAB Simulink中解算器的定步长和各模块采样时间之间的关系
    simulink使用MATLAB function的端口多出入多输出,输入输出向量设置
    simulink error:Error in default port dimensions function of S-function ‘XXXXXXXXXXX’. This function does not fully set the dimensions of output port 2.
    Git 问题:SSL certificate problem: self signed certificate
    git push失败:ssh:connect to host github.com port 22:Connection timed out
    戴尔笔记本插耳机听歌暂停后继续声音突然变大
    PDF阅读器和编辑器选择
    21天战拖记——Day15:填坑:行动任务项目的区别(2014-05-18)
    21天战拖记——Day14:如何养成一个习惯?(2014-05-17)
  • 原文地址:https://www.cnblogs.com/xing901022/p/2736259.html
Copyright © 2020-2023  润新知