2010-07-22 19 views
4

J'ai la fonction NtCreateFile() ntdll.dll accroché pour permettre/refuser l'accès de certains fichiers. Contrairement à CreateFile() de kernel32.dll qui vous donne facilement le chemin d'accès complet au fichier en question, la fonction NtCreateFile() de ntdll.dll ne vous donne que le handle du fichier. J'ai besoin d'obtenir le chemin complet du fichier depuis un descripteur de fichier, pour autoriser/refuser l'accès. J'ai cherché autour et il ne semble pas y avoir une solution de C# fonctionnante.Obtenir un nom de fichier à partir d'un descripteur de fichier?

This La solution est en C++ et documentée par Microsoft. J'ai essayé de le porter sur C# avec peu de succès. Voici ma tentative de C# équivalent de la version C de de « l'obtention d'un nom de fichier à partir d'un descripteur de fichier »:

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; 
    } 

je, bien sûr, tous les DLLImports nécessaires et types définis par l'utilisateur. Lorsque j'utilise cette fonction sur des poignées, j'obtiens une chaîne vide en retour. Il est également assez difficile de déboguer ceci, puisque cette méthode est dans une DLL qui est injectée dans un processus cible, pas comme quelque chose que vous pouvez définir un point d'arrêt et profiter du système de débogage de Visual Studio. Je suppose que je pourrais écrire un fichier journal ou un système de trace, mais je ne suis pas encore désespéré. J'ai juste besoin d'une version C# réussie de "get filename from handle de fichier".

Des informations, des corrections de code, des liens?

+2

Je vais poser la question évidente: pourquoi dans le monde que tu fais ça? * Hooking * un appel de fonction API natif avec une charge utile gérée est assez mauvais (j'espère que vous avez sous licence Détours, car aucune autre approche n'est prise en charge), mais dans le but d'appliquer une couche de sécurité? Pourquoi ne pas utiliser la sécurité intégrée dans le système de fichiers? –

+1

On dirait que vous avez besoin de regarder l'écriture pilote minifiltre qui vous permettra de prendre des décisions d'accès dans un contexte beaucoup plus approprié. Voir: http://msdn.microsoft.com/en-us/library/ff540402(v=VS.85).aspx S'il vous plaît, pas d'accrochage ... Essayez d'ouvrir un fichier sur un partage réseau ou l'exécuter sur Vista/7 x64. Le minifiltre fonctionnera, votre solution explosera. –

Répondre

0

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

« L'exemple suivant obtient un nom de fichier à partir d'une poignée à un objet de fichier en utilisant un objet de mappage de fichiers. Il utilise le CreateFileMapping et les fonctions MapViewOfFile pour créer la cartographie. Ensuite, il utilise la fonction GetMappedFileName pour obtenir le nom du fichier. "

Le code me semble légitime, j'espère que ça aide.

+1

Euh, je ne suis pas sûr si vous avez lu mon message, mais c'est ce que j'ai dit: P – Rudi

+0

Je confirmais seulement que votre code semble correct. Et en regardant l'OP, la réponse et la dernière page MSDN, le code semble toujours correct. Quelle était la cause? –

3

Résolu moi-même. Voici le code de travail avec les références et d'autres choses.

[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

Le code que vous avez publié ici a été copié à partir du MSDN. Il a plusieurs inconvénients: Il nécessite un vrai fichier de plus de 0 octets pour fonctionner. Cela ne fonctionne pas pour les fichiers de 0 octets ni pour les répertoires. (Et je ne parle même pas sur les lecteurs réseau)

J'ai posté un code parfaitement travail ici: How to get name associated with open HANDLE