2010-07-22 4 views
4

У меня есть функция NtCreateFile() ntdll.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

я задать очевидный вопрос: почему в мире вы это делаете? * Hooking * собственный вызов функции API с управляемой полезной нагрузкой является достаточно плохим (я, конечно, надеюсь, что вы лицензировали Detours, потому что никакой другой подход не поддерживается), но с целью применения уровня безопасности? Почему бы не использовать защиту, встроенную в файловую систему? –

+1

Похоже, вам нужно посмотреть на использование драйвера minifilter, который позволит вам принимать решения о доступе в гораздо более подходящем контексте. См. Http://msdn.microsoft.com/en-us/library/ff540402(v=VS.85).aspx Пожалуйста, не подключайтесь ... Попробуйте открыть файл на сетевом ресурсе или запустить его в Vista/7 x64. Minifilter будет работать, ваше решение взорвется. –

ответ

0

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

«Следующий пример получает имя файла с дескриптором объекта файла с помощью объекта отображения файла. Он использует CreateFileMapping и функции MapViewOfFile для создания отображения. Далее, он использует функцию GetMappedFileName для получения имени файла. "

Код выглядит законным для меня, надеюсь, что это поможет.

+1

Э-э, я не уверен, прочитал ли я свой пост, но вот что я сказал: P – Rudi

+0

Я только подтверждал, что ваш код выглядит правильно. И, глядя на OP, ответ и последнюю страницу MSDN, код по-прежнему выглядит правильно. В чем причина? –

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

Смежные вопросы