0%

在服务程序中启动其他程序(1)

简介

有时我们需要跟随操作系统启动某些程序,常见的做法是创建服务程序,然后使用 SYSTEM 权限来启动其他程序

控制服务的代码

服务的启动停止,可以直接使用 sc.exe 或者 net.exe 指令进行控制,比如使用 sc stop dhcp
停止 dhcp 服务,有时候停止服务时,会提示我们是否结束依赖项,使用 net stop dhcp /y 命令,可以
自动结束 dhcp 的依赖项。除此之外,我们还可以使用SDK提供的API来进行控制,如下为相关控制代码

服务安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
BOOL ServiceInstall(PCSTR pName, PCSTR pPath)
{
// 检查参数
if (pName == NULL) || (pPath == NULL) return FALSE;
// 打开服务管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL) return FALSE;
// 创建服务
SC_HANDLE hService = CreateService(
hSCM, pName, pPath, SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
pPath, NULL, NULL, "", NULL, NULL);
if (hService == NULL)
{
// 检测服务是否已经创建
if (GetLastError() == ERROR_SERVICE_EXISTS)
{
CloseServiceHandle(hSCM);
return TRUE;
}
CloseServiceHandle(hSCM);
return FALSE;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
服务启动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
BOOL ServiceStart(PCSTR pName)
{
// 检查参数
if (pName == NULL) return FALSE;
// 打开服务控制管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL) return FALSE;
// 打开服务
SC_HANDLE hService = OpenService(hSCM, m_csName.GetBuffer(), SERVICE_ALL_ACCESS);
if (hService != NULL)
{
CloseServiceHandle(hSCM);
return FALSE;
}
// 先查询服务状态
DWORD needsize = 0;
SERVICE_STATUS_PROCESS ssp;
BOOL success = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
(PBYTE)(&ssp), sizeof(SERVICE_STATUS_PROCESS), &needsize);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
// 等待pending的动作
DWORD dwOldCheckPoint = ssp.dwCheckPoint;
while ((ssp.dwCurrentState == SERVICE_START_PENDING) ||
(ssp.dwCurrentState == SERVICE_STOP_PENDING))
{
Sleep(ssp.dwWaitHint); // 休眠预估的时间
success = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
(PBYTE)(&ssp), sizeof(SERVICE_STATUS_PROCESS), &needsize);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
// 检查pending是否结束
if ((ssp.dwCurrentState != SERVICE_START_PENDING) &&
(ssp.dwCurrentState != SERVICE_STOP_PENDING)) break;
// 检查是否超时
if (ssp.dwCheckPoint == dwOldCheckPoint) break;
dwOldCheckPoint = ssp.dwCheckPoint;
}
// 启动服务
if (ssp.dwCurrentState == SERVICE_STOPPED)
{
success = StartService(hService, 0, NULL);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
服务停止
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
BOOL StopDepend(SC_HANDLE hSCM, SC_HANDLE hService)
{
if ((hSCM == NULL) || (hService == NULL)) return FALSE;
DWORD count = 0;
DWORD needsize = 0;
LPENUM_SERVICE_STATUS pDepend = NULL;
// 查询依赖服务
BOOL success = EnumDependentServices(hSCM,
SERVICE_ACTIVE, pDepend, 0, &needsize, &count);
if (success) return TRUE; // 无依赖服务
else if (GetLastError() != ERROR_MORE_DATA) return FALSE;
// 申请内存空间
pDepend = (LPENUM_SERVICE_STATUS)malloc(needsize);
if (pDepend == NULL) return FALSE;
memset(pDepend, 0, needsize);
// 再次查询依赖服务
success = EnumDependentServices(hSCM,
SERVICE_ACTIVE, pDepend, needsize, &needsize, &count);
if (!success)
{
free(pDepend);
return FALSE;
}
// 循环停止依赖服务
SC_HANDLE handle = NULL;
DWORD dwOldCheckPoint = 0;
SERVICE_STATUS_PROCESS ssp;
for (DWORD i = 0; i < count; ++i)
{
handle = OpenService(hSCM, (pDepend + i)->lpServiceName, SERVICE_ALL_ACCESS);
if (handle == NULL)
{
free(pDepend);
return FALSE;
}
success = ControlService(handle, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)(&ssp));
if (!success)
{
CloseServiceHandle(handle);
free(pDepend);
return FALSE;
}
// 等待停止完成
while (ssp.dwCurrentState != SERVICE_STOPPED)
{
Sleep(ssp.dwWaitHint); // 休眠预估的时间
success = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
(PBYTE)(&ssp), sizeof(SERVICE_STATUS_PROCESS), &needsize);
if (!success)
{
CloseServiceHandle(handle);
free(pDepend);
return TRUE;
}
if (ssp.dwCurrentState == SERVICE_STOPPED) break; // while
// 检查是否超时
if (ssp.dwCheckPoint == dwOldCheckPoint)
{
CloseServiceHandle(handle);
free(pDepend);
return TRUE;
}
dwOldCheckPoint = ssp.dwCheckPoint;
}
CloseServiceHandle(handle);
}
free(pDepend);
return TRUE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
BOOL ServiceStop(PCSTR pName)
{
if (pName == NULL) return FALSE;
// 打开服务控制管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL) return FALSE;
// 打开服务
SC_HANDLE hService = OpenService(hSCM, m_csName.GetBuffer(), SERVICE_ALL_ACCESS);
if (hService != NULL)
{
CloseServiceHandle(hSCM);
return FALSE;
}
// 先查询服务状态
DWORD needsize = 0;
SERVICE_STATUS_PROCESS ssp;
BOOL success = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
(PBYTE)(&ssp), sizeof(SERVICE_STATUS_PROCESS), &needsize);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
// 等待pending的动作
DWORD dwOldCheckPoint = ssp.dwCheckPoint;
while ((ssp.dwCurrentState == SERVICE_START_PENDING) ||
(ssp.dwCurrentState == SERVICE_STOP_PENDING))
{
Sleep(ssp.dwWaitHint); // 休眠预估的时间
success = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO,
(PBYTE)(&ssp), sizeof(SERVICE_STATUS_PROCESS), &needsize);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
// 检查pending是否结束
if ((ssp.dwCurrentState != SERVICE_START_PENDING) &&
(ssp.dwCurrentState != SERVICE_STOP_PENDING)) break;
// 检查是否超时
if (ssp.dwCheckPoint == dwOldCheckPoint) break;
dwOldCheckPoint = ssp.dwCheckPoint;
}
// 停止服务
if (ssp.dwCurrentState == SERVICE_RUNNING)
{
SERVICE_STATUS status;
success = StopDepend(hSCM, hService); // 停止依赖服务
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
success = ControlService(hService, SERVICE_CONTROL_STOP, &status);
if (!success)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
服务卸载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
BOOL ServiceUninstall(PCSTR pName)
{
if (pName == NULL) return FALSE;
// 打开服务控制管理器
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL) return FALSE;
// 打开服务
SC_HANDLE hService = OpenService(hSCM, m_csName.GetBuffer(), SERVICE_ALL_ACCESS);
if (hService != NULL)
{
CloseServiceHandle(hSCM);
return FALSE;
}
// 卸载服务
if (DeleteService(hService))
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return FALSE;
}

