一、个人防火墙技术概述

随着网络安全问题日益严重,广大用户对网络安全产品也越来越关注。防火墙作为一种网络安全工具,早已受到大家的青睐。在PC机上使用的个人防火墙,很大程度上成为广大网民的安全保护者。Windows下的个人防火墙都是基于对数据报的拦截技术之上。当然在具体的实现方式上它们却有很大的不同。总的来说可分为用户级和内核级数据报拦截两类。其中内核级主要是TDI过滤驱动程序,NDIS中间层过滤驱动程序,NDIS过滤钩子驱动程序等,它们都是利用网络驱动来实现的;而用户级的过滤包括SPI接口,Windows2000包过滤接口等。本文主要讲述基于SPI的包过滤实现,它是Winsock
2的一个新特性。

二、Winsock 2 SPI介绍

Winsock 2 是一个接口,而不是协议,所以它可以用于发现和使用任意数量的底层传输协议所提供的通信能力。起初的Winsock是围绕着TCP/IP协议运行的,但是在Winsock 2中却增加了对更多传输协议的支持。Winsock 2不仅提供了一个供应用程序访问网络服务的Windows socket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock服务提供者接口(SPI)和ws2_32.dll。本文仅讨论传输服务提供者及其应用,暂不对名字解析服务提供者进行分析。

Winsock 2的传输服务提供者是以动态链接库的形式(DLL)存在的,它是通过WSPStartup函数为上层函数提供接口,而其他的传输服务提供者函数则是通过分配表的方式来访问WS2_32.DLL。传输服务提供者的动态链接库只有在应用程序需要时才由Ws2_32.dll来装入内存中的,在不需要时则会被自动卸载。以下是winsock 2在传输服务提供者上的WOSA(Windows开放服务结构):

----------------------------

│Windows socket 2 应用程序│

--------------------------Windows socket 2 API

│       WS2_32.DLL        │

----------------------------Windows socket 2 传输SPI

│   传输服务提供者(DLL)  │

----------------------------

Windows socket SPI在服务提供者中使用了以下的函数前缀命名方式:WSP(Windows socket服务提供者),WPU(Windows socket提供者向上调用),WSC(Windows socket配置)。每一个传输服务提供者都有它自己所支持的传输协议,它是使用WSAPROTCOL_INFOW结构来实现的。传输服务提供者把所有的相关信息都存放在这个结构中,而应用程序就是通过这个结构的内容来将自己和相应的传输服务提供者相关联。

Windows socket SPI提供三种协议:分层协议,基础协议和协议链。分层协议是在基础协议的上层,依靠底层基础协议实现更高级的通信服务。基础协议是能够独立,安全地和远程端点实现数据通信的协议,它是相对与分层协议而言的。协议链是将一系列的基础协议和分层协议按特点的顺序连接在一起的链状结构,请参见下图:

API------------------------

│      WS2_32.DLL     │

SPI------------------------

│ 分层协议 │

SPI-------------

│ 分层协议 │

SPI------------------------

│       基础协议       │

------------------------

Ws2_32.dll数据传输部分的主要功能是在服务提供者和应用程序之间提供流量管理的功能。每个应用程序通过Ws2_32.dll和相应的服务提供者进行严格的数据交换。Ws2_32.dll根据应用程序在创建套接字时所提供的参数来选择特定的服务提供者,然后把应用程序的实现过程转发由所选创建套接字的服务提供者来管理。也就是说,Ws2_32.dll只是一个中间过程,而应用程序只是一个接口,数据通信的实现却是有服务提供者来完成的。我们说过,Ws2_32.dll是通过创建套接字的API函数WSASocket或socket的参数来确定使用哪一个服务提供者。而WSASocket/socket的参数中包括了地址族,套接字类型和协议类型,这三个因素共同决定了创建套接字的服务提供者。Ws2_32.dll在服务提供者中寻找第一个和前面三因素相匹配的WSAPROTOCOL_INFOW结构,然后就调用这个WSAPROTOCOL_INFOW结构相应的WSPStartup函数,(所有的数据传输服务提供者以DLL的形式,它们对外的接口就只有WSPStartup,其他的服务提供者函数都是通过WSPStartup来调用的),进而调用如WSPSocket的函数来创建套接字,WSPConnect的函数来建立连接等等。除了流量管理功能外,Ws2_32.dll还提供了其他的服务,比如协议枚举,基于线程的阻塞钩子管理和在Ws2_32.dll和服务提供者之间进行版本协商。

