How do I open a directory with CreateFile in C# to examine entries of deleted files? Or is it now impossible? I remember way back when being able to open a directory on an NTFS partition using CreateFile or possibly CreateFileEx, but that was using C++ under an older OS.
So far I've got the Windows API calls (to kernel32.dll) working enough to read an existing file but it won't open a directory:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using System.Security;
namespace Kernel_Test
{
class Program
{
static void Main(string[] args)
{
Kernel_Tools cKT = new Kernel_Tools();
cKT.DoTest("C:\\Temp");
cKT.DoTest("C:\\Temp\\test.txt");
}
}
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
class Kernel_Tools
{
public void DoTest(string cTarget)
{
IntPtr cFile = NativeMethods.CreateFile(
cTarget,
NativeMethods.GENERIC_READ /* 0 or NativeMethods.GENERIC_READ */ ,
FileShare.Read,
IntPtr.Zero /* failed try: NativeMethods.OPEN_ALWAYS */,
(FileMode) NativeMethods.OPEN_EXISTING,
NativeMethods.FILE_FLAG_BACKUP_SEMANTICS /* 0 */ ,
IntPtr.Zero);
Console.WriteLine(cTarget);
Console.WriteLine(cFile);
if ((int)cFile != -1)
{
int length = 20;
byte[] bytes = new byte[length];
int numRead = 0;
int ErrorCheck = NativeMethods.ReadFile(cFile, bytes, length, out numRead, IntPtr.Zero);
// This sample code will not work for all files.
//int r = NativeMethods.ReadFile(_handle, bytes, length, out numRead, IntPtr.Zero);
// Since we removed MyFileReader's finalizer, we no longer need to
// call GC.KeepAlive here. Platform invoke will keep the SafeHandle
// instance alive for the duration of the call.
if (ErrorCheck == 0)
{
Console.WriteLine("Read failed.");
NativeMethods.CloseHandle(cFile);
return;
//throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (numRead < length)
{
byte[] newBytes = new byte[numRead];
Array.Copy(bytes, newBytes, numRead);
bytes = newBytes;
}
for (int i = 0; i < bytes.Length; i++)
Console.Write((char)bytes[i]);
Console.Write("\n\r");
// Console.WriteLine();
NativeMethods.CloseHandle(cFile);
}
}
}
[SuppressUnmanagedCodeSecurity()]
internal static class NativeMethods
{
// Win32 constants for accessing files.
internal const int GENERIC_READ = unchecked((int)0x80000000);
internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000);
internal const int OPEN_EXISTING = unchecked((int)3);
// Allocate a file object in the kernel, then return a handle to it.
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
internal extern static IntPtr CreateFile(
String fileName,
int dwDesiredAccess,
System.IO.FileShare dwShareMode,
IntPtr securityAttrs_MustBeZero,
System.IO.FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile_MustBeZero);
// Use the file handle.
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(
IntPtr handle,
byte[] bytes,
int numBytesToRead,
out int numBytesRead,
IntPtr overlapped_MustBeZero);
// Free the kernel's file object (close the file).
[DllImport("kernel32", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal extern static bool CloseHandle(IntPtr handle);
}
}
Edit 1: Modified it to use OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, and GENERIC_READ.
This will open and display the start of a the specified text file as did the original when run as a Vista administrative user, but it still fails to open the directory. I'm guessing I need the SE_BACKUP_NAME and SE_RESTORE_NAME privileges but am unsure how to specify those other than to write this as a service that runs as Local Machine (something I have only the foggiest idea of how to do).