2017-10-13 6 views
0

Je supposais que si vous utilisiez CreateFileW demandant un accès exclusif, que s'il était déjà ouvert, je devrais recevoir une violation de partage. Cependant, j'ai trouvé un exemple où ce n'est pas le cas. Si LoadLibraryEx est appelée pour charger une DLL avec le jeu d'indicateurs LOAD_LIBRARY_AS_DATAFILE, CreateFileW est renvoyé avec succès. Cependant, certaines opérations seront rejetées (comme la définition d'attributs comme la fin du fichier). Existe-t-il un meilleur moyen de détecter si ces fichiers sont ouverts? Est-ce que j'utilise CreateFileW de manière incorrecte? Le chargement d'une DLL sans l'indicateur LOAD_LIBRARY_AS_DATAFILE entraîne l'échec de CreateFileW indiquant qu'elle ne peut pas accéder au fichier car elle est utilisée par un autre processus.CreateFileW avec accès exclusif réussit lorsque LoadLibraryEx est appelé avec LOAD_LIBRARY_AS_DATAFILE

HMODULE hModule = LoadLibraryEx(L"\\Pathto\\module.dll", NULL, NULL); 
DWORD access = GENERIC_READ | GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY; 
DWORD creation = OPEN_EXISTING; 
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT; 
HANDLE file = CreateFileW(L"\\Pathto\\module.dll", access, 0, NULL, creation, flags, 0); 

Le sera ci-dessus se traduire par CreateFileW défaut avec le code d'erreur 32 (ne peut pas accéder à la cause, il est utilisé par un autre procédé), qui est le résultat attendu. Si j'ajoute le drapeau à LoadLibraryEx:

HMODULE hModule = LoadLibraryEx(name, NULL, LOAD_LIBRARY_AS_DATAFILE);  

Et utilise le même appel exactement à CreateFileW alors je me dit que c'est un succès, même si je vais avoir des problèmes plus tard lors d'une tentative de mettre fin de fichier (par exemple) . En outre, la suppression du fichier échouera avec une erreur d'accès refusé (sans l'application ou tout autre ayant un handle ouvert).

Un autre comportement impair implique des liens matériels avec des bibliothèques chargées. Si je génère un nouveau lien physique vers le module chargé, et que j'essaie de supprimer le nouveau lien physique nouvellement créé, il échoue également (PAS de poignées de fichier ouvertes, juste un module chargé). Pourquoi? Ne devrait-il pas simplement supprimer le lien et déréférencer le nombre de liens, ou programmer la suppression sur le module de fermeture puisque j'aurais pu obtenir un accès exclusif auparavant?

A noter également, le processus lui-même fonctionne dans un compte utilisateur privilégié avec les privilèges suivants a permis: SE_SECURITY_NAME, SE_BACKUP_NAME, SE_RESTORE_NAME, SE_TAKE_OWNERSHIP_NAME

Comment peut-on déterminer si vous avez vraiment un accès exclusif à un fichier lorsque les bibliothèques sont chargées?

Editer: Juste pour vérifier deux fois, je n'ai vérifié aucune autre poignée ouverte en plus de charger le module via l'outil SysInternals "handle".

+1

Je suppose que les données sont simplement placées en mémoire mais le fichier n'est pas maintenu ouvert. https://blogs.msdn.microsoft.com/oldnewthing/20141120-00/?p=43573 peut être pertinent. –

+0

Je pense qu'il y a plus que ça. Il est clairement encore référencé par le processus propriétaire (listé comme une DLL pour la vie du processus si vous regardez dans SysInternals Process Explorer). Votre lien indique également qu'il est mappé dans l'espace d'adressage du processus. Aussi, pourquoi les downvotes sans explication? Ceci est facilement reproductible. Si c'est une question "stupide", veuillez expliquer pourquoi. – ConfusedDeveloper

+0

Le blog de Raymond suggère qu'il ne devrait pas être répertorié comme une DLL si elle a seulement été ouverte en tant que fichier de données. Btw les downvotes n'étaient pas à moi. –

Répondre

1

votre cas peut être plus clair montré dans le prochain essai

