SDDL正确定义及进程权限配置求助:仅允许管理员终止进程
问题分析与修正方案
核心问题点
- 代码执行顺序错误:
app.Run()是阻塞调用,后续的ProtectCurrentProcess()永远不会执行。 - 对象类型指定错误:进程属于
SE_PROCESS类型,而非SE_KERNEL_OBJECT,类型不匹配会导致权限设置失败。 - SDDL字符串过于宽泛:当前SDDL给管理员所有权限、拒绝普通用户所有权限,既不符合"仅限制终止权限"的需求,还会导致进程自身或其他合法操作失败。
- 潜在内存泄漏:未手动释放
ConvertStringSecurityDescriptorToSecurityDescriptor生成的安全描述符。
修正后的代码
using System.ComponentModel; using System.Diagnostics; using RemoteMaster.Client.Abstractions; using RemoteMaster.Client.Core.Abstractions; using RemoteMaster.Client.Core.Extensions; using RemoteMaster.Client.Services; using Windows.Win32.Foundation; using Windows.Win32.Security.Authorization; using static Windows.Win32.PInvoke; internal class Program { private static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args).ConfigureCoreUrls(); builder.Services.AddCoreServices(); builder.Services.AddSingleton<IScreenCapturerService, BitBltCapturer>(); builder.Services.AddSingleton<ICursorRenderService, CursorRenderService>(); builder.Services.AddSingleton<IInputService, InputService>(); builder.Services.AddSingleton<IPowerService, PowerService>(); var app = builder.Build(); ProtectCurrentProcess(); // 移至app.Run()前执行 app.MapCoreHubs(); app.Run(); } private static unsafe void ProtectCurrentProcess() { const uint DACL_SECURITY_INFORMATION = 0x00000004; const uint SDDL_REVISION_1 = 1; const uint WRITE_DAC = 0x00400000; // 显式获取带WRITE_DAC权限的进程句柄,确保有权修改DACL using var currentProcess = OpenProcess(WRITE_DAC, false, (uint)Process.GetCurrentProcess().Id); if (currentProcess.IsInvalid) { throw new Win32Exception(); } // SDDL说明: // D:P - 指定DACL // (D;;TM;;;WD) - 拒绝所有用户(WD)的进程终止权限(TM对应PROCESS_TERMINATE) // (A;;TM;;;BA) - 允许管理员组(BA)的进程终止权限 const string restrictedSddl = "D:P(D;;TM;;;WD)(A;;TM;;;BA)"; if (!ConvertStringSecurityDescriptorToSecurityDescriptor(restrictedSddl, SDDL_REVISION_1, out var sd, null)) { throw new Win32Exception(); } try { if (!GetSecurityDescriptorDacl(sd, out var daclPresent, out var pDacl, out var defaultDacl) || !daclPresent) { throw new Win32Exception(); } var result = SetSecurityInfo( currentProcess, SE_OBJECT_TYPE.SE_PROCESS, // 修正为进程对象类型 DACL_SECURITY_INFORMATION, null, null, *pDacl, null); if (result != WIN32_ERROR.ERROR_SUCCESS) { throw new Win32Exception((int)result); } } finally { LocalFree(sd); // 手动释放安全描述符,避免内存泄漏 } } }
关键修正说明
- 执行顺序调整:将进程保护逻辑移至
app.Run()前,确保Web应用启动时即完成权限配置。 - 进程句柄获取:用
OpenProcess显式获取带WRITE_DAC权限的句柄,比GetCurrentProcess的伪句柄更可靠,确保拥有修改权限的权限。 - 对象类型修正:使用
SE_PROCESS匹配进程对象类型,避免权限设置失败。 - 精准SDDL配置:仅针对进程终止权限(
TM对应PROCESS_TERMINATE)做限制,拒绝普通用户、允许管理员操作,不影响进程其他合法权限。 - 内存泄漏修复:在
finally块中调用LocalFree释放安全描述符。
进阶优化(保留原有权限)
如果需要保留进程原有权限,仅添加终止权限的限制,需避免直接替换DACL,而是基于原DACL添加ACE:
- 用
GetSecurityInfo获取进程原有DACL。 - 创建新ACL,复制原有ACE后添加拒绝普通用户、允许管理员终止权限的ACE。
- 调用
SetSecurityInfo设置新DACL。
内容的提问来源于stack exchange,提问作者vitkuz573
相关产品推荐
相关产品推荐

