日期:2007-6-1 16:20:50
很多单机版的防火墙都是利用了SPI的技术来实现对网络封包的截获处理.[当然也有结合NDIS及IMD驱动的,不再本贴范围内:)],也可以通过SPI技术实现无进程的DLL木马.这里Winsock2 SPI的原理在这就不多说了,网上多得是.
以下仅为我前段时间学习SPI技术时的写的一些代码,望大家一起来研究讨论.
以下分别为wskfilter.dll及nfilter.exe的代码,编译成功后将两个文件放在同一目录下,CMD下运行nfilter.exe便可以加载自己的LSP(分层服务提供者)来截获相关WINSOCK API的调用了.当然如何处理需要在wskfilter.dll中进行控制,在此不作详述.
/////////////////////////////////////////////////////////////////////////////////////// // //wskfilter.dll by miyagi@2007.5.21 // // //wskfilter.cpp : Defines the entry point for the DLL application. // 开发思路: // // 1)每个DLL都必须有一个入口点,故通过DllMain这个缺省函数做为入口函数。该函数负责 // DLL的初始化与结束的工作; // 1.1)在DllMain中,通过GetModuleFileName获取到当前调用该DLL的进程名称,以备后需; // 1.2)分别定义枚举服务提供者函数GetProvider(),释放服务提供者函数FreeProvider(); // // 2)通过g_NextProcTable中保存的下层服务提供者的函数列表,来Hook咸兴趣的函数,并将 // Hook的函数进行自定义处理,即实现了Winsock的过滤及监控处理; // // 3)WSPStartup是LSP必须导出的函数。同时在创建DLL工程后,先向工程中添加一个.def文件。 // 即模块定义文件,声明所有要导出的函数; // 3.1)判断WSPStartup函数是否被调用LSP(分层服务者)调用的; // 3.2)枚举各协议服务提供者,找到LSP下层协议服务提供者的WSAPROTOCOL_INFOW结构; // 3.3)通过以上遍历得到的下层服务提供者(现存放于NextProtocolInfo中)的GUID来确定其DLL // 的路径; // 3.4)通过函数WSCGetProviderPath()获取及ExpandEnvironmentStrings()扩展来得到下层服务 // 提供者的DLL; // 路径,该路径是包含了环境变量的; // 3.5)加载下层服务提供者,即加载其下载服务提供者的DLL; // 3.6)通过自定义的一个指向WSPSTARTUP函数指针,来启动下一层服务提供者; // 3.7)调用下层服务提供者的WSPStartup函数,调用成功后其中lpProcTable变量将在后期进行 // Hook时经常用到; // 3.8)通过修改传递给下层服务提供者的函数列表,Hook相关WSP函数; // ///////////////////////////////////////////////////////////////////////////////////////
#define UNICODE #define _UNICODE
#include <Winsock2.h> #include <Ws2spi.h> #include <Windows.h> #include <tchar.h> #include "Debug.h"
#pragma comment(lib, "Ws2_32.lib")
WSPUPCALLTABLE g_UpCallTable;
WSPPROC_TABLE g_NextProcTable; TCHAR g_szCurrentApp[MAX_PATH];
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch(ul_reason_for_call) { //获取调用wskfilter.dll的进程名称; case DLL_PROCESS_ATTACH: { ::GetModuleFileName(NULL,g_szCurrentApp,MAX_PATH); }
break; }
return TRUE; }
//枚举各协议的服务提供者
LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols) { DWORD dwSize = 0; int nError; LPWSAPROTOCOL_INFOW pProtoInfo = NULL; // 取得需要的长度,即通过将WSCEnumProtocols函数的dwSize参数置0进行第一次调用,后 //以获得枚举服务提供者所需的缓冲区大小,置于dwSize变量中; if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR) { if(nError != WSAENOBUFS) return NULL; } //根据dwSize中的值来申请内存空间; pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);
//第二次通过WSCEnumProtocols()正式枚举到各服务提供者并存放于pProtoInfo(数组)中, //并将服务提供者的个数存到lpnTotalProtocols中; *lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
return pProtoInfo; }
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo) { //释放用于存放服务提供者数组的内存空间,pProtoInfo; ::GlobalFree(pProtoInfo); }
//通过g_NextProcTable中保存的下层服务提供者的函数列表,来Hook咸兴趣的函数,这里Hook的是 //WSPSendTo
int WSPAPI WSPSendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, const struct sockaddr FAR * lpTo, int iTolen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno ) { ODS1(L"Filter Winsock send to...%s",g_szCurrentApp); return 0; //return g_NextProcTable.lpWSPSendTo(s,lpBuffers,dwBufferCount,lpNumberOfBytesSent, //dwFlags,lpTo,iTolen,lpOverlapped,lpCompletionRoutine, //lpThreadId,lpErrno); }
int WSPAPI WSPStartup( WORD wVersionRequested, LPWSPDATA lpWSPData, LPWSAPROTOCOL_INFO lpProtocolInfo, WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE lpProcTable ) { ODS1(L" WSPStartup......%s",g_szCurrentApp); //判断WSPStartup函数是否被调用LSP(分层服务者)调用的; if(lpProtocolInfo->ProtocolChain.ChainLen<=1) { return WSAEPROVIDERFAILEDINIT; }
g_UpCallTable=UpcallTable; //枚举各协议服务提供者,找到LSP下层协议服务提供者的WSAPROTOCOL_INFOW结构 WSAPROTOCOL_INFOW NextProtocolInfo; int nTotalProtos;
LPWSAPROTOCOL_INFOW pProtoInfo=GetProvider(&nTotalProtos);
DWORD dwBaseEntryId=lpProtocolInfo->ProtocolChain.ChainEntries[1]; for(int i=0;i<nTotalProtos;i++) { if(pProtoInfo[i].dwCatalogEntryId==dwBaseEntryId) { memcpy(&NextProtocolInfo,&pProtoInfo,sizeof(NextProtocolInfo)); break; } }
if(i>=nTotalProtos) { ODS(L"WSPStartup: Can not find underlying protocol!\n"); return WSAEPROVIDERFAILEDINIT; }
//通过以上遍历得到的下层服务提供者(现存放于NextProtocolInfo中)的GUID来确定其DLL路径; int nError; TCHAR szBaseProviderDll[MAX_PATH]; int nLen=MAX_PATH;
//故需要通过ExpandEnvironmentStrings()来扩展成绝对路径; if(::WSCGetProviderPath(&NextProtocolInfo.ProviderId,szBaseProviderDll,&nLen,&nError)==SOCKET_ERROR) { ODS1(L"WSPStartup:WSCGetProviderPath() failed %d\n",nError); return WSAEPROVIDERFAILEDINIT; }
if(!::ExpandEnvironmentStrings(szBaseProviderDll,szBaseProviderDll,MAX_PATH)) { ODS1(L"WSPStartup: ExpandEnvironmentStrings() failed %d",::GetLastError()); return WSAEPROVIDERFAILEDINIT; }
//通过上面已获取到的DLL绝对路径,来加载下层服务提供者,即加载其下载服务提供者的DLL; HMODULE hModule=::LoadLibrary(szBaseProviderDll); if(hModule==NULL) { ODS1(L"WSPStartup: LoadLibrary() failed %d",::GetLastError()); return WSAEPROVIDERFAILEDINIT; }
//通过自定义的一个指向WSPSTARTUP函数指针,来启动下一层服务提供者; LPWSPSTARTUP pfnWSPStartup=NULL;
pfnWSPStartup=(LPWSPSTARTUP)::GetProcAddress(hModule,"WSPStartup"); if(pfnWSPStartup==NULL) { ODS1(L"WSPStartup: GetProcAddress() failed %d\n",::GetLastError()); return WSAEPROVIDERFAILEDINIT; }
//调用下层服务提供者的WSPStartup函数;
LPWSAPROTOCOL_INFOW pInfo=lpProtocolInfo; if(NextProtocolInfo.ProtocolChain.ChainLen==BASE_PROTOCOL) { pInfo=&NextProtocolInfo; }
//通过自定义的pfnWSPStartup()来调用下层服务提供者的WSPStartup函数,调用成功后其中 //lpProcTable变量将在后期进行Hook时经常用到; int nRet=pfnWSPStartup(wVersionRequested,lpWSPData,pInfo,UpcallTable,lpProcTable); if(nRet!=ERROR_SUCCESS) { ODS1(L"WSPStartup: underlying provider`s WSPStartup() failed %d\n",nRet); return nRet; }
//保存下层服务提供者的函数列表; g_NextProcTable=*lpProcTable;
//通过修改传递给下层服务提供者的函数列表,Hook相关WSP函数; lpProcTable->lpWSPSendTo=WSPSendTo;
FreeProvider(pProtoInfo); return nRet;
}
//END
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // nfilter.EX by miyagi // // 开发思路: // 1)定义要安装的LSP的硬编码,在卸载LSP时还要会使用; // 2)定义GetProvider()、FreeProvider()函数,枚举服务提供者和释放枚举到的结构数组; // 3)通过InstallProvider()来安装自定义的LSP; // 3.1)通过GetProvider()来枚举所有的提供者; // 3.2)遍历pProtoInfo数据里的每个服务提供者,并将TCP、UDP、RAW对应的服务提供者结构 // 以及入口ID分别保存至OriginalProtocolInfo数组及dwOrigCatalogId数组中,同时去 // 掉XP1_IFS_HANDLES标志; // 3.3)安装我们自定义的分层协议,获取一个dwLayeredCatalogID,即LSP入口ID; // 3.3.1)任意将一个下层服务提供者的结构复制到LayeredProtocolInfo中,进行LSP服务 // 提供者结构的自定义; // 3.3.2)构造我们自定义的LSP结构; // 3.3.3)通过WSCInstallProvider()开始安装我们自定义的LSP; // 3.3.4)重新枚举各服务提供者,获取刚才我们安装好的自定义的LSP的入口ID; // 3.3.5)遍历pProtoInfo数组,寻找我们自定义的LSP的入口ID,并保存至 // dwLayeredCatalogId中; // 3.3.6)安装协议链前,分别先构造好TCP、UPD、RAW各自的协议链顺序; // 3.3.7)为协议链获取一个GUID,并通过OriginalProtocol数组来安装三个协议链; // 3.3.8)协议链安装完毕后,需要重新排序,将我们的协议链提到最前面; // 3.3.9)移除我们自定义的LSP及协议链; // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Ws2spi.h> #include <Sporder.h> // 定义了WSCWriteProviderOrder()函数 #include <windows.h> #include <stdio.h>
#pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Rpcrt4.lib") // 实现了UuidCreate()函数
//定义要安装的LSP的硬编码,在卸载LSP时还要会使用; GUID ProviderGuid={0xd3c21122, 0x85e1, 0x48f3, {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};
//枚举当前各协议服务提供者的函数; LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols) { DWORD dwSize = 0; int nError; LPWSAPROTOCOL_INFOW pProtoInfo = NULL; //用于申请存放服务提供者结构的内存空间; // 取得需要的长度,即通过将WSCEnumProtocols函数的dwSize参数置0进行第一次调用,后 //以获得枚举服务提供者所需的缓冲区大小,置于dwSize变量中; if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR) { if(nError != WSAENOBUFS) return NULL; } //根据dwSize中的值来申请内存空间; pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);
//第二次通过WSCEnumProtocols()正式枚举到各服务提供者并存放于pProtoInfo(数组)中, //并将服务提供者的个数存到lpnTotalProtocols中; *lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
//将pProtoInfo返回给函数调用者; return pProtoInfo; }
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo) { //释放用于存放服务提供者数组的内存空间,pProtoInfo; ::GlobalFree(pProtoInfo); }
//枚举现有的各服务提供者; void query() { LPWSAPROTOCOL_INFOW pProtoInfo; int nProtocols; pProtoInfo = GetProvider(&nProtocols);
for(int i=0; i<nProtocols; i++) { printf(" Protocol: %ws \n", pProtoInfo[i].szProtocol); printf(" CatalogEntryId: %d ChainLen: %d \n\n", pProtoInfo[i].dwCatalogEntryId, pProtoInfo[i].ProtocolChain.ChainLen); } }
//安装LSP int InstallProvider(WCHAR *pwszPathName) { //标识我们自定义安装的LSP的名字; WCHAR wszLSPName[]=L"^_^LSP"; LPWSAPROTOCOL_INFOW pProtoInfo; int nProtocols; WSAPROTOCOL_INFOW OriginalProtocolInfo[3];
DWORD dwOrigCatalogId[3];
int nArrayCount=0; DWORD dwLayeredCatalogId;
int nError;
//枚举所有的服务提供者; pProtoInfo=GetProvider(&nProtocols);
//通过以下三个布尔变量,来判断是否找到对应服务提供者; BOOL bFindTcp=FALSE; BOOL bFindUdp=FALSE; BOOL bFindRaw=FALSE;
//遍历pProtoInfo数据里的每个服务提供者,并将TCP、UDP、RAW对应的服务提供者结构保存; for(int i=0;i<nProtocols;i++) { if(pProtoInfo[i].iAddressFamily==AF_INET) { if(!bFindTcp&&pProtoInfo[i].iProtocol==IPPROTO_TCP) { memcpy(&OriginalProtocolInfo[nArrayCount],&pProtoInfo[i],sizeof(WSAPROTOCOL_INFOW)); OriginalProtocolInfo[nArrayCount].dwServiceFlags1=OriginalProtocolInfo[nArrayCount].dwServiceFlags1&(~XP1_IFS_HANDLES); dwOrigCatalogId[nArrayCount++]=pProtoInfo[i].dwCatalogEntryId;
bFindTcp=TRUE; //表示已找到对应服务提供者;
}
if(!bFindUdp&&pProtoInfo[i].iProtocol==IPPROTO_UDP) { memcpy(&OriginalProtocolInfo[nArrayCount],&pProtoInfo[i],sizeof(WSAPROTOCOL_INFOW)); OriginalProtocolInfo[nArrayCount].dwServiceFlags1=OriginalProtocolInfo[nArrayCount].dwServiceFlags1&(~XP1_IFS_HANDLES); dwOrigCatalogId[nArrayCount++]=pProtoInfo[i].dwCatalogEntryId;
bFindUdp=TRUE;
}
if(!bFindRaw&&pProtoInfo[i].iProtocol==IPPROTO_IP) { memcpy(&OriginalProtocolInfo[nArrayCount],&pProtoInfo[i],sizeof(WSAPROTOCOL_INFOW)); OriginalProtocolInfo[nArrayCount].dwServiceFlags1=OriginalProtocolInfo[nArrayCount].dwServiceFlags1&(~XP1_IFS_HANDLES); dwOrigCatalogId[nArrayCount++]=pProtoInfo[i].dwCatalogEntryId;
bFindRaw=TRUE; ;
}
} }
//安装我们自定义的分层协议,获取一个dwLayeredCatalogID,即LSP入口ID; //任意将一个下层服务提供者的结构复制到LayeredProtocolInfo中,进行LSP //服务提供者结构的自定义;
WSAPROTOCOL_INFOW LayeredProtocolInfo;
memcpy(&LayeredProtocolInfo,&OriginalProtocolInfo[0],sizeof(WSAPROTOCOL_INFOW));
//构造我们自定义的LSP结构; wcscpy(LayeredProtocolInfo.szProtocol,wszLSPName); LayeredProtocolInfo.ProtocolChain.ChainLen=LAYERED_PROTOCOL;
LayeredProtocolInfo.dwProviderFlags|=PFL_HIDDEN;
//通过WSCInstallProvider()开始安装我们自定义的LSP; if(::WSCInstallProvider(&ProviderGuid,pwszPathName,&LayeredProtocolInfo,1,&nError)==SOCKET_ERROR) { return nError; }
//重新枚举各服务提供者,获取刚才我们安装好的自定义的LSP的入口ID; FreeProvider(pProtoInfo); pProtoInfo=GetProvider(&nProtocols);
for(i=0;i<nProtocols;i++) { if(memcmp(&pProtoInfo[i].ProviderId,&ProviderGuid,sizeof(ProviderGuid))==0) { dwLayeredCatalogId=pProtoInfo[i].dwCatalogEntryId; break; } }
//安装协议链前,先构造好协议链的顺序; WCHAR wszChainName[WSAPROTOCOL_LEN+1]; for(i=0;i<nArrayCount;i++) { swprintf(wszChainName,L"%ws over %ws",wszLSPName,OriginalProtocolInfo[i].szProtocol); wcscpy(OriginalProtocolInfo[i].szProtocol,wszChainName);
if(OriginalProtocolInfo[i].ProtocolChain.ChainLen==1) { OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1]=dwOrigCatalogId[i]; } else { for(int j=OriginalProtocolInfo[i].ProtocolChain.ChainLen;j>0;j--) { OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j]=OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1]; } }
OriginalProtocolInfo[i].ProtocolChain.ChainLen++; OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0]=dwLayeredCatalogId;
}
//为协议链获取一个GUID,并通过OriginalProtocol数组来安装三个协议链; GUID ProviderChainGuid; if(::UuidCreate(&ProviderChainGuid)==RPC_S_OK) { if(::WSCInstallProvider(&ProviderChainGuid,pwszPathName,OriginalProtocolInfo,nArrayCount,&nError)==SOCKET_ERROR) { return nError; } } else return GetLastError();
//协议链安装完毕后,需要重新排序,将我们的协议链提到最前面;
FreeProvider(pProtoInfo); pProtoInfo=GetProvider(&nProtocols); DWORD dwIds[20]; int nIndex=0;
for(i=0;i<nProtocols;i++) { if((pProtoInfo[i].ProtocolChain.ChainLen>1)&&(pProtoInfo[i].ProtocolChain.ChainEntries[0]==dwLayeredCatalogId)) dwIds[nIndex++]=pProtoInfo[i].dwCatalogEntryId; }
//添加其他的服务提供者入口ID; for(i=0;i<nProtocols;i++) { if((pProtoInfo[i].ProtocolChain.ChainLen<=1)||(pProtoInfo[i].ProtocolChain.ChainEntries[0]!=dwLayeredCatalogId)) dwIds[nIndex++]=pProtoInfo[i].dwCatalogEntryId; }
//通过WSCWriteProviderOrder()重新按照dwIds的顺序排序; if((nError=::WSCWriteProviderOrder(dwIds,nIndex))!=ERROR_SUCCESS) { return nError; }
FreeProvider(pProtoInfo);
return nError;
}
//移除我们自定义的LSP及协议链; void RemoveProvider() { LPWSAPROTOCOL_INFOW pProtoInfo; int nProtocols; DWORD dwLayeredCatalogId; pProtoInfo=GetProvider(&nProtocols); int nError; //根据GUID来获得分层协议的入口ID; for(int i=0; i<nProtocols; i++) { if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 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)) { ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError); } }
//最后移除分层服务提供者LSP; ::WSCDeinstallProvider(&ProviderGuid, &nError); }
}
///////////////////////////////////////////////////////////////////////////////////////
int usage() {
printf("\n*********************************************************\n" "* nfilter.exe,by miyagi&echo *\n" "* *\n" "* usage:nfilter.exe [-install] [-uninstall] [-query] *\n" "*********************************************************\n"); return 0; }
int main(int argc,char* argv[]) { if(argc<2) { usage(); } else { if(strcmp(argv[1],"-install")==0) { if(InstallProvider(L"wskfilter.dll") == ERROR_SUCCESS) { printf(" Install successully!^_^ \n"); } else { printf(" Install failed!~o~ \n"); } }
if(strcmp(argv[1],"-uninstall")==0) { RemoveProvider(); printf(" Uninstall successully!^_^ \n"); }
if(strcmp(argv[1],"-query")==0) { query(); printf(" Query successully!^_^ \n"); }
}
return 1; }
|