Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1332754
  • 博文数量: 436
  • 博客积分: 7854
  • 博客等级: 少将
  • 技术积分: 3225
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-18 16:30
文章分类

全部博文(436)

文章存档

2013年(2)

2012年(56)

2011年(70)

2010年(308)

分类:

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   // 定义了WSCWriteProviderOrder()函数
#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;
 
}

阅读(1050) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~