SetNamedSecurityInfo()
返回的值与ACCESS_IS_DENIED
的Winerror.h
相对应,代码也会返回错误值5,即使该二进制文件是作为管理员运行的。最后,让我更加迷失的部分是,当我尝试使用其他已安装服务的服务名称或使用自定义字符串安全描述符(调用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服务之一的屏幕快照:
提前感谢。
我有一个应用程序,最好将它安装的服务设置为不能被用户编辑和中断(如下面安装的服务之一的屏幕快照所示……)>
OWNER_SECURITY_INFORMATION
,调用进程必须具有WRITE_OWNER
访问权限,或者必须是对象的所有者,或者必须启用SE_TAKE_OWNERSHIP_NAME
特权,或者在您将非self SID设置为对象的所有者时启用SE_RESTORE_NAME
。而且,您不需要设置对象所有者的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;
}