private static SafeStructureInOutBuffer <T> QueryObject <T>(SafeKernelObjectHandle handle, ObjectInformationClass object_info) where T : new() { SafeStructureInOutBuffer <T> ret = null; NtStatus status = NtStatus.STATUS_BUFFER_TOO_SMALL; try { int return_length; status = NtSystemCalls.NtQueryObject(handle, object_info, IntPtr.Zero, 0, out return_length); if ((status != NtStatus.STATUS_BUFFER_TOO_SMALL) && (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH)) { status.ToNtException(); } if (return_length == 0) { ret = new SafeStructureInOutBuffer <T>(); } else { ret = new SafeStructureInOutBuffer <T>(return_length, false); } status = NtSystemCalls.NtQueryObject(handle, object_info, ret.DangerousGetHandle(), ret.Length, out return_length); status.ToNtException(); } finally { if (ret != null && !status.IsSuccess()) { ret.Close(); ret = null; } } return(ret); }
/// <summary> /// Query a value by name /// </summary> /// <param name="value_name">The name of the value</param> /// <returns>The value information</returns> /// <exception cref="NtException">Thrown on error.</exception> public NtKeyValue QueryValue(string value_name) { UnicodeString name = new UnicodeString(value_name); int return_len = 0; int query_count = 0; while (query_count < 64) { using (var info = new SafeStructureInOutBuffer <KeyValuePartialInformation>(return_len, false)) { NtStatus status = NtSystemCalls.NtQueryValueKey(Handle, name, KeyValueInformationClass.KeyValuePartialInformation, info, info.Length, out return_len); if (status.IsSuccess()) { KeyValuePartialInformation result = info.Result; return(new NtKeyValue(value_name, info.Result.Type, info.Data.ReadBytes(result.DataLength), result.TitleIndex)); } if (status != NtStatus.STATUS_BUFFER_OVERFLOW && status != NtStatus.STATUS_BUFFER_TOO_SMALL) { status.ToNtException(); } ; } query_count++; } throw new NtException(NtStatus.STATUS_BUFFER_TOO_SMALL); }
/// <summary> /// Get a mitigation policy raw value /// </summary> /// <param name="policy">The policy to get</param> /// <returns>The raw policy value</returns> public int GetProcessMitigationPolicy(ProcessMitigationPolicy policy) { switch (policy) { case ProcessMitigationPolicy.ProcessDEPPolicy: case ProcessMitigationPolicy.ProcessReserved1Policy: case ProcessMitigationPolicy.ProcessMitigationOptionsMask: throw new ArgumentException("Invalid mitigation policy"); } MitigationPolicy p = new MitigationPolicy(); p.Policy = policy; using (var buffer = p.ToBuffer()) { int return_length; NtStatus status = NtSystemCalls.NtQueryInformationProcess(Handle, ProcessInfoClass.ProcessMitigationPolicy, buffer, buffer.Length, out return_length); if (!status.IsSuccess()) { if (status != NtStatus.STATUS_INVALID_PARAMETER && status != NtStatus.STATUS_NOT_SUPPORTED) { status.ToNtException(); } return(0); } return(buffer.Result.Result); } }
private static IEnumerable <string> EnumNameList(SafeKernelObjectHandle handle) { int size = 522; for (int i = 0; i < 10; ++i) { using (var buffer = new SafeHGlobalBuffer(size)) { NtStatus status = NtSystemCalls.NtUserBuildNameList(handle, buffer.Length, buffer, out size); if (!status.IsSuccess()) { if (status == NtStatus.STATUS_BUFFER_TOO_SMALL) { continue; } status.ToNtException(); } int total_count = buffer.Read <int>(4); int offset = 8; while (total_count > 0) { string name = buffer.ReadNulTerminatedUnicodeString((ulong)offset); yield return(name); offset += (name.Length + 1) * 2; total_count--; } yield break; } } throw new NtException(NtStatus.STATUS_NO_MEMORY); }
private SafeStructureInOutBuffer <T> QueryBuffer <T>(ThreadInformationClass info_class) where T : new() { SafeStructureInOutBuffer <T> info = new SafeStructureInOutBuffer <T>(); try { int return_length = 0; NtStatus status = NtSystemCalls.NtQueryInformationThread(Handle, info_class, info, info.Length, out return_length); if (status == NtStatus.STATUS_INFO_LENGTH_MISMATCH || status == NtStatus.STATUS_BUFFER_TOO_SMALL) { using (SafeBuffer to_close = info) { info = new SafeStructureInOutBuffer <T>(return_length, false); } status = NtSystemCalls.NtQueryInformationThread(Handle, info_class, info, info.Length, out return_length); } status.ToNtException(); return(info); } catch { info.Close(); throw; } }
/// <summary> /// Process Record. /// </summary> protected override void ProcessRecord() { if (SecurityDescriptor == null) { SecurityDescriptor = new SecurityDescriptor(); if (SecurityInformation.HasFlag(SecurityInformation.Dacl)) { SecurityDescriptor.Dacl = new Acl(); } if (SecurityInformation.HasFlag(SecurityInformation.Sacl)) { SecurityDescriptor.Sacl = new Acl(); } } bool do_callback = ShowProgress || PassThru; TreeProgressFunction fn = ProgressFunction; NtStatus status = Win32Security.ResetSecurityInfo(Name, Type, SecurityInformation, SecurityDescriptor, do_callback ? fn : null, ShowProgress ? ProgressInvokeSetting.PrePostError : ProgressInvokeSetting.EveryObject, KeepExplicit, !PassThru); if (!PassThru) { status.ToNtException(); } }
private void SetNamedSecurityInfo() { bool do_callback = ShowProgress || PassThru; if (Type == SeObjectType.Service) { SecurityInformation &= SecurityInformation.Owner | SecurityInformation.Group | SecurityInformation.Dacl | SecurityInformation.Label | SecurityInformation.Sacl; } string path = Name; if (Type == SeObjectType.File) { path = PSUtils.ResolveWin32Path(SessionState, path, false); } if (do_callback || Action != TreeSecInfo.Set) { TreeProgressFunction fn = ProgressFunction; NtStatus status = Win32Security.SetSecurityInfo(path, Type, SecurityInformation, SecurityDescriptor, Action, do_callback ? fn : null, ShowProgress ? ProgressInvokeSetting.PrePostError : ProgressInvokeSetting.EveryObject, !PassThru); if (!PassThru) { status.ToNtException(); } } else { Win32Security.SetSecurityInfo(path, Type, SecurityInformation, SecurityDescriptor); } }
/// <summary> /// Check if this object is exactly the same as another using NtCompareObject. /// </summary> /// <param name="obj">The object to compare against.</param> /// <returns>True if this is the same object.</returns> /// <exception cref="NtException">Thrown on error.</exception> /// <remarks>This is only supported on Windows 10 and above. For one which works on everything use SameObject.</remarks> public bool CompareObject(NtObject obj) { NtStatus status = NtSystemCalls.NtCompareObjects(Handle, obj.Handle); if (status == NtStatus.STATUS_NOT_SAME_OBJECT) { return(false); } status.ToNtException(); return(true); }
/// <summary> /// Write memory to a process. /// </summary> /// <param name="process">The process to write to.</param> /// <param name="base_address">The base address in the process.</param> /// <param name="data">The data to write.</param> /// <returns>The number of bytes written to the location</returns> /// <exception cref="NtException">Thrown on error.</exception> public static int WriteMemory(SafeKernelObjectHandle process, long base_address, byte[] data) { using (SafeHGlobalBuffer buffer = new SafeHGlobalBuffer(data)) { NtStatus status = NtSystemCalls.NtWriteVirtualMemory(process, new IntPtr(base_address), buffer, buffer.Length, out int return_length); if (status != NtStatus.STATUS_PARTIAL_COPY) { status.ToNtException(); } return(return_length); } }
/// <summary> /// Get security descriptor as a byte array /// </summary> /// <param name="security_information">What parts of the security descriptor to retrieve</param> /// <returns>The security descriptor</returns> public byte[] GetSecurityDescriptorBytes(SecurityInformation security_information) { int return_length; NtStatus status = NtSystemCalls.NtQuerySecurityObject(Handle, security_information, null, 0, out return_length); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { status.ToNtException(); } byte[] buffer = new byte[return_length]; NtSystemCalls.NtQuerySecurityObject(Handle, security_information, buffer, buffer.Length, out return_length).ToNtException(); return(buffer); }
private static int GetTypeSize() { using (var type_info = new SafeStructureInOutBuffer <ObjectAllTypesInformation>()) { Dictionary <string, NtType> ret = new Dictionary <string, NtType>(StringComparer.OrdinalIgnoreCase); NtStatus status = NtSystemCalls.NtQueryObject(SafeKernelObjectHandle.Null, ObjectInformationClass.ObjectTypesInformation, type_info, type_info.Length, out int return_length); if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { status.ToNtException(); } return(return_length); } }
/// <summary> /// Read memory from a process. /// </summary> /// <param name="process">The process to read from.</param> /// <param name="base_address">The base address in the process.</param> /// <param name="length">The length to read.</param> /// <returns>The array of bytes read from the location. /// If a read is short then returns fewer bytes than requested.</returns> /// <exception cref="NtException">Thrown on error.</exception> public static byte[] ReadMemory(SafeKernelObjectHandle process, long base_address, int length) { using (SafeHGlobalBuffer buffer = new SafeHGlobalBuffer(length)) { int return_length; NtStatus status = NtSystemCalls.NtReadVirtualMemory(process, new IntPtr(base_address), buffer, buffer.Length, out return_length); if (status != NtStatus.STATUS_PARTIAL_COPY) { status.ToNtException(); } return(buffer.ReadBytes(return_length)); } }
private static void AllocateSafeBuffer(SafeHGlobalBuffer buffer, SystemInformationClass info_class) { NtStatus status = 0; int return_length = 0; while ((status = NtSystemCalls.NtQuerySystemInformation(info_class, buffer, buffer.Length, out return_length)) == NtStatus.STATUS_INFO_LENGTH_MISMATCH) { int length = buffer.Length * 2; buffer.Resize(length); } status.ToNtException(); }
/// <summary> /// Get process image file path /// </summary> /// <param name="native">True to return the native image path, false for a Win32 style path</param> /// <returns>The process image file path</returns> public string GetImageFilePath(bool native) { ProcessInfoClass info_class = native ? ProcessInfoClass.ProcessImageFileName : ProcessInfoClass.ProcessImageFileNameWin32; int return_length = 0; NtStatus status = NtSystemCalls.NtQueryInformationProcess(Handle, info_class, SafeHGlobalBuffer.Null, 0, out return_length); if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { status.ToNtException(); } using (SafeStructureInOutBuffer <UnicodeStringOut> buf = new SafeStructureInOutBuffer <UnicodeStringOut>(return_length, false)) { NtSystemCalls.NtQueryInformationProcess(Handle, info_class, buf, buf.Length, out return_length).ToNtException(); return(buf.Result.ToString()); } }
private static Dictionary <string, NtType> LoadTypes() { var type_factories = NtTypeFactory.GetAssemblyNtTypeFactories(Assembly.GetExecutingAssembly()); SafeStructureInOutBuffer <ObjectAllTypesInformation> type_info = new SafeStructureInOutBuffer <ObjectAllTypesInformation>(); try { Dictionary <string, NtType> ret = new Dictionary <string, NtType>(StringComparer.OrdinalIgnoreCase); int return_length; NtStatus status = NtSystemCalls.NtQueryObject(SafeKernelObjectHandle.Null, ObjectInformationClass.ObjectAllInformation, type_info.DangerousGetHandle(), type_info.Length, out return_length); if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { status.ToNtException(); } type_info.Close(); type_info = null; type_info = new SafeStructureInOutBuffer <ObjectAllTypesInformation>(return_length, false); int alignment = IntPtr.Size - 1; NtSystemCalls.NtQueryObject(SafeKernelObjectHandle.Null, ObjectInformationClass.ObjectAllInformation, type_info.DangerousGetHandle(), type_info.Length, out return_length).ToNtException(); ObjectAllTypesInformation result = type_info.Result; IntPtr curr_typeinfo = type_info.DangerousGetHandle() + IntPtr.Size; for (int count = 0; count < result.NumberOfTypes; ++count) { ObjectTypeInformation info = (ObjectTypeInformation)Marshal.PtrToStructure(curr_typeinfo, typeof(ObjectTypeInformation)); string name = info.Name.ToString(); NtTypeFactory factory = type_factories.ContainsKey(name) ? type_factories[name] : _generic_factory; NtType ti = new NtType(count + 2, info, factory); ret[ti.Name] = ti; int offset = (info.Name.MaximumLength + alignment) & ~alignment; curr_typeinfo = info.Name.Buffer + offset; } return(ret); } finally { if (type_info != null) { type_info.Close(); } } }
private void SetNamedSecurityInfo() { bool do_callback = ShowProgress || PassThru; if (do_callback || Action != TreeSecInfo.Set) { TreeProgressFunction fn = ProgressFunction; NtStatus status = Win32Security.SetSecurityInfo(Name, Type, SecurityInformation, SecurityDescriptor, Action, do_callback ? fn : null, ShowProgress ? ProgressInvokeSetting.PrePostError : ProgressInvokeSetting.EveryObject, !PassThru); if (!PassThru) { status.ToNtException(); } } else { Win32Security.SetSecurityInfo(Name, Type, SecurityInformation, SecurityDescriptor); } }
/// <summary> /// Get a list of handles /// </summary> /// <param name="pid">A process ID to filter on. If -1 will get all handles</param> /// <param name="allow_query">True to allow the handles returned to query for certain properties</param> /// <returns>The list of handles</returns> public static IEnumerable <NtHandle> GetHandles(int pid, bool allow_query) { SafeHGlobalBuffer handleInfo = new SafeHGlobalBuffer(0x10000); try { NtStatus status = 0; int return_length = 0; while ((status = NtSystemCalls.NtQuerySystemInformation(SystemInformationClass.SystemHandleInformation, handleInfo.DangerousGetHandle(), handleInfo.Length, out return_length)) == NtStatus.STATUS_INFO_LENGTH_MISMATCH) { int length = handleInfo.Length * 2; handleInfo.Close(); handleInfo = new SafeHGlobalBuffer(length); } status.ToNtException(); IntPtr handleInfoBuf = handleInfo.DangerousGetHandle(); int handle_count = Marshal.ReadInt32(handleInfoBuf); List <NtHandle> ret = new List <NtHandle>(); handleInfoBuf += IntPtr.Size; for (int i = 0; i < handle_count; ++i) { SystemHandleTableInfoEntry entry = (SystemHandleTableInfoEntry)Marshal.PtrToStructure(handleInfoBuf, typeof(SystemHandleTableInfoEntry)); if (pid == -1 || entry.UniqueProcessId == pid) { ret.Add(new NtHandle(entry, allow_query)); } handleInfoBuf += Marshal.SizeOf(typeof(SystemHandleTableInfoEntry)); } return(ret); } finally { handleInfo.Close(); } }
private SafeHGlobalBuffer CreateRelativeSecurityDescriptor() { using (var sd_buffer = CreateAbsoluteSecurityDescriptor()) { int total_length = 0; NtStatus status = NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, new SafeHGlobalBuffer(IntPtr.Zero, 0, false), ref total_length); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { status.ToNtException(); } var relative_sd = new SafeHGlobalBuffer(total_length); try { NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, relative_sd, ref total_length).ToNtException(); return(Interlocked.Exchange(ref relative_sd, null)); } finally { relative_sd?.Close(); } } }
private SafeStructureInOutBuffer <T> QueryKey <T>(KeyInformationClass info_class) where T : new() { int return_length; NtStatus status = NtSystemCalls.NtQueryKey(Handle, info_class, SafeHGlobalBuffer.Null, 0, out return_length); if (status != NtStatus.STATUS_BUFFER_OVERFLOW && status != NtStatus.STATUS_INFO_LENGTH_MISMATCH && status != NtStatus.STATUS_BUFFER_TOO_SMALL) { status.ToNtException(); } SafeStructureInOutBuffer <T> buffer = new SafeStructureInOutBuffer <T>(return_length, false); try { NtSystemCalls.NtQueryKey(Handle, info_class, buffer, buffer.Length, out return_length).ToNtException(); return(Interlocked.Exchange(ref buffer, null)); } finally { if (buffer != null) { buffer.Close(); } } }
/// <summary> /// Start the new process /// </summary> /// <param name="image_path">The image path to the file to execute</param> /// <returns>The result of the process creation</returns> public CreateUserProcessResult Start(string image_path) { if (image_path == null) { throw new System.ArgumentNullException("image_path"); } IntPtr process_params = CreateProcessParameters(ImagePath ?? image_path, DllPath, CurrentDirectory, CommandLine, Environment, WindowTitle, DesktopInfo, ShellInfo, RuntimeData, 1); List <ProcessAttribute> attrs = new List <ProcessAttribute>(); try { ProcessCreateInfo create_info = new ProcessCreateInfo(); SafeKernelObjectHandle process_handle; SafeKernelObjectHandle thread_handle; attrs.Add(ProcessAttribute.ImageName(image_path)); SafeStructureInOutBuffer <SectionImageInformation> image_info = new SafeStructureInOutBuffer <SectionImageInformation>(); attrs.Add(ProcessAttribute.ImageInfo(image_info)); SafeStructureInOutBuffer <ClientId> client_id = new SafeStructureInOutBuffer <ClientId>(); attrs.Add(ProcessAttribute.ClientId(client_id)); attrs.AddRange(AdditionalAttributes); if (ParentProcess != null) { attrs.Add(ProcessAttribute.ParentProcess(ParentProcess.Handle)); } if (RestrictChildProcess || OverrideRestrictChildProcess) { attrs.Add(ProcessAttribute.ChildProcess(RestrictChildProcess, OverrideRestrictChildProcess)); } ProcessAttributeList attr_list = new ProcessAttributeList(attrs); create_info.Data.InitFlags = InitFlags | ProcessCreateInitFlag.WriteOutputOnExit; create_info.Data.ProhibitedImageCharacteristics = ProhibitedImageCharacteristics; create_info.Data.AdditionalFileAccess = AdditionalFileAccess; NtStatus status = NtSystemCalls.NtCreateUserProcess( out process_handle, out thread_handle, ProcessAccessRights.MaximumAllowed, ThreadAccessRights.MaximumAllowed, null, null, ProcessFlags, ThreadFlags, process_params, create_info, attr_list); if (!status.IsSuccess() && !ReturnOnError) { // Close handles which come from errors switch (create_info.State) { case ProcessCreateState.FailOnSectionCreate: NtSystemCalls.NtClose(create_info.Data.FileHandle); break; case ProcessCreateState.FailExeName: NtSystemCalls.NtClose(create_info.Data.IFEOKey); break; } status.ToNtException(); } if (create_info.State == ProcessCreateState.Success) { return(new CreateUserProcessResult(process_handle, thread_handle, create_info.Data, image_info.Result, client_id.Result, TerminateOnDispose)); } else { return(new CreateUserProcessResult(status, create_info.Data, create_info.State)); } } finally { NtRtl.RtlDestroyProcessParameters(process_params); foreach (ProcessAttribute attr in attrs) { attr.Dispose(); } } }
/// <summary> /// Start the new process /// </summary> /// <param name="image_path">The image path to the file to execute</param> /// <returns>The result of the process creation</returns> public CreateUserProcessResult Start(string image_path) { if (image_path == null) { throw new ArgumentNullException("image_path"); } using (var process_params = SafeProcessParametersBuffer.Create(ConfigImagePath ?? image_path, DllPath, CurrentDirectory, CommandLine, Environment, WindowTitle, DesktopInfo, ShellInfo, RuntimeData, CreateProcessParametersFlags.Normalize)) { using (var attrs = new DisposableList <ProcessAttribute>()) { ProcessCreateInfo create_info = new ProcessCreateInfo(); attrs.Add(ProcessAttribute.ImageName(image_path)); SafeStructureInOutBuffer <SectionImageInformation> image_info = new SafeStructureInOutBuffer <SectionImageInformation>(); attrs.Add(ProcessAttribute.ImageInfo(image_info)); SafeStructureInOutBuffer <ClientId> client_id = new SafeStructureInOutBuffer <ClientId>(); attrs.Add(ProcessAttribute.ClientId(client_id)); attrs.AddRange(AdditionalAttributes); if (ParentProcess != null) { attrs.Add(ProcessAttribute.ParentProcess(ParentProcess.Handle)); } if (RestrictChildProcess || OverrideRestrictChildProcess) { attrs.Add(ProcessAttribute.ChildProcess(RestrictChildProcess, OverrideRestrictChildProcess)); } if (Token != null) { attrs.Add(ProcessAttribute.Token(Token.Handle)); } using (ProcessAttributeList attr_list = ProcessAttributeList.Create(attrs)) { create_info.Data.InitFlags = InitFlags | ProcessCreateInitFlag.WriteOutputOnExit; create_info.Data.ProhibitedImageCharacteristics = ProhibitedImageCharacteristics; create_info.Data.AdditionalFileAccess = AdditionalFileAccess; using (ObjectAttributes proc_attr = new ObjectAttributes(null, AttributeFlags.None, SafeKernelObjectHandle.Null, null, ProcessSecurityDescriptor), thread_attr = new ObjectAttributes(null, AttributeFlags.None, SafeKernelObjectHandle.Null, null, ThreadSecurityDescriptor)) { NtStatus status = NtSystemCalls.NtCreateUserProcess( out SafeKernelObjectHandle process_handle, out SafeKernelObjectHandle thread_handle, ProcessDesiredAccess, ThreadDesiredAccess, proc_attr, thread_attr, ProcessFlags, ThreadFlags, process_params.DangerousGetHandle(), create_info, attr_list); if (!status.IsSuccess() && !ReturnOnError) { // Close handles which come from errors switch (create_info.State) { case ProcessCreateState.FailOnSectionCreate: NtSystemCalls.NtClose(create_info.Data.FileHandle); break; case ProcessCreateState.FailExeName: NtSystemCalls.NtClose(create_info.Data.IFEOKey); break; } status.ToNtException(); } if (create_info.State == ProcessCreateState.Success) { return(new CreateUserProcessResult(process_handle, thread_handle, create_info.Data, image_info.Result, client_id.Result, TerminateOnDispose)); } else { return(new CreateUserProcessResult(status, create_info.Data, create_info.State)); } } } } } }
/// <summary> /// Convert an NtStatus to an exception if the status is an error /// </summary> /// <param name="status">The NtStatus</param> /// <returns>The original NtStatus if not an error</returns> /// <exception cref="NtException">Thrown if status is an error.</exception> public static NtStatus ToNtException(this NtStatus status) { return(status.ToNtException(true)); }
/// <summary> /// Convert security descriptor to a byte array /// </summary> /// <returns>The binary security descriptor</returns> public byte[] ToByteArray() { SafeStructureInOutBuffer <SecurityDescriptorStructure> sd_buffer = null; SafeHGlobalBuffer dacl_buffer = null; SafeHGlobalBuffer sacl_buffer = null; SafeSidBufferHandle owner_buffer = null; SafeSidBufferHandle group_buffer = null; try { sd_buffer = new SafeStructureInOutBuffer <SecurityDescriptorStructure>(); NtRtl.RtlCreateSecurityDescriptor(sd_buffer, Revision).ToNtException(); SecurityDescriptorControl control = Control & SecurityDescriptorControl.ValidControlSetMask; NtRtl.RtlSetControlSecurityDescriptor(sd_buffer, control, control).ToNtException(); if (Dacl != null) { if (!Dacl.NullAcl) { dacl_buffer = new SafeHGlobalBuffer(Dacl.ToByteArray()); } else { dacl_buffer = new SafeHGlobalBuffer(IntPtr.Zero, 0, false); } NtRtl.RtlSetDaclSecurityDescriptor(sd_buffer, true, dacl_buffer.DangerousGetHandle(), Dacl.Defaulted).ToNtException(); } if (Sacl != null) { if (!Sacl.NullAcl) { sacl_buffer = new SafeHGlobalBuffer(Sacl.ToByteArray()); } else { sacl_buffer = new SafeHGlobalBuffer(IntPtr.Zero, 0, false); } NtRtl.RtlSetSaclSecurityDescriptor(sd_buffer, true, sacl_buffer.DangerousGetHandle(), Sacl.Defaulted).ToNtException(); } if (Owner != null) { owner_buffer = Owner.Sid.ToSafeBuffer(); NtRtl.RtlSetOwnerSecurityDescriptor(sd_buffer, owner_buffer.DangerousGetHandle(), Owner.Defaulted); } if (Group != null) { group_buffer = Group.Sid.ToSafeBuffer(); NtRtl.RtlSetGroupSecurityDescriptor(sd_buffer, group_buffer.DangerousGetHandle(), Group.Defaulted); } int total_length = 0; NtStatus status = NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, new SafeHGlobalBuffer(IntPtr.Zero, 0, false), ref total_length); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { status.ToNtException(); } using (SafeHGlobalBuffer relative_sd = new SafeHGlobalBuffer(total_length)) { NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, relative_sd, ref total_length).ToNtException(); return(relative_sd.ToArray()); } } finally { sd_buffer?.Close(); dacl_buffer?.Close(); sacl_buffer?.Close(); owner_buffer?.Close(); group_buffer?.Close(); } }