ULONG TestImageAccess(PCWSTR name, BOOL bImage, BOOL bRequestWriteAccess) 
{ 
    SetLastError(0); 

    HANDLE hFile = CreateFileW(name, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 

    if (hFile != INVALID_HANDLE_VALUE) 
    { 
     HANDLE hSection = CreateFileMappingW(hFile, 0, 
      bImage ? PAGE_READONLY|SEC_IMAGE : PAGE_READONLY|SEC_COMMIT, 0, 0, 0); 

     CloseHandle(hFile); 

     if (hSection) 
     { 
      hFile = CreateFileW(name, 
       bRequestWriteAccess ? GENERIC_WRITE : GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 

      CloseHandle(hSection); 

      if (hFile != INVALID_HANDLE_VALUE) 
      { 
       CloseHandle(hFile); 
      } 
     } 
    } 

    return GetLastError(); 
} 

void TestImageAccess(PCWSTR filename) 
{ 
    TestImageAccess(filename, TRUE, TRUE); // ERROR_SHARING_VIOLATION 
    TestImageAccess(filename, FALSE, TRUE); // NOERROR 
    TestImageAccess(filename, TRUE, FALSE); // NOERROR 
    TestImageAccess(filename, FALSE, FALSE);// NOERROR 
} 

nous avons ERROR_SHARING_VIOLATION lorsque nous demandons écrire un accès au fichier et le fichier cartographié comme l'image

ce cas est décrit dans Executable Images :

Si l'utilisateur veut un accès en écriture au fichier, assurez-vous qu'il n'y a pas un mappage de processus ce fichier comme une image

l'appel à MmFlushImageSection avec MmFlushForWrite échouent et vous avez obtenu STATUS_SHARING_VIOLATION - exactement sur cette ligne.

LoadLibraryEx avec le drapeau LOAD_LIBRARY_AS_DATAFILE créer la section sur le fichier avec SEC_COMMIT quand avec 0 en drapeau - avec SEC_IMAGE - afin section d'image

les privilèges ici absolu non liés

Comment peut-on déterminer si vous avez vraiment avoir un accès exclusif à un fichier lorsque les bibliothèques sont chargées?

Ouvrez simplement le fichier avec l'accès dont vous avez besoin et faites ce dont vous avez besoin. et oui, vous pouvez obtenir l'erreur ERROR_USER_MAPPED_FILE lorsque vous essayez de tronquer le fichier mappé. mais ici rien ne peut être fait. exemple 2

ULONG TestImage2(PCWSTR name) 
{ 
    HANDLE hFile = CreateFileW(name, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 

    if (hFile != INVALID_HANDLE_VALUE) 
    { 
     HANDLE hSection = CreateFileMappingW(hFile, 0, PAGE_READONLY|SEC_COMMIT, 0, 0, 0); 

     CloseHandle(hFile); 

     if (hSection) 
     { 
      PVOID pv = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); 

      CloseHandle(hSection); 

      if (pv) 
      { 
       hFile = CreateFileW(name,GENERIC_WRITE|GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); 

       if (hFile != INVALID_HANDLE_VALUE) 
       { 
        FILE_END_OF_FILE_INFO eof = { }; 
        // ERROR_USER_MAPPED_FILE will be here 
        SetFileInformationByHandle(hFile, FileEndOfFileInfo, &eof, sizeof(eof)); 
        CloseHandle(hFile); 
       } 

       UnmapViewOfFile(pv); 
      } 
     } 
    } 

    return GetLastError(); 
} 
+0

Merci beaucoup pour la réponse détaillée.Comme une solution de contournement j'ai décidé que je peux essayer de définir la fin du marqueur de fichier (même taille) via SetFileInformationByHandle et vérifier l'erreur 1224 (ERROR_USER_MAPPED_FILE) comme un moyen de détecter cela. Existe-t-il une meilleure façon de déterminer si un processus a une section de fichier mappée? – ConfusedDeveloper

+0

@ConfusedDeveloper - pour ce que vous avez besoin de le détecter? quel est votre objectif? et même vous en quelque sorte détecter cela, après cela à tout moment la situation peut changer. Alors, quel est le sens de ce genre de détection? ta vraie cible est quoi? – RbMm

+0

et définir la fin du fichier à moins de taille que la section - ce n'est pas vérifier, mais les dommages de données de fichier – RbMm