diff --git a/RpcInvestigator.csproj b/RpcInvestigator.csproj
index 5b8592b..8f67aae 100644
--- a/RpcInvestigator.csproj
+++ b/RpcInvestigator.csproj
@@ -209,6 +209,9 @@
Component
+
+ Form
+
Form
@@ -249,6 +252,9 @@
Resources.resx
True
+
+ SecurityDescriptorView.cs
+
Services.cs
diff --git a/TabPages/ContextMenu.cs b/TabPages/ContextMenu.cs
index fe843eb..f6cdd99 100644
--- a/TabPages/ContextMenu.cs
+++ b/TabPages/ContextMenu.cs
@@ -6,6 +6,9 @@
// the LICENSE file found in the root directory of this source tree.
//
using BrightIdeasSoftware;
+using NtApiDotNet.Win32;
+using RpcInvestigator.Util;
+using RpcInvestigator.Windows;
using System;
using System.Collections.Generic;
using System.Text;
@@ -167,5 +170,27 @@ namespace RpcInvestigator.TabPages
});
Args.MenuStrip.Items.Add(textbox);
}
+
+ public
+ static
+ void
+ ContextMenuViewSecurityDescriptor(
+ object Sender,
+ EventArgs Args
+ )
+ {
+ object tag = ((ToolStripMenuItem)Sender).Tag;
+ if (tag == null)
+ {
+ return;
+ }
+ var args = (CellRightClickEventArgs)tag;
+ var model = args.Model as RpcAlpcServer;
+ var sd = model.SecurityDescriptor;
+
+ var sdView = new SecurityDescriptorView();
+ sdView.BuildSdView(sd.ToString());
+ sdView.Show();
+ }
}
}
diff --git a/TabPages/RpcAlpcServerList.cs b/TabPages/RpcAlpcServerList.cs
index 9a5b6bc..cfd81ba 100644
--- a/TabPages/RpcAlpcServerList.cs
+++ b/TabPages/RpcAlpcServerList.cs
@@ -20,6 +20,8 @@ using System.Security.AccessControl;
using Newtonsoft.Json.Linq;
using RpcInvestigator.Util;
using System.ServiceModel.Channels;
+using System.Text;
+using RpcInvestigator.Windows;
namespace RpcInvestigator
{
@@ -68,14 +70,7 @@ namespace RpcInvestigator
{
if (col.Name == "SecurityDescriptor")
{
- col.AspectToStringConverter = delegate (object Item)
- {
- if (Item == null)
- {
- return "";
- }
- return SddlParser.Parse(Item.ToString());
- };
+ col.IsVisible = false;
}
});
@@ -204,6 +199,7 @@ namespace RpcInvestigator
{
TabPages.ContextMenu.BuildRightClickMenu(Args, new List{
new ToolStripMenuItem("Open in Library", null, ContextMenuOpenAlpcServerInLibrary),
+ new ToolStripMenuItem("View Security Descriptor", null, TabPages.ContextMenu.ContextMenuViewSecurityDescriptor),
});
}
diff --git a/Util/SddlParser.cs b/Util/SddlParser.cs
index 118c46f..97458dc 100644
--- a/Util/SddlParser.cs
+++ b/Util/SddlParser.cs
@@ -15,6 +15,7 @@ using AceType = NtApiDotNet.AceType;
using AceFlags = NtApiDotNet.AceFlags;
using System.Runtime.InteropServices;
using System.Diagnostics;
+using RpcInvestigator.Windows;
namespace RpcInvestigator.Util
{
@@ -22,11 +23,11 @@ namespace RpcInvestigator.Util
public static class SddlParser
{
- private static string SidToString(SecurityIdentifier SidValue)
+ public static string SidToString(SecurityIdentifier SidValue)
{
try
{
- return SidValue.Translate(typeof(NTAccount)).Value;
+ return SidValue.ToString() + " (" + SidValue.Translate(typeof(NTAccount)).Value + ")";
}
catch
{
@@ -34,6 +35,54 @@ namespace RpcInvestigator.Util
}
}
+ public static Ace GetAce(GenericAce ace)
+ {
+ var aceData = new byte[ace.BinaryLength];
+ IntPtr acePointer = Marshal.AllocHGlobal(ace.BinaryLength);
+ IntPtr currentPointer = acePointer;
+ try
+ {
+ ace.GetBinaryForm(aceData, 0);
+ Marshal.Copy(aceData, 0, currentPointer, ace.BinaryLength);
+ var header = (ACE_HEADER)Marshal.PtrToStructure(
+ currentPointer, typeof(ACE_HEADER));
+ //
+ // What follows the header depends on the ACE type, but the
+ // access mask, which is the last part we need, is always
+ // directly after the header.
+ //
+ currentPointer = IntPtr.Add(
+ currentPointer, Marshal.SizeOf(typeof(ACE_HEADER)));
+ var accessMask = Marshal.ReadInt32(currentPointer);
+ currentPointer = IntPtr.Add(currentPointer, 4);
+ var type = (AceType)header.AceType;
+ if (IsObjectAceType(type))
+ {
+ //
+ // Skip 32 bytes (object type and inherited object type)
+ //
+ currentPointer = IntPtr.Add(currentPointer, 32);
+ }
+
+ var sid = new Sid(currentPointer);
+ return new Ace((AceType)header.AceType,
+ (AceFlags)header.AceFlags,
+ accessMask,
+ sid);
+ }
+ catch (Exception ex)
+ {
+ Trace(TraceLoggerType.SddlParser,
+ TraceEventType.Error,
+ "Exception parsing SDDL string: " + ex.Message);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(acePointer);
+ }
+ return null;
+ }
+
private static string AclToString(RawAcl Acl)
{
StringBuilder result = new StringBuilder();
@@ -44,50 +93,17 @@ namespace RpcInvestigator.Util
}
foreach (var ace in Acl)
{
- var aceData = new byte[ace.BinaryLength];
- IntPtr acePointer = Marshal.AllocHGlobal(ace.BinaryLength);
- IntPtr currentPointer = acePointer;
- try
+ var ntAce = GetAce(ace);
+ if (ntAce != null)
{
- ace.GetBinaryForm(aceData, 0);
- Marshal.Copy(aceData, 0, currentPointer, ace.BinaryLength);
- var header = (ACE_HEADER)Marshal.PtrToStructure(
- currentPointer, typeof(ACE_HEADER));
- //
- // What follows the header depends on the ACE type, but the
- // access mask, which is the last part we need, is always
- // directly after the header.
- //
- currentPointer = IntPtr.Add(
- currentPointer, Marshal.SizeOf(typeof(ACE_HEADER)));
- var accessMask = Marshal.ReadInt32(currentPointer);
- currentPointer = IntPtr.Add(currentPointer, 4);
- var type = (AceType)header.AceType;
- if (IsObjectAceType(type))
+ if (ntAce.Type != AceType.Allowed)
{
- //
- // Skip 32 bytes (object type and inherited object type)
- //
- currentPointer = IntPtr.Add(currentPointer, 32);
+ result.Append("Type: " + ntAce.Type.ToString() + ", ");
}
-
- var sid = new Sid(currentPointer);
- var ntAce = new Ace((AceType)header.AceType,
- (AceFlags)header.AceFlags,
- accessMask,
- sid);
- result.Append(ntAce.ToString() + ", ");
- }
- catch (Exception ex)
- {
- Trace(TraceLoggerType.SddlParser,
- TraceEventType.Error,
- "Exception parsing SDDL string: " + ex.Message);
- break;
- }
- finally
- {
- Marshal.FreeHGlobal(acePointer);
+ result.Append("Sid: " + ntAce.Sid.ToString() +
+ " (" + ntAce.Sid.Name + ")" +
+ ", Mask: " + String.Format("0x{0:X}", ntAce.Mask));
+ result.AppendLine();
}
}
return result.ToString();
@@ -110,6 +126,7 @@ namespace RpcInvestigator.Util
result.AppendLine("Owner: " + SidToString(descriptor.Owner));
result.AppendLine("Group: " + SidToString(descriptor.Group));
result.Append("Discretionary ACL: ");
+ result.AppendLine();
result.Append(AclToString(descriptor.DiscretionaryAcl));
result.AppendLine();
result.Append("System ACL: ");
diff --git a/Windows/SecurityDescriptorView.cs b/Windows/SecurityDescriptorView.cs
new file mode 100644
index 0000000..2dfcadc
--- /dev/null
+++ b/Windows/SecurityDescriptorView.cs
@@ -0,0 +1,256 @@
+using BrightIdeasSoftware;
+using RpcInvestigator.Util;
+using System;
+using System.Security.AccessControl;
+using System.Windows.Forms;
+using NtApiDotNet;
+
+namespace RpcInvestigator.Windows
+{
+ public partial class SecurityDescriptorView : Form
+ {
+ private RichTextBox richTextBox1;
+ private CheckedListBox checkedListBox1;
+ private FastObjectListView fastObjectListView1;
+ private OLVColumn olvColumn1;
+ private OLVColumn olvColumn2;
+ private OLVColumn olvColumn3;
+ private OLVColumn olvColumn4;
+ private Button button1;
+
+ public SecurityDescriptorView(
+
+ )
+ {
+ InitializeComponent();
+ }
+
+ public void AddRow(
+ Ace ace
+ )
+ {
+ AceView aceView = new AceView();
+ aceView.Flags = ace.Flags;
+ aceView.Type = ace.Type;
+ aceView.Mask = ace.Mask;
+ aceView.Sid = ace.Sid.ToString() + " (" + ace.Sid.Name + ")";
+
+ fastObjectListView1.AddObject(aceView);
+ }
+
+ public void AddOwner(
+ string Owner
+ )
+ {
+ this.richTextBox1.Text += "Owner: " + Owner + "\n";
+ }
+ public void AddGroup(
+ string Group
+ )
+ {
+ this.richTextBox1.Text += "Group: " + Group + "\n";
+ }
+
+ private void InitializeComponent()
+ {
+ this.button1 = new System.Windows.Forms.Button();
+ this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+ this.checkedListBox1 = new System.Windows.Forms.CheckedListBox();
+ this.fastObjectListView1 = new BrightIdeasSoftware.FastObjectListView();
+ this.olvColumn1 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
+ this.olvColumn2 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
+ this.olvColumn3 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
+ this.olvColumn4 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
+ ((System.ComponentModel.ISupportInitialize)(this.fastObjectListView1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // button1
+ //
+ this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.button1.Location = new System.Drawing.Point(543, 262);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(71, 26);
+ this.button1.TabIndex = 0;
+ this.button1.Text = "OK";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // richTextBox1
+ //
+ this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.richTextBox1.Location = new System.Drawing.Point(12, 158);
+ this.richTextBox1.Name = "richTextBox1";
+ this.richTextBox1.ReadOnly = true;
+ this.richTextBox1.Size = new System.Drawing.Size(304, 100);
+ this.richTextBox1.TabIndex = 2;
+ this.richTextBox1.Text = "";
+ //
+ // checkedListBox1
+ //
+ this.checkedListBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.checkedListBox1.FormattingEnabled = true;
+ this.checkedListBox1.Items.AddRange(new object[] {
+ "Connect",
+ "Delete",
+ "Read Control",
+ "Write DAC",
+ "Write Owner",
+ "Synchronize"});
+ this.checkedListBox1.Location = new System.Drawing.Point(322, 158);
+ this.checkedListBox1.Name = "checkedListBox1";
+ this.checkedListBox1.SelectionMode = System.Windows.Forms.SelectionMode.None;
+ this.checkedListBox1.Size = new System.Drawing.Size(292, 89);
+ this.checkedListBox1.TabIndex = 3;
+ //
+ // fastObjectListView1
+ //
+ this.fastObjectListView1.AllColumns.Add(this.olvColumn1);
+ this.fastObjectListView1.AllColumns.Add(this.olvColumn2);
+ this.fastObjectListView1.AllColumns.Add(this.olvColumn3);
+ this.fastObjectListView1.AllColumns.Add(this.olvColumn4);
+ this.fastObjectListView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.fastObjectListView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.olvColumn1,
+ this.olvColumn2,
+ this.olvColumn3,
+ this.olvColumn4});
+ this.fastObjectListView1.HideSelection = false;
+ this.fastObjectListView1.Location = new System.Drawing.Point(12, 12);
+ this.fastObjectListView1.Name = "fastObjectListView1";
+ this.fastObjectListView1.ShowGroups = false;
+ this.fastObjectListView1.Size = new System.Drawing.Size(602, 140);
+ this.fastObjectListView1.TabIndex = 4;
+ this.fastObjectListView1.UseCompatibleStateImageBehavior = false;
+ this.fastObjectListView1.View = System.Windows.Forms.View.Details;
+ this.fastObjectListView1.VirtualMode = true;
+ this.fastObjectListView1.SelectedIndexChanged += FastObjectListView1_SelectedIndexChanged;
+ //
+ // olvColumn1
+ //
+ this.olvColumn1.AspectName = "Sid";
+ this.olvColumn1.IsEditable = false;
+ this.olvColumn1.Text = "Sid";
+ this.olvColumn1.Width = 250;
+ //
+ // olvColumn2
+ //
+ this.olvColumn2.AspectName = "Mask";
+ this.olvColumn2.IsEditable = false;
+ this.olvColumn2.Text = "Mask";
+ this.olvColumn2.Width = 50;
+ //
+ // olvColumn3
+ //
+ this.olvColumn3.AspectName = "Type";
+ this.olvColumn3.IsEditable = false;
+ this.olvColumn3.Text = "Type";
+ this.olvColumn3.Width = 70;
+ //
+ // olvColumn4
+ //
+ this.olvColumn4.AspectName = "Flags";
+ this.olvColumn4.IsEditable = false;
+ this.olvColumn4.Text = "Flags";
+ this.olvColumn4.Width = 50;
+ //
+ // SecurityDescriptorView
+ //
+ this.ClientSize = new System.Drawing.Size(626, 300);
+ this.Controls.Add(this.fastObjectListView1);
+ this.Controls.Add(this.checkedListBox1);
+ this.Controls.Add(this.richTextBox1);
+ this.Controls.Add(this.button1);
+ this.Name = "SecurityDescriptorView";
+ this.Text = "Security Descriptor";
+ ((System.ComponentModel.ISupportInitialize)(this.fastObjectListView1)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ private void FastObjectListView1_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ FastObjectListView view = (FastObjectListView)sender;
+ if (view.SelectedIndex < 0)
+ {
+ return;
+ }
+ var row = this.fastObjectListView1.Items[view.SelectedIndex];
+ var mask = Convert.ToInt32(row.SubItems[1].Text.ToString(), 16);
+
+ foreach (int i in this.checkedListBox1.CheckedIndices)
+ {
+ this.checkedListBox1.SetItemCheckState(i, CheckState.Unchecked);
+ }
+ if ((mask & 1) == 1)
+ {
+ this.checkedListBox1.SetItemCheckState(0, CheckState.Checked);
+ }
+ if ((mask & 0x10000) == 0x10000)
+ {
+ this.checkedListBox1.SetItemCheckState(1, CheckState.Checked);
+ }
+ if ((mask & 0x20000) == 0x20000)
+ {
+ this.checkedListBox1.SetItemCheckState(2, CheckState.Checked);
+ }
+ if ((mask & 0x40000) == 0x40000)
+ {
+ this.checkedListBox1.SetItemCheckState(3, CheckState.Checked);
+ }
+ if ((mask & 0x80000) == 0x80000)
+ {
+ this.checkedListBox1.SetItemCheckState(4, CheckState.Checked);
+ }
+ if ((mask & 0x100000) == 0x100000)
+ {
+ this.checkedListBox1.SetItemCheckState(5, CheckState.Checked);
+ }
+ }
+
+ public void BuildSdView(
+ string SddlString
+ )
+ {
+ RawSecurityDescriptor descriptor;
+ try
+ {
+ descriptor = new RawSecurityDescriptor(SddlString);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to create RawSecurityDescriptor from " +
+ "the provided SDDL string '" + SddlString + "': " + ex.Message);
+ }
+
+ AddOwner(SddlParser.SidToString(descriptor.Owner));
+ AddGroup(SddlParser.SidToString(descriptor.Group));
+ if (descriptor.DiscretionaryAcl == null)
+ {
+ return;
+ }
+ foreach (var ace in descriptor.DiscretionaryAcl)
+ {
+ var ntAce = SddlParser.GetAce(ace);
+ if (ntAce != null)
+ {
+ AddRow(ntAce);
+ }
+ }
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ this.Close();
+ }
+ }
+ class AceView
+ {
+ public NtApiDotNet.AceType Type { get; set; }
+ public NtApiDotNet.AceFlags Flags { get; set; }
+ public AccessMask Mask { get; set; }
+ public string Sid { get; set; }
+ }
+}
diff --git a/Windows/SecurityDescriptorView.resx b/Windows/SecurityDescriptorView.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/Windows/SecurityDescriptorView.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file