- 浏览: 228118 次
- 性别:
- 来自: 杭州
文章分类
最新评论
如何使用lsp的hook技术解决TCP链接超时测试场景的模拟
<p><span style="font-size: medium;">问题:在测试网络层链接建立工具的时候,遇到这样的测试用例:需要模拟不同链接按预定的链接先后次序建立,如TCP链接先于UDP链接或者UDP链接先于TCP链接。查用了很多防火墙,都没有提供类似的功能。后来我们使用了<span style="font-size: small;">WinsockLSP 开发了小工具解决了这个问题!</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">关于WinSock LSP网上有详细的例子和讲解如下:</span></span></p>
<p><span style="font-size: medium;"></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSP :分层服务提供者,顾名思义是某种服务的提供者且具有分层的特性,它是 WinSock2 的特性吧,与以往的 WinSock1.0 不同,WinSock1.0 仅围绕着TCP/IP协议运行的,但是在Winsock2中却增加了对更多传输协议的支持。“Winsock2不仅提供了一个供应用程序访问网络服务的Windowssocket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock服务提供者接口(SPI)和ws2_32.dll。”。就现在 NT 以后的网络而言(不知道Vista及后的了),应用层EXE创建套接字时,会先在 WinSock 目录中寻找全适的协议(如 TCP、UDP ......),找到之后再调用此协议的 提供者 来完成各种功能,其中 提供者 又是通过 SPI函数 来完成任务的。所以,对于这种类型的网络调用而言, LSP 是主题而其中的 SPI 则是灵魂,没有 SPI 的话 LSP 就只是一个框架而已,LSP大概的层次如图 :</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">---------------------------------<br>│ Windows socket 2 EXE│<br>---------------------------------Windows socket 2 API<br>│ WS2_32.DLL │<br>---------------------------------Windows socket 2 传输SPI<br>│ LSP DLL │ <br>-----------------------------------<br>│ 基础服务提供程序 │ <br>----------------------------------</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 现在可以知道几乎所有的 WinSock API 调用都会先告诉 WS2_32.DLL ,再由 WS2_32.DLL 传达给 LSP (类型转换的那些不是,不知道还有没有......-_-!),最后到 基础服务提供程序 全权代理实现。所以,大多数的 WinSock API 都是可以 HOOK 的,前提是要安装了 LSP ,由 SPI 进行 HOOK。</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 上图中已示意了 LSP 其实是 DLL 的形式,它是不可以直接执行的,得由 EXE 程序来安装,所以在想采用 LSP 来过滤封包,还得先编译个可执行程序来安装这,至于这个安装 LSP 的程序很多时候都是一个固定的框架:枚举 LSP、安装 LSP、卸载 LSP ,在实现的时候,我用了一个头文件来实现这个框架(本想用类来封装的~~~):</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSPIn-Unstall.h</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define UNICODE<br>#define _UNICODE</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <Ws2spi.h><br>// 定义了WSCWriteProviderOrder函数<br>#include <Sporder.h> <br>#include <windows.h><br>#include <stdio.h></span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#pragma comment(lib, "Ws2_32.lib")<br>// 实现了UuidCreate函数<br>#pragma comment(lib, "Rpcrt4.lib")</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 要安装的LSP的硬编码,在移除的时候还要使用它<br>GUID ProviderGuid = {0x8a, 0x88b, 0x888c, <br> {0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a}};</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//获得所有已经安装的传输服务提供者<br>LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)<br>{<br>DWORD dwSize = 0;<br>int nError;<br>LPWSAPROTOCOL_INFOW pProtoInfo = NULL;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 取得需要的长度<br>if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)<br>{<br> if(nError != WSAENOBUFS)<br> return NULL;<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);<br>*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);<br>return pProtoInfo;<br>}<br>//释放存储空间<br>void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)<br>{<br>::GlobalFree(pProtoInfo);<br>}<br>//安装分层协议,协议链及排序<br>//这里将指定LSP提供者安装到TCP UDP 和原始套节字之上<br>BOOL InstallProvider(WCHAR *pwszPathName)<br>{<br>//LSP的名字<br>WCHAR wszLSPName[] = L"MyFirstLSP";<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>WSAPROTOCOL_INFOW OriginalProtocolInfo[3];<br>DWORD dwOrigCatalogId[3];<br>int nArrayCount = 0;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 我们分层协议的目录ID号<br>DWORD dwLayeredCatalogId; </span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">int nError;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 找到我们的下层协议,将信息放入数组中<br>// 枚举所有服务程序提供者<br>pProtoInfo = GetProvider(&nProtocols);<br>BOOL bFindUdp = FALSE;<br>BOOL bFindTcp = FALSE;<br>BOOL bFindRaw = FALSE;<br>for(int i=0; i<nProtocols; i++)<br>{<br> if(pProtoInfo[i].iAddressFamily == AF_INET)<br> {<br> if(!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindUdp = TRUE;<br> }</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> if(!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindTcp = TRUE;<br> } <br> if(!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindRaw = TRUE;<br> }<br> }<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 安装我们的分层协议,获取一个dwLayeredCatalogId<br>// 随便找一个下层协议的结构复制过来即可<br>WSAPROTOCOL_INFOW LayeredProtocolInfo;<br>memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));<br>// 修改协议名称,类型,设置PFL_HIDDEN标志<br>wcscpy(LayeredProtocolInfo.szProtocol, wszLSPName);<br>LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;<br>LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN;<br>// 安装<br>if(::WSCInstallProvider(&ProviderGuid, <br> pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR)<br>{<br> return FALSE;<br>}<br>// 重新枚举协议,获取分层协议的目录ID号<br>FreeProvider(pProtoInfo);<br>pProtoInfo = GetProvider(&nProtocols);<br>for(i=0; i<nProtocols; i++)<br>{<br> if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0)<br> {<br> dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;<br> break;<br> }<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 安装协议链<br>// 修改协议名称,类型<br>WCHAR wszChainName[WSAPROTOCOL_LEN + 1];<br>for(i=0; i<nArrayCount; i++)<br>{<br> swprintf(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);<br> wcscpy(OriginalProtocolInfo[i].szProtocol, wszChainName);<br> if(OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)<br> {<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];<br> }<br> else<br> {<br> for(int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j>0; j--)<br> {<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] <br> = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];<br> }<br> }<br> OriginalProtocolInfo[i].ProtocolChain.ChainLen ++;<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; <br>}<br>// 获取一个Guid,安装之<br>GUID ProviderChainGuid;<br>if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK)<br>{<br> if(::WSCInstallProvider(&ProviderChainGuid, <br> pwszPathName, OriginalProtocolInfo, nArrayCount, &nError) == SOCKET_ERROR)<br> {<br> return FALSE; <br> }<br>}<br>else<br> return FALSE;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 重新排序Winsock目录,将我们的协议链提前<br>// 重新枚举安装的协议<br>FreeProvider(pProtoInfo);<br>pProtoInfo = GetProvider(&nProtocols);</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">DWORD dwIds[20];<br>int nIndex = 0;<br>// 添加我们的协议链<br>for(i=0; i<nProtocols; i++)<br>{<br> if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))<br> dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;<br>}<br>// 添加其它协议<br>for(i=0; i<nProtocols; i++)<br>{<br> if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))<br> dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;<br>}<br>// 重新排序Winsock目录<br>if((nError = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS)<br>{<br> return FALSE;<br>}<br>FreeProvider(pProtoInfo);<br>return TRUE;<br>}<br>//卸载分层协议和协议链<br>BOOL RemoveProvider()<br>{<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>DWORD dwLayeredCatalogId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 根据Guid取得分层协议的目录ID号<br>pProtoInfo = GetProvider(&nProtocols);<br>int nError;<br>for(int i=0; i<nProtocols; i++)<br>{<br> if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0)<br> {<br> dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;<br> break;<br> }<br>}<br>if(i < nProtocols)<br>{<br> // 移除协议链<br> for(i=0; i<nProtocols; i++)<br> {<br> if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))<br> {<br> ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);<br> }<br> }<br> // 移除分层协议<br> ::WSCDeinstallProvider(&ProviderGuid, &nError);<br>}<br>return TRUE;<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 接着就是主函数的调用了:</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSPControl.cpp</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <iostream.h><br>#include "LSPIn-Unstall.h"</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//安装LSP<br>void install();<br>//卸载LSP<br>void remove();<br>//查看已安装了的LSP<br>void view();</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">void main()<br>{<br>//命令参数<br>char order[128];</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">while(1)<br>{<br> cin.getline(order,128);<br> if(strcmp(order,"exit")==0)<br> break;<br> else if(strcmp(order,"install")==0)<br> install();<br> else if(strcmp(order,"remove")==0)<br> remove();<br> else if(strcmp(order,"view")==0)<br> view();<br>}<br>}<br>//安装LSP<br>void install()<br>{<br>TCHAR szPathName[256];<br>TCHAR* p;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//LSP所在的路径<br>if(::GetFullPathName(L"MyFirstLSP.dll", 256, szPathName, &p) != 0)<br>{<br> if(InstallProvider(szPathName))<br> {<br> printf(" ^-^ 安装成功!/n");<br> return;<br> }<br>}<br>printf(" o_o! 安装失败!/n");<br>}<br>//卸载LSP<br>void remove()<br>{<br>if(RemoveProvider())<br> printf(" ^-^ 卸载成功!/n");<br>else<br> printf(" o_o! 卸载失败!/n");<br>}<br>//查看已安装了的LSP<br>void view()<br>{<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>pProtoInfo = GetProvider(&nProtocols);</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">printf("/n --------------------------- 已安装的LSP --------------------------- /n/n");<br>for(int i=0; i<nProtocols; i++)<br>{<br> printf(" Protocol: %ws /n", pProtoInfo[i].szProtocol);<br> printf(" CatalogEntryId: %d ChainLen: %d /n/n", pProtoInfo[i].dwCatalogEntryId, pProtoInfo[i].ProtocolChain.ChainLen);<br>}<br>printf("/n --------------------------- 已安装的LSP --------------------------- /n/n");<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 看起来是很繁琐,实际上也就是一些框架,已经实现了查看(view)、安装(install)、卸载(remove)。</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 有了可以操控 LSP 程序,接下来就是生成 LSP 了,LSP 以DLL的形式来实现的,这里用的是 VC++6.0 的动态链接工程,在建立好该工程后,还要在工程里头导入一个 .def 格式的文件,其中有导出 LSP WSPStarUP 函数的 EXPORTS 语句,之后就是编写代码了。LSP 只是提供了一个接口,有些代码跟上面的一样看似繁,实则是一个框架,了解就OK了(汗,说到繁,NDIS 更让人头晕```),下面的代码中,最后的 WSPSendTo()、WSPBind() 函数的定义就是 SPI 了,累了那么久,就是用到这些 SPI 来进行包过滤(甚至是实现防火墙等):</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">Debug.h</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#ifndef __DEBUG_H__<br>#define __DEBUG_H__<br>#ifdef _DEBUG</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS(szOut) /<br>{ /<br> OutputDebugString(szOut); /<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS1(szOut, var) /<br>{ /<br> TCHAR sz[1024]; /<br> _stprintf(sz, szOut, var); /<br> OutputDebugString(sz); /<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#else</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS(szOut)<br>#define ODS1(szOut, var)</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#endif</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#endif</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSP.cpp</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// --- 声明要使用UNICODE字符串---(到了驱动的话,大都是用 UNICODE 的)<br>#define UNICODE<br>#define _UNICODE</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <Winsock2.h><br>#include <Ws2spi.h><br>#include <Windows.h><br>#include <tchar.h><br>#include "Debug.h"<br>#include <fstream.h></span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#pragma comment(lib, "Ws2_32.lib")</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">WSPUPCALLTABLE g_pUpCallTable; // 上层函数列表。如果LSP创建了自己的伪句柄,才使用这个函数列表<br>WSPPROC_TABLE g_NextProcTable; // 下层函数列表<br>TCHAR g_szCurrentApp[MAX_PATH]; // 当前调用本DLL的程序的名称</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">BOOL APIENTRY DllMain( HANDLE hModule, <br> DWORD ul_reason_for_call, <br> LPVOID lpReserved<br> )<br>{<br>switch (ul_reason_for_call)<br>{<br>case DLL_PROCESS_ATTACH:<br> {<br> // 取得主模块的名称<br> ::GetModuleFileName(NULL, g_szCurrentApp, MAX_PATH);<br> }<br> break;<br>}<br>return TRUE;<br>}<br>//得到当前所有已安装的LSP<br>LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)<br>{<br>DWORD dwSize = 0;<br>int nError;<br>LPWSAPROTOCOL_INFOW pProtoInfo = NULL;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 取得需要的长度<br>if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)<br>{<br> if(nError != WSAENOBUFS)<br> return NULL;<br>}<br>pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);<br>*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);<br>return pProtoInfo;<br>}<br>//释放空间<br>void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)<br>{<br>::GlobalFree(pProtoInfo);<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">
<p><br>int WSPAPI WSPSendTo(<br>SOCKET s,<br>LPWSABUF lpBuffers,<br>DWORD dwBufferCount,<br>LPDWORD lpNumberOfBytesSent,<br>DWORD dwFlags,<br>const struct sockaddr FAR * lpTo,<br>int iTolen,<br>LPWSAOVERLAPPED lpOverlapped,<br>LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,<br>LPWSATHREADID lpThreadId,<br>LPINT lpErrno<br>)<br>{<br>ODS1(L" query send to... %s", g_szCurrentApp);</p>
<p>SOCKADDR_IN sa = *(SOCKADDR_IN*)lpTo;<br>if(sa.sin_port == htons(要过滤的端口<为 int 类型>) ) // 若符合则过滤掉了</p>
<p>{<br> int iError;<br> g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &iError);<br> *lpErrno = WSAECONNABORTED;</p>
<p> ODS(L" deny a sendto ");<br> return SOCKET_ERROR;<br>}</p>
<p><br>return g_NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo<br> , iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);<br>}</p>
<p>int WSPAPI WSPBind(SOCKET s, const struct sockaddr* name, int namelen, LPINT lpErrno)<br>{<br>//这里再进行处理(一般情况之下,Bind 都是作为服务程序用的函数:绑定端口后再进而监听)<br>return g_NextProcTable.lpWSPBind(s, name, namelen, lpErrno);<br>}</p>
<p>//这里为入口函数(必备)<br>int WSPAPI WSPStartup(<br>WORD wVersionRequested,<br>LPWSPDATA lpWSPData,<br>LPWSAPROTOCOL_INFO lpProtocolInfo,<br>WSPUPCALLTABLE UpcallTable,<br>LPWSPPROC_TABLE lpProcTable<br>)<br>{<br>ODS1(L" WSPStartup... %s /n", g_szCurrentApp);</p>
<p>if(lpProtocolInfo->ProtocolChain.ChainLen <= 1)<br>{ <br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 保存向上调用的函数表指针(在这里没有使用它)<br>g_pUpCallTable = UpcallTable;</p>
<p>// 枚举协议,找到下层协议的WSAPROTOCOL_INFOW结构 <br>WSAPROTOCOL_INFOW NextProtocolInfo;<br>int nTotalProtos;<br>LPWSAPROTOCOL_INFOW pProtoInfo = GetProvider(&nTotalProtos);<br>// 下层入口ID <br>DWORD dwBaseEntryId = lpProtocolInfo->ProtocolChain.ChainEntries[1];<br>for(int i=0; i<nTotalProtos; i++)<br>{<br> if(pProtoInfo[i].dwCatalogEntryId == dwBaseEntryId)<br> {<br> memcpy(&NextProtocolInfo, &pProtoInfo[i], sizeof(NextProtocolInfo));<br> break;<br> }<br>}<br>if(i >= nTotalProtos)<br>{<br> ODS(L" WSPStartup: Can not find underlying protocol /n");<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 加载下层协议的DLL<br>int nError;<br>TCHAR szBaseProviderDll[MAX_PATH];<br>int nLen = MAX_PATH;<br>// 取得下层提供程序DLL路径<br>if(::WSCGetProviderPath(&NextProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)<br>{<br> ODS1(L" WSPStartup: WSCGetProviderPath() failed %d /n", nError);<br> return WSAEPROVIDERFAILEDINIT;<br>}<br>if(!::ExpandEnvironmentStrings(szBaseProviderDll, szBaseProviderDll, MAX_PATH))<br>{<br> ODS1(L" WSPStartup: ExpandEnvironmentStrings() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}<br>// 加载下层提供程序<br>HMODULE hModule = ::LoadLibrary(szBaseProviderDll);<br>if(hModule == NULL)<br>{<br> ODS1(L" WSPStartup: LoadLibrary() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 导入下层提供程序的WSPStartup函数<br>LPWSPSTARTUP pfnWSPStartup = NULL;<br>pfnWSPStartup = (LPWSPSTARTUP)::GetProcAddress(hModule, "WSPStartup");<br>if(pfnWSPStartup == NULL)<br>{<br> ODS1(L" WSPStartup: GetProcAddress() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 调用下层提供程序的WSPStartup函数<br>LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;<br>if(NextProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)<br> pInfo = &NextProtocolInfo;</p>
<p>int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, pInfo, UpcallTable, lpProcTable);<br>if(nRet != ERROR_SUCCESS)<br>{<br> ODS1(L" WSPStartup: underlying provider's WSPStartup() failed %d /n", nRet);<br> return nRet;<br>}<br>// 保存下层提供者的函数表<br>g_NextProcTable = *lpProcTable;<br>// 修改传递给上层的函数表,Hook感兴趣的函数<br>// 好像可以 Hook 30个函数,书里头写着列表有 30 个ISP函数<br>lpProcTable->lpWSPSendTo = WSPSendTo;<br>lpProcTable->lpWSPBind = WSPBind;</p>
<p>FreeProvider(pProtoInfo);<br>return nRet;<br>}</p>
<p> 一个防火墙的模型就出来了,不过在用户模式下它虽然不错,但是并非能够过滤所有的封包,除非编写内核模式的 NDIS 驱动(强捍的NDIS)~~~</p>
<span style="font-size: medium;"><font size="3">
<p> 编译成 DLL 后,将上面生成的操作 LSP 的程序与 生成的 DLL 放在同一目录之下,DLL 的由字要是 MyFirstLSP (因为上面:GetFullPathName(L"MyFirstLSP.dll", 256, szPathName, &p) 中的DLL文件就是它,<br> 以前调试的时候忘记看了,试了N次都没找出失误的原因 @_@ )<br></p>
</font></span></span>
<p></p>
</span></p>
<p></p>
<p><span style="font-size: medium;"><span style="font-size: small;">关于WinSock LSP网上有详细的例子和讲解如下:</span></span></p>
<p><span style="font-size: medium;"></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSP :分层服务提供者,顾名思义是某种服务的提供者且具有分层的特性,它是 WinSock2 的特性吧,与以往的 WinSock1.0 不同,WinSock1.0 仅围绕着TCP/IP协议运行的,但是在Winsock2中却增加了对更多传输协议的支持。“Winsock2不仅提供了一个供应用程序访问网络服务的Windowssocket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock服务提供者接口(SPI)和ws2_32.dll。”。就现在 NT 以后的网络而言(不知道Vista及后的了),应用层EXE创建套接字时,会先在 WinSock 目录中寻找全适的协议(如 TCP、UDP ......),找到之后再调用此协议的 提供者 来完成各种功能,其中 提供者 又是通过 SPI函数 来完成任务的。所以,对于这种类型的网络调用而言, LSP 是主题而其中的 SPI 则是灵魂,没有 SPI 的话 LSP 就只是一个框架而已,LSP大概的层次如图 :</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">---------------------------------<br>│ Windows socket 2 EXE│<br>---------------------------------Windows socket 2 API<br>│ WS2_32.DLL │<br>---------------------------------Windows socket 2 传输SPI<br>│ LSP DLL │ <br>-----------------------------------<br>│ 基础服务提供程序 │ <br>----------------------------------</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 现在可以知道几乎所有的 WinSock API 调用都会先告诉 WS2_32.DLL ,再由 WS2_32.DLL 传达给 LSP (类型转换的那些不是,不知道还有没有......-_-!),最后到 基础服务提供程序 全权代理实现。所以,大多数的 WinSock API 都是可以 HOOK 的,前提是要安装了 LSP ,由 SPI 进行 HOOK。</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 上图中已示意了 LSP 其实是 DLL 的形式,它是不可以直接执行的,得由 EXE 程序来安装,所以在想采用 LSP 来过滤封包,还得先编译个可执行程序来安装这,至于这个安装 LSP 的程序很多时候都是一个固定的框架:枚举 LSP、安装 LSP、卸载 LSP ,在实现的时候,我用了一个头文件来实现这个框架(本想用类来封装的~~~):</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSPIn-Unstall.h</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define UNICODE<br>#define _UNICODE</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <Ws2spi.h><br>// 定义了WSCWriteProviderOrder函数<br>#include <Sporder.h> <br>#include <windows.h><br>#include <stdio.h></span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#pragma comment(lib, "Ws2_32.lib")<br>// 实现了UuidCreate函数<br>#pragma comment(lib, "Rpcrt4.lib")</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 要安装的LSP的硬编码,在移除的时候还要使用它<br>GUID ProviderGuid = {0x8a, 0x88b, 0x888c, <br> {0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a}};</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//获得所有已经安装的传输服务提供者<br>LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)<br>{<br>DWORD dwSize = 0;<br>int nError;<br>LPWSAPROTOCOL_INFOW pProtoInfo = NULL;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 取得需要的长度<br>if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)<br>{<br> if(nError != WSAENOBUFS)<br> return NULL;<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);<br>*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);<br>return pProtoInfo;<br>}<br>//释放存储空间<br>void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)<br>{<br>::GlobalFree(pProtoInfo);<br>}<br>//安装分层协议,协议链及排序<br>//这里将指定LSP提供者安装到TCP UDP 和原始套节字之上<br>BOOL InstallProvider(WCHAR *pwszPathName)<br>{<br>//LSP的名字<br>WCHAR wszLSPName[] = L"MyFirstLSP";<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>WSAPROTOCOL_INFOW OriginalProtocolInfo[3];<br>DWORD dwOrigCatalogId[3];<br>int nArrayCount = 0;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 我们分层协议的目录ID号<br>DWORD dwLayeredCatalogId; </span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">int nError;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 找到我们的下层协议,将信息放入数组中<br>// 枚举所有服务程序提供者<br>pProtoInfo = GetProvider(&nProtocols);<br>BOOL bFindUdp = FALSE;<br>BOOL bFindTcp = FALSE;<br>BOOL bFindRaw = FALSE;<br>for(int i=0; i<nProtocols; i++)<br>{<br> if(pProtoInfo[i].iAddressFamily == AF_INET)<br> {<br> if(!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindUdp = TRUE;<br> }</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> if(!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindTcp = TRUE;<br> } <br> if(!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)<br> {<br> memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));<br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = <br> OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES); <br><br> dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> bFindRaw = TRUE;<br> }<br> }<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 安装我们的分层协议,获取一个dwLayeredCatalogId<br>// 随便找一个下层协议的结构复制过来即可<br>WSAPROTOCOL_INFOW LayeredProtocolInfo;<br>memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));<br>// 修改协议名称,类型,设置PFL_HIDDEN标志<br>wcscpy(LayeredProtocolInfo.szProtocol, wszLSPName);<br>LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;<br>LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN;<br>// 安装<br>if(::WSCInstallProvider(&ProviderGuid, <br> pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR)<br>{<br> return FALSE;<br>}<br>// 重新枚举协议,获取分层协议的目录ID号<br>FreeProvider(pProtoInfo);<br>pProtoInfo = GetProvider(&nProtocols);<br>for(i=0; i<nProtocols; i++)<br>{<br> if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0)<br> {<br> dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;<br> break;<br> }<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 安装协议链<br>// 修改协议名称,类型<br>WCHAR wszChainName[WSAPROTOCOL_LEN + 1];<br>for(i=0; i<nArrayCount; i++)<br>{<br> swprintf(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);<br> wcscpy(OriginalProtocolInfo[i].szProtocol, wszChainName);<br> if(OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)<br> {<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];<br> }<br> else<br> {<br> for(int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j>0; j--)<br> {<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] <br> = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];<br> }<br> }<br> OriginalProtocolInfo[i].ProtocolChain.ChainLen ++;<br> OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; <br>}<br>// 获取一个Guid,安装之<br>GUID ProviderChainGuid;<br>if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK)<br>{<br> if(::WSCInstallProvider(&ProviderChainGuid, <br> pwszPathName, OriginalProtocolInfo, nArrayCount, &nError) == SOCKET_ERROR)<br> {<br> return FALSE; <br> }<br>}<br>else<br> return FALSE;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 重新排序Winsock目录,将我们的协议链提前<br>// 重新枚举安装的协议<br>FreeProvider(pProtoInfo);<br>pProtoInfo = GetProvider(&nProtocols);</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">DWORD dwIds[20];<br>int nIndex = 0;<br>// 添加我们的协议链<br>for(i=0; i<nProtocols; i++)<br>{<br> if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))<br> dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;<br>}<br>// 添加其它协议<br>for(i=0; i<nProtocols; i++)<br>{<br> if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))<br> dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;<br>}<br>// 重新排序Winsock目录<br>if((nError = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS)<br>{<br> return FALSE;<br>}<br>FreeProvider(pProtoInfo);<br>return TRUE;<br>}<br>//卸载分层协议和协议链<br>BOOL RemoveProvider()<br>{<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>DWORD dwLayeredCatalogId;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 根据Guid取得分层协议的目录ID号<br>pProtoInfo = GetProvider(&nProtocols);<br>int nError;<br>for(int i=0; i<nProtocols; i++)<br>{<br> if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0)<br> {<br> dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;<br> break;<br> }<br>}<br>if(i < nProtocols)<br>{<br> // 移除协议链<br> for(i=0; i<nProtocols; i++)<br> {<br> if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&<br> (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))<br> {<br> ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);<br> }<br> }<br> // 移除分层协议<br> ::WSCDeinstallProvider(&ProviderGuid, &nError);<br>}<br>return TRUE;<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 接着就是主函数的调用了:</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSPControl.cpp</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <iostream.h><br>#include "LSPIn-Unstall.h"</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//安装LSP<br>void install();<br>//卸载LSP<br>void remove();<br>//查看已安装了的LSP<br>void view();</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">void main()<br>{<br>//命令参数<br>char order[128];</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">while(1)<br>{<br> cin.getline(order,128);<br> if(strcmp(order,"exit")==0)<br> break;<br> else if(strcmp(order,"install")==0)<br> install();<br> else if(strcmp(order,"remove")==0)<br> remove();<br> else if(strcmp(order,"view")==0)<br> view();<br>}<br>}<br>//安装LSP<br>void install()<br>{<br>TCHAR szPathName[256];<br>TCHAR* p;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">//LSP所在的路径<br>if(::GetFullPathName(L"MyFirstLSP.dll", 256, szPathName, &p) != 0)<br>{<br> if(InstallProvider(szPathName))<br> {<br> printf(" ^-^ 安装成功!/n");<br> return;<br> }<br>}<br>printf(" o_o! 安装失败!/n");<br>}<br>//卸载LSP<br>void remove()<br>{<br>if(RemoveProvider())<br> printf(" ^-^ 卸载成功!/n");<br>else<br> printf(" o_o! 卸载失败!/n");<br>}<br>//查看已安装了的LSP<br>void view()<br>{<br>LPWSAPROTOCOL_INFOW pProtoInfo;<br>int nProtocols;<br>pProtoInfo = GetProvider(&nProtocols);</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">printf("/n --------------------------- 已安装的LSP --------------------------- /n/n");<br>for(int i=0; i<nProtocols; i++)<br>{<br> printf(" Protocol: %ws /n", pProtoInfo[i].szProtocol);<br> printf(" CatalogEntryId: %d ChainLen: %d /n/n", pProtoInfo[i].dwCatalogEntryId, pProtoInfo[i].ProtocolChain.ChainLen);<br>}<br>printf("/n --------------------------- 已安装的LSP --------------------------- /n/n");<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 看起来是很繁琐,实际上也就是一些框架,已经实现了查看(view)、安装(install)、卸载(remove)。</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;"> 有了可以操控 LSP 程序,接下来就是生成 LSP 了,LSP 以DLL的形式来实现的,这里用的是 VC++6.0 的动态链接工程,在建立好该工程后,还要在工程里头导入一个 .def 格式的文件,其中有导出 LSP WSPStarUP 函数的 EXPORTS 语句,之后就是编写代码了。LSP 只是提供了一个接口,有些代码跟上面的一样看似繁,实则是一个框架,了解就OK了(汗,说到繁,NDIS 更让人头晕```),下面的代码中,最后的 WSPSendTo()、WSPBind() 函数的定义就是 SPI 了,累了那么久,就是用到这些 SPI 来进行包过滤(甚至是实现防火墙等):</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">Debug.h</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#ifndef __DEBUG_H__<br>#define __DEBUG_H__<br>#ifdef _DEBUG</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS(szOut) /<br>{ /<br> OutputDebugString(szOut); /<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS1(szOut, var) /<br>{ /<br> TCHAR sz[1024]; /<br> _stprintf(sz, szOut, var); /<br> OutputDebugString(sz); /<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#else</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#define ODS(szOut)<br>#define ODS1(szOut, var)</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#endif</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#endif</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">LSP.cpp</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// --- 声明要使用UNICODE字符串---(到了驱动的话,大都是用 UNICODE 的)<br>#define UNICODE<br>#define _UNICODE</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#include <Winsock2.h><br>#include <Ws2spi.h><br>#include <Windows.h><br>#include <tchar.h><br>#include "Debug.h"<br>#include <fstream.h></span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">#pragma comment(lib, "Ws2_32.lib")</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">WSPUPCALLTABLE g_pUpCallTable; // 上层函数列表。如果LSP创建了自己的伪句柄,才使用这个函数列表<br>WSPPROC_TABLE g_NextProcTable; // 下层函数列表<br>TCHAR g_szCurrentApp[MAX_PATH]; // 当前调用本DLL的程序的名称</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">BOOL APIENTRY DllMain( HANDLE hModule, <br> DWORD ul_reason_for_call, <br> LPVOID lpReserved<br> )<br>{<br>switch (ul_reason_for_call)<br>{<br>case DLL_PROCESS_ATTACH:<br> {<br> // 取得主模块的名称<br> ::GetModuleFileName(NULL, g_szCurrentApp, MAX_PATH);<br> }<br> break;<br>}<br>return TRUE;<br>}<br>//得到当前所有已安装的LSP<br>LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)<br>{<br>DWORD dwSize = 0;<br>int nError;<br>LPWSAPROTOCOL_INFOW pProtoInfo = NULL;</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">// 取得需要的长度<br>if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)<br>{<br> if(nError != WSAENOBUFS)<br> return NULL;<br>}<br>pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);<br>*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);<br>return pProtoInfo;<br>}<br>//释放空间<br>void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)<br>{<br>::GlobalFree(pProtoInfo);<br>}</span></span></p>
<p><span style="font-size: medium;"><span style="font-size: small;">
<p><br>int WSPAPI WSPSendTo(<br>SOCKET s,<br>LPWSABUF lpBuffers,<br>DWORD dwBufferCount,<br>LPDWORD lpNumberOfBytesSent,<br>DWORD dwFlags,<br>const struct sockaddr FAR * lpTo,<br>int iTolen,<br>LPWSAOVERLAPPED lpOverlapped,<br>LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,<br>LPWSATHREADID lpThreadId,<br>LPINT lpErrno<br>)<br>{<br>ODS1(L" query send to... %s", g_szCurrentApp);</p>
<p>SOCKADDR_IN sa = *(SOCKADDR_IN*)lpTo;<br>if(sa.sin_port == htons(要过滤的端口<为 int 类型>) ) // 若符合则过滤掉了</p>
<p>{<br> int iError;<br> g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &iError);<br> *lpErrno = WSAECONNABORTED;</p>
<p> ODS(L" deny a sendto ");<br> return SOCKET_ERROR;<br>}</p>
<p><br>return g_NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo<br> , iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);<br>}</p>
<p>int WSPAPI WSPBind(SOCKET s, const struct sockaddr* name, int namelen, LPINT lpErrno)<br>{<br>//这里再进行处理(一般情况之下,Bind 都是作为服务程序用的函数:绑定端口后再进而监听)<br>return g_NextProcTable.lpWSPBind(s, name, namelen, lpErrno);<br>}</p>
<p>//这里为入口函数(必备)<br>int WSPAPI WSPStartup(<br>WORD wVersionRequested,<br>LPWSPDATA lpWSPData,<br>LPWSAPROTOCOL_INFO lpProtocolInfo,<br>WSPUPCALLTABLE UpcallTable,<br>LPWSPPROC_TABLE lpProcTable<br>)<br>{<br>ODS1(L" WSPStartup... %s /n", g_szCurrentApp);</p>
<p>if(lpProtocolInfo->ProtocolChain.ChainLen <= 1)<br>{ <br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 保存向上调用的函数表指针(在这里没有使用它)<br>g_pUpCallTable = UpcallTable;</p>
<p>// 枚举协议,找到下层协议的WSAPROTOCOL_INFOW结构 <br>WSAPROTOCOL_INFOW NextProtocolInfo;<br>int nTotalProtos;<br>LPWSAPROTOCOL_INFOW pProtoInfo = GetProvider(&nTotalProtos);<br>// 下层入口ID <br>DWORD dwBaseEntryId = lpProtocolInfo->ProtocolChain.ChainEntries[1];<br>for(int i=0; i<nTotalProtos; i++)<br>{<br> if(pProtoInfo[i].dwCatalogEntryId == dwBaseEntryId)<br> {<br> memcpy(&NextProtocolInfo, &pProtoInfo[i], sizeof(NextProtocolInfo));<br> break;<br> }<br>}<br>if(i >= nTotalProtos)<br>{<br> ODS(L" WSPStartup: Can not find underlying protocol /n");<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 加载下层协议的DLL<br>int nError;<br>TCHAR szBaseProviderDll[MAX_PATH];<br>int nLen = MAX_PATH;<br>// 取得下层提供程序DLL路径<br>if(::WSCGetProviderPath(&NextProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)<br>{<br> ODS1(L" WSPStartup: WSCGetProviderPath() failed %d /n", nError);<br> return WSAEPROVIDERFAILEDINIT;<br>}<br>if(!::ExpandEnvironmentStrings(szBaseProviderDll, szBaseProviderDll, MAX_PATH))<br>{<br> ODS1(L" WSPStartup: ExpandEnvironmentStrings() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}<br>// 加载下层提供程序<br>HMODULE hModule = ::LoadLibrary(szBaseProviderDll);<br>if(hModule == NULL)<br>{<br> ODS1(L" WSPStartup: LoadLibrary() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 导入下层提供程序的WSPStartup函数<br>LPWSPSTARTUP pfnWSPStartup = NULL;<br>pfnWSPStartup = (LPWSPSTARTUP)::GetProcAddress(hModule, "WSPStartup");<br>if(pfnWSPStartup == NULL)<br>{<br> ODS1(L" WSPStartup: GetProcAddress() failed %d /n", ::GetLastError());<br> return WSAEPROVIDERFAILEDINIT;<br>}</p>
<p>// 调用下层提供程序的WSPStartup函数<br>LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;<br>if(NextProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)<br> pInfo = &NextProtocolInfo;</p>
<p>int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, pInfo, UpcallTable, lpProcTable);<br>if(nRet != ERROR_SUCCESS)<br>{<br> ODS1(L" WSPStartup: underlying provider's WSPStartup() failed %d /n", nRet);<br> return nRet;<br>}<br>// 保存下层提供者的函数表<br>g_NextProcTable = *lpProcTable;<br>// 修改传递给上层的函数表,Hook感兴趣的函数<br>// 好像可以 Hook 30个函数,书里头写着列表有 30 个ISP函数<br>lpProcTable->lpWSPSendTo = WSPSendTo;<br>lpProcTable->lpWSPBind = WSPBind;</p>
<p>FreeProvider(pProtoInfo);<br>return nRet;<br>}</p>
<p> 一个防火墙的模型就出来了,不过在用户模式下它虽然不错,但是并非能够过滤所有的封包,除非编写内核模式的 NDIS 驱动(强捍的NDIS)~~~</p>
<span style="font-size: medium;"><font size="3">
<p> 编译成 DLL 后,将上面生成的操作 LSP 的程序与 生成的 DLL 放在同一目录之下,DLL 的由字要是 MyFirstLSP (因为上面:GetFullPathName(L"MyFirstLSP.dll", 256, szPathName, &p) 中的DLL文件就是它,<br> 以前调试的时候忘记看了,试了N次都没找出失误的原因 @_@ )<br></p>
</font></span></span>
<p></p>
</span></p>
<p></p>
相关推荐
delphi注册LSP(SPI)协议 拦截HTTP 头,检查URL并按规则过滤指定广告网址。
LSP 劫持 TCP协议 UDP协议 HTTP协议 拦截 VS 2013 VC开发 例子有 TCP 拦截 修改 转发 UDP 拦截 转发 修改 HTTP 修改 转发
LSP安装和拦截函数例子 VS2008工程 LSPDEMO是安装程序 TinyLSP为实现函数
用LSP技术构筑简单的防火墙用
lsp集合学习专用lsp集合学习专用lsp集合学习专用
修复LSP是解决无法上网的一个方法,本工具操作简单,傻瓜版。
LSP Manager技术白皮书.pdf
cad经典LSP文件,各种应用实例 如果您使用 AutoCAD,下面的内容对您一定有帮助。在某些方面能大大提高 您的工作效率。下面的程序均以源程序方式给出,您可以使用、参考、修改它。 bg.lsp --- 表格自动生成 asc.lsp -...
lsp Hook WSPConnect 与易的通信,命名管道通信api通信,易的管道通信有问题【可能是官方封装那出问题了,经常出现E的内核Bug,还是找不出问题的BUG】只能用API, LSP我还加上了 DLL注入,还有内存加载DLL 【建议dll...
lsp autocadlsp
Lsp最好的入门示例 WSPStartup IP及端口拦截
LSP网络分层服务提供者dll源码和安装程序源码,安装了TCP、UDP、RAW协议的钩子程序,VC实现。
快速连接tmp.lsp
插件命令快捷键说明: 1、CC 尺寸 2、BX 变虚 3、BS 变实 4、BL 比例 5、ZD 折断线 6、YC 引出线 7、BG 标高 8、TM 图名 9、SM 索引图名 10、PM 剖面符号 11、PS 剖切索引 12、SY 索引符号
CAD lsp自己常用的LSP快捷键CAD lsp自己常用的LSP快捷键CAD lsp自己常用的LSP快捷键
包含LSP分层服务提供者过滤DLL源码、LSP安装程序源码、测试程序源码
如果CAD文件夹里出现很多这个文件acaddoc.lsp,那么你的电脑是中毒了,acaddoc.lsp是一个木马! 解决方法: 一、你可以下载绿盟为您准备的这款acaddoc.lsp专杀工具进行查杀 二、也可以手工清除: 1、查找acaddoc....
快速选择同类图元.lsp cad程序应用
3DARRAY.LSP
根据高程点或等高线内插高程点的LSP源代码