【问题标题】:Configuring a windows service application to not be editable by the user将 Windows 服务应用程序配置为用户不可编辑
【发布时间】:2020-01-27 13:55:02
【问题描述】:

我有一个 Windows 服务应用程序,它安装在用户机器上并显示在服务页面 (services.msc) 下。我希望用户(通过服务 UI)无法配置启动选项,如下面的屏幕截图所示(对于 Windows Defender 防病毒服务):

提前致谢。

【问题讨论】:

  • 通过SetServiceObjectSecurity 在您的服务上设置一些安全描述符。说O:BAD:(A;;GA;;;SY)(A;;GRGX;;;IU)
  • 嗨,hecate,您是否尝试过我回答中的示例?如果它不适合你,请随时告诉我。
  • @RbMM SetServiceObjectSecurity() 函数不是解决此要求的推荐方法,因为它已被弃用。 MSFT 建议在 aclapi.h 中使用 SetNamedSecurityInfoA() 函数。
  • @hecate - SetServiceObjectSecuritySetNamedSecurityInfoW 更好更高效,我建议完全使用 SetServiceObjectSecurity

标签: .net windows winapi service


【解决方案1】:

@RbMm 是对的。

以下是在 C++ 中使用 winapi 的示例。

#include <windows.h>
#include <sddl.h>

#pragma comment(lib, "Advapi32")

int main()
{
    SC_HANDLE sHdl = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
    if (sHdl == NULL)
        printf("OpenSCManager error: %d\n", GetLastError());

    SC_HANDLE serviceHdl = OpenService(sHdl, L"MyTestDirectXService", READ_CONTROL | WRITE_OWNER | WRITE_DAC);
    if (sHdl == NULL)
        printf("OpenService error: %d\n", GetLastError());

    char buf[1024];
    DWORD retLen = 0;

    // ### Query
    if(!QueryServiceObjectSecurity(serviceHdl, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, buf, sizeof(buf), &retLen))
        printf("QueryServiceObjectSecurity error: %d\n", GetLastError());

    LPWSTR strBuf = NULL;
    unsigned long strLen = 0;
    if (!ConvertSecurityDescriptorToStringSecurityDescriptor(buf, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &strBuf, &strLen))
        printf("ConvertSecurityDescriptorToStringSecurityDescriptor error: %d\n", GetLastError());

    wprintf(strBuf);

    // ### Set
    PSECURITY_DESCRIPTOR sDescriptor = {0};
    if(!ConvertStringSecurityDescriptorToSecurityDescriptor(L"O:BAD:(A;;GA;;;SY)(A;;GRGX;;;IU)", SDDL_REVISION_1, &sDescriptor, NULL))
        printf("ConvertStringSecurityDescriptorToSecurityDescriptor error: %d\n", GetLastError());

    if (!SetServiceObjectSecurity(serviceHdl, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, sDescriptor))
        printf("SetServiceObjectSecurity error: %d\n", GetLastError());

    // ### Check
    if (!QueryServiceObjectSecurity(serviceHdl, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, buf, sizeof(buf), &retLen))
        printf("QueryServiceObjectSecurity error: %d\n", GetLastError());

    strBuf = NULL;
    strLen = 0;
    if (!ConvertSecurityDescriptorToStringSecurityDescriptor(buf, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &strBuf, &strLen))
        printf("ConvertSecurityDescriptorToStringSecurityDescriptor error: %d\n", GetLastError());

    wprintf(strBuf);

    getchar();
}

运行上述代码后,启动选项被禁用,如下所示:

更新:由于“[SetServiceObjectSecurity 可用于要求部分中指定的操作系统。在后续版本中可能会更改或不可用。请改用SetNamedSecurityInfo 函数。]”以下是使用SetNamedSecurityInfo API 的示例。

// ### Set
PSECURITY_DESCRIPTOR sDescriptor = { 0 };
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"O:BAD:(A;;GA;;;SY)(A;;GRGX;;;IU)", SDDL_REVISION_1, &sDescriptor, NULL))
    printf("ConvertStringSecurityDescriptorToSecurityDescriptor error: %d\n", GetLastError());

char daclBuf[100];
char ownerBuf[100];
char abBuf[100];

DWORD abLen = sizeof(abBuf);
DWORD dLen = sizeof(daclBuf);
DWORD oLen = sizeof(ownerBuf);
DWORD sLen = 0;
DWORD gLen = 0;

// Only owner and DACL security information valid in String security descriptor so here set DACL and Primary Group buffer to NULL. 
BOOL returnVal = MakeAbsoluteSD(sDescriptor, abBuf, &abLen, (PACL)daclBuf, &dLen, NULL, &sLen, ownerBuf, &oLen, NULL, &gLen);
if ((!returnVal) && (ERROR_INSUFFICIENT_BUFFER) == GetLastError())
    printf("One or more of the buffers is too small.\n");

WCHAR serviceName[] = L"MySecondService";
DWORD result = SetNamedSecurityInfo(serviceName, SE_SERVICE, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, ownerBuf, NULL, (ACL*)daclBuf, NULL);
if(ERROR_SUCCESS != result)
    printf("ConvertStringSecurityDescriptorToSecurityDescriptor error: %d\n", result);

【讨论】:

  • SetServiceObjectSecurity() 函数不是解决此要求的推荐方法,因为它已被弃用。 MSFT 建议在aclapi.h 中使用SetNamedSecurityInfoA() 函数。
  • @hecate 更新SetNamedSecurityInfo函数示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
  • 2011-01-20
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多