传输服务提供者实现的功能包括建立连接,传输数据,实现流控制和差错控制等函数。其实Ws2_32.dll并不知道服务提供者的请求等活动是如何实现了,Ws2_32.dll在应用程序和服务提供者之间实现了媒介的功能。传输服务提供者可分为两类:套接字描述符是可安装的文件系统(IFS)句柄的提供者;剩下的是非IFS的提供者。在我们的程序中选用了非IFS提供者。可见,服务提供者实现了底层的与网络相关的协议。Ws2_32.dll提供了介质级别的流量管理,应用程序则提供了有关如何实现网络相关的操作,它实现了用户所希望的功能。

在传输服务提供者的实现过程中,安装顺序是非常重要的。我们不仅要正确的安装服务提供者,而且还必须在Windows socket中注册,将相关的系统信息保存在数据库中,这样Ws2_32.dll才能够方便的获得下层服务提供者的相关信息。在Ws2_32.dll中提供了用来安装服务提供者的函数WSCInstallProvider,它需要服务提供者的有关数据,比如DLL的名称和路径。同时Ws2_32.dll还提供了卸载服务提供者的函数WSCDeinstallProvider,在不需要时通过它将特定的服务提供者从系统中删除。为什么说传输服务者的安装顺序很重要呢?在服务提供者配置函数中的WSCEnumProtocols是用来枚举系统中所有已安装的服务提供者,它按照服务提供者的安装顺序相应的列出他们。在前面我们也提到过,Ws2_32.dll在服务提供者中按安装顺序搜寻和WSASocket/socket提供的三个参数相匹配的服务提供者,所以安装顺序在一定程度上是决定了服务提供者是否被正确调用的关键。Windows
socket 2还提供了一个动态链接库Sporder.dll,它提供了对已安装的所有服务提供者顺序的重新排列(此DLL系统没有自带,common目录中已提供)。在附录中的T-Sporder.exe是一个查询当前已安装所有数据传输服务提供者属性的工具。

服务提供者系统中区分基础协议,分层协议和协议链是通过结构WSAPROTOCOL_INFOW中的Protocolchain结构的ChainLen值来实现的。分层协议的ChainLen值为0,基础协议的值为1,而协议链的值是大于1。在数据传输服务提供者的实现方式中分层协议和基础协议几乎是相同的,它们的不同之处在安装上。Windows中,现有的系统服务提供者(系统自带)几乎已提供了所有基本的服务,因此我们所写的服务提供者程序,都可以对数据报进行适当“修饰”后调用系统服务提供者来完成绝大部分剩下的功能,无论是基础服务提供者还是分层服务提供者都可以使用这种技术,免去不必要的劳动。基础服务提供者的实现过程主要是替换当前系统服务提供者的安装路径为自己的服务提供者的安装路径即可,当然我们必须保存所以系统服务者的相关数据,在我们卸载自己的服务提供者还原系统服务提供者时要用到这些信息,如系统服务者DLL的名称和路径。而协议链就不同了,首先我们必须安装好所有的基础协议和分层协议后,再构造协议链的WSAPROTOCOL_INFOW结构链,组成协议链的每个协议都会在协议链的ProtocolChain.ChainEntries数组中被定义,协议链数组中的第一个协议应该是第一个分层服务提供者。当然在安装分层协议及协议链时我们不会改变系统服务提供者,最多只是改变系统服务提供者的安装顺序罢了。在此,我们以分层服务提供者为例来说明数据传输服务提供者的安装过程。

Ws2_32.dll是使用标准的动态链接库来加载服务提供者接口的DLL到系统中去的,并调用WSPStartup来初始化。WSPStartup是Windows Socket 2应用程序调用SPI程序的初始化函数,也就是入口函数。WSPStartup的参数LPWSAPROTOCOL_INFOW指针提供应用程序所期望的协议信息,然后通过这个结构指针我们可以获得所保存的系统服务提供者的DLL名称和路径,加载系统服务提供者后查找到系统SPI程序的WSPStartup函数的指针,通过这个指针我们就可以将自己服务提供者的WSPStartup函数和系统SPI程序的WSPStartup函数相关联,进而调用系统的各个服务提供者函数。在数据传输服务提供者的实现中,我们需要两个程序,一个是可执行文件用来安装传输服务提供者;另一个就是DLL形式的数据传输服务提供者。下面我们就对安装程序(instif.exe)和实现程序(ipfilter.dll)所使用的主要函数进行简要分析。

