zoukankan      html  css  js  c++  java
  • SPI学习

    Winsock2服务提供者接口。Winsock2不仅提供了一个供应用程序访问网络服务的windows socket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的winsock服务提供者接口SPI和ws2_32.dll。他们的层次关系如图:

    一个应用程序 在调用 Winsock 2 函数时,Ws2_32.dll会调用相应的Winsock SPI函数,利用特定的服务提供者执行所请求的服务。

    eg:    select  ->  WSPSelect    connect 对应 WSAConnect API -> WSPConnect SPI


    传输服务提供者 是以DLL的形式存于系统之中的。  实际上WINDOWS 系统中有多个传输服务提供者,被顺序注册在系统中形成一个有序的WINSOCK目录

    IceSword 可以查看系统中注册的 SPI动态库

    SPI(Service Provider Interface)


    下面叙述 TCP协议安装我们的传输服务提供者 从而实现过滤拦截功能的步骤:

    1)首先在WINSOCK 目录安装一个基于 TCP协议的传输服务提供者的分层协议

    2)安装一个基于TCP协议的传输服务提供者的协议链

    3)协议链中将TCP协议所需的基础协议和我们先前安装的分层协议连接起来

    4)最后调整协议链在WINSOCK目录中的顺序使协议链位于最顶端

    下面是函数介绍:

    The UuidCreate function creates a new UUID.
    
    RPC_STATUS RPC_ENTRY UuidCreate(
      UUID *Uuid
    );
    The WSCInstallProvider function installs the specified transport provider into the system configuration database.
    
    int WSCInstallProvider (
      const LPGUID lpProviderId,
      const LPWSTR lpszProviderDllPath,
      const LPWSAPROTOCOL_INFOW lpProtocolInfoList,
      DWORD dwNumberOfEntries,
      LPINT lpErrno 
    );

    The WSCEnumProtocols function retrieves information about available transport protocols.
    
    int WSCEnumProtocols (
      LPINT lpiProtocols,
      LPWSAPROTOCOL_INFOW lpProtocolBuffer,
      LPDWORD lpdwBufferLength,
      LPINT lpErrno 
    );
    typedef struct _WSAPROTOCOL_INFO {
      DWORD  dwServiceFlags1;
      DWORD  dwServiceFlags2;
      DWORD  dwServiceFlags3;
      DWORD  dwServiceFlags4;
      DWORD  dwProviderFlags;
      GUID  ProviderId;
      DWORD  dwCatalogEntryId;
      WSAPROTOCOLCHAIN  ProtocolChain;
      int  iVersion;
      int  iAddressFamily;
      int  iMaxSockAddr;
      int  iMinSockAddr;
      int  iSocketType;
      int  iProtocol;
      int  iProtocolMaxOffset;
      int  iNetworkByteOrder;
      int  iSecurityScheme;
      DWORD  dwMessageSize;
      DWORD  dwProviderReserved;
      TCHAR  szProtocol[WSAPROTOCOL_LEN+1];
    } WSAPROTOCOL_INFO, *LPWSAPROTOCOL_INFO;
    
    The WSCDeinstallProvider function removes the specified transport provider from the system configuration database.
    
    int WSCDeinstallProvider (
      LPGUID lpProviderId,
      LPINT lpErrno 
    );
    The WSCWriteProviderOrder function is used to reorder the available transport providers. The order of the protocols determines the priority of a protocol when being enumerated or selected for us.
    
    int WSCWriteProviderOrder (
      LPDWORD lpwdCatalogEntryId,
      DWORD dwNumberOfEntries 
    );


    下面是修改一下就可用的   安装SPI  和  删除指定  GUID SPI  的代码:

    // InstallProvider.cpp : Defines the entry point for the console application.
    //
    
    #define UNICODE
    #define _UNICODE
    
    #include "stdafx.h"
    #include <RPC.H>
    #include <Rpcdce.h>
    #include <Ws2spi.h>
    #include <Sporder.h>		// 定义了WSCWriteProviderOrder函数
    #include <windows.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Sporder.lib")	// 实现了UuidCreate函数
    #pragma comment(lib, "Rpcrt4.lib")	// 实现了UuidCreate函数
    #pragma comment(lib, "WS2_32")	// 链接到WS2_32.lib
    
    BOOL UnInstall(GUID guidFilter);
    int GetProvider(LPWSAPROTOCOL_INFOW &pProtoInfo)
    {	
    	//  首次调用,pProtoInfo传入NULL,取得需要的缓冲区长度
    	DWORD dwSize = 0;
    	int nError = 0;
    	if(WSCEnumProtocols(NULL, NULL, &dwSize, &nError) == SOCKET_ERROR)
    	{
    		if(nError != WSAENOBUFS)
    		{
    			return 0;
    		}
    	}
    	// 申请足够缓冲区内存。
    	pProtoInfo = (LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR, dwSize);
    	if (pProtoInfo == NULL)
    	{
    		return 0;
    	}
    	//再次调用WSCEnumProtocols函数
    	return WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
    }
    #define Safe_Delete(pPointer) if(pPointer != NULL) {delete []pPointer; pPointer=NULL;}
    #define Safe_New(pPointer, Type, Size)  pPointer = new Type[Size]; if (pPointer == NULL) goto Exit;
    
    BOOL InstallProvider(WCHAR * pProviderName, WCHAR * pwszPathName, int *pProtocols, int iNum)
    {
    	if (pwszPathName == NULL || pProviderName == NULL)
    	{
    		return FALSE;
    	}
    	LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
    	//保存要安装的协议类型
    	int nIndex = 0, nProtocols, nError, i=0, nArrayCount = 0, *pTemp = NULL;
    	DWORD dwSize = 0, *pdwIds = NULL,*pdwOrigCatalogId = NULL;
    	WSAPROTOCOL_INFOW *pOriginalProtocolInfo = NULL;
    	BOOL bRet = FALSE;
    	Safe_New(pTemp, int, iNum)
    	//备份一份要安装的协议于pTemp指向的内存中
    	memcpy(pTemp, pProtocols, iNum*sizeof(int));
    	//为每个协议链准备WSAPROTOCOL_INFOW结构体
    	Safe_New(pOriginalProtocolInfo, WSAPROTOCOL_INFOW, iNum)
    	//pdwOrigCatalogId指向的数组成员用于保存分层协议下层的基础协议目录ID
    	Safe_New(pdwOrigCatalogId, DWORD, iNum)
    	DWORD dwLayeredCatalogId;// 我们分层协议的目录ID号
    	// 枚举所有服务程序提供者
    	nProtocols = GetProvider(pProtoInfo);
    	//将所有要安装新提供者的协议在Winsock目录中已存在的位于前端的提供者的WSAPROTOCOL_INFOW保存起来
    	for(; i<nProtocols; i++) 	//遍历Winsock目录中所有提供者
    	{   
    
    		if (i==16 || i==17)
    		{
    			UnInstall(pProtoInfo[i].ProviderId);
    		}
    // 		for (int j=0; j<iNum; j++)
    // 		{	//有iNum个协议要安装新提供者。
    // 			//判断当前提供者对应的协议是否是要安装新提供者的协议
    // 			if(pProtoInfo[i].iAddressFamily == AF_INET && pProtoInfo[i].iProtocol == pTemp[j])
    // 			{
    // 				pTemp[j] = -1; //清除此类型,确保不要查找到重复协议的提供者,只要最前端的。
    // 				//保存该协议正在使用的提供者的信息
    // 				memcpy(&pOriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
    // 				//分层协议中应该去除XP1_IFS_HANDLES标志。
    // 				pOriginalProtocolInfo[nArrayCount].dwServiceFlags1 = 
    // 					pOriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); 
    // 				//将该协议正在使用的提供者的目录ID保存起来。
    // 				pdwOrigCatalogId[nArrayCount] = pProtoInfo[i].dwCatalogEntryId;
    // 				nArrayCount++;
    // 				break; //找到后不必再循环查找其他的
    // 			}
    // 		}
    	}  
    	// 安装我们的分层协议,获取一个目录ID。
    	// 随便找一个下层协议的结构复制过来即可
    	WSAPROTOCOL_INFOW LayeredProtocolInfo;
    	memcpy(&LayeredProtocolInfo, &pOriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));
    	// 修改协议名称,类型,设置PFL_HIDDEN标志
    	wcscpy(LayeredProtocolInfo.szProtocol, pProviderName);
    	LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 设置分层协议标志;
    	LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN;
    	
    	// 获取一个Guid,安装分层协议
    	GUID ProviderLayeredGuid;
    	if(UuidCreate(&ProviderLayeredGuid) == RPC_S_OK)
    	{
    		if(WSCInstallProvider(&ProviderLayeredGuid,
    			pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR)
    		{
    			goto Exit;
    		}
    	}
    	// 重新枚举协议,获取分层协议的目录ID号
    	GlobalFree(pProtoInfo);
    	nProtocols = GetProvider(pProtoInfo);
    	for(i=0; i<nProtocols; i++)
    	{	//查找新安装的分层协议提供者的ID并保存。
    		if(memcmp(&pProtoInfo[i].ProviderId, &ProviderLayeredGuid, 
    			sizeof(ProviderLayeredGuid)) == 0)
    		{
    			dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
    			break;
    		}
    	}
    	// 安装协议链,多个协议链共用一个分层协议。有多少个协议要安装新提供者就要安装多少个协议链
    	// 修改协议名称,类型
    	WCHAR wszChainName[WSAPROTOCOL_LEN + 1];
    	for(i=0; i<iNum; i++)
    	{
    		swprintf(wszChainName, L"%ws over %ws", pProviderName, pOriginalProtocolInfo[i].szProtocol);
    		wcscpy(pOriginalProtocolInfo[i].szProtocol, wszChainName);
    		if(pOriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)
    		{	//当前协议正在使用的提供者是基础提供者,令该提供者的ID位于新安装的协议链中第二个位置
    			pOriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = pdwOrigCatalogId[i];
    		}
    		else
    		{
    			//当前协议正在使用的提供者是协议链提供者,则令该协议链整体后移,协议链首位置放分层协议
    			for(int j = pOriginalProtocolInfo[i].ProtocolChain.ChainLen; j>0; j--)
    			{
    				pOriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] 
    				= pOriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];
    			}
    		}
    		//将刚安装的分层协议放置到协议链的链首.
    		pOriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
    		//协议链中新安装了一个分层协议,所以使协议链中所链的协议数量加1。
    		pOriginalProtocolInfo[i].ProtocolChain.ChainLen++;	
    	}
    	// 获取一个Guid,安装协议链
    	GUID ProviderChainGuid;
    	if(UuidCreate(&ProviderChainGuid) == RPC_S_OK)
    	{
    		if(WSCInstallProvider(&ProviderChainGuid,
    			pwszPathName, pOriginalProtocolInfo, iNum, &nError) == SOCKET_ERROR)
    		{
    			goto Exit;	
    		}
    	}
    	else
    	{
    		goto Exit;
    	}
    	// 重新排序Winsock目录,将我们的协议链提前
    	// 重新枚举安装的协议
    	GlobalFree(pProtoInfo);
    	nProtocols = GetProvider(pProtoInfo);
    	Safe_New(pdwIds, DWORD,nProtocols)
    	// 将我们新安装的协议链提供者ID放置到ID数组前端
    	for(i=0; i<nProtocols; i++)
    	{
    		if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
    			(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
    		{	//我们新安装的所有协议链的链首都是分层协议,据此查找新安装的协议链
    			pdwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
    		}
    	}
    	// 添加其它协议提供者ID到ID数组中
    	for(i=0; i<nProtocols; i++)
    	{
    		if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||
    			(pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))
    			pdwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
    	}
    	// 根据ID数组中顺序重新排序Winsock目录
    	if((nError = ::WSCWriteProviderOrder(pdwIds, nIndex)) != ERROR_SUCCESS)
    	{
    		goto Exit;
    	}
    	bRet = TRUE;   //到这里安装成功
    Exit:
    	Safe_Delete(pdwIds)
    	Safe_Delete(pOriginalProtocolInfo)
    	Safe_Delete(pTemp)
    	Safe_Delete(pdwOrigCatalogId)
    	if (pProtoInfo != NULL)
    	{
    		GlobalFree(pProtoInfo);
    		pProtoInfo = NULL;
    	}
    	return bRet;
    }
    
    BOOL UnInstall(GUID guidFilter)
    {
    	BOOL bRet = FALSE;
    	LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
    	DWORD dwLayeredCatalogId;
    	// 根据Guid取得分层协议的目录ID号
    	int nProtocols = GetProvider(pProtoInfo);
    	int nError, i=0;
    	for(; i<nProtocols; i++)
    	{
    		if(memcmp(&guidFilter, &pProtoInfo[i].ProviderId, sizeof(guidFilter)) == 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))
    			{
    				bRet = WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
    			}
    		}
    		// 移除分层协议
    		bRet = WSCDeinstallProvider(&guidFilter, &nError);
    	}
    	return bRet;
    }
    
    int main(int argc, char* argv[])
    {
    	int iArray[3] = {IPPROTO_UDP, IPPROTO_TCP, IPPROTO_IP};
    	InstallProvider(L"SpiDll2", L"SpiDll2.dll", iArray, 3);
    	return 0;
    }
    


    例外这里:

    WSAStartup API 被调用时不会去调用对应的WSPStartup SPI 而是

    在应用程序 调用 socket/WSASocket 时 在WINsock目录中查找匹配的提供者

    找到后加载对应的DLL库,然后调用它的WSPStartup函数

    而WSPStartup功能是获得其他SPI函数的地址

    并且将各个函数地址保存到WSPStartup函数的第五个参数所指向的内存中

    可以称这块内存为SPI函数地址表

    其他的WINsock API在调用相应的Winsock SPI时就可以利用这个SPI 函数地址表查找相应的SPI函数地址,然后调用


    源码中这个DLL中含有过滤函数。

    处理方案:

    1)将Winsock目录下的病毒安装的传输服务提供者删除掉,上面有源码

    2)使用函数将系统中所有DLL模块的线程结束掉,当然我们不知道是什么DLL   使用 UnLoadModuleInSystem函数卸载系统中所有的指定的DLL:



    用这个软件业可以去卸载掉 handle

    卸载DLL用  CProcess中的源码







  • 相关阅读:
    php单元测试
    git配置本地环境(phpstudy/tortoisegit/git等)
    xp/win7中系统安装memcached服务,卸载memcached服务,以及删除memcached服务
    memcached装、启动和卸载
    如何安装memcached
    三元运算符、逻辑运算符
    移动端页面怎么适配ios页面
    javascript正则表达式——元字符
    一个div添加多个背景图片
    GNU Screen使用入门
  • 原文地址:https://www.cnblogs.com/zcc1414/p/3982486.html
Copyright © 2011-2022 走看看