/// <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()); } }
/// <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> /// 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> /// Enumerate all atoms. /// </summary> /// <returns>An enumeration of all atoms on the system.</returns> public static IEnumerable <NtAtom> GetAtoms() { int size = 1024; while (size < 5 * 1024 * 1024) { using (SafeStructureInOutBuffer <AtomTableInformation> buffer = new SafeStructureInOutBuffer <AtomTableInformation>(size, true)) { int return_length; NtStatus status = NtSystemCalls.NtQueryInformationAtom(0, AtomInformationClass.AtomTableInformation, buffer, buffer.Length, out return_length); if (status.IsSuccess()) { AtomTableInformation table = buffer.Result; IntPtr data = buffer.Data.DangerousGetHandle(); for (int i = 0; i < table.NumberOfAtoms; ++i) { ushort atom = (ushort)Marshal.ReadInt16(data); yield return(new NtAtom(atom)); data += 2; } } else if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { throw new NtException(status); } size *= 2; } } }
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); }
/// <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); } }
/// <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()); } } }
private static IEnumerable <NtAtom> GetGlobalAtoms() { int size = 1024; while (size < 5 * 1024 * 1024) { using (var buffer = new SafeStructureInOutBuffer <AtomTableInformation>(size, true)) { NtStatus status = NtSystemCalls.NtQueryInformationAtom(0, AtomInformationClass.AtomTableInformation, buffer, buffer.Length, out int return_length); if (status.IsSuccess()) { AtomTableInformation table = buffer.Result; IntPtr data = buffer.Data.DangerousGetHandle(); ushort[] atoms = new ushort[table.NumberOfAtoms]; buffer.Data.ReadArray(0, atoms, 0, atoms.Length); return(atoms.Select(a => new NtAtom(a, true)).ToArray()); } else if (status != NtStatus.STATUS_INFO_LENGTH_MISMATCH) { throw new NtException(status); } size *= 2; } } return(new NtAtom[0]); }
private NtStatus ParseSecurityDescriptor(SafeBuffer buffer) { if (!NtRtl.RtlValidSecurityDescriptor(buffer)) { return(NtStatus.STATUS_INVALID_SECURITY_DESCR); } Owner = QuerySid(buffer, NtRtl.RtlGetOwnerSecurityDescriptor); Group = QuerySid(buffer, NtRtl.RtlGetGroupSecurityDescriptor); Dacl = QueryAcl(buffer, NtRtl.RtlGetDaclSecurityDescriptor); Sacl = QueryAcl(buffer, NtRtl.RtlGetSaclSecurityDescriptor); NtStatus status = NtRtl.RtlGetControlSecurityDescriptor(buffer, out SecurityDescriptorControl control, out uint revision); if (!status.IsSuccess()) { return(status); } if (NtRtl.RtlGetSecurityDescriptorRMControl(buffer, out byte rm_control)) { RmControl = rm_control; } Control = control; Revision = revision; return(NtStatus.STATUS_SUCCESS); }
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); }
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> /// Convert an NtStatus to an exception if the status is an error and throw_on_error is true. /// </summary> /// <param name="status">The NtStatus</param> /// <param name="throw_on_error">True to throw an exception onerror.</param> /// <returns>The original NtStatus if not thrown</returns> /// <exception cref="NtException">Thrown if status is an error and throw_on_error is true.</exception> public static NtStatus ToNtException(this NtStatus status, bool throw_on_error) { if (throw_on_error && !status.IsSuccess()) { throw new NtException(status); } return(status); }
/// <summary> /// Sleep the current thread /// </summary> /// <param name="alertable">Set if the thread should be alertable</param> /// <param name="delay">The delay, negative values indicate relative times.</param> /// <returns>True if the thread was alerted before the delay expired.</returns> public static bool Sleep(bool alertable, long delay) { NtStatus status = NtSystemCalls.NtDelayExecution(alertable, new LargeInteger(delay)); if (!status.IsSuccess()) { throw new NtException(status); } return status == NtStatus.STATUS_ALERTED; }
/// <summary> /// Initialize a Silo, /// </summary> /// <param name="root_dir_flags">Flags for root directory.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The NT status code.</returns> public NtStatus InitializeSilo(SiloObjectRootDirectoryControlFlags root_dir_flags, bool throw_on_error) { NtStatus status = SetLimitFlags(JobObjectLimitFlags.Application, throw_on_error); if (!status.IsSuccess()) { return(status); } status = CreateSilo(throw_on_error); if (!status.IsSuccess()) { return(status); } status = AssignProcessPseudoHandle(throw_on_error); if (!status.IsSuccess()) { return(status); } return(SetSiloObjectRootDirectory(root_dir_flags, throw_on_error)); }
/// <summary> /// Create an NT result object. If status is successful then call function otherwise use default value. /// </summary> /// <typeparam name="T">The result type.</typeparam> /// <param name="status">The associated status case.</param> /// <param name="throw_on_error">Throw an exception on error.</param> /// <param name="create_func">Function to call to create an instance of the result</param> /// <returns>The created result.</returns> internal static NtResult <T> CreateResult <T>(this NtStatus status, bool throw_on_error, Func <NtStatus, T> create_func) { if (status.IsSuccess()) { return(new NtResult <T>(status, create_func(status))); } if (throw_on_error) { throw new NtException(status); } return(new NtResult <T>(status, default(T))); }
internal NtStatus CompleteCall(NtStatus status) { if (status == NtStatus.STATUS_PENDING) { if (WaitForComplete()) { status = _io_status.Result.Status; } } else if (status.IsSuccess()) { _result = _io_status.Result; } return(status); }
/// <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 the source of inherited ACEs. /// </summary> /// <param name="name">The name of the resource.</param> /// <param name="type">The type of the resource.</param> /// <param name="container">Whether the resource is a container.</param> /// <param name="object_types">Optional list of object types.</param> /// <param name="security_descriptor">The security descriptor for the resource.</param> /// <param name="sacl">True to check the SACL otherwise checks the DACL.</param> /// <param name="generic_mapping">Generic mapping for the resource.</param> /// <param name="query_security">Query security descriptors for sources.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The list of inheritance sources.</returns> public static NtResult <IEnumerable <SecurityDescriptorInheritanceSource> > GetInheritanceSource( string name, SeObjectType type, bool container, Guid[] object_types, SecurityDescriptor security_descriptor, bool sacl, GenericMapping generic_mapping, bool query_security, bool throw_on_error) { Acl acl = sacl ? security_descriptor.Sacl : security_descriptor.Dacl; if (acl == null || acl.NullAcl) { return(NtStatus.STATUS_INVALID_ACL.CreateResultFromError <IEnumerable <SecurityDescriptorInheritanceSource> >(throw_on_error)); } using (var list = new DisposableList()) { SafeGuidArrayBuffer guids = SafeGuidArrayBuffer.Null; if (object_types?.Length > 0) { guids = list.AddResource(new SafeGuidArrayBuffer(object_types)); } NtType native_type = GetNativeType(type); INHERITED_FROM[] inherited_from = new INHERITED_FROM[acl.Count]; NtStatus status = NtStatus.STATUS_INVALID_PARAMETER; try { status = Win32NativeMethods.GetInheritanceSource(name, type, sacl ? SecurityInformation.Sacl : SecurityInformation.Dacl, container, guids, guids.Count, acl.ToByteArray(), IntPtr.Zero, ref generic_mapping, inherited_from).MapDosErrorToStatus(); return(status.CreateResult(throw_on_error, () => (IEnumerable <SecurityDescriptorInheritanceSource>)inherited_from .Select((s, i) => new SecurityDescriptorInheritanceSource(acl[i], s, type, native_type, container, query_security, sacl)).Where(s => s.Depth != -1).ToArray())); } finally { if (status.IsSuccess()) { Win32NativeMethods.FreeInheritedFromArray(inherited_from, (ushort)inherited_from.Length, IntPtr.Zero); } } } }
private static NtStatus Decompress(RtlCompressionFormat format, byte[] compressed_buffer, byte[] uncompressed_buffer, out int final_size) { if (format == RtlCompressionFormat.XPRESS_HUFF) { NtStatus status = NtRtl.RtlGetCompressionWorkSpaceSize(format, out int compress_size, out int fragment_size); if (!status.IsSuccess()) { final_size = 0; return(status); } byte[] workspace = new byte[compress_size]; return(NtRtl.RtlDecompressBufferEx(format, uncompressed_buffer, uncompressed_buffer.Length, compressed_buffer, compressed_buffer.Length, out final_size, workspace)); } return(NtRtl.RtlDecompressBuffer(format, uncompressed_buffer, uncompressed_buffer.Length, compressed_buffer, compressed_buffer.Length, out final_size)); }
/// <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()); } }
internal async Task <NtStatus> CompleteCallAsync(NtStatus status, CancellationToken token) { try { if (status == NtStatus.STATUS_PENDING) { if (await WaitForCompleteAsync(token)) { return(_result.Status); } } else if (status.IsSuccess()) { _result = _io_status.Result; } return(status); } catch (TaskCanceledException) { // Cancel and then rethrow. Cancel(); throw; } }
/// <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; } }
/// <summary> /// Enable a provider. /// </summary> /// <param name="provider_id">The GUID of the provider.</param> /// <param name="level">The level for the events.</param> /// <param name="match_any_keyword">Any keywords to match.</param> /// <param name="match_all_keyword">All keywords to match.</param> /// <param name="timeout">The timeout.</param> /// <param name="descriptors">List of optional descriptors.</param> /// <param name="throw_on_error">True to throw on error.</param> /// <returns>The resulting status code.</returns> public NtStatus EnableProvider(Guid provider_id, EventTraceLevel level, ulong match_any_keyword, ulong match_all_keyword, int timeout, IEnumerable <EventFilterDescriptor> descriptors, bool throw_on_error) { var ds = descriptors.Select(d => new EVENT_FILTER_DESCRIPTOR() { Ptr = d.Ptr.ToInt64(), Size = d.Size, Type = d.Type }).ToArray(); using (var buffer = ds.ToBuffer()) { ENABLE_TRACE_PARAMETERS enable_trace = new ENABLE_TRACE_PARAMETERS { Version = 2, SourceId = SessionGuid, EnableFilterDesc = buffer.DangerousGetHandle(), FilterDescCount = ds.Length }; NtStatus status = Win32NativeMethods.EnableTraceEx2( _handle, ref provider_id, EventControlCode.EnableProvider, level, match_any_keyword, match_all_keyword, timeout, enable_trace ).MapDosErrorToStatus().ToNtException(throw_on_error); if (status.IsSuccess()) { _providers.Add(new EnabledProvider() { ProviderId = provider_id, Level = level }); } return(status); } }
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); } })); } }
/// <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)); } } } } } }
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()); }