今天給大家講下怎樣做一個服務程序...本來是想詳細講的,不過寫着寫着累得要命..很多
地方就沒詳細...不過代碼我加了點注...如果還有一些不明白的自己查下MSDN......便宜
環境,,VC++6.0...代碼有倆段,一段是服務程序的..另一段是安裝服務程序的...這個程序
的功能是開機發出滴滴聲....安裝成功后自己點啟動...下次開機就自動起動了....
load.exe的實現是比較簡單,本來想弄個匯編版本...不過真的累...就算了..這里一個服
務的基本框架就完成了...剩下的只是添加你自己的功能代碼...
怎樣安裝::我在C盤建一個名為sysnap的文件夾..里面放着倆個EXE..一個是sv.exe 另一
個是svload.exe 然后cmd到這個文件夾,輸入svload.exe則服務安裝成功...開機后就有一
個服務進程sv.exe...這樣我們就有了一個名為sysnap的服務..在注冊表里可以找到相關
信息....當然你可以把服務名改為你自己的....svload.exe的代碼很簡單..我沒有注
釋,,,,如果需要我回帖再注..我現在累
一個服務的基本框架
1感性認識什么是服務
2用INF文件安裝服務
3關於服務的一些基本理論知識
4一個服務的創建流程和基本組成
5詳說各個基本函數
6所用到的一些數據結構和API說明
7開始我們的第一個服務,完整代碼
8運行我們的服務,完整代碼
1感性認識什么是服務
在運行框輸入SERVICES.MSC..看到沒,,這些都是windows的服務..里面有一些是windows自己的,有一些是第三方服務,,比如我們的殺毒軟件大部分都有一個服務
那服務有什么用呢,..讓我們先看一下服務的定義吧
服務:是一種應用程序類型,它在后台運行。
可見如果我們把程序做成服務后也可以照樣運行起來...如果是設置成手動的,那開機后我們的服務程序就自動運行起來...所以很多木馬都搞成服務啟動,,這比在注冊表里什么RUN
要隱蔽多了
系統有倆種服務.一種叫win32服務,他運行在用戶態,對應的映像文件是.EXE或.DLL..我們這里講的就是win32服務
另外一種叫系統服務,它運行在內核態,對應的映像文件是.SYS也就是驅動程序..其實這倆個概念現在也沒必要細分了吧..區別除了運行態不同外,另外還有一個區別,就是在注冊表中除了在HKEY_LOCAL_MACHINE/SYSTE/CurrentControlSet/Services下都有一個服務名外,系統服務還多了一個設備硬健HKEY_LOCAL_MACHINESystem/CurrentControlSet/Enum子鍵,因為是驅動程序嘛,在刪除一些內核木馬時.這個建默認是無法刪除的,因為需要SYSTEM權限..不過右鍵->權限->添加->高級就可以搞定
2用INF文件安裝服務
現在我們就用.INF文件來把我們的EXE程序變成服務..隨開機的運行而運行,這個EXE文件我是用我前幾天在吧里發的哪個小程序,依然是輸出電腦的用戶名...在C盤建一個文件夾,命名為SYSNAP..把我們的程序sysnap.exe放進去
打開筆記本,那下面代碼寫進去,保存為sysnap.inf
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=sysnap,,My_AddService_Name
[My_AddService_Name]
DisplayName=sysnap
Description=顯示電腦用戶名
ServiceType=0x10
StartType=2
ErrorControl=0
ServiceBinary=C:/SYSNAP/sysnap.exe
說明一下
1、ServiceType服務類型:0x10為獨立進程服務,0x20為共享進程服務(比如svchost)
2、StartType啟動類型:0 系統引導時加載,1 OS初始化時加載,2 由SCM(服務控制管理器)自動啟動,3 手動啟動,4 禁用(注意,0和1只能用於驅動程序)
3、ErrorControl錯誤控制:0 忽略,1 繼續並警告,2 切換到LastKnownGood的設置,3藍屏
4、ServiceBinary服務程序位置
好了..在CMD下運行命令
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:/SYSNAP/sysnap.inf
這樣就安裝了一個名為sysnap的服務,是不是很簡單呢..當然后.INF文件安裝服務有時候是不太好,,,下面我們就通過編成來實現,,,也是主要的目的..先講一下理論吧
3關於服務的一些基本理論知識
WIN32服務由三部分組成:服務應用程序、服務控制程序SCP,和服務控制管理器SCM。
服務應用程序:就是接下來我們要實現的程序,他是一個EXE文件..也可以是.DLL,這里我們是sysnap.exe
服務控制程序:控制服務應用程序的功能塊,也是服務應用程序同服務管理器(SCM)之間的橋梁
服務控制管理器:負責加載和初始化AUTO_ATRT的服務程序,SCM維護着注冊表中的服務數據庫,位於:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services。其下的子鍵就是安裝的服務和驅動服務。每個子鍵的名稱就是服務名,當安裝的時候由服務安全程序的CreateService 函數指定
還有就不寫了..可以參考<<inside windows 2000>>他們講的已經足夠好了...,不夠里面涉及的東西很多.建議看下后面的程序...不懂的再去參考他們比較好..因為這個程序不要求你全要理解他們
4一個服務的創建流程一個服務的創建流程和基本組成
A編寫我們的main()函數,該函數必須在30秒內調用StartServiceCtrlDispatcher 函數..這樣我們的EXE文件就在SCM里注冊了
B編寫我們的ServiceMain(),ServiceMain()要立即調用RegisterServiceCtrlHandler 注冊服務控制處理函數,然后用RegisterServiceCtrlHandler返回的句柄向SCM發送狀態信息,接着開始完成實際的服務任務和工作線程,一旦線程開始,ServiceMain()就等待一個事件的發生,知道服務停止,ServiceMain()才返回
C編寫我們的控制處理器ServiceCtrlHandler,接受來自SCM的請求並作出反應,其實請求一般是下面幾個值(也可以自己定義)
停止服務:SERVICE_CONTROL_STOP
暫停服務:SERVICE_CONTROL_PAUSE
恢復被暫停的服務:SERVICE_CONTROL_CONTINUE
返回服務的更新狀態信息:SERVICE_CONTROL_INTERROGATE
D編寫這個服務要實現的功能函數,也就是我們這個服務要完成什么功能,這里依然是輸出電腦用戶名
可見,一個完整的服務包括:
main():他告訴SCM 關於ServiceMain()的一些信息
ServiceMain():開始ServiceThread(),告訴SCM關於控制處理器的一些信息
ServiceCtrlHandler:接受來自SCM的請求並做出響應
InitThread():由ServiceMain()打開,執行我們的任務,,就是建立一個線程來運行我們的任務
5詳說各個基本函數
A main()
SCM是一個管理系統所有服務的進程,當SCM啟動某個服務時,它等待某個進程的主線程來調用StartServiceCtrlDispatcher(),這樣把調用進程的住線程轉換為控制分配器,控制分配器啟動一個新線程,新線程運行分配表里每個服務的ServiceMain()
B ServiceMain()
是服務的入口點.它運行在一個單獨的線程中,主要是為服務注冊控制處理器,它指示控制分配器調用ServiceCtrlHandler()來處理SCM的請求,注冊完成后將返回一個句柄
通過調用SetServiceStatus,用這個句柄和SERVICE_STATUS向SCM報告服務狀態,,,因為這樣的動作經常發生,,,所以我們把這個過程寫成一個函數ReportStatusToSCMgr()
RegisterServiceCtrlHandler(strServiceName, (LPHANDLER_FUNCTION)ServiceCtrlHandler);
接着調用ReportStatusToSCMgr()向SCM報告服務狀態 ReportStatusToSCMgr();
創建一個事件,在函數的最后將調用該事件來保持函數的運行知道SCM發出停止請求才返回 CreateEvent();
創建一個線程來運行我們的服務函數 sysnap();
最后ServiceThread()完成后返回ServiceMain(),ServiceMain()調用 WaitForSingleObject()
C ServiceCtrlHandler()
檢查SCM發送了什么請求並且做出反應...當用戶關閉系統,所有的控制處理要調用SetServiceStatus設置SERVICE_ACCEPT_SHUTDOWN控制碼去接收SERVICE_CONTROL_SHUTDOWN控制碼,如果服務需要時間去清除,它可以發送 STOP_PENDING狀態消息,連同一個等待時間,這樣,服務控制器在報告系統服務關閉之前才知道應該待多長時間,無論如何,都有一個服務控制器需要等待的時間,防止服務停留在shutdown狀態。要改變這個時間限制,可以修改HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control中的WaitToKillServiceTimeout值。
switch(nControlCode)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
nServiceCurrentStatus=SERVICE_STOP_PENDING;
success=ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);
KillService();
return;
default:
break;
}
6所用到的一些數據結構和API說明
本來想寫,,算了.自己查MSDN///累....下面代碼我會加點注射
下面就直接代碼吧...可以自己編譯
sv.exe的代碼
#include <stdio.h>
#include <windows.h>
#include <winsvc.h>
//定義一些全局變量和函數
void ServiceMain(DWORD argc, LPTSTR *argv);
void ServiceCtrlHandler(DWORD dwControlCode);
//SCM報告服務狀態信息
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
DWORD dwWaitHint);
BOOL InitThread(); //創建線程來運行我們的任務
DWORD sysnap(LPDWORD param); //我們這個服務所要完成的任務
HANDLE hServiceThread;
void KillService();
char *strServiceName = "sysnap"; ////標識服務的內部名
SERVICE_STATUS_HANDLE nServiceStatusHandle; //存儲調用RegisterServiceCtrlHandler返回的句柄
HANDLE killServiceEvent;
BOOL nServiceRunning;
DWORD nServiceCurrentStatus;
void main(int argc, char* argv[])
{
// SERVICE_TABLE_ENTRY 結構類型的數組,他包含了調用進程所提供的每個服務的入口函數和字符串名。表中的最后一個元素必須為 NULL,指明入口表結束
SERVICE_TABLE_ENTRY servicetable[]=
{
{strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL,NULL}
};
BOOL success;
// StartServiceCtrlDispatcher 函數負責把程序主線程連接到服務控制管理程序
success=StartServiceCtrlDispatcher(servicetable);
if(!success)
{
printf("fialed!");
}
}
void ServiceMain(DWORD argc, LPTSTR *argv)
{
BOOL success;
//把ServiceCtrlHandler注冊為服務控制器,接受來自SCM的請求並做出處理,
nServiceStatusHandle=RegisterServiceCtrlHandler(strServiceName,
(LPHANDLER_FUNCTION)ServiceCtrlHandler);
//判斷是否注冊成功,否則返回
if(!nServiceStatusHandle)
{
return;
}
//注冊成功后向SCM報告服務狀態信息,因為服務還沒初始化完成,所以當前服務狀態為SERVICE_START_PENDING
success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,1,3000);
if(!success)
{
return;
}
//創建一個事件,在函數的最后將用該事件來保持函數的運行直到SCM發出停止請求才返回
killServiceEvent=CreateEvent(0,TRUE,FALSE,0);
if(killServiceEvent==NULL)
{
return;
}
//向SCM報告服務狀態信息
success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,2,1000);
if(!success)
{
return;
}
//InitThread()創建一個線程來運行我們的sysnap()函數
success=InitThread();
if(!success)
{
return;
}
//我們的服務開始運行任務了,當前狀態設置為SERVICE_RUNNING
nServiceCurrentStatus=SERVICE_RUNNING;
success=ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0,0,0);
if(!success)
{
return;
}
//sysnap()函數運行完了之后返回ServiceMain(),ServiceMain()調用WaitForSingleObject,因為服務被停止之前ServiceMain()不會結束
WaitForSingleObject(killServiceEvent,INFINITE);
CloseHandle(killServiceEvent);
}
//向SCM報告服務狀態信息,可以說是更新信息吧,它接受的參數都是SERVICE_STATUS結構成員
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
DWORD dwWaitHint)
{
BOOL success;
SERVICE_STATUS nServiceStatus; //定義一個SERVICE_STATUS類型結構nServiceStatus
nServiceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; //表示我們的服務是獨占一個進程的服務
nServiceStatus.dwCurrentState=dwCurrentState; //當前服務狀態
//
if(dwCurrentState==SERVICE_START_PENDING)
{
nServiceStatus.dwControlsAccepted=0; //服務的初始化沒有完成
}
else
{
nServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP //通知 SCM 服務接受哪個域。這里允許 STOP 和SHUTDOWN 請求
|SERVICE_ACCEPT_SHUTDOWN;
}
//dwServiceSpecificExitCode在你終止服務並報告退出細節時很有用。初始化服務時並不退出,因此值為 0
if(dwServiceSpecificExitCode==0)
{
nServiceStatus.dwWin32ExitCode=dwWin32ExitCode;
}
else
{
nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
}
nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode;
//
nServiceStatus.dwCheckPoint=dwCheckPoint;
nServiceStatus.dwWaitHint=dwWaitHint;
//設置好nServiceStatus后,向SCM報告服務狀態
success=SetServiceStatus(nServiceStatusHandle,&nServiceStatus);
if(!success)
{
KillService();
return success;
}
else
return success;
}
BOOL InitThread()
{
DWORD id;
hServiceThread=CreateThread(0,0,
(LPTHREAD_START_ROUTINE)sysnap,
0,0,&id);
if(hServiceThread==0)
{
return false;
}
else
{
nServiceRunning=true;
return true;
}
}
DWORD sysnap(LPDWORD param)
{
while(nServiceRunning)
{
Beep(450,150);
Sleep(4000);
}
return 0;
}
void KillService()
{
nServiceRunning=false;
SetEvent(killServiceEvent);
ReportStatusToSCMgr(SERVICE_STOPPED,NO_ERROR,0,0,0);
}
void ServiceCtrlHandler(DWORD dwControlCode)
{
BOOL success;
switch(dwControlCode)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
nServiceCurrentStatus=SERVICE_STOP_PENDING;
success=ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,0,1,3000);//先更新服務狀態為SERVICDE_STOP_PENDING,再停止服務
KillService();
return;
default:
break;
}
ReportStatusToSCMgr(nServiceCurrentStatus,NO_ERROR,0,0,0);
}
svload.exe的代碼
#include <stdio.h>
#include <windows.h>
#include <winsvc.h>
int main(int argc, char* argv[])
{
char* showInfo="sysnap's first Windows service"; //注意寬字符的轉換(L)
char* showName="sysnap";
char* sv_Path="C://sysnap//sv.exe";
SC_HANDLE Hsysnap;
SC_HANDLE hSCManager;
hSCManager=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
if(!hSCManager)
{
printf("failed");
return 1;
}
Hsysnap=CreateService(hSCManager,TEXT(showName),
TEXT(showInfo),
SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
sv_Path,
0,0,0,0,0);
if(!Hsysnap)
{
CloseServiceHandle(hSCManager);
printf("failed");
return 1;
}
CloseServiceHandle(Hsysnap);
CloseServiceHandle(hSCManager);
return 0;
}
倆個EXE文件一共334K....如果不想編譯我可以把他們發到你郵葙
哈哈..謝謝給個精品..當時在寫的時候認為很清晰..不過現在自己再看一遍..是比較長..我把他的整體弄上來,,,看了才不灰亂
void main()
{
調用StartServiceCtrlDispatcher(),把控制交給控制分配器,控制分配器新建一個線程來運行ServiceMain..也就是真正進入服務
}
void ServiceMain(DWORD argc, LPTSTR *argv)
{
RegisterServiceCtrlHandler注冊為服務控制器,接受來自SCM的請求並做出處理
創建一個事件,在函數的最后將用該事件來保持函數的運行直到SCM發出停止請求 才返回
創建一個線程來運行我們的函數
函數運行完了之后返回ServiceMain(),ServiceMain()調用
}
BOOL ReportStatusToSCMgr()
{
填充SERVICE_STATUS 成員..並把它做為參數傳給etServiceStatus()向SCM報告服務狀 態
}
BOOL InitThread()
{
創建運行sysnap()的線程
}
DWORD sysnap(LPDWORD param)
{
我們要做的工作
}
void KillService()
{
停止服務
}
void ServiceCtrlHandler(DWORD dwControlCode)
{
接受來自SCM的請求並做出反應..這里要自己實現幾個函數;
}
總之記住看的時候以main(),ServiceMain()和ServiceCtrlHandler()為中心..其他函數都是比較簡單的
http://blog.csdn.net/jiangxinyu/article/details/5265673