三、相关程序代码分析

1.instif.exe

可执行程序instif.exe的主要功能是安装我们自己的分层传输服务提供者,并重新排列所有传输服务提供者的顺序,使我们的服务提供者位于协议链的顶端,这样相应类型的应用程序就会首先进入我们的传输服务提供者接口。本程序只有一个参数,就是安装(-install)或卸载(-remove)。作为演示,本程序只安装了IP分层协议及与UDP相关的协议链。(在ipfilter.dll中,我们只过滤目标端口为8000的UDP数据报)

自定义函数:

BOOL  getfilter();     //获得所有已经安装的传输服务提供者

void  freefilter();    //释放存储空间

void  installfilter(); //安装分层协议,协议链及排序

void  removefilter();  //卸载分层协议和协议链

代码分析:

protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize);

//分配WSAPROTOCOL_INFOW结构的存储空间

totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);

//获得系统中已安装的所有服务提供者

GetCurrentDirectory(MAX_PATH,filter_path);

//得到当前的路径

_tcscpy(filter_name,_T("\\ipfilter.dll"));

//构造服务提供者文件ipfilter.dll的路径全名

WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode);

//安装自定义的IP分层协议

iplayercataid=protoinfo[i].dwCatalogEntryId;

//获得已安装自定义IP分层协议的由Ws2_32.dll分配的唯一标志

udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;

//将自定义的IP分层协议作为自定义UDP协议链的根分层服务提供者安装在协议链的顶端

WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode);

//安装协议链

WSCWriteProviderOrder(cataentries,totalprotos);

//更新所有服务提供者的安装顺序,把自定义的服务提供者排在所有协议的最前列

WSCDeinstallProvider(&filterguid,&errorcode);

//卸载IP分层协议

WSCDeinstallProvider(&filterchainguid,&errorcode);

//卸载协议链

2.ipfilter.dll 

传输服务提供者都是以动态链接库的形式存在的,在应用程序需要时由Ws2_32.dll加载,在用完之后就被卸载。本文的ipfilter.dll提供了对发送的UDP数据报进行过滤的功能。也就是自定义WSPSendTo函数,在调用系统服务提供者之前进行过滤,判断是否继续向下调用,而其他的函数都是直接调用下层的系统服务提供者由它们直接处理。传输服务提供者只有一个入口函数就是WSPStartup,它是Windows Socket 应用程序调用SPI的初始化函数,其他SPI函数的调用都是通过WSPStartup的参

WSPUPCALLTABLE来实现的。

自定义函数:

int  WSPAPI WSPSendTo(SOCKET s,LPWSABUF lpbuffer,DWORD dwbuffercount,LPDWORD lpnumberofbytessent,

DWORD dwflags,const struct sockaddr FAR *lpto,int itolen,LPWSAOVERLAPPED lpoverlapped,

LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpcompletionroutine,LPWSATHREADID lpthreadid,LPINT lperrno);

//SPI函数WSPSendTo和Windows Socket 2的API函数WSASendTo相对应

int  WSPAPI WSPStartup(WORD wversionrequested,LPWSPDATA lpwspdata,LPWSAPROTOCOL_INFOW lpprotoinfo,

WSPUPCALLTABLE upcalltable,LPWSPPROC_TABLE lpproctable);

//SPI函数WSPStartup和Windows Socket 2的API函数WSAStartup相对应,WSPStartup是唯一的入口函数,剩下的30个SPI函数则是通过参数upcalltable来实现的,它们只能在内部调用,不向外提供入口

代码分析:

GetModuleFileName(NULL,processname,MAX_PATH);

//获得调用本服务提供者动态链接库的可执行文件的全名

OutputDebugString(_T("WSPSendTo Tencent Filtered"));

//输出调试信息

nextproctable.lpWSPSendTo(s,lpbuffer,dwbuffercount,lpnumberofbytessent,dwflags,lpto,

itolen,lpoverlapped,lpcompletionroutine,lpthreadid,lperrno);

//如果数据报满足发送条件,调用下层系统服务提供者发送数据

layerid=protoinfo[i].dwCatalogEntryId;

//获得已安装自定义IP分层协议的由Ws2_32.dll分配的唯一标志

nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];

//获得下一层传输服务提供者的标志信息

WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode);

//获得下一层传输服务提供者的安装路径

ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH);

//扩展环境变量

hfilter=LoadLibrary(filterpath));

//装载下一层传输服务提供者

wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"));

//获得下一层传输服务提供者的入口函数WSPStartup,以便调用

wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable);

//调用下一层传输服务提供者的WSPStartup函数,实现钩子功能

nextproctable=*lpproctable;

//保存下一层服务提供者的30个服务函数指针

lpproctable->lpWSPSendTo=WSPSendTo;

//调用自定义函数WSPSendTo

由于以动态链接库形式的服务提供者要向外提供一个入口函数,因此还须一个配置文件ipfilter.def:

EXPORTS    WSPStartup

//向外提供入口函数WSPStartup

3.T-Sporder.exe

T-Sporder.exe是一个辅助工具,用来查看当前系统中所有已经安装的传输服务提供者的属性。

totalprotocols=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);

//获得系统中的所有传输服务提供者,然后根据参数输出它们的各项属性。

四、小结与后记

本文向大家介绍了Windows Socket 2的一个新特性,那就是服务提供者接口SPI(Service Provider Interface)。它不仅包括我们主要讲解的传输服务提供者接口,还包括名字空间服务提供者接口。当然,基于SPI的包过滤安全措施并不是特别的好,因为很多建立在TDI上面的数据传输并不会受到SPI的影响,所以当前流行的防火墙大都是建立在NDIS之上的。

传输服务提供者是以DLL的形式存在于系统之中的,在基于IP协议的网络程序运行时,如果参数相匹配就会加载我们的传输服务提供者程序。而且在Windows下有很多系统网络服务,它们都是在系统启动时自动加载的,这就为我们隐藏木马的进程提供了有利的条件。也就是说在传输服务提供者程序里嵌入木马程序,很多基于IP协议的网络系统程序在开机时运行,这样我们嵌入的木马程序就会在系统启动时自动加载,在系统关闭时才会卸载。它的特点是只要安装一次后每每系统启动就会加载我们的传输服务提供者(里面包含木马程序),而不必像远程注入线程那样在系统每次启动时执行安装程序,并且它可同时被多个系统网络程序加载。

