如何灰化基于Win32 API开发的自研Windows服务启动类型?
如何通过Win32 API限制Windows服务的启动类型修改
要实现类似WinDefend服务那样灰化启动类型选项、阻止用户修改的效果,核心是通过修改服务的安全权限,移除或拒绝普通用户拥有修改服务配置的权限(即SERVICE_CHANGE_CONFIG权限)。以下是具体实现步骤及代码示例:
实现思路
Windows服务的启动类型修改属于服务配置变更操作,需要调用方拥有SERVICE_CHANGE_CONFIG权限。我们通过修改服务的安全描述符(SD),添加拒绝普通用户/组获取该权限的访问控制项(ACE),即可阻止用户修改启动类型。
具体步骤
打开服务管理器与目标服务
使用OpenSCManager打开本地服务管理器,再通过OpenService打开目标服务,需确保拥有READ_CONTROL(读取安全设置)和WRITE_DAC(修改权限)权限。获取当前服务的安全描述符
调用QueryServiceObjectSecurity获取服务当前的安全描述符,用于后续修改。构建新的访问控制列表(DACL)
创建拒绝SERVICE_CHANGE_CONFIG权限的ACE,针对目标用户/组(比如普通用户组Users),通过SetEntriesInAcl将该ACE合并到原有的DACL中,生成新的DACL。应用修改后的安全描述符
将包含新DACL的安全描述符通过SetServiceObjectSecurity应用到目标服务上,完成权限限制。
代码示例(C++ Win32 API)
#include <windows.h> #include <aclapi.h> // 限制指定服务的启动类型修改权限 BOOL RestrictServiceStartupTypeChange(LPCWSTR szServiceName) { // 打开服务管理器 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!hSCManager) return FALSE; // 打开目标服务,需拥有读写权限 SC_HANDLE hService = OpenService(hSCManager, szServiceName, READ_CONTROL | WRITE_DAC); if (!hService) { CloseServiceHandle(hSCManager); return FALSE; } // 获取当前安全描述符 PSECURITY_DESCRIPTOR pSD = NULL; DWORD dwBytesNeeded = 0; if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, NULL, 0, &dwBytesNeeded) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwBytesNeeded); if (!pSD) goto Cleanup; if (!QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, pSD, dwBytesNeeded, &dwBytesNeeded)) goto Cleanup; } // 提取原有DACL PACL pOldDACL = NULL; BOOL bDaclPresent = FALSE, bDaclDefaulted = FALSE; if (!GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pOldDACL, &bDaclDefaulted)) goto Cleanup; // 创建拒绝SERVICE_CHANGE_CONFIG权限的ACE(针对普通用户组) EXPLICIT_ACCESS ea = {0}; ea.grfAccessPermissions = SERVICE_CHANGE_CONFIG; ea.grfAccessMode = DENY_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea.Trustee.ptstrName = L"Users"; PACL pNewDACL = NULL; if (SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS) goto Cleanup; // 更新安全描述符的DACL并应用到服务 BOOL bResult = FALSE; if (SetSecurityDescriptorDacl(pSD, TRUE, pNewDACL, FALSE)) { bResult = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, pSD); } Cleanup: // 释放资源 if (pNewDACL) LocalFree(pNewDACL); if (pSD) LocalFree(pSD); CloseServiceHandle(hService); CloseServiceHandle(hSCManager); return bResult; }
注意事项
- 操作必须以管理员身份执行,否则无法获取修改服务权限的权限。
- 可根据需求调整目标用户/组(比如替换
L"Users"为L"Authenticated Users"或特定用户名)。 - 权限设置生效后,普通用户打开服务属性窗口时,启动类型下拉框会被灰化,无法修改。
- 若需恢复修改权限,只需移除对应的拒绝ACE即可,流程与上述步骤类似,将
DENY_ACCESS改为REVOKE_ACCESS或删除目标ACE。
内容的提问来源于stack exchange,提问作者NImIPKZvUc
相关产品推荐
相关产品推荐

