Skip to content
This repository has been archived by the owner on Jul 26, 2023. It is now read-only.

Adding NtOpenSection, NtClose methods and corresponding structs #189

Closed
wants to merge 11 commits into from
121 changes: 121 additions & 0 deletions src/NTDll.Desktop/NTDll+OBJECT_ATTRIBUTES.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace PInvoke
{
using System;
using System.Runtime.InteropServices;

/// <content>
/// Contains the <see cref="OBJECT_ATTRIBUTES"/> nested struct.
/// </content>
public static partial class NTDll
{
/// <summary>
/// The OBJECT_ATTRIBUTES structure specifies attributes that can be applied to objects or object handles by routines that create objects and/or return handles to objects.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[OfferIntPtrPropertyAccessors]
public unsafe partial struct OBJECT_ATTRIBUTES
{
/// <summary>
/// The number of bytes of data contained in this structure. The <see cref="Create"/> method sets this member to <c>sizeof(OBJECT_ATTRIBUTES)</c>.
/// </summary>
public int Length;

/// <summary>
/// Optional handle to the root object directory for the path name specified by the ObjectName member.
/// If RootDirectory is NULL, <see cref="ObjectName"/> must point to a fully qualified object name that includes the full path to the target object.
/// If RootDirectory is non-NULL, <see cref="ObjectName"/> specifies an object name relative to the RootDirectory directory.
/// The RootDirectory handle can refer to a file system directory or an object directory in the object manager namespace.
/// </summary>
public IntPtr RootDirectory;

/// <summary>
/// A <see cref="UNICODE_STRING"/> that contains the name of the object for which a handle is to be opened.
/// This must either be a fully qualified object name, or a relative path name to the directory specified by the <see cref="RootDirectory"/> member.
/// </summary>
public UNICODE_STRING* ObjectName;

/// <summary>
/// Bitmask of flags that specify object handle attributes.
/// </summary>
public ObjectHandleAttributes Attributes;

/// <summary>
/// Specifies a security descriptor (SECURITY_DESCRIPTOR) for the object when the object is created. If this member is NULL, the object will receive default security settings.
/// </summary>
public Kernel32.SECURITY_DESCRIPTOR* SecurityDescriptor;

/// <summary>
/// Optional quality of service to be applied to the object when it is created. Used to indicate the security impersonation level and context tracking mode (dynamic or static). Currently, the InitializeObjectAttributes macro sets this member to <see langword="null"/>.
/// </summary>
public void* SecurityQualityOfService;

/// <summary>
/// Possible flags for the <see cref="Attributes"/> field.
/// </summary>
[Flags]
public enum ObjectHandleAttributes
{
/// <summary>
/// This handle can be inherited by child processes of the current process.
/// </summary>
OBJ_INHERIT = 0x00000002,

/// <summary>
/// This flag only applies to objects that are named within the object manager. By default, such objects are deleted when all open handles to them are closed. If this flag is specified, the object is not deleted when all open handles are closed. Drivers can use the ZwMakeTemporaryObject routine to make a permanent object non-permanent.
/// </summary>
OBJ_PERMANENT = 0x00000010,

/// <summary>
/// If this flag is set and the <see cref="OBJECT_ATTRIBUTES"/> structure is passed to a routine that creates an object, the object can be accessed exclusively. That is, once a process opens such a handle to the object, no other processes can open handles to this object.
/// If this flag is set and the <see cref="OBJECT_ATTRIBUTES"/> structure is passed to a routine that creates an object handle, the caller is requesting exclusive access to the object for the process context that the handle was created in. This request can be granted only if the OBJ_EXCLUSIVE flag was set when the object was created.
/// </summary>
OBJ_EXCLUSIVE = 0x00000020,

/// <summary>
/// If this flag is specified, a case-insensitive comparison is used when matching the name pointed to by the ObjectName member against the names of existing objects. Otherwise, object names are compared using the default system settings.
/// </summary>
OBJ_CASE_INSENSITIVE = 0x00000040,

/// <summary>
/// If this flag is specified, by using the object handle, to a routine that creates objects and if that object already exists, the routine should open that object. Otherwise, the routine creating the object returns an NTSTATUS code of STATUS_OBJECT_NAME_COLLISION.
/// </summary>
OBJ_OPENIF = 0x00000080,

/// <summary>
/// If an object handle, with this flag set, is passed to a routine that opens objects and if the object is a symbolic link object, the routine should open the symbolic link object itself, rather than the object that the symbolic link refers to (which is the default behavior).
/// </summary>
OBJ_OPENLINK = 0x00000100,

/// <summary>
/// The handle is created in system process context and can only be accessed from kernel mode.
/// </summary>
OBJ_KERNEL_HANDLE = 0x00000200,

/// <summary>
/// The routine that opens the handle should enforce all access checks for the object, even if the handle is being opened in kernel mode.
/// </summary>
OBJ_FORCE_ACCESS_CHECK = 0x00000400,

/// <summary>
/// The mask of all valid attributes.
/// </summary>
OBJ_VALID_ATTRIBUTES = 0x000007F2,
}

/// <summary>
/// Initializes a new instance of the <see cref="OBJECT_ATTRIBUTES"/> structure.
/// </summary>
/// <returns>An <see cref="OBJECT_ATTRIBUTES"/> instance with <see cref="Length"/> initialized.</returns>
public static OBJECT_ATTRIBUTES Create()
{
return new OBJECT_ATTRIBUTES
{
Length = Marshal.SizeOf(typeof(OBJECT_ATTRIBUTES)),
};
}
}
}
}
54 changes: 54 additions & 0 deletions src/NTDll.Desktop/NTDll+SafeNTObjectHandle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace PInvoke
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

