Функция SetNamedSecurityInfo () возвращает ACCESS_IS_DENIED (код ошибки 5 в Winerror.h), даже когда приложение запускается от имени администратора - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть приложение, в котором предпочтительно установить установленные им сервисы так, чтобы они не редактировались и не прерывались пользователем (как видно на скриншоте одного из установленных сервисов ниже), и я реализовал вариант следующие логи c для выполнения sh this:

  1. Прочитайте дескриптор безопасности службы Windows, который не позволяет пользователю редактировать его и каким-либо образом прекратить его (как видно из нижеприведенный снимок экрана, на котором свойства службы соответствующего сервиса не позволяют пользователю даже завершить его, гарантируя, что он работает постоянно и прекращается только тогда, когда он окончательно удален).
  2. Установить ранее прочитанное дескриптор безопасности службы, установленной приложением для демонстрации тех же функций.

Вот реальная проблема: код возвращает значение ошибки 5 в качестве значения, возвращаемого SetNamedSecurityInfo(), что соответствует ACCESS_IS_DENIED согласно Winerror.h, даже когда соответствующий двоичный файл запускается от имени администратора. или. Наконец, часть, в которой я потерял еще больше, это когда я пытался использовать имена служб других установленных служб или использовал собственный дескриптор безопасности строки (при вызове функции ConvertStringSecurityDescriptorToSecurityDescriptor()), я не получил никакой ошибки, поскольку код работал как требуется. Даже при дальнейших исследованиях я обнаружил, что эта ошибка воспроизводима только при использовании имен службы, которые реализуют требуемое поведение: не позволяя конечному пользователю редактировать тип запуска, а также статус службы службы.

Код, используемый для выполнения указанной задачи:

// Fetch the security descriptor for "WdNisSvc" (Service name that corresponds to the display name of "Windows Security Service")
LPCWSTR serviceNameToGetSecurityInformationFrom = L"WdNisSvc";
SC_HANDLE serviceManagerHandle = NULL, serviceHandle = NULL;
char securityDescriptorBuffer[1024];
DWORD lengthOfReturnedValue = 0;
LPWSTR stringBuffer = NULL;
unsigned long lengthOfString = 0;
PSECURITY_DESCRIPTOR securityDescriptor = { 0 };
LPSTR daclBuffer = nullptr, ownerSidBuffer = nullptr, absoluteSecurityDescriptionBuffer = nullptr;
DWORD daclBufferSize = NULL, ownerSidBufferSize = NULL, absoluteSecurityDescriptionBufferSize = NULL, saclBufferSize = NULL, primaryGroupSidBufferSize = NULL;
WCHAR serviceName[] = L"test_service";
DWORD securityInfoChangeOperationErrorValue = NULL;
BOOL securityDescriptorInAbsoluteFormatCreationErrorValue = NULL;
serviceManagerHandle = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (serviceManagerHandle == nullptr) {
    cout << "Error opening Service Manager Handle (" << GetLastError() << ").\n";
}
else {
    serviceHandle = OpenService(serviceManagerHandle, serviceNameToGetSecurityInformationFrom, READ_CONTROL); //| WRITE_OWNER | WRITE_DAC
    if (serviceHandle == nullptr) {
        cout << "Error opening service (" << GetLastError() << ").\n";
    }
    else {
        if (!QueryServiceObjectSecurity(serviceHandle, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, securityDescriptorBuffer, sizeof(securityDescriptorBuffer), &lengthOfReturnedValue)) {
            cout << "Error obtaining service's security information (" << GetLastError() << ").\n";
        }
        else {
            if (!ConvertSecurityDescriptorToStringSecurityDescriptor(securityDescriptorBuffer, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &stringBuffer, &lengthOfString)) {
                cout << "Error getting string value corresponding to the security information (" << GetLastError() << ")";
            }
            else {

                if (!ConvertStringSecurityDescriptorToSecurityDescriptor(stringBuffer, SDDL_REVISION_1, &securityDescriptor, NULL)) {
                    cout << "Conversion of string descriptor to security descriptor failed with error " << GetLastError() << ".\n";
                } 
                else {
                    absoluteSecurityDescriptionBuffer = new CHAR[0];
                    ownerSidBuffer = new CHAR[0];
                    daclBuffer = new CHAR[0];
                    securityDescriptorInAbsoluteFormatCreationErrorValue = MakeAbsoluteSD(securityDescriptor, absoluteSecurityDescriptionBuffer, &absoluteSecurityDescriptionBufferSize, (PACL)daclBuffer, &daclBufferSize, NULL, &saclBufferSize, ownerSidBuffer, &ownerSidBufferSize, NULL, &primaryGroupSidBufferSize);
                    if ((!securityDescriptorInAbsoluteFormatCreationErrorValue) && (ERROR_INSUFFICIENT_BUFFER) == GetLastError()) {
                        // Induced error
                        //cout << "ERROR: Inadequate size of the buffers implemented.\n";
                        delete[] absoluteSecurityDescriptionBuffer;
                        delete[] ownerSidBuffer;
                        delete[] daclBuffer;
                        absoluteSecurityDescriptionBuffer = new CHAR[absoluteSecurityDescriptionBufferSize];
                        ownerSidBuffer = new CHAR[ownerSidBufferSize];
                        daclBuffer = new CHAR[daclBufferSize];
                        securityDescriptorInAbsoluteFormatCreationErrorValue = MakeAbsoluteSD(securityDescriptor, absoluteSecurityDescriptionBuffer, &absoluteSecurityDescriptionBufferSize, (PACL)daclBuffer, &daclBufferSize, NULL, &saclBufferSize, ownerSidBuffer, &ownerSidBufferSize, NULL, &primaryGroupSidBufferSize);
                    }
                    securityInfoChangeOperationErrorValue = SetNamedSecurityInfo(serviceName, SE_SERVICE, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, ownerSidBuffer, NULL, (ACL*)daclBuffer, NULL);
                    if (securityInfoChangeOperationErrorValue != ERROR_SUCCESS) {
                        cout << "Error setting security info (" << securityInfoChangeOperationErrorValue << ").\n";
                    }
                    delete[] absoluteSecurityDescriptionBuffer;
                    delete[] ownerSidBuffer;
                    delete[] daclBuffer;
                }
            }
        }
    }
}

