|
费尔防火墙是一种典型的SPI型的防火墙。SPI意指服务提供者接口(Service Provider Interface)。在Winsock 2中增加了对更多传输协议的支持。Winsock 2不仅提供了一个供应用程序访问网络服务的Windows socket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock服务提供者接口也就是我们现在要讲的SPI。
Winsock 2的SPI是以动态链接库的形式(DLL)存在的,它是通过WSPStartup函数为上层函数提供接口,而其他的传输服务提供者函数则是通过分配表的方式来访问WS2_32.DLL。传输服务提供者的动态链接库只有在应用程序需要时才由Ws2_32.dll来装入内存中的,在不需要时则会被自动卸载。
费尔防火墙的工作核心就是一个DLL,它的安装方式是破坏性的,它用自己替换了系统里当前的SPI,在应用程序访问网络时,首先调用费尔的DLL,再由费尔的DLL调用系统当前默认的SPI。一旦系统在安装费尔防火墙之后安装另外的基于SPI工作的程序,必将扰乱了系统的SPI链。甚至引起SPI链的死锁。如下所示:
↓数据 ↓数据 ↓数据
|系统SPI--1| |费尔SPI--1|→|系统SPI--1| |第三方SPI| |系统SPI--1|
↓数据 ↓数据 ↓数据 ↓数据
|系统SPI--2| |费尔SPI--2|→|系统SPI--2| |费尔SPI--1|→|系统SPI--2|
↓数据 ↓数据 ↓数据 ↓数据
|系统SPI--3| |系统SPI--3|←←← |费尔SPI--2|→ ←
↓数据 ↓数据
|系统SPI--3|
正常情况下 加了费尔防火墙以后 又加了第三方SPI以后
所以真正健壮的SPI型防火墙的DLL安装方式不应该是替换,而是加入到SPI链里。流程如下:
获取系统所有的SPI(WSCEnumProtocols)
找到IPPROTO_TCP类的SPI信息
构造一个类似的SPI信息做自己的注册信息(GUID不同)
安装自己的SPI注册(WSCInstallProvider)
重新整理SPI的链表次序,确保自己是在首位的(WSCWriteProviderOrder)
做完了安装的功能还要处理SPI的工作DLL,即重构WSPStartup函数。在WSPStartup函数里,我们要做的工作仅仅是找到自己DLL在链表中的位置,再找到自己的下一个SPI,保留它的函数表到自己函数表。
即然知道了SPI防火墙的工作原理,我们就可以轻易跳过它了。我们只要在自己的DLL的WSPStartup里动动手脚,让它永远指向系统的SPI就可以了。
PS:SPI的安装类的代码文件在COMMON文件夹里。由于它的析构函数会卸载SPI,所以要把类对象声明成全局的。另外在DLL的范例里,WSPStartup里有一段被注释的代码,那段代码就是用来让本身的SPI指向系统SPI的。我是根据名称判断的,其实严谨的方法应该是通过GUID。在这段代码下面被注释条包起来的一段代码是用于查找链表中下一个SPI服务的。大家可以自己试试。最后提醒大家,玩SPI可能会导致你的系统上不了网,请先保存注册表项分支:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries。
最后友情提示一下:我的类里面有个函数对汉字支持不好,请不要在汉字路径下运行。要不自己修改一下也好。
发现这段代码没有处理行末符,现在我重写了一个……
void CSocketHook::Convert2Unicode(WCHAR *pWChar, CHAR *pChar)
{
int wNeedLen = MultiByteToWideChar(CP_ACP, 0, pChar, -1, pWChar, 0);
if(wNeedLen > 0)
{
WCHAR * wPbuf = new WCHAR[wNeedLen];
MultiByteToWideChar(CP_ACP, 0, pChar, -1, wPbuf, wNeedLen);
wcscpy(pWChar,wPbuf);
delete[] wPbuf;
pWChar[wNeedLen + 1] = ’\0’;
}
} |
|