/// <content>
/// Contains the <see cref="SafeNTObjectHandle"/> nested type.
/// </content>
public partial class NTDll
{
/// <summary>
/// A <see cref="SafeHandle"/> that closes with <see cref="NtClose(IntPtr)"/>.
/// </summary>
public class SafeNTObjectHandle : SafeHandle
{
public static readonly SafeNTObjectHandle Null = new SafeNTObjectHandle(IntPtr.Zero, false);

/// <summary>
/// Initializes a new instance of the <see cref="SafeNTObjectHandle"/> class.
/// </summary>
public SafeNTObjectHandle()
: base(IntPtr.Zero, true)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="SafeNTObjectHandle"/> class.
/// </summary>
/// <param name="preexistingHandle">An object that represents the pre-existing handle to use.</param>
/// <param name="ownsHandle"><see langword="true"/> to reliably release the handle during the finalization
/// phase; <see langword="false"/> to prevent reliable release.</param>
public SafeNTObjectHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(IntPtr.Zero, ownsHandle)
{
this.SetHandle(preexistingHandle);
}

/// <inheritdoc />
public override bool IsInvalid => this.handle == IntPtr.Zero;

/// <inheritdoc />
protected override bool ReleaseHandle()
{
return NtClose(this.handle).Severity == NTSTATUS.SeverityCode.STATUS_SEVERITY_SUCCESS;
}
}
}
}
39 changes: 39 additions & 0 deletions src/NTDll.Desktop/NTDll+UNICODE_STRING.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace PInvoke
{
using System;
using System.Runtime.InteropServices;

#pragma warning disable SA1401 // Fields must be private

/// <content>
/// Contains the <see cref="UNICODE_STRING"/> nested struct.
/// </content>
public static partial class NTDll
{
/// <summary>
/// The UNICODE_STRING structure is used to define Unicode strings.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[OfferIntPtrPropertyAccessors]
public unsafe partial struct UNICODE_STRING
{
/// <summary>
/// The length, in bytes, of the string stored in <see cref="Buffer"/>.
/// </summary>
public ushort Length;

/// <summary>
/// The length, in bytes, of <see cref="Buffer"/>.
/// </summary>
public ushort MaximumLength;

/// <summary>
/// Pointer to a buffer used to contain a string of wide characters.
/// </summary>
public char* Buffer;
}
}
}
11 changes: 11 additions & 0 deletions src/NTDll.Desktop/NTDll.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<ExcludeFromNuPkg>true</ExcludeFromNuPkg>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\Kernel32.Desktop\Kernel32.Desktop.csproj">
<Project>{18ba8c60-9a63-4eea-bb5c-c9899d86f5b8}</Project>
<Name>Kernel32.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\Windows.Core\Windows.Core.csproj">
<Project>{b08c3c79-4cdd-4d37-933c-07d3452fd5f1}</Project>
<Name>Windows.Core</Name>
Expand All @@ -45,6 +49,13 @@
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="NTDll+SafeNTObjectHandle.cs" />
<Compile Include="NTDll+UNICODE_STRING.cs">
<Generator>MSBuild:GenerateCodeFromAttributes</Generator>
</Compile>
<Compile Include="NTDll+OBJECT_ATTRIBUTES.cs">
<Generator>MSBuild:GenerateCodeFromAttributes</Generator>
</Compile>
<Compile Include="NTDll.cs">
<Generator>MSBuild:GenerateCodeFromAttributes</Generator>
</Compile>
Expand Down
23 changes: 23 additions & 0 deletions src/NTDll.Desktop/NTDll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,28 @@ public static partial class NTDll
/// </remarks>
[DllImport(nameof(NTDll))]
public static extern Win32ErrorCode RtlNtStatusToDosError(NTSTATUS Status);

/// <summary>
/// The NtOpenSection routine opens a handle for an existing section object.
/// </summary>
/// <param name="sectionHandle">Pointer to a HANDLE variable that receives a handle to the section object.</param><param name="desiredAccess">Specifies an ACCESS_MASK value that determines the requested access to the object.</param><param name="objectAttributes">Pointer to an OBJECT_ATTRIBUTES structure that specifies the object name and other attributes. Use InitializeObjectAttributes to initialize this structure.</param>
/// <returns>
/// Returns <see cref="NTSTATUS.Code.STATUS_SUCCESS"/> on success, or the appropriate <see cref="NTSTATUS"/> error code on failure.
/// </returns>
[DllImport(nameof(NTDll), CharSet = CharSet.Unicode)]
public static extern unsafe NTSTATUS NtOpenSection(
out SafeNTObjectHandle sectionHandle,
ACCESS_MASK desiredAccess,
[Friendly(FriendlyFlags.In)] OBJECT_ATTRIBUTES* objectAttributes);

