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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM