using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Permissions; using Microsoft.Win32; using System.Runtime.InteropServices; using System.Diagnostics; using System.Collections; using System.Threading; using System.Security.AccessControl; using System.Security.Principal; using Microsoft.Win32.SafeHandles; using System.ComponentModel; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Diagnostics; using System.Text; using System.Threading; namespace EnumerateMutexACL { class Win32API { [DllImport("ntdll.dll")] public static extern int NtQueryObject (IntPtr ObjectHandle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, ref int returnLength); [DllImport("kernel32.dll", SetLastError = true)] public static extern uint QueryDosDevice (string lpDeviceName, StringBuilder lpTargetPath, int ucchMax); [DllImport("ntdll.dll")] public static extern uint NtQuerySystemInformation (int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int returnLength); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess (ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll")] public static extern int CloseHandle (IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateHandle (IntPtr hSourceProcessHandle, ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll")] public static extern IntPtr GetCurrentProcess (); public enum ObjectInformationClass : int { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [Flags] public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VMOperation = 0x00000008, VMRead = 0x00000010, VMWrite = 0x00000020, DupHandle = 0x00000040, SetInformation = 0x00000200, QueryInformation = 0x00000400, Synchronize = 0x00100000 } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_BASIC_INFORMATION { // Information Class 0 public int Attributes; public int GrantedAccess; public int HandleCount; public int PointerCount; public int PagedPoolUsage; public int NonPagedPoolUsage; public int Reserved1; public int Reserved2; public int Reserved3; public int NameInformationLength; public int TypeInformationLength; public int SecurityDescriptorLength; public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime; } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_TYPE_INFORMATION { // Information Class 2 public UNICODE_STRING Name; public int ObjectCount; public int HandleCount; public int Reserved1; public int Reserved2; public int Reserved3; public int Reserved4; public int PeakObjectCount; public int PeakHandleCount; public int Reserved5; public int Reserved6; public int Reserved7; public int Reserved8; public int InvalidAttributes; public GENERIC_MAPPING GenericMapping; public int ValidAccess; public byte Unknown; public byte MaintainHandleDatabase; public int PoolType; public int PagedPoolUsage; public int NonPagedPoolUsage; } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_NAME_INFORMATION { // Information Class 1 public UNICODE_STRING Name; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] public struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_INFORMATION { // Information Class 16 public int ProcessID; public byte ObjectTypeNumber; public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT public ushort Handle; public int Object_Pointer; public UInt32 GrantedAccess; } public const int MAX_PATH = 260; public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public const int DUPLICATE_SAME_ACCESS = 0x2; } class Token { [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000; private static uint STANDARD_RIGHTS_READ = 0x00020000; private static uint TOKEN_ASSIGN_PRIMARY = 0x0001; private static uint TOKEN_DUPLICATE = 0x0002; private static uint TOKEN_IMPERSONATE = 0x0004; private static uint TOKEN_QUERY = 0x0008; private static uint TOKEN_QUERY_SOURCE = 0x0010; private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020; private static uint TOKEN_ADJUST_GROUPS = 0x0040; private static uint TOKEN_ADJUST_DEFAULT = 0x0080; private static uint TOKEN_ADJUST_SESSIONID = 0x0100; private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY); private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID); [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid); public const string SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege"; public const string SE_AUDIT_NAME = "SeAuditPrivilege"; public const string SE_BACKUP_NAME = "SeBackupPrivilege"; public const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege"; public const string SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege"; public const string SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege"; public const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege"; public const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege"; public const string SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege"; public const string SE_DEBUG_NAME = "SeDebugPrivilege"; public const string SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege"; public const string SE_IMPERSONATE_NAME = "SeImpersonatePrivilege"; public const string SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege"; public const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"; public const string SE_INC_WORKING_SET_NAME = "SeIncreaseWorkingSetPrivilege"; public const string SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege"; public const string SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege"; public const string SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege"; public const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege"; public const string SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege"; public const string SE_RELABEL_NAME = "SeRelabelPrivilege"; public const string SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege"; public const string SE_RESTORE_NAME = "SeRestorePrivilege"; public const string SE_SECURITY_NAME = "SeSecurityPrivilege"; public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; public const string SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege"; public const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege"; public const string SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege"; public const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege"; public const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege"; public const string SE_TCB_NAME = "SeTcbPrivilege"; public const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege"; public const string SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege"; public const string SE_UNDOCK_NAME = "SeUndockPrivilege"; public const string SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege"; [StructLayout(LayoutKind.Sequential)] public struct LUID { public UInt32 LowPart; public Int32 HighPart; } public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001; public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002; public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004; public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000; [StructLayout(LayoutKind.Sequential)] public struct TOKEN_PRIVILEGES { public UInt32 PrivilegeCount; public LUID Luid; public UInt32 Attributes; } [StructLayout(LayoutKind.Sequential)] public struct LUID_AND_ATTRIBUTES { public LUID Luid; public UInt32 Attributes; } // Use this signature if you do not want the previous state [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 Zero, IntPtr Null1, IntPtr Null2); public static IntPtr GetToken(IntPtr hProcess) { IntPtr hToken; LUID luidSEDebugNameValue; TOKEN_PRIVILEGES tkpPrivileges; if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken)) { Console.WriteLine("OpenProcessToken() failed, error = {0} . SeDebugPrivilege is not available", Marshal.GetLastWin32Error()); return IntPtr.Zero; } else { Console.WriteLine("OpenProcessToken() successfully"); } if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out luidSEDebugNameValue)) { Console.WriteLine("LookupPrivilegeValue() failed, error = {0} .SeDebugPrivilege is not available", Marshal.GetLastWin32Error()); Win.CloseHandle(hToken); return IntPtr.Zero; } else { Console.WriteLine("LookupPrivilegeValue() successfully"); } tkpPrivileges.PrivilegeCount = 1; tkpPrivileges.Luid = luidSEDebugNameValue; tkpPrivileges.Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, false, ref tkpPrivileges, 0, IntPtr.Zero, IntPtr.Zero)) { Console.WriteLine("LookupPrivilegeValue() failed, error = {0} .SeDebugPrivilege is not available", Marshal.GetLastWin32Error()); return IntPtr.Zero; } else { Console.WriteLine("SeDebugPrivilege is now available"); return hToken; } } } class Win { [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenMutex(uint dwDesiredAccess, bool bInheritHandle, string lpName); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); } class Program { static void testMutex(string mutexName) { Mutex m = null; bool doesNotExist = false; bool unauthorized = false; // Attempt to open the named mutex. try { m = Mutex.OpenExisting(mutexName, MutexRights.FullControl); } catch (WaitHandleCannotBeOpenedException) { Console.WriteLine("Mutex does not exist."); doesNotExist = true; } catch (UnauthorizedAccessException ex) { Console.WriteLine("Unauthorized access: {0}", ex.Message); unauthorized = true; } if (unauthorized) { // Open the mutex to read and change the access control // security. The access control security defined above // allows the current user to do this. // try { m = Mutex.OpenExisting(mutexName, MutexRights.ReadPermissions | MutexRights.ChangePermissions); // Get the current ACL. This requires // MutexRights.ReadPermissions. MutexSecurity mSec = m.GetAccessControl(); string user = Environment.UserDomainName + "\\" + Environment.UserName; // First, the rule that denied the current user // the right to enter and release the mutex must // be removed. MutexAccessRule rule = new MutexAccessRule(user, MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Deny); mSec.RemoveAccessRule(rule); // Now grant the user the correct rights. // rule = new MutexAccessRule(user, MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow); mSec.AddAccessRule(rule); // Update the ACL. This requires // MutexRights.ChangePermissions. m.SetAccessControl(mSec); Console.WriteLine("Updated mutex security."); // Open the mutex with (MutexRights.Synchronize // | MutexRights.Modify), the rights required to // enter and release the mutex. // m = Mutex.OpenExisting(mutexName); } catch (UnauthorizedAccessException ex) { Console.WriteLine("Unable to change permissions: {0}", ex.Message); return; } } return; } private static void parseMutex(string name) { Mutex m; string mutexName = name; try { m = Mutex.OpenExisting(mutexName); MutexSecurity mSec = m.GetAccessControl(); Console.WriteLine(mSec.ToString()); } catch (WaitHandleCannotBeOpenedException) { Console.WriteLine("Mutex does not exist."); } catch (UnauthorizedAccessException ex) { Console.WriteLine("Unauthorized access: {0}", ex.Message); try { m = Mutex.OpenExisting(mutexName, MutexRights.FullControl); MutexSecurity mSec = m.GetAccessControl(); ShowSecurity(mSec); } catch (Exception e) { Console.WriteLine("*******Unauthorized access: {0}", ex.Message); } } } private static void ShowSecurity(MutexSecurity security) { Console.WriteLine("\r\nAccess rules:\r\n"); foreach (MutexAccessRule ar in security.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine(" User: {0}", ar.IdentityReference); Console.WriteLine(" Type: {0}", ar.AccessControlType); Console.WriteLine(" Rights: {0}", ar.MutexRights); Console.WriteLine(); } } static void Main(string[] args) { IntPtr p, pp, ppp, pppp, hToken; string mutexname = "MSCTF.Asm.MutexDefault1"; const uint DUPLICATE_CLOSE_SOURCE = 0x00000001; const UInt32 MUTEX_ALL_ACCESS = 0x1F0001; testMutex(mutexname); parseMutex(mutexname); p = Process.GetProcessesByName("calc")[0].Handle; hToken = Token.GetToken(p); pp = Win.CreateMutex(IntPtr.Zero, false, mutexname); if (Marshal.GetLastWin32Error() == 183) Console.WriteLine("CreateMutex() Found mutex {0} already existing, using handle {1}", mutexname, pp); else if (Marshal.GetLastWin32Error() == 0) Console.WriteLine("CreateMutex() did not find mutex {0}, creating new mutex: handle {1}", mutexname, pp); else Console.WriteLine("CreateMutex() failed, error = {0}", Marshal.GetLastWin32Error()); pp = Win.OpenMutex(MUTEX_ALL_ACCESS, false, mutexname); if (pp == IntPtr.Zero) Console.WriteLine("OpenMutex() failed, error = {0}", Marshal.GetLastWin32Error()); else Console.WriteLine("OpenMutex() Found mutex {0}, using handle {1}", mutexname, pp); ppp = Process.GetCurrentProcess().Handle; pppp = IntPtr.Zero; //Process.GetProcessesByName("calc")[0].Handle; if (!Win.DuplicateHandle(p, pp, ppp, out pppp, MUTEX_ALL_ACCESS, false, DUPLICATE_CLOSE_SOURCE)) Console.WriteLine("DuplicateHandle() failed, error = {0}", Marshal.GetLastWin32Error()); if (Win.OpenMutex(MUTEX_ALL_ACCESS, false, mutexname) == IntPtr.Zero) Console.WriteLine("OpenMutex() failed, error = {0} -- YOU WIN", Marshal.GetLastWin32Error()); else Console.WriteLine("OpenMutex() Found mutex {0}, using handle {1} -- YOU FAILED", mutexname, pp); Win.CloseHandle(hToken); Win.CloseHandle(pppp); Console.Read(); return; } } }