已编译好的可执行文件(过滤QQ数据报),您可以在我们的网站(http://fz5fz.yeah.net)下载。

五、附录之源程序

1.instif.exe

001.#define 
UNICODE    
002.#define 
_UNICODE        
003. 
004.#include
< stdio.h >
005.#include
< tchar.h >
006.#include
< string.h >
007.#include
< ws2spi.h >
008.#include
< sporder.h >
009. 
010.GUID 
filterguid={0x4d1e91fd,0x116a,0x44aa,{0x8f,0xd4,0x1d,0x2c,0xf2,0x7b,0xd9,0xa9}};
011. 
012.GUID 
filterchainguid={0xd3c21121,0x85e1,0x48f3,{0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};
013. 
014.BOOL  getfilter();
015.void  freefilter();
016.void  installfilter();
017.void  removefilter();
018.void  start();
019.void  usage();
020. 
021.int                   totalprotos=0;
022.DWORD                 protoinfosize=0;
023.LPWSAPROTOCOL_INFOW  
protoinfo=NULL;
024. 
025.int main(int argc,char *argv[])          
026.{
027.start();
028. 
029.if(argc==2)
030.{
031.if(strcmp(argv[1],"-install")==0)  
032.{
033.installfilter();
034.return 0;
035.}
036.else if(strcmp(argv[1],"-remove")==0) 
037.{
038.removefilter();
039.return 0;
040.}
041.}
042.usage();
043.return 0;
044.}
045. 
046.BOOL getfilter()
047.{
048.int  errorcode;
049. 
050.protoinfo=NULL;
051.totalprotos=0;
052.protoinfosize=0;
053. 
054.if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
055.{
056.if(errorcode!=WSAENOBUFS)
057.{
058._tprintf(_T("First
WSCEnumProtocols Error: %d\n"
),errorcode);
059.return FALSE;
060.}
061.}
062. 
063.if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
064.{
065._tprintf(_T("GlobalAlloc
in getfilter Error: %d\n"
),GetLastError());
066.return FALSE;
067.}
068. 
069.if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
070.{
071._tprintf(_T("Second
WSCEnumProtocols Error: %d\n"
),GetLastError());
072.return FALSE;
073.}
074. 
075._tprintf(_T("Found
%d protocols!\n"
),totalprotos);
076.return TRUE;
077.}
078. 
079.void freefilter()
080.{
081.GlobalFree(protoinfo);
082.}
083. 
084.void installfilter()
085.{
086.int                i;
087.int                provcnt;
088.int                cataindex;
089.int                errorcode;
090.BOOL               rawip=FALSE;
091.BOOL               udpip=FALSE;
092.DWORD              iplayercataid=0,udporigcataid=0;
093.TCHAR              filter_path[MAX_PATH];           
094.TCHAR              filter_name[MAX_PATH];
095.TCHAR              chainname[WSAPROTOCOL_LEN+1];     
096.LPDWORD            cataentries;
097.WSAPROTOCOL_INFOW 
iplayerinfo,udpchaininfo,chainarray[1];
098. 
099.getfilter();
100. 
101.for(i=0;i<
totalprotos;i++)
102.{
103.if(!rawip
104.&&
protoinfo[i].iAddressFamily==AF_INET
105.&&
protoinfo[i].iProtocol==IPPROTO_IP)
106.{
107.rawip=TRUE;
108.memcpy(&iplayerinfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
109.iplayerinfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1
& (~XP1_IFS_HANDLES);
110.}
111. 
112.if(!udpip
113.&&
protoinfo[i].iAddressFamily==AF_INET
114.&&
protoinfo[i].iProtocol==IPPROTO_UDP)
115.{
116.udpip=TRUE;
117.udporigcataid=protoinfo[i].dwCatalogEntryId;
118.memcpy(&udpchaininfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
119.udpchaininfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1
& (~XP1_IFS_HANDLES);
120.}
121.}
122. 
123._tcscpy(iplayerinfo.szProtocol,_T("T-IpFilter"));
124.iplayerinfo.ProtocolChain.ChainLen=LAYERED_PROTOCOL;
125. 
126.if(GetCurrentDirectory(MAX_PATH,filter_path)==0)
127.{
128._tprintf(_T("GetCurrentDirectory
Error: %d\n"
),GetLastError());
129.return ;
130.}
131._tcscpy(filter_name,_T("\\ipfilter.dll")); 
132._tcscat(filter_path,filter_name);
133. 
134.if(WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode)==SOCKET_ERROR)
135.{
136._tprintf(_T("WSCInstallProvider
Error: %d\n"
),errorcode);
137.return ;
138.}
139. 
140.freefilter();
141. 
142.getfilter();
143. 
144.for(i=0;i<
totalprotos;i++)
145.{
146.if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
147.{
148.iplayercataid=protoinfo[i].dwCatalogEntryId;
149.break;
150.}
151.}
152. 
153.provcnt=0;
154.if(udpip)
155.{
156._tcscpy(chainname,_T("T-UdpFilter"));
157._tcscpy(udpchaininfo.szProtocol,chainname);
158. 
159.if(udpchaininfo.ProtocolChain.ChainLen==BASE_PROTOCOL)
160.{
161.udpchaininfo.ProtocolChain.ChainEntries[1]=udporigcataid;
162.}
163.else
164.{
165.for(i=udpchaininfo.ProtocolChain.ChainLen;i>0;i--)
166.{
167.udpchaininfo.ProtocolChain.ChainEntries[i+1]=udpchaininfo.ProtocolChain.ChainEntries[i];
168.}
169.}
170. 
171.udpchaininfo.ProtocolChain.ChainLen++;
172.udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
173. 
174.memcpy(&chainarray[provcnt++],&udpchaininfo,sizeof(WSAPROTOCOL_INFOW));
175.}
176. 
177.if(WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode)==SOCKET_ERROR)
178.{
179._tprintf(_T("WSCInstallProvider
for chain Error: %d\n"
),errorcode);
180.return ;
181.}
182. 
183.freefilter();
184. 
185.getfilter();
186. 
187.if((cataentries=(LPDWORD)GlobalAlloc(GPTR,totalprotos*sizeof(WSAPROTOCOL_INFOW)))==NULL)
188.{
189._tprintf(_T("GlobalAlloc
int installfilter Error: %d\n"
),errorcode);
190.return ;
191.}
192. 
193.cataindex=0;
194.for(i=0;i<
totalprotos;i++)
195.{
196.if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0
197.|| memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))==0)
198.{
199.cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
200.}
201.}
202. 
203.for(i=0;i<
totalprotos;i++)
204.{
205.if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))!=0
206.&& memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))!=0)
207.{
208.cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
209.}
210.}
211. 
212.if((errorcode==WSCWriteProviderOrder(cataentries,totalprotos))!=ERROR_SUCCESS)
213.{
214._tprintf(_T("WSCWriteProviderOrder
Error: %d\n"
),GetLastError());
215.return ;
216.}
217. 
218.freefilter();
219. 
220._tprintf(_T("\nInstall
IP Filter Successfully"
));
221.return ;
222.}
223. 
224.void removefilter()
225.{
226.int  errorcode;
227.BOOL signal=TRUE;
228. 
229.if(WSCDeinstallProvider(&filterguid,&errorcode)==SOCKET_ERROR)
230.{
231._tprintf(_T("WSCDeinstall
filterguid Error: %d\n"
),errorcode);
232.signal=FALSE;
233.}
234. 
235.if(WSCDeinstallProvider(&filterchainguid,&errorcode)==SOCKET_ERROR)
236.{
237._tprintf(_T("WSCDeinstall
filterchainguid Error: %d\n"
),errorcode);
238.signal=FALSE;
239.}
240. 
241.if(signal)
242.{
243._tprintf(_T("Deinstall
IP Filter Successfully"
));
244.}
245.return ;
246.}
247. 
248.void  start()
249.{
250._tprintf(_T("Install
IP Filter, by TOo2y\n"
));
251._tprintf(_T("E-Mail:
TOo2y@safechina.net\n"
));
252._tprintf(_T("HomePage:
www.safechina.net\n"
));
253._tprintf(_T("Date:
10-29-2002\n\n"
));
254.return ;
255.}
256. 
257.void  usage()
258.{
259._tprintf(_T("Usage: 
instif  [ -install │ -remove ]\n"
));
260.return ;
261.}

2.ipfilter.dll

001.#define 
UNICODE
002.#define 
_UNICODE
003. 
004.#include
< ws2spi.h >
005.#include
< tchar.h >
006. 
007.GUID 
filterguid={0x4d1e91fd,0x116a,0x44aa,{0x8f,0xd4,0x1d,0x2c,0xf2,0x7b,0xd9,0xa9}};
008. 
009.LPWSAPROTOCOL_INFOW 
protoinfo=NULL;
010.WSPPROC_TABLE       
nextproctable;
011.DWORD                protoinfosize=0;
012.int                  totalprotos=0;
013. 
014.BOOL getfilter()
015.{
016.int    errorcode;
017. 
018.protoinfo=NULL;
019.protoinfosize=0;
020.totalprotos=0;
021. 
022.if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
023.{
024.if(errorcode!=WSAENOBUFS)
025.{
026.OutputDebugString(_T("First
WSCEnumProtocols Error!"
));
027.return FALSE;
028.}
029.}
030. 
031.if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
032.{
033.OutputDebugString(_T("GlobalAlloc
Error!"
));               
034.return FALSE;
035.}
036. 
037.if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
038.{
039.OutputDebugString(_T("Second
WSCEnumProtocols Error!"
));  
040.return FALSE;
041.}
042. 
043.return TRUE;
044.}
045. 
046.void freefilter()
047.{
048.GlobalFree(protoinfo);
049.}
050. 
051.BOOL WINAPI
DllMain(
HINSTANCE hmodule,
052.DWORD     reason,
053.LPVOID    lpreserved)
054.{
055.TCHAR   processname[MAX_PATH];
056.TCHAR   showmessage[MAX_PATH+25];
057. 
058. 
059.if(reason==DLL_PROCESS_ATTACH)
060.{
061.GetModuleFileName(NULL,processname,MAX_PATH);
062._tcscpy(showmessage,processname);
063._tcscat(showmessage,_T("
Loading IPFilter ..."
));
064.OutputDebugString(showmessage); 
065.}
066.return TRUE;
067.}
068. 
069.int WSPAPI
WSPSendTo(SOCKET s,
070.LPWSABUF        
lpbuffer,
071.DWORD            dwbuffercount,
072.LPDWORD          lpnumberofbytessent,
073.DWORD            dwflags,
074.const struct     sockaddr
FAR *lpto,
075.int              itolen,
076.LPWSAOVERLAPPED 
lpoverlapped,
077.LPWSAOVERLAPPED_COMPLETION_ROUTINE 
lpcompletionroutine,
078.LPWSATHREADID   
lpthreadid,
079.LPINT            lperrno)
080.{
081. 
082.struct sockaddr_in sin;
083. 
084.sin=*(const struct sockaddr_in
*)lpto;
085.if(sin.sin_port==htons(8000))       
086.{
087.OutputDebugString(_T("WSPSendTo
Tencent Filtered"
));
088.return 0;
089.}
090.else
091.{
092.return nextproctable.lpWSPSendTo(s,lpbuffer,dwbuffercount,
093.lpnumberofbytessent,dwflags,lpto,itolen,
094.lpoverlapped,lpcompletionroutine,lpthreadid,lperrno);
095.}
096.}
097. 
098.int WSPAPI
WSPStartup(
099.WORDwversionrequested,
100.LPWSPDATA        
lpwspdata,
101.LPWSAPROTOCOL_INFOWlpprotoinfo,
102.WSPUPCALLTABLEupcalltable,
103.LPWSPPROC_TABLElpproctable
104.)
105.{
106.OutputDebugString(_T("IPFilter
WSPStartup ..."
));
107. 
108.int           i;
109.int           errorcode;
110.int           filterpathlen;
111.DWORD         layerid=0;
112.DWORD         nextlayerid=0;
113.TCHAR         *filterpath;
114.HINSTANCE     hfilter;
115.LPWSPSTARTUP 
wspstartupfunc=NULL;
116. 
117.if(lpprotoinfo->ProtocolChain.ChainLenProtocolChain.ChainEntries[i]==layerid)
118.{
119.nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
120.break;
121.}
122.}
123. 
124.filterpathlen=MAX_PATH;
125.filterpath=(TCHAR*)GlobalAlloc(GPTR,filterpathlen); 
126.for(i=0;i<
totalprotos;i++)
127.{
128.if(nextlayerid==protoinfo[i].dwCatalogEntryId)
129.{
130.if(WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode)==SOCKET_ERROR)
131.{
132.OutputDebugString(_T("WSCGetProviderPath
Error!"
)); 
133.return WSAEPROVIDERFAILEDINIT;
134.}
135.break;
136.}
137.}
138. 
139.if(!ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH))
140.{
141.OutputDebugString(_T("ExpandEnvironmentStrings
Error!"
));   
142.return WSAEPROVIDERFAILEDINIT;
143.}
144. 
145.if((hfilter=LoadLibrary(filterpath))==NULL)
146.{
147.OutputDebugString(_T("LoadLibrary
Error!"
));
148.return WSAEPROVIDERFAILEDINIT;
149.}
150. 
151.if((wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL)
152.{
153.OutputDebugString(_T("GetProcessAddress
Error!"
)); 
154.return WSAEPROVIDERFAILEDINIT;
155.}
156. 
157.if((errorcode=wspstartupfunc(wversionrequested,lpwspdata,
158.lpprotoinfo,upcalltable,lpproctable))!=ERROR_SUCCESS)
159.{
160.OutputDebugString(_T("wspstartupfunc
Error!"
)); 
161.return errorcode;
162.}
163. 
164.nextproctable=*lpproctable;
165.lpproctable->lpWSPSendTo=WSPSendTo;
166. 
167.freefilter();
168.return 0;
169.}

