本博文由CSDN部落客zuishikonghuan所作,版權歸zuishikonghuan所有,轉載請注明出處:http://blog.csdn.net/zuishikonghuan/article/details/47720285
在上幾篇博文中,我示範了如何編寫一個系統服務,介紹了如何穿透Session 0在目前使用者的桌面上建立一個使用者程序,也可以擷取服務自己的權限令牌在使用者的桌面上建立一個擁有SYSTEM權限的程序。這一篇,我就說說如何使用自定義控制碼與服務程式通信。
其實這一篇呢應該放到我以後的服務管理API系列去講,但是畢竟服務開發嗎,沒有應用程式與服務的通信實在是說不過去,于是還是簡單說一說。
隻是與服務通信的時候也會受Session 0隔離的影響,比如:無法共享Windows消息啊,無法遠端注入,無法遠端讀寫記憶體等等。但是其他的程序間通信機制并不受影響,比如:命名管道,我們可以将自定義控制碼和命名管道結合起來,實作程序通信。
首先來看看如何向服務發送自定義控制碼
關于控制碼,使用者自定義控制碼的範圍,已經在[Win32] 服務程式開發(1)基本概念和服務程式的架構中講過了,不再重複。
第一步:在服務程式的HandlerEx裡注冊使用者控制碼:(這裡我用的200)
DWORD WINAPI HandlerEx(_In_ DWORD dwControl, _In_ DWORD dwEventType, _In_ LPVOID lpEventData, _In_ LPVOID lpContext)
{
switch (dwControl)
{
case SERVICE_CONTROL_STOP://控制代碼:要求停止停止
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);//報告服務運作狀态
return 0;
case SERVICE_CONTROL_SHUTDOWN://控制代碼:關機
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ServiceStatus);//報告服務運作狀态
return 0;
case 200:
//這裡是接收此控制碼時的邏輯,可以在此處讀命名管道。這裡簡單彈一個對話框
ShowMessage(L"收到自定義控制碼", L"服務");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);//報告服務運作狀态
return 0;
default:
break;
}
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);//報告服務運作狀态
return 0;
}
第二步:在使用者程序中發送控制碼
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager != NULL){
SC_HANDLE hService = OpenService(hSCManager, TEXT("zz"), SERVICE_USER_DEFINED_CONTROL);
if (hService != NULL){
SERVICE_STATUS status;
if (!ControlService(hService, 200, &status)){
//發生控制碼失敗
}
CloseServiceHandle(hService);
}
else{
//OpenService失敗
}
CloseServiceHandle(hSCManager);
}
else{
//OpenSCManager失敗
}
這個代碼可以在管理者權限的程式中執行也可以在非管理者權限的程序中執行。原因是權限設定:SC_MANAGER_CONNECT和SERVICE_USER_DEFINED_CONTROL限制了服務句柄隻能用于發送使用者自定義控制碼。