/// <summary> /// Create and initialize a Server Silo, /// </summary> /// <param name="root_dir_flags">Flags for root directory.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <param name="system_root">Path to the system root.</param> /// <param name="delete_event">Event to signal when silo deleted.</param> /// <param name="downlevel_container">True if a downlevel container.</param> /// <returns>The Job object.</returns> public static NtResult <NtJob> CreateServerSilo(SiloObjectRootDirectoryControlFlags root_dir_flags, string system_root, NtEvent delete_event, bool downlevel_container, bool throw_on_error) { using (var job = CreateSilo(root_dir_flags, throw_on_error)) { if (!job.IsSuccess) { return(job); } NtStatus status = job.Result.SetSiloSystemRoot(system_root, throw_on_error); if (!status.IsSuccess()) { return(status.CreateResultFromError <NtJob>(throw_on_error)); } var silo_dir = job.Result.QuerySiloRootDirectory(throw_on_error); if (!silo_dir.IsSuccess) { return(silo_dir.Cast <NtJob>()); } string device_path = $@"{silo_dir.Result}\Device"; using (var device_dir = NtDirectory.Open(@"\Device", null, DirectoryAccessRights.MaximumAllowed, throw_on_error)) { if (!device_dir.IsSuccess) { return(device_dir.Cast <NtJob>()); } using (var obja = new ObjectAttributes(device_path, AttributeFlags.CaseInsensitive | AttributeFlags.Permanent | AttributeFlags.OpenIf)) { using (var dir = NtDirectory.Create(obja, DirectoryAccessRights.MaximumAllowed, device_dir.Result, throw_on_error)) { if (!dir.IsSuccess) { return(dir.Cast <NtJob>()); } } } } status = job.Result.InitializeServerSilo(delete_event, downlevel_container, throw_on_error); if (!status.IsSuccess()) { return(status.CreateResultFromError <NtJob>(throw_on_error)); } return(job.Result.Duplicate().CreateResult()); } }
private static NtResult <SafeStructureInOutBuffer <T> > QueryObject <T>(SafeKernelObjectHandle handle, ObjectInformationClass object_info, bool throw_on_error) where T : new() { SafeStructureInOutBuffer <T> ret = null; NtStatus status = NtStatus.STATUS_BUFFER_TOO_SMALL; try { status = NtSystemCalls.NtQueryObject(handle, object_info, SafeHGlobalBuffer.Null, 0, out int return_length); if ((status != NtStatus.STATUS_BUFFER_TOO_SMALL) && (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH)) { return(status.CreateResultFromError <SafeStructureInOutBuffer <T> >(throw_on_error)); } if (return_length == 0) { ret = new SafeStructureInOutBuffer <T>(); } else { ret = new SafeStructureInOutBuffer <T>(return_length, false); } status = NtSystemCalls.NtQueryObject(handle, object_info, ret, ret.Length, out return_length); return(status.CreateResult(throw_on_error, () => ret)); } finally { if (ret != null && !status.IsSuccess()) { ret.Close(); ret = null; } } }
/// <summary> /// Query the image path from a process ID. /// </summary> /// <param name="pid">The ID of the process.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The image path.</returns> /// <remarks>This method can be called without any permissions on the process.</remarks> public static NtResult <string> GetProcessIdImagePath(int pid, bool throw_on_error) { var info = new SystemProcessIdInformation() { ProcessId = new IntPtr(pid) }; using (var buffer = info.ToBuffer()) { NtStatus status = _system_info_object.QueryInformation( SystemInformationClass.SystemProcessIdInformation, buffer, out int length); if (status.IsSuccess()) { return(new NtResult <string>(NtStatus.STATUS_SUCCESS, string.Empty)); } if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { return(status.CreateResultFromError <string>(throw_on_error)); } using (var str = new UnicodeStringAllocated(buffer.Result.ImageName.MaximumLength)) { info = new SystemProcessIdInformation() { ProcessId = new IntPtr(pid), ImageName = str.String }; return(Query(SystemInformationClass.SystemProcessIdInformation, info, throw_on_error).Map(r => r.ImageName.ToString())); } } }
/// <summary> /// Query memory information for a process. /// </summary> /// <param name="process">The process to query.</param> /// <param name="base_address">The base address.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The memory information for the region.</returns> /// <exception cref="NtException">Thrown on error.</exception> public static NtResult <MemoryInformation> QueryMemoryInformation(SafeKernelObjectHandle process, long base_address, bool throw_on_error) { MemoryBasicInformation basic_info = new MemoryBasicInformation(); string mapped_image_path = string.Empty; using (var buffer = new SafeStructureInOutBuffer <MemoryBasicInformation>()) { NtStatus status = NtSystemCalls.NtQueryVirtualMemory(process, new IntPtr(base_address), MemoryInformationClass.MemoryBasicInformation, buffer, buffer.LengthIntPtr, out IntPtr ret_length); if (!status.IsSuccess()) { return(status.CreateResultFromError <MemoryInformation>(throw_on_error)); } basic_info = buffer.Result; } if (basic_info.Type == MemoryType.Image || basic_info.Type == MemoryType.Mapped) { var name = QuerySectionName(process, base_address, false); if (name.IsSuccess) { mapped_image_path = name.Result; } } return(new MemoryInformation(basic_info, mapped_image_path).CreateResult()); }
/// <summary> /// Retried LSA privilege data. /// </summary> /// <param name="system_name">The system containing the LSA instance.</param> /// <param name="keyname">The name of the key.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The private data as bytes.</returns> public static NtResult <byte[]> LsaRetrievePrivateData(string system_name, string keyname, bool throw_on_error) { if (keyname is null) { throw new ArgumentNullException(nameof(keyname)); } using (var policy = SafeLsaHandle.OpenPolicy(system_name, Policy.LsaPolicyAccessRights.GetPrivateInformation, throw_on_error)) { if (!policy.IsSuccess) { return(policy.Cast <byte[]>()); } NtStatus status = SecurityNativeMethods.LsaRetrievePrivateData(policy.Result, new UnicodeString(keyname), out SafeLsaMemoryBuffer data); if (!status.IsSuccess()) { return(status.CreateResultFromError <byte[]>(throw_on_error)); } using (data) { data.Initialize <UnicodeStringOut>(1); return(data.Read <UnicodeStringOut>(0).ToArray().CreateResult()); } } }
/// <summary> /// Convert a DOS filename to an NT filename and get as an ObjectAttributes structure /// </summary> /// <param name="filename">The DOS filename.</param> /// <param name="attributes">The object attribute flags.</param> /// <param name="sqos">An optional security quality of service.</param> /// <param name="security_descriptor">An optional security descriptor.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The object attributes</returns> public static NtResult <ObjectAttributes> DosFileNameToObjectAttributes(string filename, AttributeFlags attributes, SecurityQualityOfService sqos, SecurityDescriptor security_descriptor, bool throw_on_error) { if (filename == null) { throw new ArgumentNullException("filename"); } UnicodeStringOut nt_name = new UnicodeStringOut(); RtlRelativeName relative_name = new RtlRelativeName(); try { NtStatus status = NtRtl.RtlDosPathNameToRelativeNtPathName_U_WithStatus(filename, out nt_name, out IntPtr short_path, relative_name); if (!status.IsSuccess()) { return(status.CreateResultFromError <ObjectAttributes>(throw_on_error)); } string final_name; SafeKernelObjectHandle root = SafeKernelObjectHandle.Null; if (relative_name.RelativeName.Buffer != IntPtr.Zero) { final_name = relative_name.RelativeName.ToString(); root = new SafeKernelObjectHandle(relative_name.ContainingDirectory, false); } else { final_name = nt_name.ToString(); } return(status.CreateResult(false, () => new ObjectAttributes(final_name, attributes, root, sqos, security_descriptor))); } finally { if (nt_name.Buffer != IntPtr.Zero) { NtRtl.RtlFreeUnicodeString(ref nt_name); } if (relative_name.RelativeName.Buffer != IntPtr.Zero) { NtRtl.RtlReleaseRelativeName(relative_name); } } }
/// <summary> /// Get a notification synchronously. /// </summary> /// <param name="timeout">Optional timeout for getting the notification.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The transaction notification.</returns> public NtResult <TransactionNotification> GetNotification(NtWaitTimeout timeout, bool throw_on_error) { NtStatus status = NtSystemCalls.NtGetNotificationResourceManager(Handle, SafeHGlobalBuffer.Null, 0, timeout.ToLargeInteger(), out int return_length, 0, IntPtr.Zero); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { return(status.CreateResultFromError <TransactionNotification>(throw_on_error)); } using (var buffer = new SafeStructureInOutBuffer <TransactionNotificationData>(return_length, false)) { return(NtSystemCalls.NtGetNotificationResourceManager(Handle, buffer, buffer.Length, timeout.ToLargeInteger(), out return_length, 0, IntPtr.Zero) .CreateResult(throw_on_error, () => new TransactionNotification(buffer))); } }
/// <summary> /// Query a single system environment value. /// </summary> /// <param name="name">The name of the value.</param> /// <param name="vendor_guid">The associated vendor guid</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The system environment value.</returns> public static NtResult <SystemEnvironmentValue> QuerySystemEnvironmentValue(string name, Guid vendor_guid, bool throw_on_error) { UnicodeString name_string = new UnicodeString(name); int value_length = 0; NtStatus status = NtSystemCalls.NtQuerySystemEnvironmentValueEx(name_string, ref vendor_guid, null, ref value_length, 0); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { return(status.CreateResultFromError <SystemEnvironmentValue>(throw_on_error)); } byte[] value = new byte[value_length]; OptionalInt32 attributes = new OptionalInt32(); return(NtSystemCalls.NtQuerySystemEnvironmentValueEx(name_string, ref vendor_guid, value, ref value_length, attributes) .CreateResult(throw_on_error, () => new SystemEnvironmentValue(name, value, attributes, vendor_guid))); }
/// <summary> /// Query a license value. While technically not directly a registry key /// it has many of the same properties such as using the same registry /// value types. /// </summary> /// <param name="name">The name of the license value.</param> /// <param name="throw_on_error">True to throw an exception on error</param> /// <returns>The license value key</returns> public static NtResult <NtKeyValue> QueryLicenseValue(string name, bool throw_on_error) { RegistryValueType type; int ret_length; UnicodeString name_string = new UnicodeString(name); NtStatus status = NtSystemCalls.NtQueryLicenseValue(name_string, out type, SafeHGlobalBuffer.Null, 0, out ret_length); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { return(status.CreateResultFromError <NtKeyValue>(throw_on_error)); } using (var buffer = new SafeHGlobalBuffer(ret_length)) { return(NtSystemCalls.NtQueryLicenseValue(name_string, out type, buffer, buffer.Length, out ret_length) .CreateResult(throw_on_error, () => new NtKeyValue(name, type, buffer.ToArray(), 0))); } }
/// <summary> /// Retrieve LSA privilege data. /// </summary> /// <param name="keyname">The name of the key.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The private data as bytes.</returns> public NtResult <byte[]> RetrievePrivateData(string keyname, bool throw_on_error) { if (keyname is null) { throw new ArgumentNullException(nameof(keyname)); } NtStatus status = SecurityNativeMethods.LsaRetrievePrivateData(Handle, new UnicodeString(keyname), out SafeLsaMemoryBuffer data); if (!status.IsSuccess()) { return(status.CreateResultFromError <byte[]>(throw_on_error)); } using (data) { return(data.GetUnicodeString().ToArray().CreateResult()); } }
/// <summary> /// Enumerate window handles. /// </summary> /// <param name="desktop">Desktop containing the Windows. Optional.</param> /// <param name="parent">The parent Window. Optional.</param> /// <param name="enum_children">True to enumerate child Windows.</param> /// <param name="hide_immersive">Hide immersive Windows.</param> /// <param name="thread_id">The thread ID that owns the Window.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The enumerated Window Handles.</returns> public static NtResult <IEnumerable <NtWindow> > GetWindows(NtDesktop desktop, NtWindow parent, bool enum_children, bool hide_immersive, int thread_id, bool throw_on_error) { int count = 64; while (true) { IntPtr[] handles = new IntPtr[count]; NtStatus status = NtSystemCalls.NtUserBuildHwndList(desktop.GetHandle(), parent.Handle, enum_children, hide_immersive, thread_id, handles.Length, handles, out int required_count); if (status.IsSuccess()) { return(handles.Take(required_count).Select(i => new NtWindow(i)).CreateResult()); } if (status != NtStatus.STATUS_BUFFER_TOO_SMALL || count > required_count) { return(status.CreateResultFromError <IEnumerable <NtWindow> >(throw_on_error)); } count = required_count; } }
private NtResult <SafeHGlobalBuffer> CreateRelativeSecurityDescriptor(bool throw_on_error) { using (var sd_buffer = CreateAbsoluteSecurityDescriptor(throw_on_error)) { if (!sd_buffer.IsSuccess) { return(sd_buffer); } int total_length = 0; NtStatus status = NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer.Result, SafeHGlobalBuffer.Null, ref total_length); if (status != NtStatus.STATUS_BUFFER_TOO_SMALL) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } using (var relative_sd = new SafeHGlobalBuffer(total_length)) { return(NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer.Result, relative_sd, ref total_length) .CreateResult(throw_on_error, () => relative_sd.Detach())); } } }
private static NtResult <NtToken> LsaLogonUser(SecurityLogonType type, string auth_package, string origin_name, SafeBuffer buffer, IEnumerable <UserGroup> local_groups, bool throw_on_error) { using (var list = new DisposableList()) { var hlsa = list.AddResource(SafeLsaLogonHandle.Connect(throw_on_error)); if (!hlsa.IsSuccess) { return(hlsa.Cast <NtToken>()); } NtStatus status = SecurityNativeMethods.LsaLookupAuthenticationPackage( hlsa.Result, new LsaString(auth_package), out uint auth_pkg); if (!status.IsSuccess()) { return(status.CreateResultFromError <NtToken>(throw_on_error)); } var groups = local_groups == null ? SafeTokenGroupsBuffer.Null : list.AddResource(SafeTokenGroupsBuffer.Create(local_groups)); TOKEN_SOURCE tokenSource = new TOKEN_SOURCE("NT.NET"); SecurityNativeMethods.AllocateLocallyUniqueId(out tokenSource.SourceIdentifier); QUOTA_LIMITS quota_limits = new QUOTA_LIMITS(); return(SecurityNativeMethods.LsaLogonUser(hlsa.Result, new LsaString(origin_name), type, auth_pkg, buffer, buffer.GetLength(), groups, tokenSource, out SafeLsaReturnBufferHandle profile, out int cbProfile, out Luid logon_id, out SafeKernelObjectHandle token_handle, quota_limits, out NtStatus subStatus).CreateResult(throw_on_error, () => { using (profile) { return NtToken.FromHandle(token_handle); } })); } }
private NtResult <SafeHGlobalBuffer> CreateAbsoluteSecurityDescriptor(bool throw_on_error) { byte[] dacl = Dacl?.ToByteArray(); byte[] sacl = Sacl?.ToByteArray(); byte[] owner = Owner?.Sid.ToArray(); byte[] group = Group?.Sid.ToArray(); int total_size = GetLength(dacl) + GetLength(sacl) + GetLength(owner) + GetLength(group); using (var sd_buffer = new SafeStructureInOutBuffer <SecurityDescriptorStructure>(total_size, true)) { NtStatus status = NtRtl.RtlCreateSecurityDescriptor(sd_buffer, Revision); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } SecurityDescriptorControl control = Control & SecurityDescriptorControl.ValidControlSetMask; status = NtRtl.RtlSetControlSecurityDescriptor(sd_buffer, control, control); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } int current_ofs = 0; if (Dacl != null) { IntPtr ptr = UpdateBuffer(sd_buffer, Dacl.NullAcl ? null : dacl, ref current_ofs); status = NtRtl.RtlSetDaclSecurityDescriptor(sd_buffer, true, ptr, Dacl.Defaulted); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } } if (Sacl != null) { IntPtr ptr = UpdateBuffer(sd_buffer, Sacl.NullAcl ? null : sacl, ref current_ofs); status = NtRtl.RtlSetSaclSecurityDescriptor(sd_buffer, true, ptr, Sacl.Defaulted); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } } if (Owner != null) { IntPtr ptr = UpdateBuffer(sd_buffer, owner, ref current_ofs); status = NtRtl.RtlSetOwnerSecurityDescriptor(sd_buffer, ptr, Owner.Defaulted); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } } if (Group != null) { IntPtr ptr = UpdateBuffer(sd_buffer, group, ref current_ofs); status = NtRtl.RtlSetGroupSecurityDescriptor(sd_buffer, ptr, Group.Defaulted); if (!status.IsSuccess()) { return(status.CreateResultFromError <SafeHGlobalBuffer>(throw_on_error)); } } return(status.CreateResult <SafeHGlobalBuffer>(throw_on_error, () => sd_buffer.Detach())); } }
/// <summary> /// Parse the policy from the Local Security Authority. /// </summary> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The list of Central Access Policies.</returns> public static NtResult <CentralAccessPolicy[]> ParseFromLsa(bool throw_on_error) { NtStatus status = SecurityNativeMethods.LsaGetAppliedCAPIDs(null, out SafeLsaMemoryBuffer capids, out int capid_count); if (!status.IsSuccess()) { return(status.CreateResultFromError <CentralAccessPolicy[]>(throw_on_error)); } List <CentralAccessPolicy> ret = new List <CentralAccessPolicy>(); using (capids) { status = SecurityNativeMethods.LsaQueryCAPs(capids.DangerousGetHandle(), capid_count, out SafeLsaMemoryBuffer caps, out uint cap_count); if (!status.IsSuccess()) { return(status.CreateResultFromError <CentralAccessPolicy[]>(throw_on_error)); } caps.Initialize <CENTRAL_ACCESS_POLICY>(cap_count); CENTRAL_ACCESS_POLICY[] policies = new CENTRAL_ACCESS_POLICY[cap_count]; caps.ReadArray(0, policies, 0, policies.Length); foreach (var policy in policies) { SafeHGlobalBuffer buffer = new SafeHGlobalBuffer(policy.CAPEs, policy.CAPECount * IntPtr.Size, false); IntPtr[] rule_entries = new IntPtr[policy.CAPECount]; buffer.ReadArray(0, rule_entries, 0, policy.CAPECount); List <CentralAccessRule> rules = new List <CentralAccessRule>(); foreach (var ptr in rule_entries) { var entry = new SafeStructureInOutBuffer <CENTRAL_ACCESS_POLICY_ENTRY>(ptr, Marshal.SizeOf(typeof(CENTRAL_ACCESS_POLICY_ENTRY)), false); var r = entry.Result; SecurityDescriptor sd = null; SecurityDescriptor staged_sd = null; string applies_to = string.Empty; if (r.LengthSD > 0) { var result = SecurityDescriptor.Parse(r.SD, throw_on_error); if (!result.IsSuccess) { return(result.Cast <CentralAccessPolicy[]>()); } sd = result.Result; } if (r.LengthStagedSD > 0) { var result = SecurityDescriptor.Parse(r.StagedSD, throw_on_error); if (!result.IsSuccess) { return(result.Cast <CentralAccessPolicy[]>()); } staged_sd = result.Result; } if (r.LengthAppliesTo > 0) { byte[] condition = new byte[r.LengthAppliesTo]; Marshal.Copy(r.AppliesTo, condition, 0, r.LengthAppliesTo); var result = NtSecurity.ConditionalAceToString(condition, throw_on_error); if (!result.IsSuccess) { return(result.Cast <CentralAccessPolicy[]>()); } applies_to = result.Result; } rules.Add(new CentralAccessRule(r.Name.ToString(), r.Description.ToString(), sd, staged_sd, applies_to, r.ChangeId.ToString(), r.Flags)); } var capid = Sid.Parse(policy.CAPID, throw_on_error); if (!capid.IsSuccess) { return(capid.Cast <CentralAccessPolicy[]>()); } ret.Add(new CentralAccessPolicy(capid.Result, policy.Flags, policy.Name.ToString(), policy.Description.ToString(), policy.ChangeId.ToString(), rules)); } } return(ret.ToArray().CreateResult()); }