基于SPI的数据报过滤原理与实现的更多相关文章

  1. 基于IMD的包过滤防火墙原理与实现

    一.前言二.IMD中间层技术介绍三.passthru例程分析四.部分演示代码五.驱动编译与安装六. 总结 一.前言 前段时间,在安全焦点上看到了TOo2y朋友写的<基于SPI的数据报过滤原理与实 ...

  2. ItemCF_基于物品的协同过滤_MapReduceJava代码实现思路

    ItemCF_基于物品的协同过滤 1.    概念 2.    原理 如何给用户推荐? 给用户推荐他没有买过的物品--103 3.    java代码实现思路 数据集: 第一步:构建物品的同现矩阵 第 ...

  3. ItemCF_基于物品的协同过滤

    ItemCF_基于物品的协同过滤 1.    概念 2.    原理 如何给用户推荐? 给用户推荐他没有买过的物品--103 3.    java代码实现思路 数据集: 第一步:构建物品的同现矩阵 第 ...

  4. 基于用户的协同过滤的电影推荐算法(tensorflow)

    数据集: https://grouplens.org/datasets/movielens/ ml-latest-small 协同过滤算法理论基础 https://blog.csdn.net/u012 ...

  5. 推荐召回--基于物品的协同过滤:ItemCF

    目录 1. 前言 2. 原理&计算&改进 3. 总结 1. 前言 说完基于用户的协同过滤后,趁热打铁,我们来说说基于物品的协同过滤:"看了又看","买了又 ...

  6. 推荐召回--基于用户的协同过滤UserCF

    目录 1. 前言 2. 原理 3. 数据及相似度计算 4. 根据相似度计算结果 5. 相关问题 5.1 如何提炼用户日志数据? 5.2 用户相似度计算很耗时,有什么好的方法? 5.3 有哪些改进措施? ...

  7. MixItUp:超炫!基于 CSS3 & jQuery 的过滤和排序插件

    MixItUp 是一款轻量,但功能强大的 jQuery 插件,提供了对分类和有序内容的美丽的动画过滤和排序功能.特别适合用于作品集网站,画廊,图片博客以及任何的分类或有序内容. 它是如何工作的? Mi ...

  8. SPI协议及工作原理分析

    说明.文章摘自:SPI协议及其工作原理分析 http://blog.csdn.net/skyflying2012/article/details/11710801 一.概述. SPI, Serial ...

  9. 转】Mahout分步式程序开发 基于物品的协同过滤ItemCF

    原博文出自于: http://blog.fens.me/hadoop-mahout-mapreduce-itemcf/ 感谢! Posted: Oct 14, 2013 Tags: Hadoopite ...