Снимок экрана одного из установленных сервисов Windows, который демонстрирует требуемое поведение: Screenshot of the properties box of

Заранее спасибо.

1 Ответ

0 голосов
/ 12 февраля 2020

Чтобы установить OWNER_SECURITY_INFORMATION, вызывающий процесс должен иметь доступ WRITE_OWNER, либо должен быть владельцем объекта, либо иметь включенную привилегию SE_TAKE_OWNERSHIP_NAME, либо SE_RESTORE_NAME, если вы не указали собственный SID в качестве владельца объекта. , И вам не нужно устанавливать SID владельца необходимого объекта. Следующий образец работает для меня:

#include <windows.h>
#include <iostream>
#include <sddl.h>
#include <aclapi.h>
#include <WinError.h>
#pragma comment(lib, "Advapi32.lib")
using namespace std;
int main(int argc, char* argv[])
{
    // Fetch the security descriptor for "WdNisSvc" (Service name that corresponds to the display name of "Windows Security Service")

    LPCWSTR serviceNameToGetSecurityInformationFrom = L"SecurityHealthService";
    SC_HANDLE serviceManagerHandle = NULL, serviceHandle = NULL;
    char securityDescriptorBuffer[1024];
    DWORD lengthOfReturnedValue = 0;
    LPSTR daclBuffer = nullptr, absoluteSecurityDescriptionBuffer = nullptr;
    DWORD daclBufferSize = NULL, ownerSidBufferSize = NULL, absoluteSecurityDescriptionBufferSize = NULL, saclBufferSize = NULL, primaryGroupSidBufferSize = NULL;
    WCHAR serviceName[] = L"MySampleService1";
    DWORD securityInfoChangeOperationErrorValue = NULL;
    BOOL securityDescriptorInAbsoluteFormatCreationErrorValue = NULL;
    serviceManagerHandle = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
    if (serviceManagerHandle == nullptr) {
        cout << "Error opening Service Manager Handle (" << GetLastError() << ").\n";
    }
    else {
        serviceHandle = OpenService(serviceManagerHandle, serviceNameToGetSecurityInformationFrom, READ_CONTROL); //| WRITE_OWNER | WRITE_DAC


        if (serviceHandle == nullptr) {
            cout << "Error opening service (" << GetLastError() << ").\n";
        }
        else {
            if (!QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, securityDescriptorBuffer, sizeof(securityDescriptorBuffer), &lengthOfReturnedValue)) {
                cout << "Error obtaining service's security information (" << GetLastError() << ").\n";
            }
            else {
                BOOL bDaclPresent = false, bDaclDefaulted = false;
                PACL pDacl = NULL;
                BOOL ret = GetSecurityDescriptorDacl(securityDescriptorBuffer, &bDaclPresent, &pDacl, &bDaclDefaulted);
                if (bDaclPresent)
                {
                    securityInfoChangeOperationErrorValue = SetNamedSecurityInfo(serviceName, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, NULL, pDacl, NULL);
                }
                else
                {
                    cout << "The security descriptor doesn't contain a DACL" << endl;
                }
                //SC_HANDLE target_service = OpenService(serviceManagerHandle, serviceName, WRITE_DAC); //| WRITE_OWNER | WRITE_DAC
                //if (serviceHandle == nullptr) {
                //    cout << "Error opening service (" << GetLastError() << ").\n";
                //}
                //else {
                //    BOOL ret = SetServiceObjectSecurity(target_service, DACL_SECURITY_INFORMATION, securityDescriptorBuffer);
                //    if (ret == 0) {
                //        cout << "Error SetServiceObjectSecurity (" << GetLastError() << ").\n";
                //    }
                //    CloseServiceHandle(target_service);
                //}

            }
            CloseServiceHandle(serviceHandle);
        }
        CloseServiceHandle(serviceManagerHandle);
    }
    return 0;
}

Или просто используйте SetServiceObjectSecurity:

#include <windows.h>
#include <iostream>
#include <sddl.h>
#include <aclapi.h>
#include <WinError.h>
#pragma comment(lib, "Advapi32.lib")
using namespace std;
int main(int argc, char* argv[])
{
    // Fetch the security descriptor for "WdNisSvc" (Service name that corresponds to the display name of "Windows Security Service")

    LPCWSTR serviceNameToGetSecurityInformationFrom = L"SecurityHealthService";
    SC_HANDLE serviceManagerHandle = NULL, serviceHandle = NULL;
    char securityDescriptorBuffer[1024];
    DWORD lengthOfReturnedValue = 0;
    LPSTR daclBuffer = nullptr, absoluteSecurityDescriptionBuffer = nullptr;
    DWORD daclBufferSize = NULL, ownerSidBufferSize = NULL, absoluteSecurityDescriptionBufferSize = NULL, saclBufferSize = NULL, primaryGroupSidBufferSize = NULL;
    WCHAR serviceName[] = L"MySampleService1";
    DWORD securityInfoChangeOperationErrorValue = NULL;
    BOOL securityDescriptorInAbsoluteFormatCreationErrorValue = NULL;
    serviceManagerHandle = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
    if (serviceManagerHandle == nullptr) {
        cout << "Error opening Service Manager Handle (" << GetLastError() << ").\n";
    }
    else {
        serviceHandle = OpenService(serviceManagerHandle, serviceNameToGetSecurityInformationFrom, READ_CONTROL); //| WRITE_OWNER | WRITE_DAC


        if (serviceHandle == nullptr) {
            cout << "Error opening service (" << GetLastError() << ").\n";
        }
        else {
            if (!QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, securityDescriptorBuffer, sizeof(securityDescriptorBuffer), &lengthOfReturnedValue)) {
                cout << "Error obtaining service's security information (" << GetLastError() << ").\n";
            }
            else {
                //securityDescriptorInAbsoluteFormatCreationErrorValue = MakeAbsoluteSD(securityDescriptorBuffer, NULL, &absoluteSecurityDescriptionBufferSize, (PACL)daclBuffer, &daclBufferSize, NULL, &saclBufferSize, NULL, &ownerSidBufferSize, NULL, &primaryGroupSidBufferSize);
                //if ((!securityDescriptorInAbsoluteFormatCreationErrorValue) && (ERROR_INSUFFICIENT_BUFFER) == GetLastError()) {
                //    // Induced error
                //    //cout << "ERROR: Inadequate size of the buffers implemented.\n";
                //    absoluteSecurityDescriptionBuffer = new CHAR[absoluteSecurityDescriptionBufferSize];
                //    daclBuffer = new CHAR[daclBufferSize];
                //    securityDescriptorInAbsoluteFormatCreationErrorValue = MakeAbsoluteSD(securityDescriptorBuffer, absoluteSecurityDescriptionBuffer, &absoluteSecurityDescriptionBufferSize, (PACL)daclBuffer, &daclBufferSize, NULL, &saclBufferSize, NULL, &ownerSidBufferSize, NULL, &primaryGroupSidBufferSize);
                //}
                //securityInfoChangeOperationErrorValue = SetNamedSecurityInfo(serviceName, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL, NULL, (ACL*)daclBuffer, NULL);
                //if (securityInfoChangeOperationErrorValue != ERROR_SUCCESS) {
                //    cout << "Error setting security info (" << securityInfoChangeOperationErrorValue << ").\n";
                //}
                //delete[] absoluteSecurityDescriptionBuffer;
                //delete[] daclBuffer;
                SC_HANDLE target_service = OpenService(serviceManagerHandle, serviceName, WRITE_DAC); //| WRITE_OWNER | WRITE_DAC
                if (serviceHandle == nullptr) {
                    cout << "Error opening service (" << GetLastError() << ").\n";
                }
                else {
                    BOOL ret = SetServiceObjectSecurity(target_service, DACL_SECURITY_INFORMATION, securityDescriptorBuffer);
                    if (ret == 0) {
                        cout << "Error SetServiceObjectSecurity (" << GetLastError() << ").\n";
                    }
                    CloseServiceHandle(target_service);
                }

            }
            CloseServiceHandle(serviceHandle);
        }
        CloseServiceHandle(serviceManagerHandle);
    }
    return 0;
}

enter image description here

Примечание:

[SetServiceObjectSecurity доступно для использования в операционных системах, указанных в разделе «Требования». Это может быть изменено или недоступно в последующих версиях. Вместо этого используйте функцию SetNamedSecurityInfo.]

...