LSP (Layered Service Providers)

LSP itself is a DLL, you can install it to winsock directory to create socket applications do not have to know anything about this LSP will be able to call it.

Operating principle:

  Socket creation function to find the right protocol in the directory winsock

  Export function provided by calling the agreement, the completion of various functions.

Purpose of writing:

  Allowing users to call from the service provider-defined, service providers have a custom call to the underlying provider. This will intercept all winsock calls.

 

Service provider itself is DLL, export some of winsock API corresponding SPI function. winsock library when loading a service provider, we rely on these functions to achieve winsockAPI.

LSP is true, it exported up all the SPI for Ws2_32.dll function call , in achieving these SPI provider by calling the foundation interior .


Installation LSP:

Before implementing LSP, the first hierarchical directory winsock provider installed, the installation includes a WSAPPROTOCOL_INFOW structure, defines the characteristics of hierarchical LSP provider and fill in chain fashion. (Also called inlet Protocol)


 

Agreement chain:

  Chain layered protocol described order of addition of the provider of the directory winsock.

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

ChainLen to 0: 1 based protocol is a layered protocol protocol chain is greater than 1

When ChainLen 0 or 1, ChainEntries array meaningless

Is greater than 1, each of the service provider ID is included in the directory array.

 

DLL to achieve the LSP or another LSP is loaded, either directly WS2_32.DLL loaded. Depending on its location.

If no LSP, will be located at the top of the chain in its upper layer protocol chain LSP loaded, otherwise, it will be WS2_32.DLL loaded.

 

When installing the LSP, you must be installed in the directory winsock two protocols: a layered protocol , a protocol chain .

Installation layered protocol deemed the acquisition winsock library catalog assigned an ID number, to identify their place in the side chain agreement.

Agreement chain is winsock directory entry LSP true, even in his own catalog contains the ID number and the lower layer protocol provider directory ID number.

 

During installation, the first installation of a layered protocol , assigned to the system with a layered protocol directory ID and the underlying provider ID directory construct a ChainEntries array , and then build a WSAPROTOCOL_INFOW structure, and then install the protocol chain .


Installation function:

Provide LSP GUID DLL WSAPROTOCOL_INFOW structure can be.

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

Each mounting a provider needs to identify its entry GUID, GUID can UUIDGEN command-line tools or by using programming function to generate UuidCreate.

The LSP WSAPROTOCOL_INFOW structures typically copied from a lower layer to be provided by its layered

1 szProtocol domain to be modified to include the name of the new provider

2 If you include XP1_IFS_HANDLES identity, from dwServiceFlags1 domain removed.


 

Re directory sort WSCWriteProviderOrder

Newly installed LSP is installed by default to the end of winsock catalog, so when the system calls, or calls LSP original call, only to re-sort to make a system call to the newly installed LSP.


to sum up:

  Mounting layered protocol inlet , in order to obtain the system ID number assigned to the directory.

  2 is mounted one or more protocol-chain , the number of mounting depends on the number of underlying protocols to be layered.

  3 at the end of catalog ordering .


Sample code:

////////////////////////////////////////////////////////
// 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();
}

Reproduced in: https: //my.oschina.net/u/204616/blog/545523

Guess you like

Origin blog.csdn.net/weixin_33758863/article/details/91989432