Wird eine DLL entfernt, wenn die DLL, die sie geladen hat, entladen wird?

8

Nehmen Sie eine Standard-Windows-Anwendung. Es lädt eine DLL mit LoadLibrary, um eine Funktion darin aufzurufen (wir nennen das DLL_A). Diese Funktion lädt eine andere DLL (wir nennen sie DLL_B). Die Anwendung entlädt jetzt die DLL_A DLL mithilfe von FreeLibrary, da sie nicht mehr benötigt wird.

Die Frage ist: Ist DLL_B noch im Speicher und geladen?

Ist das etwas, auf das ich mich verlassen kann, oder ist es undokumentiert?

    
mj2008 05.03.2009, 16:46
quelle

4 Antworten

10

Nein. DLL_B wird nicht entladen. Der Aufruf LoadLibrary() von DLL_A erhöht den Ladezähler für DLL_B . Da für FreeLibrary() kein entsprechender DLL_B -Aufruf vorhanden ist, wird der Refcount nicht auf Null gesetzt.

Aus der LoadLibrary () -Dokumentation:

  

Das System behält einen pro-Prozess bei   Referenzzähler auf allen geladenen Modulen.   Durch den Aufruf von LoadLibrary wird der Wert von   Referenzzahl Anrufen der   FreeLibrary oder   FreeLibraryAndExitThread-Funktion   dekrementiert den Referenzzähler. Das   System entlädt ein Modul, wenn es   Referenzzählung erreicht Null oder wann   der Prozess endet (unabhängig von   die Referenzzahl).

    
Michael Burr 05.03.2009, 16:49
quelle
3

Sie haben ein Handle-Leck in dem Fall:

%Vor%

Kein Code wird implizit von einem Modul ausgeführt, das entladen wird, um die geladenen Module zu entladen.

Da kein Code ausgeführt wird, um die Referenzzählung zu verringern, wird das Modul B niemals entladen.

Hier sind die Regeln zum Laden / Entladen von DLLs:

  • Jeder Aufruf von LoadLibrary und LoadLibraryEx erhöht die Referenzzahl für dieses Modul. Dies ist nur im Kontext des aufrufenden Prozesses, nicht über Prozessgrenzen hinweg.
  • Jeder Aufruf von FreeLibrary oder FreeLibraryAndExitThread dekrementiert den Referenzzähler.
  • Wenn der Referenzzähler 0 erreicht, wird er entladen.
  • Wenn Windows sieht, dass Ihr Programm geschlossen ist, werden alle durchgesickerten unbestückten Module entladen.
  • Je nachdem, was Sie gerade tun, DllCanUnloadNow könnte nützlich sein Sie.

Immer noch im Speicher vs noch geladen:

Es gibt keine Garantie, dass Ihr Modul zu einem bestimmten Zeitpunkt aus dem Speicher freigegeben wird, wenn die Referenz 0 erreicht. Sie sollten das Modul jedoch so betrachten, als ob es entladen wird, wenn der Referenzzähler 0 erreicht.

Stoppen des Entladens der DLL:

Um das Entladen der DLL zu erzwingen, können Sie

versuchen
  • Das System ruft DllMain mit dem Flag DLL_PROCESS_DETACH auf. Du könntest versuchen, nicht durch irgendeine Art von Blockieroperation von diesem zurückzukommen.
  • Sie könnten versuchen, LoadLibrary innerhalb der DLL aufzurufen, die Sie nicht entladen können. (Selbstlade)

Bearbeiten:

Sie haben erwähnt, dass Ihr Ziel es ist, Code in das laufende Programm zu injettieren und dass Sie den Griff absichtlich durchlecken wollten.

Das ist in Ordnung, aber wenn Sie diese Operation viel ausführen, kann dies zu einem Absturz in Ihrem Quellprogramm führen, weil zu viele Handles verwendet werden oder schließlich zu viel Speicher verwendet wird.

Sie können FALSE von Ihrem DllMain zurückgeben, damit es nicht geladen wird, damit Sie keinen Speicher verschwenden. Sie tun dies, wenn fdwReason DLL_PROCESS_ATTACH ist. Sie können hier mehr darüber lesen .

Wenn Sie versuchen, eine DLL zu emulieren und Ihre eigenen zusätzlichen Funktionen hinzuzufügen, müssen Sie alle Funktionen implementieren, die von der Quell-DLL implementiert werden, und jeden Aufruf an die Quell-DLL delegieren.

    
Brian R. Bondy 05.03.2009 16:56
quelle
1

Lesen Sie den Abschnitt Hinweise für eine detaillierte Erläuterung.

Der wichtigste Punkt ist:

  

Das System behält für jedes geladene Modul eine pro-process-Referenzzählung bei

und weiter unten

  

Wenn die Referenzzählung eines Moduls null erreicht oder der Prozess beendet wird, entlädt das System das Modul aus dem Adressraum des Prozesses

Von MSDN :

  

Gibt das geladene DLL-Modul (dynamic-link library) frei und dekrementiert bei Bedarf die Anzahl der Referenzen. Wenn der Referenzzähler null erreicht, wird das Modul aus dem Adressraum des aufrufenden Prozesses entladen und das Handle ist nicht mehr gültig.

    
dirkgently 05.03.2009 16:49
quelle
1

DLLs in Windows werden als Referenz gezählt. Wenn A entladen ist, dekrementieren Sie die Referenzzählung auf A, wenn sie Null erreicht, wird sie entladen und (unter der Annahme, dass keine Fehler im Code vorhanden sind) die Referenzzahl auf B verringern. Wenn die Refcount auf B auf Null geht, wird sie entladen . Es ist möglich, dass DLL C einen Refcount auf B hat, und das Entladen von A wird B nicht entladen.

    
grieve 05.03.2009 16:50
quelle

Tags und Links