Une DLL est-elle supprimée si la DLL chargée est déchargée?

Prenez une application Windows standard. Il charge une DLL en utilisant LoadLibrary pour y appeler une fonction (nous appellerons cette DLL_A). Cette fonction charge une autre DLL (nous l’appellerons DLL_B). L’application décharge maintenant la DLL DLL_A en utilisant FreeLibrary car elle ne le nécessite plus.

La question est: DLL_B est-il toujours en mémoire et chargé?

Est-ce quelque chose sur lequel je peux compter, ou est-ce que c’est sans papiers?

Non, DLL_B ne sera pas déchargé. L’appel LoadLibrary() effectué par DLL_A incrémente le nombre de charges pour DLL_B . Comme il n’y a pas d’appel FreeLibrary() correspondant à DLL_B , le refcount ne sera pas nul.

A partir des documents LoadLibrary ():

Le système gère un nombre de références par processus sur tous les modules chargés. L’appel de LoadLibrary incrémente le nombre de références. L’appel de la fonction FreeLibrary ou FreeLibraryAndExitThread décrémente le nombre de références. Le système décharge un module lorsque son compte de référence atteint zéro ou lorsque le processus se termine (quel que soit le compte de référence).

Vous aurez une fuite de poignée dans le cas:

 Program -Load> Dll A -Load> Dll B -Unload> Dll A 

Aucun code n’est implicitement exécuté par un module en cours de déchargement pour décharger les modules chargés.

Aucun code n’étant exécuté pour diminuer le compte de référence, le module B ne sera jamais déchargé.

Voici les règles de chargement / déchargement des DLL:

  • Chaque appel à LoadLibrary et LoadLibraryEx augmentera le nombre de références pour ce module. Cela se situe dans le contexte du processus d’appel uniquement, et non à travers les limites du processus.
  • Chaque appel à FreeLibrary ou FreeLibraryAndExitThread décrémentera le nombre de références.
  • Lorsque le compte de référence atteint 0, il sera déchargé.
  • Lorsque Windows voit que votre programme est fermé , tous les modules déchargés qui ont fui sont alors déchargés.
  • Selon ce que vous faites, DllCanUnloadNow pourrait vous être utile.

Toujours en mémoire vs encore chargé:

Il n’y a aucune garantie que votre module sera libéré de la mémoire à un moment donné lorsque la référence atteindra 0. Mais vous devriez considérer le module comme s’il était déchargé lorsque le nombre de références atteint 0.

Arrêter le déchargement de la DLL:

Pour forcer le déchargement de la DLL, vous pouvez essayer

  • Le système appelle DllMain avec l’indicateur DLL_PROCESS_DETACH. Vous pouvez essayer de ne pas y revenir via une opération de blocage.
  • Vous pouvez essayer d’appeler LoadLibrary depuis la DLL que vous ne souhaitez pas pouvoir décharger. (Auto-charge)

Modifier:

Vous avez mentionné que votre objective est d’injecter du code dans le programme en cours d’exécution et que vous vouliez fuir le handle volontairement.

C’est bien, mais si vous exécutez beaucoup cette opération, cela peut entraîner un plantage dans votre programme source, car trop de descripteurs seront utilisés ou trop de mémoire sera utilisée.

Vous pouvez renvoyer FALSE à partir de votre DllMain pour l’empêcher d’être chargé afin que vous ne perdiez pas de mémoire. Vous faites cela lorsque fdwReason est DLL_PROCESS_ATTACH. Vous pouvez en savoir plus à ce sujet ici .

Si vous essayez d’émuler une DLL et d’append vos propres fonctionnalités supplémentaires, vous devrez implémenter toutes les fonctions implémentées par la DLL source et déléguer chaque rappel à la DLL source.

Lisez la section Remarques pour une explication détaillée.

L’essentiel à noter est:

Le système gère un nombre de références par processus pour chaque module chargé

et plus bas

Lorsque le compte de référence d’un module atteint zéro ou que le processus se termine, le système décharge le module de l’espace d’adressage du processus.

De MSDN :

Libère le module DLL (Dynamic-Link Library) chargé et, si nécessaire, décrémente son compte de référence. Lorsque le compteur de références atteint zéro, le module est déchargé de l’espace adresse du processus appelant et le descripteur n’est plus valide.

Les DLL des fenêtres sont comptées. Lorsque A est déchargé, vous décrémentez le compte de référence sur A, s’il atteint zéro, il sera déchargé et (en supposant qu’il n’y ait pas de bogue dans le code) décrémente le compte de référence sur B. Si le compte sur B passe à zéro, il sera déchargé . Il est possible que DLL C ait un refcount sur B et que le déchargement A ne décharge pas B.