应用程序的示例

当我们需要常驻运行某个程序时,可以在服务中定时轮询检测并启动。如下为实例程序代码

头文件
1
2
3
4
5
6
#include <tlhelp32.h>
#include <shellapi.h>
#include <userenv.h>
#pragma comment(lib, "userenv.lib")
#include <wtsapi32.h>
#pragma comment(lib, "wtsapi32.lib")
全局变量
1
2
3
4
// 全局变量
SERVICE_STATUS g_svcStatus = { 0 };
SERVICE_STATUS_HANDLE g_hSvcStatus = NULL;
OSVERSIONINFO g_osVersion = { 0 };
其他函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
DWORD GetPidByName(IN PCSTR pName)
{
if (pName == NULL) return 0;
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
// 创建进程快照
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
// 获取首个进程信息
if (!Process32First(hSnapshot, &pe))
{
CloseHandle(hSnapshot);
return 0;
}
// 循环遍历进程
do
{
if (_stricmp(pName, pe.szExeFile) == 0)
{
CloseHandle(hSnapshot);
return pe.th32ProcessID;
}
memset(&pe, 0, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);
} while (Process32Next(hSnapshot, &pe));
CloseHandle(hSnapshot);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
BOOL VistaStartProcess(IN PSTR pCmdLine)
{
if (pCmdLine == NULL) return FALSE;
// 获取活动控制台会话
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if (dwSessionId == 0xFFFFFFFF) return FALSE;
// 获取指定(会话/进程)令牌信息
HANDLE hToken = NULL;
if (!WTSQueryUserToken(dwSessionId, &hToken)) return FALSE;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) return FALSE;
// 复制到新令牌
HANDLE hTokenDup = NULL;
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
SecurityIdentification, TokenPrimary, &hTokenDup))
{
CloseHandle(hToken);
return FALSE;
}
// 如果需要,修改新令牌的会话信息
if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)))
{
CloseHandle(hTokenDup);
CloseHandle(hToken);
return FALSE;
}
// 关闭旧令牌句柄
CloseHandle(hToken);
// 创建环境变量块
LPVOID pEnv = NULL;
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (CreateEnvironmentBlock(&pEnv, hTokenDup, TRUE))
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
else
pEnv = NULL;
// 启动进程
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcessAsUser(hTokenDup, NULL, pCmdLine,
NULL, NULL, FALSE, dwCreationFlags, pEnv, NULL, &si, &pi))
{
if (pEnv != NULL) DestroyEnvironmentBlock(pEnv);
CloseHandle(hTokenDup);
return FALSE;
}
// 销毁环境变量块
if (pEnv != NULL) DestroyEnvironmentBlock(pEnv);
CloseHandle(hTokenDup);
return TRUE;
}
服务函数
1
2
3
4
void WINAPI ServiceCtrl(DWORD dwOpcode)
{
// 不提供服务控制
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
// 注册服务控制函数
g_hSvcStatus = RegisterServiceCtrlHandler("MyService", ServiceCtrl);
if (g_hSvcStatus == NULL) return;
// 设置服务为pending状态
g_svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
g_svcStatus.dwCurrentState = SERVICE_START_PENDING;
g_svcStatus.dwControlsAccepted = 0; // SERVICE_ACCEPT_STOP; // 停止服务变灰
g_svcStatus.dwWin32ExitCode = 0;
g_svcStatus.dwServiceSpecificExitCode = 0;
g_svcStatus.dwCheckPoint = 0;
g_svcStatus.dwWaitHint = 0;
SetServiceStatus(g_hSvcStatus, &g_svcStatus);
// 设置服务为running状态
g_svcStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(g_hSvcStatus, &g_svcStatus);
// 循环启动进程
PSTR pPath = "c:\\test.exe";
while (1)
{
if (GetPidByName("test.exe") == 0)
{
if (g_osVersion.dwMajorVersion > 5)
VistaStartProcess(pPath);
else
StartProcess(pPath);
}
// 休眠1分钟
Sleep(60000);
}
// 服务设置SERVICE_RUNNING以后会自动维持运行
// 除非需要循环执行某些命令,否则不需要手动维持运行
}
主函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nCmdShow)
{
// 获取操作系统版本号
OSVERSIONINFO osver = { 0 };
if (!GetVersionEx(&osver)) return 0;
if (g_osVersion.dwMajorVersion < 6) return 0;
// 低权限内核对象属性描述
SECURITY_DESCRIPTOR secDesc = { 0 };
InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&secDesc, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES secAttrib = { 0 };
secAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttrib.lpSecurityDescriptor = &secDesc;
secAttrib.bInheritHandle = FALSE;
// 创建防多开事件
HANDLE hEvent = CreateEvent(&secAttrib, FALSE, FALSE, "Global\\MyService");
// 创建失败,则退出
if (hEvent == NULL) return 0;
// 已存在,则退出
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hEvent);
return 0;
}
// 设置服务主函数
SERVICE_TABLE_ENTRY st[] = {
{ "MyService", ServiceMain },
{ NULL, NULL } };
// 运行服务主函数
StartServiceCtrlDispatcher(st);
CloseHandle(hEvent);
return 0;
}

其他事项

以上启动的程序全都是 SYSTEM 权限的,如果想以其他权限运行,就需要在 CreateProcessAsUser 时,
使用其他程序的 token 信息,比如获取 explorer.exe 程序的 token 信息