Recently, I have studied SPI filter technology (that is, the firewall based user-level filter), and it is also a matter of printing. Now, it is a bit experienced. Therefore, writing this one is also a summary, and it is a thing of the experience to share it out and share it. I hope to use it for everyone. Before entering the topic, I would like to thank those seniors who have selfless sharing their own research results, especially SafeChina's TOO2Y, his article "SPI-based datagram filtration principle and implementation" can be said to be the SPI filter technology The nurser, I am not listening, I am actually the relish of his source code. Speaking of the SPI filter, first look to the Winsock2 SPI. SPI Chinese name is called a service provider interface. Winsock2 SPI allows development of two service providers: Transport providers and namespace providers, where we are using the transmission provider. Winsock2 SPI corresponds to the Winsock2 API, at both ends of Winsock, respectively. The specific structure is as follows: ------------------------------------- | Windows Socket 2 app | ----------------------------------------- Windows Socket 2 API | WS2_32.DLL | --------------------------------------- Windows Socket 2 SPI | Hierarchy | ------------------- SPI | Hierarchical Provider | ----------------------- ------------ SPI | Basic Provider | ------------------------------------------------------------------------------------------------------------------------------------------ ---
For most WINSOCK2 API functions, they correspond to a Winsock2 SPI function. When these Winsock2 API functions are called, WS2_32.dll maps them to a WINSOCK2 SPI function and then executes our normal communication (such as WSASend to Wspsend). These SPI functions enters memory in the form of loading DLL when needed. Therefore, each service provider corresponds to a DLL, when the service provider is required, WS2_32.dll will load its corresponding DLL. However, it can be seen by the above figure, the transmission service provider can more than one (in fact, the service provider in a system will only have one), allowing multiple layers of service providers, then we are implementing communication applications Which service provider's DLL will be loaded? This is WS2_32.dll's work. Winsock 2 has a system configuration table that stores information about all transport service providers in the system. When the application establishes a socket, WS2_32.dll searches the first transmission service provider that matches the socket in this Winsock 2 system configuration table, and then loads the DLL corresponding to this provider. The above is the basic principle of the application service provider, but we are now a filter package, what should we do? In fact, as long as we can build a service provider, then put it in the top of all service providers, then WS2_32.dll will load our own service provider when needed, and load our own DLL So, we only need to implement the filter in our own DLL. But what should I do? Let us go back to the picture first. As can be seen from the figure, the service provider can be hierarchical. For example, we are now loaded is the DLL of the first layer of service provider. In this DLL, there is a unique entry function is Wspstartup, which corresponds to the API WSAStartup, its function prototype as follows: int Word WVersionRequested , lPWSPDATA lpwspdata, LPWSAPROTOCOL_INFOW lpprotoinfo, WSPUPCALLTABLE upcalltable, LPWSPPROC_TABLE lpproctable); said earlier, this function is the only function of the transmission service provider entry, while the other corresponds with the api spi function is given by the parameters of the lpProcTable. LPPROCTABLE is a pointer, pointing to a structure, and this structure is stored in the pointer of the SPI function. Ok, return to the original question, suppose we now load the first layer service provider's DLL, then, when the application calls the API, if you are WSASEND, you will find the SPI function Wspsend through the Wspstartup function, then look for the SPI function wspsend and execute. In general, in the Wspsend function of this layer SPI, after executing its specific operation, the next layer of service provider's Wspsend function is called, and the transfer of the next layer (this is to load the next layer of SPI) DLL, find its Wspstartup function to be implemented). This is normal communication. Now, we have to filter packages, then, as long as we don't call the next layer of Wspsend in this layer of Wspsend function? correct! This is my idea of this SPI filter. The source code is given below, including the installation section and the DLL section, you are welcome to criticize.
1. Install some #define unicode #define _unicode # include "stdafx.h" #include
GUID FilterGuid = {0xfdfdfdfd, 0x116a, 0x5151, {0x8f, 0xd4,0x21,0x21,0xf2,0x7b, 0xd9,0xa9}}; GUID FilterChainGuid = {0xfdfdfdfd, 0x2121,0x5151, {0x8f, 0xd4,0x21,0x21,0xcc, 0x7b, 0xD9, 0XAA}}; wsaprotocol_infow * lpallprotoinfo; int TotalNum
Void usage () {Printf ("******************************************************************************); Printf "* Made by ffantasyd * / n"); Printf ("* qq: 76889713 * / n"); Printf ("* email: ffantasyd@163.com * / n"); printf ("****** ***************************** / N "); Printf (" this Program Have 1 param: installfilter (/ install or / remove ) / N "); Printf (" if you select '/ install', you will install the filter; / n "); Printf (" And if you select '/ remove ", you will remove the filter thing you have installed. / N ");
Void ChangeFromunicode (unsigned short * uvalue, char * value) {INT i = 0;
While (uview [i]! = 0) {value [i] = uvalue [i]; i ;} value [i] = 0;}
Void ChangeTounicode (Char * Value, unsigned short * uvalue) {int i = 0;
While (Value [i]! = 0) {uview [i] = value [i]; i ;} uvalue [i] = 0;}
Bool getFilter () {dWord size = 0; int error; lpallprotoinfo = null; totalnum = 0;
:: WSCENUMPROTOCOLS (NULL, LPALLPROTOINFO, & SIZE, & ERROR); if (Error! = WSAENOBUFS) {Return 0;}
lpAllProtoInfo = new WSAPROTOCOL_INFOW [size]; memset (lpAllProtoInfo, 0, size); if ((TotalNum = :: WSCEnumProtocols (NULL, lpAllProtoInfo, & size, & Error)) == SOCKET_ERROR) {return 0;} return 1;} bool FreeFilter () {Delete [] lpallProtoInfo; Return 1;}
void install () {int i; DWORD ThisId, NextId; WSAPROTOCOL_INFOW ipProtoInfo, ipChainInfo; char szProto [WSAPROTOCOL_LEN 1] = {0}; char dllPath [MAX_PATH] = {0}; unsigned short UDllPath [MAX_PATH] = {0} DWORD * LPCATALOGENTRY = NULL; int iptrue = 0, TCPTRUE = 0;
// The following section is installing its own service provider getAllFilter (); for (i = 0; i STRCPY (SZProto, "IP_FILTER"); ChangeTounicode (Szproto, IpprotoInfo.szprotocol); ipprotoinfo.protocolchain.chainlen = 0; // Represents a hierarchical service provider :: GetCurrentDirectory (MAX_PATH, dllPath); strcat (dllPath, "// PacketFilter.dll"); ChangeToUnicode (dllPath, UDllPath); if (:: WSCInstallProvider (& FilterGuid, UDllPath, & ipProtoInfo, 1, NULL) == SOCKET_ERROR) { Printf ("Install Provider Failed! / N"); return;} freefilter (); // The following section is installing protocol chain getAllFilter (); for (i = 0; i if (ipChainInfo.ProtocolChain.ChainLen == 1) {ipChainInfo.ProtocolChain.ChainEntries [1] = NextId;} else {for (i = ipChainInfo.ProtocolChain.ChainLen; i> 0; i--) {ipChainInfo.ProtocolChain.ChainEntries [i] = ipchaininfo.protocolchain.chainentries [i-1];}}}}} ipchaininfo.protocolchain.chainlen ; ipchaininfo.protocolchain.chainentries [0] = thisID; // Put custom service provider to the top of the protocol chain IF (: wscinstallProvider (& Filterchainguid, UdllPath, & IpchainInfo, 1, NULL) == Socket_ERROR) {Printf ("Install chain failed! / n"); return;} freefilter (); // The following section is a service provider in the rearrangement system getAllfilter (); lpcatalogentry = new dword [totalnum]; int K = 0; for (i = 0; i if (! :: WSCWriteProviderOrder (lpCatalogEntry, TotalNum) = ERROR_SUCCESS) {printf ( "Write the provider's order failed / n!"); return;} delete [] lpCatalogEntry; FreeFilter (); printf ( "! Install successful / n" Return;} void remove () {if (:: WSCDeinstallProvider (& FilterChainGuid, NULL) == SOCKET_ERROR) {printf ( "! Remove Chain failed / n"); return;} if (:: WSCDeinstallProvider (& FilterGuid, NULL) == SOCKET_ERROR) { Printf ("Remove Provider Failed! / N"); Return; "Remove Successful! / N"); Return;} INT Main (int Argc, char * argv []) {usage (); if (argc! = 2) {RETURN 0;} printf ("start ............ / n" ); If (strCMP (Argv [1], "/ INSTALL") == 0) {install ();} if (strcmp (argv [1], "/ remove") == 0) {transove ();} Return 0;} 2.DLL section #define unicode # define _unicode #include "stdafx.h" #include "ws2spi.h" #include "tchar.h" #pragma comment (lib, "ws2_32.lib") // extern "C" __declspec (dllexport) int WSPAPI WSPStartup (WORD wversionrequested, // LPWSPDATA lpwspdata, // LPWSAPROTOCOL_INFOW lpprotoinfo, // WSPUPCALLTABLE upcalltable, // LPWSPPROC_TABLE lpproctable); GUID FilterGuid = {0xfdfdfdfd, 0x116a, 0x5151, {0x8f 0xD4, 0x21, 0x21, 0xF2, 0x7b, 0xD9, 0xA9}}; wsaprotocol_infow * lpallProtoInfo; int TotalNum Void ChangeFromunicode (unsigned short * ufilterpath, char * filterpath) {INT i = 0; While (ufilterpath [i]! = 0) {filterpath [i] = ufilterpath [i]; i ;} filterpath [i] = 0;} Bool getFilter () {dWord size; int error; lpallprotoinfo = null; totalnum = 0; :: WSCENUMPROTOCOLS (NULL, LPALLPROTOINFO, & SIZE, & ERROR); if (Error! = WSAENOBUFS) {Return 0;} lpAllProtoInfo = new WSAPROTOCOL_INFOW [size]; memset (lpAllProtoInfo, 0, size); if ((TotalNum = :: WSCEnumProtocols (NULL, lpAllProtoInfo, & size, & Error)) == SOCKET_ERROR) {return 0;} return 1;} bool FreeFilter () {Delete [] lpallProtoInfo; Return 1;} int WSPAPI WSPSend (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE, LPWSATHREADID lpthreadid, LPINT lperrno) {// do not pass down one spi, to achieve the purpose of the filter pack. To screen for the package, it can also be processed here. Return 0;} 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) {// do not down one spi Pass to achieve the purpose of the filter. To screen for the package, it can also be processed here. Return 0;} int WSPAPI WSPStartup (WORD wversionrequested, LPWSPDATA lpwspdata, LPWSAPROTOCOL_INFOW lpprotoinfo, WSPUPCALLTABLE upcalltable, LPWSPPROC_TABLE lpproctable) {DWORD ThisLayerId, NextLayerId; HINSTANCE hNextDll; LPWSPSTARTUP lpWspStartup; int Error; int i; GetAllFilter (); For (i = 0; i INT DLLPATHSIZE = max_path; unsigned short unicodedllpath [MAX_PATH] = {0}; char dllpath [max_path] = {0}, expanddllpath [max_path] = {0}; for (i = 0; i :: ExpandEnvironmentStrings (DllPath, ExpandDllPath, MAX_PATH); hNextDll = :: LoadLibrary (ExpandDllPath); // load the next layer of service providers lpWspStartup = (LPWSPSTARTUP) :: GetProcAddress (hNextDll, "WSPStartup"); LPWSPSTARTUP (WversionRequested, LPWSPDATA, LPPROTOINFO, UPCALLTABLE, LPPROCTABLE); LPPROCTABLE-> LPWSPSENDTO = Wspsendto; lpproctable-> lpwspsend = wspsend; Freefilter (); return 0; Bool Apientry Dllmain (Handle Hmodule, DWORD UL_REASON_FOR_CALL, LPVOID LPRESERVED) {Return True;} The text written is written, I hope everyone will forgive me. If you don't understand anything, please see the "SPI-based Data Reporting Principle and Implementation" and "Windows Network Programming Technology" Chapter 14 Winsock 2 service provider interface.