分类:
2010-08-24 16:40:46
很多单机版的防火墙都是利用了SPI的技术来实现对网络封包的截获处理.[当然也有结合NDIS及IMD驱动的,不再本贴范围内:)],也可以通过SPI技术实现无进程的DLL木马.这里Winsock2 SPI的原理在这就不多说了,网上多得是.
以下仅为我前段时间学习SPI技术时的写的一些代码,望大家一起来研究讨论.
以下分别为wskfilter.dll及nfilter.exe的代码,编译成功后将两个文件放在同一目录下,CMD下运行nfilter.exe便可以加载自己的LSP(分层服务提供者)来截获相关WINSOCK API的调用了.当然如何处理需要在wskfilter.dll中进行控制,在此不作详述.
///////////////////////////////////////////////////////////////////////////////////////
//
//wskfilter.dll by
//
//
//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
#include
#include
#include
#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
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
#include
#include
#include
#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
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
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
if(memcmp(&pProtoInfo[i].ProviderId,&ProviderGuid,sizeof(ProviderGuid))==0)
{
dwLayeredCatalogId=pProtoInfo[i].dwCatalogEntryId;
break;
}
}
//安装协议链前,先构造好协议链的顺序;
WCHAR wszChainName[WSAPROTOCOL_LEN+1];
for(i=0;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
if((pProtoInfo[i].ProtocolChain.ChainLen>1)&&(pProtoInfo[i].ProtocolChain.ChainEntries[0]==dwLayeredCatalogId))
dwIds[nIndex++]=pProtoInfo[i].dwCatalogEntryId;
}
//添加其他的服务提供者入口ID;
for(i=0;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
if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0)
{
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
if(i
for(i=0; 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;
}