├── LICENSE ├── README.md ├── SDDLViewer.sln ├── SDDLViewer ├── App.xaml ├── App.xaml.cs ├── BoolStringClass.cs ├── Logic │ ├── DirectorySearcher.cs │ ├── Model.cs │ ├── SecurityUnit │ │ ├── ACE.cs │ │ └── SecurityDescriptor.cs │ └── Win32Native.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── SDDLViewer.csproj ├── UIFolderRegPicker │ ├── FolderRegPickerWindow.xaml │ └── FolderRegPickerWindow.xaml.cs ├── UIPerformWork │ ├── UIPerformWorkWindow.xaml │ └── UIPerformWorkWindow.xaml.cs ├── UIReport │ ├── ReportModel.cs │ ├── UIReportWindow.xaml │ └── UIReportWindow.xaml.cs └── sddl_terminal.ico └── Screenshots └── MainWindow.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Advanced monitoring 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SDDL Viewer 2 | 3 | This is a small tool to view SDDL-strings. Allows to filter users, SIDs and rights. 4 | 5 | # Screenshots 6 | 7 | ![Main window](Screenshots/MainWindow.png) 8 | 9 | # Links 10 | 11 | Short view: https://habr.com/ru/company/pm/blog/442662/ -------------------------------------------------------------------------------- /SDDLViewer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.9 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDDLViewer", "SDDLViewer\SDDLViewer.csproj", "{6929B669-D82D-49B5-B4ED-7172BC900D18}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {6929B669-D82D-49B5-B4ED-7172BC900D18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {6929B669-D82D-49B5-B4ED-7172BC900D18}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {6929B669-D82D-49B5-B4ED-7172BC900D18}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {6929B669-D82D-49B5-B4ED-7172BC900D18}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /SDDLViewer/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /SDDLViewer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace SDDLViewer 9 | { 10 | /// 11 | /// Interaction logic for App.xaml 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SDDLViewer/BoolStringClass.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Media; 2 | 3 | namespace SDDLViewer 4 | { 5 | public class BoolStringClass 6 | { 7 | public BoolStringClass(string text, string tag) 8 | { 9 | Text = text; 10 | Tag = tag; 11 | IsSelected = true; 12 | TextBrush = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 13 | } 14 | 15 | public string Text { get; } 16 | public string Tag { get; } 17 | public bool IsSelected { get; set; } 18 | public SolidColorBrush TextBrush { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /SDDLViewer/Logic/DirectorySearcher.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace SDDLViewer.Logic 5 | { 6 | static class DirectorySearcher 7 | { 8 | public static List MyGetDirectories(string path) 9 | { 10 | return Search(path, false); 11 | } 12 | 13 | public static List MyGetFiles(string path) 14 | { 15 | return Search(path, true); 16 | } 17 | 18 | private static List Search(string path, bool isFiles) 19 | { 20 | var fullPath = Path.GetFullPath(path); 21 | var searchPath = Path.Combine(fullPath, "*.*"); 22 | var rv = new List(); 23 | var findData = new Win32Native.WIN32_FIND_DATA(); 24 | using (var hndFindFile = Win32Native.FindFirstFile(searchPath, findData)) 25 | { 26 | if (hndFindFile == null) 27 | return rv; 28 | var retval = true; 29 | while (retval) 30 | { 31 | if ((findData.cFileName == ".") || (findData.cFileName == "..")) 32 | { 33 | retval = Win32Native.FindNextFile(hndFindFile, findData); 34 | continue; 35 | } 36 | if (((findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory) != isFiles) 37 | rv.Add(Path.Combine(fullPath, findData.cFileName)); 38 | retval = Win32Native.FindNextFile(hndFindFile, findData); 39 | } 40 | } 41 | return rv; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SDDLViewer/Logic/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Security.AccessControl; 8 | using System.ServiceProcess; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Windows.Controls; 12 | using System.Windows.Media; 13 | using System.Windows.Threading; 14 | using Microsoft.Win32; 15 | using SDDLViewer.UIFolderRegPicker; 16 | using SDDLViewer.UIPerformWork; 17 | using SDDLViewer.UIReport; 18 | 19 | namespace SDDLViewer.Logic 20 | { 21 | public static class Model 22 | { 23 | public static MainWindow MW { set; private get; } 24 | 25 | public static void SelectionChangedRightsCombobox() 26 | { 27 | var selected = ((ComboBoxItem)MW.CmbxRightsType.SelectedItem).Content as string; 28 | MW.RightsList.Clear(); 29 | foreach (var r in new List {"GA", "GX", "GW", "GR", "SD", "RC", "WD", "WO"}) 30 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r), r)); 31 | switch (selected) 32 | { 33 | case "Service Access Rights": 34 | foreach (var r in new List { "CC", "DC", "LC", "DW", "RP", "WP", "DT", "LO", "CR" }) 35 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r, 0), r)); 36 | break; 37 | 38 | case "Directory Access Rights": 39 | foreach (var r in new List { "CC", "DC", "LC", "SW", "RP", "WP", "DT", "LO", "CR" }) 40 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r, 1), r)); 41 | break; 42 | 43 | case "File Access Rights": 44 | foreach (var r in new List { "CC", "DC", "LC", "SW", "RP", "WP", "LO", "CR", "FA", "FR", "FW", "FX" }) 45 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r, 2), r)); 46 | break; 47 | 48 | case "File and Directory Access Rights": 49 | foreach (var r in new List { "CC", "DC", "LC", "SW", "RP", "WP", "DT", "LO", "CR", "FA", "FR", "FW", "FX" }) 50 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r, 3), r)); 51 | break; 52 | 53 | case "Registry Key Access Rights": 54 | foreach (var r in new List { "CC", "DC", "LC", "SW", "RP", "WP", "KA", "KR", "KW", "KX" }) 55 | MW.RightsList.Add(new BoolStringClass(ACE.RigthToLong(r, 4), r)); 56 | break; 57 | } 58 | TextChangedContentEdit(); 59 | } 60 | 61 | private static readonly ManualResetEvent TextChangedEvent = new ManualResetEvent(false); 62 | private static Thread _textChangedThread; 63 | private static Thread _textChangedSpinnerThread; 64 | 65 | public static void TextChangedContentEdit() 66 | { 67 | if (_textChangedThread != null && _textChangedThread.IsAlive) 68 | { 69 | TextChangedEvent.Set(); 70 | _textChangedThread.Join(); 71 | } 72 | TextChangedEvent.Reset(); 73 | _textChangedThread = new Thread(TextChangedFunc); 74 | _textChangedThread.Start(MW.GetContent()); 75 | _textChangedSpinnerThread = new Thread(TextChangedSpinnerFunc); 76 | _textChangedSpinnerThread.Start(); 77 | } 78 | 79 | private static int _textChangedIndex; 80 | 81 | private static void TextChangedSpinnerFunc() 82 | { 83 | while (true) 84 | { 85 | Thread.Sleep(300); 86 | var head = "User/Group/SID"; 87 | if (_textChangedThread != null && _textChangedThread.IsAlive) 88 | { 89 | _textChangedIndex = (_textChangedIndex + 1) % 4; 90 | head = "[" + "|/-\\"[_textChangedIndex] + "] " + head; 91 | } 92 | MW.Dispatcher.BeginInvoke(DispatcherPriority.Background, 93 | new Action((x) => MW.grpUGS.Header = x), head); 94 | if (TextChangedEvent.WaitOne(0)) 95 | { 96 | MW.Dispatcher.BeginInvoke(DispatcherPriority.Background, 97 | new Action(() => MW.grpUGS.Header = "User/Group/SID")); 98 | Thread.CurrentThread.Abort(); 99 | return; 100 | } 101 | } 102 | } 103 | 104 | private static void TextChangedFunc(object o) 105 | { 106 | var data = (string)o; 107 | var lines = data.Split('\r', '\n'); 108 | var allSIDs = new List(); 109 | var allRights = new List(); 110 | var prevSids = 0; 111 | var prevRights = 0; 112 | foreach (var line in lines) 113 | { 114 | if (!string.IsNullOrWhiteSpace(line)) 115 | { 116 | var sd = new SecurityDescriptor(line.Trim()); 117 | if (!sd.IsOk) 118 | continue; 119 | 120 | var lSIDs = sd.GetAllSIDs(); 121 | foreach (var sid in lSIDs) 122 | if (!allSIDs.Contains(sid)) 123 | allSIDs.Add(sid); 124 | 125 | var lRights = sd.GetAllRights(); 126 | foreach (var right in lRights) 127 | if (!allRights.Contains(right)) 128 | allRights.Add(right); 129 | 130 | if (allSIDs.Count != prevSids) 131 | { 132 | prevSids = allSIDs.Count; 133 | var sortedSIDs = allSIDs.OrderBy(q => q[1] == '-' ? "ZZ" + q : q).ToList(); 134 | MW.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action>((x) => 135 | { 136 | MW.SIDList.Clear(); 137 | foreach (var sid in x) 138 | MW.SIDList.Add(new BoolStringClass(SecurityDescriptor.SIDToLong(sid, MW.IsTranslateSID), sid)); 139 | }), sortedSIDs); 140 | } 141 | 142 | if (allRights.Count != prevRights) 143 | { 144 | prevRights = allRights.Count; 145 | MW.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => 146 | { 147 | var newRightsList = new ObservableCollection(); 148 | foreach (var element in MW.RightsList) 149 | { 150 | if (allRights.Contains(element.Tag)) 151 | element.TextBrush = new SolidColorBrush(Color.FromRgb(50, 150, 255)); 152 | newRightsList.Add(element); 153 | } 154 | MW.RightsList.Clear(); 155 | foreach (var element in newRightsList) 156 | MW.RightsList.Add(element); 157 | })); 158 | } 159 | } 160 | if (TextChangedEvent.WaitOne(0)) 161 | { 162 | if (_textChangedSpinnerThread != null && _textChangedSpinnerThread.IsAlive) 163 | _textChangedSpinnerThread.Join(); 164 | Thread.CurrentThread.Abort(); 165 | return; 166 | } 167 | } 168 | 169 | TextChangedEvent.Set(); 170 | if (_textChangedSpinnerThread != null && _textChangedSpinnerThread.IsAlive) 171 | _textChangedSpinnerThread.Join(); 172 | Thread.CurrentThread.Abort(); 173 | } 174 | 175 | private static string _fillData; 176 | 177 | public static void ButtonFillServicesClicked() 178 | { 179 | var work = new Thread(ServiceFill); 180 | var abortEvent = new ManualResetEvent(false); 181 | var dlg = new UIPerformWorkWindow(MW, abortEvent, "Count services..."); 182 | work.Start(dlg); 183 | if (dlg.ShowDialog() ?? false) 184 | { 185 | MW.SetContent(); 186 | if (MW.CmbxRightsType.SelectedIndex != 0) 187 | MW.CmbxRightsType.SelectedIndex = 0; 188 | MW.SetContent(_fillData); 189 | } 190 | work.Join(); 191 | } 192 | 193 | private static void ServiceFill(object o) 194 | { 195 | var ww = (UIPerformWorkWindow) o; 196 | var sb = new StringBuilder(); 197 | var services = ServiceController.GetServices(); 198 | var managerHandle = Win32Native.OpenSCManager(null, null, 0x20004); 199 | for (var i = 0; i < services.Length; i++) 200 | { 201 | var service = services[i]; 202 | try 203 | { 204 | var localSb = new StringBuilder(); 205 | localSb.AppendLine($"{service.DisplayName} ({service.ServiceName})"); 206 | var serviceHandle = Win32Native.OpenService(managerHandle, service.ServiceName, 0x20000); 207 | uint sdSize; 208 | var result = Win32Native.QueryServiceObjectSecurity(serviceHandle, 7, null, 0, out sdSize); 209 | var gle = Marshal.GetLastWin32Error(); 210 | if (result || (gle != 122)) 211 | { 212 | Win32Native.CloseServiceHandle(serviceHandle); 213 | throw new System.ComponentModel.Win32Exception(gle); 214 | } 215 | var binarySd = new byte[sdSize]; 216 | result = Win32Native.QueryServiceObjectSecurity(serviceHandle, 7, binarySd, binarySd.Length, out sdSize); 217 | gle = Marshal.GetLastWin32Error(); 218 | if (!result) 219 | { 220 | Win32Native.CloseServiceHandle(serviceHandle); 221 | throw new System.ComponentModel.Win32Exception(gle); 222 | } 223 | var cd = new CommonSecurityDescriptor(false, false, binarySd, 0); 224 | localSb.AppendLine(cd.GetSddlForm(AccessControlSections.All)); 225 | sb.AppendLine(localSb.ToString()); 226 | Win32Native.CloseServiceHandle(serviceHandle); 227 | ww.Percentage = (int) ((i + 0.0) * 100.0 / (services.Length + 0.0)); 228 | if (ww.AbortEvent.WaitOne(0)) 229 | break; 230 | } 231 | catch 232 | { 233 | // continue 234 | } 235 | } 236 | Win32Native.CloseServiceHandle(managerHandle); 237 | _fillData = sb.ToString(); 238 | ww.AbortEvent.Set(); 239 | } 240 | 241 | public static void ButtonFillDirectoryClicked() 242 | { 243 | var dlg = new UIFolderRegPickerWindow(MW, true); 244 | if (dlg.ShowDialog() ?? false) 245 | { 246 | var work = new Thread(DirectoryFill); 247 | var abortEvent = new ManualResetEvent(false); 248 | var w = new UIPerformWorkWindow(MW, abortEvent, "Count directories..."); 249 | work.Start(new Tuple(dlg, w)); 250 | if (w.ShowDialog() ?? false) 251 | { 252 | int target = 1; 253 | if (dlg.IsFilesInclude) 254 | target = 3; 255 | MW.SetContent(); 256 | if (MW.CmbxRightsType.SelectedIndex != target) 257 | MW.CmbxRightsType.SelectedIndex = target; 258 | MW.SetContent(_fillData); 259 | } 260 | work.Join(); 261 | } 262 | } 263 | 264 | private static int _maxFiles; 265 | private static int _currentFiles; 266 | private static bool _isFileInclude; 267 | private static bool _isRecursing; 268 | private static UIPerformWorkWindow _ww; 269 | private static StringBuilder _sb; 270 | 271 | private static void DirectoryFill(object o) 272 | { 273 | var t = (Tuple) o; 274 | _sb = new StringBuilder(); 275 | _ww = t.Item2; 276 | _currentFiles = 0; 277 | _isFileInclude = t.Item1.IsFilesInclude; 278 | _isRecursing = t.Item1.IsRecursing; 279 | _maxFiles = CalcDirCount(t.Item1.PathName) + 1; 280 | UpdateDirectory(t.Item1.PathName); 281 | _fillData = _sb.ToString(); 282 | t.Item2.AbortEvent.Set(); 283 | } 284 | 285 | private static int CalcDirCount(string path) 286 | { 287 | if (_ww.AbortEvent.WaitOne(0)) 288 | return 0; 289 | List dirs; 290 | try 291 | { 292 | dirs = DirectorySearcher.MyGetDirectories(path); 293 | } 294 | catch 295 | { 296 | return 1; 297 | } 298 | var c = 1; 299 | if (_isRecursing) 300 | foreach (var dir in dirs) 301 | c += CalcDirCount(dir); 302 | if (_isFileInclude) 303 | c += DirectorySearcher.MyGetFiles(path).Count; 304 | return c; 305 | } 306 | 307 | private static void UpdateDirectory(string path) 308 | { 309 | var localSb = new StringBuilder(); 310 | localSb.AppendLine(path); 311 | _currentFiles++; 312 | var sddlString = "Unable obtain SDDL"; 313 | try 314 | { 315 | sddlString = Directory.GetAccessControl(path).GetSecurityDescriptorSddlForm(AccessControlSections.All); 316 | } 317 | catch 318 | { 319 | // ignore 320 | } 321 | localSb.AppendLine(sddlString); 322 | _sb.AppendLine(localSb.ToString()); 323 | foreach (var dir in DirectorySearcher.MyGetDirectories(path)) 324 | { 325 | try 326 | { 327 | if (_isRecursing) 328 | UpdateDirectory(dir); 329 | else 330 | { 331 | localSb.Clear(); 332 | localSb.AppendLine(dir); 333 | _currentFiles++; 334 | localSb.AppendLine(Directory.GetAccessControl(dir).GetSecurityDescriptorSddlForm(AccessControlSections.All)); 335 | _sb.AppendLine(localSb.ToString()); 336 | } 337 | } 338 | catch 339 | { 340 | // ignore 341 | } 342 | _ww.Percentage = (int)((_currentFiles + 0.0) * 100.0 / (_maxFiles + 0.0)); 343 | if (_ww.AbortEvent.WaitOne(0)) 344 | return; 345 | } 346 | if (_isFileInclude) 347 | foreach (var file in DirectorySearcher.MyGetFiles(path)) 348 | { 349 | try 350 | { 351 | localSb.Clear(); 352 | localSb.AppendLine(file); 353 | _currentFiles++; 354 | localSb.AppendLine(File.GetAccessControl(file).GetSecurityDescriptorSddlForm(AccessControlSections.All)); 355 | _sb.AppendLine(localSb.ToString()); 356 | } 357 | catch 358 | { 359 | // ignore 360 | } 361 | _ww.Percentage = (int)((_currentFiles + 0.0) * 100.0 / (_maxFiles + 0.0)); 362 | if (_ww.AbortEvent.WaitOne(0)) 363 | return; 364 | } 365 | } 366 | 367 | public static void ButtonFillFilesClicked() 368 | { 369 | var dlg = new OpenFileDialog 370 | { 371 | Multiselect = true, 372 | Filter = "All files (*.*)|*.*" 373 | }; 374 | if (dlg.ShowDialog() ?? false) 375 | { 376 | MW.SetContent(); 377 | if (MW.CmbxRightsType.SelectedIndex != 2) 378 | MW.CmbxRightsType.SelectedIndex = 2; 379 | var sb = new StringBuilder(); 380 | foreach (var file in dlg.FileNames) 381 | { 382 | try 383 | { 384 | if ((string.IsNullOrWhiteSpace(file)) || (!File.Exists(file))) 385 | continue; 386 | var localSb = new StringBuilder(); 387 | localSb.AppendLine($"{file}"); 388 | var sddlString = "Unable obtain SDDL"; 389 | try 390 | { 391 | sddlString = File.GetAccessControl(file).GetSecurityDescriptorSddlForm(AccessControlSections.All); 392 | } 393 | catch 394 | { 395 | // ignore 396 | } 397 | localSb.AppendLine(sddlString); 398 | sb.AppendLine(localSb.ToString()); 399 | } 400 | catch 401 | { 402 | // continue 403 | } 404 | } 405 | MW.SetContent(sb.ToString()); 406 | } 407 | } 408 | 409 | public static void ButtonFillRegistryClicked() 410 | { 411 | var dlg = new UIFolderRegPickerWindow(MW, false); 412 | if (dlg.ShowDialog() ?? false) 413 | { 414 | var work = new Thread(RegistryFill); 415 | var abortEvent = new ManualResetEvent(false); 416 | var w = new UIPerformWorkWindow(MW, abortEvent, "Count reg-keys..."); 417 | work.Start(new Tuple(dlg, w)); 418 | if (w.ShowDialog() ?? false) 419 | { 420 | MW.SetContent(); 421 | if (MW.CmbxRightsType.SelectedIndex != 4) 422 | MW.CmbxRightsType.SelectedIndex = 4; 423 | MW.SetContent(_fillData); 424 | } 425 | work.Join(); 426 | } 427 | } 428 | 429 | private static void RegistryFill(object o) 430 | { 431 | var t = (Tuple)o; 432 | _sb = new StringBuilder(); 433 | _ww = t.Item2; 434 | _currentFiles = 0; 435 | _isFileInclude = t.Item1.IsFilesInclude; 436 | _isRecursing = t.Item1.IsRecursing; 437 | var key = UIFolderRegPickerWindow.GetKeyFromString(t.Item1.PathName); 438 | _maxFiles = CalcKeyCount(key) + 1; 439 | UpdateRegKey(key); 440 | _fillData = _sb.ToString(); 441 | t.Item2.AbortEvent.Set(); 442 | } 443 | 444 | private static int CalcKeyCount(RegistryKey key) 445 | { 446 | if (_ww.AbortEvent.WaitOne(0)) 447 | return 0; 448 | string[] keys; 449 | try 450 | { 451 | keys = key.GetSubKeyNames(); 452 | } 453 | catch 454 | { 455 | return 1; 456 | } 457 | var c = 1; 458 | if (_isRecursing) 459 | foreach (var k in keys) 460 | try 461 | { 462 | c += CalcKeyCount(key.OpenSubKey(k)); 463 | } 464 | catch 465 | { 466 | c++; 467 | } 468 | return c; 469 | } 470 | 471 | private static void UpdateRegKey(RegistryKey key) 472 | { 473 | var localSb = new StringBuilder(); 474 | localSb.AppendLine(key.Name); 475 | _currentFiles++; 476 | var sddlString = "Unable obtain SDDL"; 477 | try 478 | { 479 | sddlString = key.GetAccessControl().GetSecurityDescriptorSddlForm(AccessControlSections.All); 480 | } 481 | catch 482 | { 483 | // ignore 484 | } 485 | localSb.AppendLine(sddlString); 486 | _sb.AppendLine(localSb.ToString()); 487 | if (key.SubKeyCount != 0) 488 | foreach (var sub in key.GetSubKeyNames()) 489 | { 490 | try 491 | { 492 | var oKey = key.OpenSubKey(sub); 493 | if (oKey != null) 494 | if (_isRecursing) 495 | UpdateRegKey(oKey); 496 | else 497 | { 498 | localSb.Clear(); 499 | localSb.AppendLine(oKey.Name); 500 | _currentFiles++; 501 | localSb.AppendLine( 502 | oKey.GetAccessControl().GetSecurityDescriptorSddlForm(AccessControlSections.All)); 503 | _sb.AppendLine(localSb.ToString()); 504 | } 505 | } 506 | catch 507 | { 508 | // ignored 509 | } 510 | _ww.Percentage = (int) ((_currentFiles + 0.0) * 100.0 / (_maxFiles + 0.0)); 511 | if (_ww.AbortEvent.WaitOne(0)) 512 | return; 513 | } 514 | } 515 | 516 | public static void ButtonSaveClicked() 517 | { 518 | var dlg = new SaveFileDialog 519 | { 520 | FileName = "raw_sddl", 521 | DefaultExt = ".txt", 522 | Filter = "Text documents (*.txt)|*.txt|All files (*.*)|*.*", 523 | FilterIndex = 0, 524 | OverwritePrompt = true 525 | }; 526 | if (dlg.ShowDialog() ?? false) 527 | File.WriteAllText(dlg.FileName, MW.GetContent()); 528 | } 529 | 530 | public static void ButtonAll(int listboxNumber, bool state) 531 | { 532 | ListBox lb = null; 533 | switch (listboxNumber) 534 | { 535 | case 0: 536 | lb = MW.LstChkSIDs; 537 | break; 538 | 539 | case 1: 540 | lb = MW.LstChkRights; 541 | break; 542 | } 543 | if (lb != null) 544 | foreach (var lbItem in lb.ItemsSource) 545 | if (lbItem is BoolStringClass) 546 | (lbItem as BoolStringClass).IsSelected = state; 547 | List tmp; 548 | switch (listboxNumber) 549 | { 550 | case 0: 551 | tmp = new List(MW.SIDList); 552 | MW.SIDList.Clear(); 553 | foreach (var element in tmp) 554 | MW.SIDList.Add(element); 555 | break; 556 | 557 | case 1: 558 | tmp = new List(MW.RightsList); 559 | MW.RightsList.Clear(); 560 | foreach (var element in tmp) 561 | MW.RightsList.Add(element); 562 | break; 563 | } 564 | } 565 | 566 | public static void ButtonMakeReport() 567 | { 568 | var listInterestSIDs = (from sid in MW.SIDList where sid.IsSelected select sid.Tag).ToList(); 569 | var listInterestRights = (from right in MW.RightsList where right.IsSelected select right.Tag).ToList(); 570 | 571 | new UIReportWindow(MW, MW.GetContent(), listInterestSIDs, listInterestRights, MW.CmbxRightsType.SelectedIndex).ShowDialog(); 572 | } 573 | 574 | public static void OnClose() 575 | { 576 | if (!TextChangedEvent.WaitOne(0)) 577 | TextChangedEvent.Set(); 578 | } 579 | 580 | public static void ButtonOpenClicked() 581 | { 582 | var dlg = new OpenFileDialog 583 | { 584 | FileName = "raw_sddl", 585 | DefaultExt = ".txt", 586 | Filter = "Text documents (*.txt)|*.txt|All files (*.*)|*.*", 587 | FilterIndex = 0, 588 | CheckFileExists = true, 589 | CheckPathExists = true 590 | }; 591 | if (dlg.ShowDialog() ?? false) 592 | { 593 | MW.SetContent(); 594 | MW.SetContent(File.ReadAllText(dlg.FileName)); 595 | } 596 | } 597 | 598 | public static void ButtonTranslateClicked() 599 | { 600 | TextChangedContentEdit(); 601 | } 602 | } 603 | } 604 | -------------------------------------------------------------------------------- /SDDLViewer/Logic/SecurityUnit/ACE.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Text; 5 | 6 | namespace SDDLViewer 7 | { 8 | public class ACE 9 | { 10 | public const int AllowRule = 0; 11 | public const int DenyRule = 1; 12 | public const int OtherRule = 2; 13 | 14 | private readonly string _ace; 15 | public readonly bool IsOk; 16 | 17 | private readonly string _type; 18 | private readonly string _righs; 19 | private readonly string _sid; 20 | 21 | private static readonly List> RightsValues = new List>() 22 | { 23 | new Tuple(0x001200A0, "FX"), 24 | new Tuple(0x00120116, "FW"), 25 | new Tuple(0x00120089, "FR"), 26 | new Tuple(0x001F01FF, "FA"), 27 | new Tuple(0x00120116, "FW"), 28 | 29 | new Tuple(0x00000100, "CR"), 30 | new Tuple(0x00000080, "LO"), 31 | new Tuple(0x00000040, "DT"), 32 | new Tuple(0x00000020, "WP"), 33 | new Tuple(0x00000010, "RP"), 34 | new Tuple(0x00000008, "SW"), 35 | new Tuple(0x00000004, "LC"), 36 | new Tuple(0x00000002, "DC"), 37 | new Tuple(0x00000001, "CC"), 38 | 39 | new Tuple(0x00010000, "SD"), 40 | new Tuple(0x00020000, "RC"), 41 | new Tuple(0x00040000, "Wd"), 42 | new Tuple(0x00080000, "WO"), 43 | }; 44 | 45 | public ACE(string ace) 46 | { 47 | _ace = ace; 48 | try 49 | { 50 | var lst = _ace.Substring(1, _ace.Length - 2).Split(';'); 51 | if (lst.Length != 6) 52 | throw new Exception(); 53 | _type = lst[0]; 54 | _righs = lst[2]; 55 | if (_righs.StartsWith("0x")) 56 | { 57 | var r = ""; 58 | UInt32 v = UInt32.Parse(_righs.Substring(2), NumberStyles.AllowHexSpecifier); 59 | UInt32 v2 = 0; 60 | foreach (var value in RightsValues) 61 | { 62 | if ((v & value.Item1) == value.Item1) 63 | { 64 | r += value.Item2; 65 | v2 |= value.Item1; 66 | } 67 | } 68 | if (v2 != v) 69 | r += "??"; 70 | _righs = r; 71 | } 72 | _sid = lst[5]; 73 | IsOk = true; 74 | } 75 | catch 76 | { 77 | IsOk = false; 78 | } 79 | } 80 | 81 | public string GetSID() 82 | { 83 | return _sid; 84 | } 85 | 86 | public List GetAllRights() 87 | { 88 | var rv = new List(); 89 | for (var i = 0; i < _righs.Length / 2; i++) 90 | rv.Add(_righs.Substring(2 * i, 2)); 91 | return rv; 92 | } 93 | 94 | public string WithNewRights(List newRights) 95 | { 96 | var sb = new StringBuilder(); 97 | sb.Append('('); 98 | var lst = _ace.Substring(1, _ace.Length - 2).Split(';'); 99 | for (int i = 0; i < lst.Length; i++) 100 | { 101 | if (i != 0) 102 | sb.Append(';'); 103 | if (i == 2) 104 | foreach (var r in newRights) 105 | sb.Append(r); 106 | else 107 | sb.Append(lst[i]); 108 | } 109 | sb.Append(')'); 110 | return sb.ToString(); 111 | } 112 | 113 | public static string RigthToLong(string right, int rightsType = -1) 114 | { 115 | switch (right) 116 | { 117 | case "GA": return "[GA] Generic All"; 118 | case "GX": return "[GX] Generic Execute/Traverse"; 119 | case "GW": return "[GW] Generic Write"; 120 | case "GR": return "[GR] Generic Read"; 121 | case "SD": return "[SD] Standard Delete"; 122 | case "RC": return "[RC] Read Control"; 123 | case "WD": return "[WD] Write Discretionary Access Control"; 124 | case "WO": return "[WO] Write Owner"; 125 | } 126 | switch (rightsType) 127 | { 128 | case 0: 129 | switch (right) 130 | { 131 | case "CC": return "[CC] Query Configuration"; 132 | case "DC": return "[DC] Change Configuration"; 133 | case "LC": return "[LC] Query Status"; 134 | case "DW": return "[SW] Enumerate Dependencies"; 135 | case "RP": return "[RP] Start"; 136 | case "WP": return "[WP] Stop"; 137 | case "DT": return "[DT] Pause"; 138 | case "LO": return "[LO] Interrogate"; 139 | case "CR": return "[CR] User Defined"; 140 | } 141 | break; 142 | 143 | case 1: 144 | switch (right) 145 | { 146 | case "CC": return "[CC] List Directory"; 147 | case "DC": return "[DC] Create File"; 148 | case "LC": return "[LC] Create Subdirectory"; 149 | case "SW": return "[SW] Read Extended Attributes"; 150 | case "RP": return "[RP] Write Extended Attributes"; 151 | case "WP": return "[WP] Traverse Directory"; 152 | case "DT": return "[DT] Delete Tree"; 153 | case "LO": return "[LO] Read Attributes"; 154 | case "CR": return "[CR] Write Attributes"; 155 | } 156 | break; 157 | 158 | case 2: 159 | switch (right) 160 | { 161 | case "CC": return "[CC] Read Data"; 162 | case "DC": return "[DC] Write Data"; 163 | case "LC": return "[LC] Append Data"; 164 | case "SW": return "[SW] Read Extended Attributes"; 165 | case "RP": return "[RP] Write Extended Attributes"; 166 | case "WP": return "[WP] Execute File"; 167 | case "LO": return "[LO] Read Attributes"; 168 | case "CR": return "[CR] Write Attributes"; 169 | case "FA": return "[FA] File All"; 170 | case "FR": return "[FR] File Read"; 171 | case "FW": return "[FW] File Write"; 172 | case "FX": return "[FX] File Execute"; 173 | } 174 | break; 175 | 176 | case 3: 177 | switch (right) 178 | { 179 | case "CC": return "[CC] Read Data / List Directory"; 180 | case "DC": return "[DC] Write Data / Create File"; 181 | case "LC": return "[LC] Append Data / Create Subdirectory"; 182 | case "SW": return "[SW] Read Extended Attributes"; 183 | case "RP": return "[RP] Write Extended Attributes"; 184 | case "WP": return "[WP] Execute File / Traverse Directory"; 185 | case "DT": return "[DT] Delete Tree"; 186 | case "LO": return "[LO] Read Attributes"; 187 | case "CR": return "[CR] Write Attributes"; 188 | case "FA": return "[FA] File All"; 189 | case "FR": return "[FR] File Read"; 190 | case "FW": return "[FW] File Write"; 191 | case "FX": return "[FX] File Execute"; 192 | } 193 | break; 194 | 195 | case 4: 196 | switch (right) 197 | { 198 | case "CC": return "[CC] Query Value"; 199 | case "DC": return "[DC] Set Value"; 200 | case "LC": return "[LC] Create Subkey"; 201 | case "SW": return "[SW] Enumerate Subkeys"; 202 | case "RP": return "[RP] Notify"; 203 | case "WP": return "[WP] Create Link"; 204 | case "KA": return "[KA] Key All"; 205 | case "KR": return "[KR] Key Read"; 206 | case "KW": return "[KW] Key Write"; 207 | case "KX": return "[KX] Key Execute"; 208 | } 209 | break; 210 | } 211 | return $"[{right}] ??"; 212 | } 213 | 214 | public static string RightType(int rightsType) 215 | { 216 | switch (rightsType) 217 | { 218 | case 0: 219 | return "Service Access Rights"; 220 | case 1: 221 | return "Directory Access Rights"; 222 | case 2: 223 | return "File Access Rights"; 224 | case 3: 225 | return "File and Directory Access Rights"; 226 | case 4: 227 | return "Registry Key Access Rights"; 228 | default: 229 | return "??"; 230 | } 231 | } 232 | 233 | public int GetRuleType() 234 | { 235 | switch (_type) 236 | { 237 | case "A": 238 | return ACE.AllowRule; 239 | case "D": 240 | return ACE.DenyRule; 241 | default: 242 | return ACE.OtherRule; 243 | } 244 | } 245 | } 246 | } -------------------------------------------------------------------------------- /SDDLViewer/Logic/SecurityUnit/SecurityDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Principal; 4 | 5 | namespace SDDLViewer 6 | { 7 | public class SecurityDescriptor 8 | { 9 | private readonly string _sddl; 10 | 11 | private readonly string _owner; 12 | private readonly string _group; 13 | private readonly List _dacl; 14 | private readonly List _sacl; 15 | 16 | public readonly bool IsOk; 17 | 18 | public SecurityDescriptor(string sddl) 19 | { 20 | _sddl = sddl.Trim(); 21 | _owner = ""; 22 | _group = ""; 23 | _dacl = new List(); 24 | _sacl = new List(); 25 | var state = 0; // 1 - dacl, 2-sacl 26 | 27 | try 28 | { 29 | var index = 0; 30 | while (index < _sddl.Length) 31 | { 32 | if (_sddl[index] == 'O') 33 | { 34 | if (_sddl[index+1] != ':') 35 | { 36 | IsOk = false; 37 | return; 38 | } 39 | index += 2; 40 | _owner = ParseSID(_sddl, ref index); 41 | continue; 42 | } 43 | if (_sddl[index] == 'G') 44 | { 45 | if (_sddl[index + 1] != ':') 46 | { 47 | IsOk = false; 48 | return; 49 | } 50 | index += 2; 51 | _group = ParseSID(_sddl, ref index); 52 | continue; 53 | } 54 | if (_sddl[index] == 'D') 55 | { 56 | if (_sddl[index + 1] != ':') 57 | { 58 | IsOk = false; 59 | return; 60 | } 61 | index += 2; 62 | ParseFlags(_sddl, ref index); 63 | state = 1; 64 | continue; 65 | } 66 | if (_sddl[index] == 'S') 67 | { 68 | if (_sddl[index + 1] != ':') 69 | { 70 | IsOk = false; 71 | return; 72 | } 73 | index += 2; 74 | ParseFlags(_sddl, ref index); 75 | state = 2; 76 | continue; 77 | } 78 | if (_sddl[index] == '(') 79 | { 80 | var ace = ParseACE(_sddl, ref index); 81 | if (!ace.IsOk) 82 | { 83 | IsOk = false; 84 | return; 85 | } 86 | switch (state) 87 | { 88 | case 1: 89 | _dacl.Add(ace); 90 | break; 91 | case 2: 92 | _sacl.Add(ace); 93 | break; 94 | default: 95 | IsOk = false; 96 | return; 97 | } 98 | continue; 99 | } 100 | IsOk = false; 101 | return; 102 | } 103 | IsOk = true; 104 | } 105 | catch 106 | { 107 | IsOk = false; 108 | } 109 | } 110 | 111 | private static readonly List KnownSIDsList = new List 112 | { 113 | "AA", "AC", "AN", "AO", "AU", "BA", "BG", "BO", "BU", "CA", 114 | "CD", "CG", "CN", "CO", "CY", "DA", "DC", "DD", "DG", "DU", 115 | "EA", "ED", "ER", "ES", "HA", "HI", "IS", "IU", "LA", "LG", 116 | "LS", "LU", "LW", "ME", "MP", "MS", "MU", "NO", "NS", "NU", 117 | "OW", "PA", "PO", "PS", "PU", "RA", "RC", "RD", "RE", "RM", 118 | "RO", "RS", "RU", "SA", "SI", "SO", "SU", "SY", "UD", "WD", 119 | "WR" 120 | }; 121 | 122 | private string ParseSID(string s, ref int index) 123 | { 124 | var tmp = s.Substring(index, 2); 125 | if (KnownSIDsList.Contains(tmp)) 126 | { 127 | index += 2; 128 | return tmp; 129 | } 130 | if (tmp != "S-") 131 | throw new Exception(); 132 | var start = index; 133 | index += 2; 134 | while (index < s.Length) 135 | { 136 | if ("0123456789-".IndexOf(s[index]) == -1) 137 | break; 138 | index++; 139 | } 140 | var sid = s.Substring(start, index - start); 141 | if ((sid.IndexOf("--") != -1) || (sid[sid.Length - 1] == '-')) 142 | throw new Exception(); 143 | return sid; 144 | } 145 | 146 | private void ParseFlags(string s, ref int index) 147 | { 148 | while (index < s.Length) 149 | { 150 | if (s[index] == 'P') 151 | { 152 | index++; 153 | continue; 154 | } 155 | var tmp = s.Substring(index, 2); 156 | if ((tmp == "AI") || (tmp == "AR")) 157 | { 158 | index += 2; 159 | continue; 160 | } 161 | return; 162 | } 163 | } 164 | 165 | private ACE ParseACE(string s, ref int index) 166 | { 167 | var start = index; 168 | while (s[index] != ')') 169 | index++; 170 | index++; 171 | var rv = new ACE(s.Substring(start, index - start)); 172 | return rv; 173 | } 174 | 175 | public List GetAllSIDs() 176 | { 177 | var rv = new List(); 178 | if (!string.IsNullOrWhiteSpace(_owner)) 179 | if (!rv.Contains(_owner)) 180 | rv.Add(_owner); 181 | if (!string.IsNullOrWhiteSpace(_group)) 182 | if (!rv.Contains(_group)) 183 | rv.Add(_group); 184 | foreach (var ace in _dacl) 185 | if (!string.IsNullOrWhiteSpace(ace.GetSID())) 186 | if (!rv.Contains(ace.GetSID())) 187 | rv.Add(ace.GetSID()); 188 | foreach (var ace in _sacl) 189 | if (!string.IsNullOrWhiteSpace(ace.GetSID())) 190 | if (!rv.Contains(ace.GetSID())) 191 | rv.Add(ace.GetSID()); 192 | return rv; 193 | } 194 | 195 | public static string SIDToLong(string sid, bool translateSID) 196 | { 197 | if (sid.Length < 2) 198 | return sid; 199 | if (sid[1] == '-') 200 | { 201 | if (!translateSID) 202 | return "\t" + sid; 203 | try 204 | { 205 | var t = new SecurityIdentifier(sid).Translate(typeof(NTAccount)).ToString(); 206 | return "[??]\t" + sid + " \t" + (string.IsNullOrWhiteSpace(t) ? "??" : t); 207 | } 208 | catch 209 | { 210 | return "[??]\t" + sid; 211 | } 212 | } 213 | switch (sid) 214 | { 215 | case "AA": return "[AA]\tS-1-5-32-579 \tAccess Control Assistance Operators"; 216 | case "AC": return "[AC]\tS-1-15-2-1 \tAll App Packages"; 217 | case "AN": return "[AN]\tS-1-5-7 \tAnonymous Logged-on Users"; 218 | case "AO": return "[AO]\tS-1-5-32-548 \tAccount Operators"; 219 | case "AU": return "[AU]\tS-1-5-11 \tAuthenticated Users"; 220 | case "BA": return "[BA]\tS-1-5-32-544 \tBuilt-in (Local) Administrators"; 221 | case "BG": return "[BG]\tS-1-5-32-546 \tBuilt-in (Local) Guests"; 222 | case "BO": return "[BO]\tS-1-5-32-551 \tBackup Operators"; 223 | case "BU": return "[BU]\tS-1-5-32-545 \tBuilt-in (Local) Users"; 224 | case "CA": return "[CA]\tS-1-5-32-517 \tCertificate Server Administrators"; 225 | case "CD": return "[CD]\tS-1-5-32-574 \tUsers who can connect to certification authorities using Distributed Component Object Model (DCOM)"; 226 | case "CG": return "[CG]\tS-1-3-1 \tCreator Group"; 227 | case "CN": return "[CN]\tS-1-5-32-522 \tCloneable Controllers"; 228 | case "CO": return "[CO]\tS-1-3-0 \tCreator Owner"; 229 | case "CY": return "[CY]\tS-1-5-32-569 \tCrypto Operators"; 230 | case "DA": return "[DA]\tS-1-5-32-512 \tDomain Administrators"; 231 | case "DC": return "[DC]\tS-1-5-32-515 \tDomain Computers"; 232 | case "DD": return "[DD]\tS-1-5-32-516 \tDomain Controllers"; 233 | case "DG": return "[DG]\tS-1-5-32-514 \tDomain Guests"; 234 | case "DU": return "[DU]\tS-1-5-32-513 \tDomain Users"; 235 | case "EA": return "[EA]\tS-1-5-32-519 \tEnterprise Administrators"; 236 | case "ED": return "[ED]\tS-1-5-9 \tEnterprise Domain Controllers"; 237 | case "ER": return "[ER]\tS-1-5-32-573 \tEvent Log Readers"; 238 | case "ES": return "[ES]\tS-1-5-32-576 \tRDS Endpoint Servers"; 239 | case "HA": return "[HA]\tS-1-5-32-578 \tHyper-V Administrators"; 240 | case "HI": return "[HI]\tS-1-16-12288 \tHigh Integrity Level"; 241 | case "IS": return "[IS]\tS-1-5-32-568 \tAnonymous Internet Users"; 242 | case "IU": return "[IU]\tS-1-5-4 \tInteractive Logged-on Users"; 243 | case "LA": return "[LS]\tS-1-5-21-*-*-*-500 \tLocal Administrator Account"; 244 | case "LG": return "[LG]\tS-1-5-21-*-*-*-501 \tLocal Guest Account"; 245 | case "LS": return "[LS]\tS-1-5-19 \tLocal Service Account"; 246 | case "LU": return "[LU]\tS-1-5-32-559 \tPerformance Log Users"; 247 | case "LW": return "[LW]\tS-1-16-4096 \tLow Security Level"; 248 | case "ME": return "[ME]\tS-1-16-8192 \tMedium Security Level"; 249 | case "MP": return "[MP]\tS-1-16-8448 \tMedium Plus Security Level"; 250 | case "MS": return "[MS]\tS-1-5-32-577 \tRDS Management Servers"; 251 | case "MU": return "[MU]\tS-1-5-32-558 \tPerformance Monitor Users"; 252 | case "NO": return "[NO]\tS-1-5-32-556 \tNetwork Configuration Operators"; 253 | case "NS": return "[NS]\tS-1-5-20 \tNetwork Service Account"; 254 | case "NU": return "[NU]\tS-1-5-2 \tNetwork Logged-on Users"; 255 | case "OW": return "[OW]\tS-1-3-4 \tOwner Rights"; 256 | case "PA": return "[PA]\tS-1-5-32-520 \tGroup Policy Administrators"; 257 | case "PO": return "[PO]\tS-1-5-32-550 \tPrinter Operators"; 258 | case "PS": return "[PS]\tS-1-5-10 \tPrincipal Self/Personal Self"; 259 | case "PU": return "[PU]\tS-1-5-32-547 \tPower Users"; 260 | case "RA": return "[RA]\tS-1-5-32-575 \tRDS Remote Access Servers"; 261 | case "RC": return "[RC]\tS-1-5-12 \tRestricted Code"; 262 | case "RD": return "[RD]\tS-1-5-32-555 \tTerminal Server Users (Remote Desktop)"; 263 | case "RE": return "[RE]\tS-1-5-32-552 \tReplicator"; 264 | case "RM": return "[RM]\tS-1-5-32-580 \tRemote Management Users"; 265 | case "RO": return "[RO]\tS-1-5-32-498 \tEnterprise Read-Only Domain Controllers"; 266 | case "RS": return "[RS]\tS-1-5-32-553 \tRemote Access Servers"; 267 | case "RU": return "[RU]\tS-1-5-32-554 \tAlias to grant permissions to accounts using applications compatible with Windows NT 4.0 operating systems"; 268 | case "SA": return "[SA]\tS-1-5-32-518 \tSchema Administrators"; 269 | case "SI": return "[SI]\tS-1-16-16384 \tSystem Integrity Level"; 270 | case "SO": return "[SO]\tS-1-5-32-549 \tServer Operators"; 271 | case "SU": return "[SU]\tS-1-5-6 \tService Logged-on Users"; 272 | case "SY": return "[SY]\tS-1-5-18 \tLocal System Account"; 273 | case "UD": return "[UD]\tS-1-5-84-0-0-0-0-0 \tUser-Mode Drivers"; 274 | case "WD": return "[WD]\tS-1-1-0 \tWorld (Everyone)"; 275 | case "WR": return "[WR]\tS-1-5-33 \tWrite Restricted Code"; 276 | default: 277 | return sid; 278 | } 279 | } 280 | 281 | public List GetAllRights() 282 | { 283 | var rv = new List(); 284 | foreach (var ace in _dacl) 285 | { 286 | var l = ace.GetAllRights(); 287 | foreach (var right in l) 288 | { 289 | if (!rv.Contains(right)) 290 | rv.Add(right); 291 | } 292 | } 293 | foreach (var ace in _sacl) 294 | { 295 | var l = ace.GetAllRights(); 296 | foreach (var right in l) 297 | { 298 | if (!rv.Contains(right)) 299 | rv.Add(right); 300 | } 301 | } 302 | return rv; 303 | } 304 | 305 | public string GetOwner() 306 | { 307 | return _owner; 308 | } 309 | 310 | public string GetGroup() 311 | { 312 | return _group; 313 | } 314 | 315 | public List GetACEs() 316 | { 317 | return _dacl; 318 | } 319 | } 320 | } -------------------------------------------------------------------------------- /SDDLViewer/Logic/Win32Native.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.ConstrainedExecution; 4 | using System.Runtime.InteropServices; 5 | using System.Security.Permissions; 6 | using Microsoft.Win32.SafeHandles; 7 | 8 | namespace SDDLViewer 9 | { 10 | public static class Win32Native 11 | { 12 | [DllImport("advapi32.dll", SetLastError = true)] 13 | public static extern bool QueryServiceObjectSecurity(IntPtr serviceHandle, UInt32 secInfo, byte[] lpSecDesrBuf, int bufSize, out uint bufSizeNeeded); 14 | 15 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 16 | public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); 17 | 18 | [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] 19 | public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess); 20 | 21 | [DllImport("advapi32.dll", SetLastError = true)] 22 | [return: MarshalAs(UnmanagedType.Bool)] 23 | public static extern bool CloseServiceHandle(IntPtr hSCObject); 24 | 25 | [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto), BestFitMapping(false)] 26 | internal class WIN32_FIND_DATA 27 | { 28 | public FileAttributes dwFileAttributes; 29 | public uint ftCreationTime_dwLowDateTime; 30 | public uint ftCreationTime_dwHighDateTime; 31 | public uint ftLastAccessTime_dwLowDateTime; 32 | public uint ftLastAccessTime_dwHighDateTime; 33 | public uint ftLastWriteTime_dwLowDateTime; 34 | public uint ftLastWriteTime_dwHighDateTime; 35 | public uint nFileSizeHigh; 36 | public uint nFileSizeLow; 37 | public int dwReserved0; 38 | public int dwReserved1; 39 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 40 | public string cFileName; 41 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] 42 | public string cAlternateFileName; 43 | } 44 | 45 | internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid 46 | { 47 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 48 | [DllImport("kernel32.dll")] 49 | private static extern bool FindClose(IntPtr handle); 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] 55 | internal SafeFindHandle() 56 | : base(true) 57 | { 58 | } 59 | 60 | /// 61 | /// When overridden in a derived class, executes the code required to free the handle. 62 | /// 63 | /// 64 | /// true if the handle is released successfully; otherwise, in the 65 | /// event of a catastrophic failure, false. In this case, it 66 | /// generates a releaseHandleFailed MDA Managed Debugging Assistant. 67 | /// 68 | protected override bool ReleaseHandle() 69 | { 70 | return FindClose(handle); 71 | } 72 | } 73 | 74 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 75 | internal static extern SafeFindHandle FindFirstFile(string fileName, [In, Out] WIN32_FIND_DATA data); 76 | 77 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 78 | internal static extern bool FindNextFile(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATA lpFindFileData); 79 | } 80 | } -------------------------------------------------------------------------------- /SDDLViewer/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |