2010-07-22 90 views
4

我有掛鉤ntdll.dll的NtCreateFile()函數來允許/拒絕某些文件的訪問。與kernel32.dll的CreateFile()不同,它很容易爲您提供相關文件的完整路徑,ntdll.dll的NtCreateFile()函數僅爲您提供該文件的句柄。我需要從文件句柄中獲取文件的完整路徑,從而允許/拒絕訪問。我周圍搜索,似乎並沒有工作的C#解決方案。從文件句柄中獲取文件名?

This解決方案使用C++,並且來自Microsoft的文檔。我試圖將它移植到C#上,但沒有取得太大的成功。這是我嘗試在C#相當於C++版本「從獲得的文件句柄的文件名」的:

public string GetFileNameFromHandle(IntPtr FileHandle) 
    { 
     string fileName = String.Empty; 
     IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero; 
     UInt32 fileSizeLo = 0; 

     fileSizeLo = GetFileSize(FileHandle, fileSizeHi); 

     if (fileSizeLo == 0 && fileSizeHi == IntPtr.Zero) 
     { 
      // cannot map an 0 byte file 
      return String.Empty; 
     } 

     fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null); 

     if (fileMap != IntPtr.Zero) 
     { 
      IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1); 
      if (pMem != IntPtr.Zero) 
      { 
       StringBuilder fn = new StringBuilder(250); 
       GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, pMem, fn, 250); 
       if (fileName.Length > 0) 
       { 
        UnmapViewOfFile(pMem); 
        CloseHandle(FileHandle); 
        return fn.ToString(); 
       } 
       else 
       { 
        UnmapViewOfFile(pMem); 
        CloseHandle(FileHandle); 
        return String.Empty; 
       } 
      } 
     } 

     return String.Empty; 
    } 

我有,當然,所有必要的DLLImports和用戶定義的類型。當我在句柄上使用這個函數時,我得到一個空字符串作爲回報。調試它也很困難,因爲這種方法存在於一個注入目標進程的DLL中,而不是你可以設置斷點的東西,並享受Visual Studio的調試系統。我想我可以寫一個日誌文件或一些跟蹤系統,但我還沒那麼絕望。我只需要一個成功的C#版本的「從文件句柄獲取文件名」。

任何見解,代碼修復,鏈接?

+2

我會問一個顯而易見的問題:爲什麼在世界上你在幹什麼呢? *掛鉤*使用託管有效內容的本地API函數調用已經夠糟糕了(我當然希望您已經授權了Detours,因爲沒有其他方法可以支持),但是其目的是應用一個安全層?爲什麼不使用內置在文件系統中的安全性? – 2010-07-23 00:03:47

+1

看起來你需要看寫迷你過濾驅動程序,這將允許您在更合適的上下文中做出訪問決策。請參閱:http://msdn.microsoft.com/en-us/library/ff540402(v=VS.85).aspx請不要掛鉤...嘗試打開網絡共享上的文件或在Vista/7上運行它64。微過濾器將工作,你的解決方案將炸燬。 – 2010-07-23 06:00:07

回答

0

http://msdn.microsoft.com/en-us/library/aa366789.aspx

「以下示例從手柄到使用文件映射對象的文件對象獲取的文件名。它使用的CreateFileMapping和MapViewOfFile函數來創建的映射。接着,它使用GetMappedFileName功能獲取文件名「。代碼看起來合法,希望有所幫助。

+1

呃,我不確定你是否看過我的帖子,但這就是我所說的:P – Rudi 2010-07-22 23:25:02

+0

我只是確認你的代碼看起來不錯。看着OP,答案和最新的MSDN頁面,代碼看起來仍然合適。原因是什麼? – 2013-06-29 08:04:47

3

解決它自己。這是與參考和東西的工作代碼。

[DllImport("kernel32.dll")] 
static extern uint GetFileSize(IntPtr hFile, IntPtr lpFileSizeHigh); 

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern IntPtr CreateFileMapping(
    IntPtr hFile, 
    IntPtr lpFileMappingAttributes, 
    FileMapProtection flProtect, 
    uint dwMaximumSizeHigh, 
    uint dwMaximumSizeLow, 
    [MarshalAs(UnmanagedType.LPTStr)]string lpName); 

[Flags] 
public enum FileMapProtection : uint 
{ 
    PageReadonly = 0x02, 
    PageReadWrite = 0x04, 
    PageWriteCopy = 0x08, 
    PageExecuteRead = 0x20, 
    PageExecuteReadWrite = 0x40, 
    SectionCommit = 0x8000000, 
    SectionImage = 0x1000000, 
    SectionNoCache = 0x10000000, 
    SectionReserve = 0x4000000, 
} 

[DllImport("kernel32.dll", SetLastError = true)] 
static extern IntPtr MapViewOfFile(
    IntPtr hFileMappingObject, 
    FileMapAccess dwDesiredAccess, 
    uint dwFileOffsetHigh, 
    uint dwFileOffsetLow, 
    uint dwNumberOfBytesToMap); 

[Flags] 
public enum FileMapAccess : uint 
{ 
    FileMapCopy = 0x0001, 
    FileMapWrite = 0x0002, 
    FileMapRead = 0x0004, 
    FileMapAllAccess = 0x001f, 
    fileMapExecute = 0x0020, 
} 

[DllImport("psapi.dll", SetLastError = true)] 
public static extern uint GetMappedFileName(IntPtr m_hProcess, IntPtr lpv, StringBuilder 
     lpFilename, uint nSize); 

[DllImport("kernel32.dll", SetLastError = true)] 
static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); 

[DllImport("kernel32.dll", SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool CloseHandle(IntPtr hObject); 

public static string GetFileNameFromHandle(IntPtr FileHandle) 
{ 
    string fileName = String.Empty; 
    IntPtr fileMap = IntPtr.Zero, fileSizeHi = IntPtr.Zero; 
    UInt32 fileSizeLo = 0; 

    fileSizeLo = GetFileSize(FileHandle, fileSizeHi); 

    if (fileSizeLo == 0) 
    { 
     // cannot map an 0 byte file 
     return "Empty file."; 
    } 

    fileMap = CreateFileMapping(FileHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 1, null); 

    if (fileMap != IntPtr.Zero) 
    { 
     IntPtr pMem = MapViewOfFile(fileMap, FileMapAccess.FileMapRead, 0, 0, 1); 
     if (pMem != IntPtr.Zero) 
     { 
      StringBuilder fn = new StringBuilder(250); 
      GetMappedFileName(System.Diagnostics.Process.GetCurrentProcess().Handle, pMem, fn, 250); 
      if (fn.Length > 0) 
      { 
       UnmapViewOfFile(pMem); 
       CloseHandle(FileHandle); 
       return fn.ToString(); 
      } 
      else 
      { 
       UnmapViewOfFile(pMem); 
       CloseHandle(FileHandle); 
       return "Empty filename."; 
      } 
     } 
    } 

    return "Empty filemap handle."; 
} 
0

你張貼在這裏的代碼已經從MSDN複製。 它有幾個缺點:它需要一個大於0字節的真實文件才能工作。它不適用於0字節的文件,也不適用於目錄。 (我甚至不談論網絡驅動器)

我已經張貼在這裏完美的工作代碼: How to get name associated with open HANDLE