c++ - 即使应用程序以管理员身份运行,SetNamedSecurityInfo() 函数也会返回 ACCESS_IS_DENIED(Winerror.h 中的错误代码 5)
问题描述
我有一个应用程序,最好将其安装的服务设置为用户不可编辑和中断(如下面已安装服务之一的屏幕截图所示),并且我已经实现了以下逻辑的变体做到这一点:
- 读取不允许用户编辑的 Windows 服务的安全描述符并以任何方式终止它(如下面的屏幕截图所示,相关服务的服务属性甚至不允许用户终止它,确保它会永久运行,并且只有在最终被移除时才会终止)。
- 将先前读取的安全描述符设置为应用程序安装的服务以展示相同的功能。
这是真正的问题:代码返回错误值 5 作为 的返回值SetNamedSecurityInfo()
,对应于ACCESS_IS_DENIED
as per 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;
}
}
}
}
}
提前致谢。
解决方案
要设置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;
}
笔记:
[
SetServiceObjectSecurity
可用于“要求”部分中指定的操作系统。在后续版本中可能会更改或不可用。相反,请使用该SetNamedSecurityInfo
功能。]
推荐阅读
- python - 在装饰器中访问 self 对象和装饰器参数
- javascript - 输入字段输入时的输入状态
- python - 在 Python 中计算列中日期之间时间间隔的简单方法
- typescript - 具有父子关系的 2 个实体的 GraphQL 突变返回第二个实体的旧值
- acumatica - 更新网格上所有行的字段
- c# - 从回测结果中寻找每日利润
- maven - 将带有分类器的工件发布到共享 pom 的 GitHub 包时,如何解决冲突?
- python - Python - 如果我不导入日志记录模块会发生日志记录
- mysql - AWS Data Pipeline - SQLActivity 到 S3 (MySQL DB)
- mysql - 如何从崩溃的 Cloud SQL 实例中保存数据而不丢失数据