随机推荐

  1. 如何将项目中的package.json文件中的模块更新到最新版本

    有时候自己之前开发的项目回头运行的时候发行好多模块的版本不是最新的,此时想更为为最新版本,使用如下命令即可: npm i -g npm-check-updates ncu -u npm install

  2. Android中对消息机制(Handler)的再次解读

    今天遇到一些关于在子线程中操作Handler的问题,感觉又要研究源代码了,但是关于Handler的话,我之前研究过,可以参考这篇文章:http://blog.csdn.net/jiangwei0910 ...

  3. 最长上升子序列(LIS)问题

    最长上升子序列(LIS)问题 此处我们只讨论严格单调递增的子序列求法. 前面O(n2)的算法我们省略掉,直接进入O(nlgn)算法. 方法一:dp + 树状数组 定义dp[i]:末尾数字是i时最长上升 ...

  4. RichViewEdit

    RichViewEdit特殊操作 RichviewEdit 图文保存操作 首先要转换成stream后才能对RichviewEdit进行正确的读和写 function SaveRVFToField(rv ...

  5. (转)XMPP协议原理

    本文介绍XMPP协议原理及相关信息. XMPP协议简介   XMPP(Extensible Messageing and Presence Protocol:可扩展消息与存在协议)是目前主流的四种IM ...

  6. NAT和路由器 基本概念

    NAT(Network Address Translation, 网络地址转换)是1994年提出的.当在专用网内部的一些主机本来已经分配到了本地IP地址(即 仅在本专用网内使用的专用地址),但现在又想 ...

  7. http://elasticsearch-py.readthedocs.io/en/master/api.html

    API Documentation All the API calls map the raw REST api as closely as possible, including the disti ...

  8. mongodb update操作

    //修改字段名称,把synonymsList表的name_status修改为status db.getCollection('synonymsList').update({}, {$rename : ...

  9. JAVA 字符串索引

    String类的substring()方法   截取字符串,在java语言中的用法 1.  public String substring(int beginIndex) 返回一个新字符串,它是此字符 ...

  10. chrony实现局域网时间同步

    chrony基于cs架构实现,配置一台服务主机与其他客户主机即可 服务端 #yum install chrony --RHEL7默认已安装chrony,而没有安装ntpd. #systemctl st ...