/// <summary>
/// The NtClose routine closes an object handle.
/// </summary>
/// <param name="handle">Handle to an object of any type.</param>
/// <returns>
/// Returns <see cref="NTSTATUS.Code.STATUS_SUCCESS"/> on success, or the appropriate <see cref="NTSTATUS"/> error code on failure.
/// </returns>
[DllImport(nameof(NTDll))]
private static extern NTSTATUS NtClose(IntPtr handle);
}
}
3 changes: 2 additions & 1 deletion src/NTDll.NuGet/NTDll.NuGet.nuproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<EmbedSourceFiles>true</EmbedSourceFiles>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Kernel32.NuGet\Kernel32.NuGet.nuproj" />
<ProjectReference Include="..\NTDll\NTDll.csproj" />
<ProjectReference Include="..\NTDll.Desktop\NTDll.Desktop.csproj" />
<ProjectReference Include="..\Windows.Core.NuGet\Windows.Core.NuGet.nuproj" />
Expand All @@ -43,4 +44,4 @@
</ItemGroup>
<Import Project="$(NuProjPath)\NuProj.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
</Project>
</Project>
54 changes: 54 additions & 0 deletions src/NTDll.Shared/NTDll+ACCESS_MASK.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace PInvoke
{
/// <content>
/// Contains the <see cref="ACCESS_MASK"/> nested type.
/// </content>
public partial class NTDll
{
/// <summary>
/// The ACCESS_MASK type is a bitmask that specifies a set of access rights in the access mask of an access control entry.
/// </summary>
public enum ACCESS_MASK : uint
{
/// <summary>
/// Delete access.
/// </summary>
DELETE = 0x00010000,

/// <summary>
/// Read access to the owner, group, and discretionary access control list (DACL) of the security descriptor.
/// </summary>
READ_CONTROL = 0x00020000,

/// <summary>
/// Write access to the DACL.
/// </summary>
WRITE_DAC = 0x00040000,

/// <summary>
/// Write access to owner.
/// </summary>
WRITE_OWNER = 0x00080000,

/// <summary>
/// Synchronize access.
/// </summary>
SYNCHRONIZE = 0x00100000,

STANDARD_RIGHTS_REQUIRED = 0x000F0000,

STANDARD_RIGHTS_READ = READ_CONTROL,

STANDARD_RIGHTS_WRITE = READ_CONTROL,

STANDARD_RIGHTS_EXECUTE = READ_CONTROL,

STANDARD_RIGHTS_ALL = 0x001F0000,

SPECIFIC_RIGHTS_ALL = 0x0000FFFF,
}
}
}
3 changes: 2 additions & 1 deletion src/NTDll.Shared/NTDll.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
<Import_RootNamespace>PInvoke</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)NTDll+ACCESS_MASK.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NTDll.Helpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NTDll.cs">
<Generator>MSBuild:GenerateCodeFromAttributes</Generator>
</Compile>
</ItemGroup>
</Project>
</Project>
4 changes: 4 additions & 0 deletions src/NTDll.Tests/NTDll.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Kernel32.Desktop\Kernel32.Desktop.csproj">
<Project>{18ba8c60-9a63-4eea-bb5c-c9899d86f5b8}</Project>
<Name>Kernel32.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\NTDll.Desktop\NTDll.Desktop.csproj">
<Project>{62872B6B-BB44-4890-B308-3EEC6984B542}</Project>
<Name>NTDll.Desktop</Name>
Expand Down
21 changes: 21 additions & 0 deletions src/NTDll.Tests/NTDllFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,25 @@ public void RtlNtStatusToDosError_Test()
////Assert.Equal(Win32ErrorCode.ERROR_FILE_NOT_FOUND, RtlNtStatusToDosError(NTStatus.STATUS_NDIS_FILE_NOT_FOUND));
////Assert.Equal(Win32ErrorCode.ERROR_MUI_FILE_NOT_FOUND, RtlNtStatusToDosError(NTStatus.STATUS_MUI_FILE_NOT_FOUND));
}

[Fact]
public unsafe void NtOpenSection_Test()
{
string nameString = "\\Device\\PhysicalMemory";
fixed (char* name = nameString)
{
var objectNameUnicode = new UNICODE_STRING
{
Buffer = name,
Length = (ushort)(nameString.Length * sizeof(char)),
MaximumLength = (ushort)(nameString.Length * sizeof(char)),
};
var attrs = OBJECT_ATTRIBUTES.Create();
attrs.ObjectName = &objectNameUnicode;
attrs.Attributes = OBJECT_ATTRIBUTES.ObjectHandleAttributes.OBJ_CASE_INSENSITIVE;
SafeNTObjectHandle hObject;
NTSTATUS status = NtOpenSection(out hObject, ACCESS_MASK.STANDARD_RIGHTS_READ, attrs);
Assert.Equal<NTSTATUS>(NTSTATUS.Code.STATUS_ACCESS_DENIED, status);
}
}
}