DLL Instanzenzähler auslesen



  • Hallo zusammen,

    gibt es eine Möglichkeit den aktuellen DLL-Instanzenzähler zu bestimmen? Z.B. wenn ich mich innerhalb der DLL befinde (beim Aufruf von DllMain mit DLL_PROCESS_ATTACH)?

    Wenn nicht, was wäre denn eine Alternative um an diesen Wert zu kommen?

    Vielen Dank schon einmal

    Ciao



  • Das ist eine Funktion von meinem ProcessExplorer Plugin:

    sub GetDllLoadCount(opt BOOL interactive = false),DWORD
    {
    	DWORD    dwLoadCount = 0;
    	HANDLE   hProcess;
    	HMODULE  hModule;
    	WCHAR *lpwszErrorString = NULL;
    	DWORD         dwRequired;
    	dwstring      wsz[64];
    	LDR_MODULE    module;
    
    	while (1)
    	{
    		hProcess = GetProcessHandle(0); // OpenProcess...
    		if (!hProcess)
    		{
    			MessageBoxW(g_hwndApp, L"OpenProcess failed",0,0);
    			break;
    		}
    		hModule = GetListViewInt(g_hwndDlls, L"Base", STIF_SUPPORT_HEX);
    		if (!hModule)
    		{
    			lpwszErrorString = L"invalid HMODULE";
    			break;
    		}
    		PROCESS_BASIC_INFORMATION pbi;
    		if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &dwRequired))
    		{
    			lpwszErrorString = L"NtQueryInformationProcess failed";
    			break;
    		}
    		PEB peblock;
    		if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peblock, sizeof(peblock), NULL))
    		{
    			lpwszErrorString = L"failed to read PEB";
    			break;
    		}
    		PEB_LDR_DATA  ldr;
    		if (!ReadProcessMemory(hProcess, peblock.LoaderData, &ldr, sizeof(ldr), NULL))
    		{
    			lpwszErrorString = L"failed to read PEB_LDR_DATA";
    			break;
    		}
    		if (!ldr.Initialized)
    		{
    			lpwszErrorString = L"PEB_LDR_DATA is not initialized";
    			break;
    		}
    		if (ldr.Length < 20) // Length + Initialized + SsHandle + InLoadOrderModuleList
    		{
    			lpwszErrorString = L"PEB_LDR_DATA is to small";
    			break;
    		}
    		// enumerate all loaded modules
    		LDR_MODULE *pFirst = ldr.InLoadOrderModuleList.Flink; // pointer valid in remote process context
    		LDR_MODULE *pNode  = ldr.InLoadOrderModuleList.Flink; // pointer valid in remote process context
    		while (1)
    		{
    			if (!ReadProcessMemory(hProcess, pNode, &module, sizeof(module), NULL))
    			{
    				lpwszErrorString = L"failed to read LDR_MODULE";
    				break;
    			}
    			if (module.BaseAddress == hModule)
    			{
    				dwLoadCount = module.LoadCount; // ******** deine Antwort *****
    
    				if (interactive)
    				{
    					if (module.LoadCount == -1)
    					{
    						MessageBoxW(g_hwndApp, L"Module is loaded statically", L"", 0);
    					}
    					else
    					{
    						wsprintf(wsz, L"LoadCount: %d", module.LoadCount);
    						MessageBoxW(g_hwndApp, wsz, L"", 0);
    					}
    				}
    				break;
    			}
    			pNode = module.InLoadOrderModuleList.Flink;
    			if (pNode == pFirst) break;
    		}
    		if (!dwLoadCount)
    		{
    			lpwszErrorString = L"The module was not found in process module list";
    		}
    		break;
    	}
    
    	if (hProcess)
    	{
    		CloseHandle(hProcess);
    	}
    	if (lpwszErrorString && interactive)
    	{
    		MessageBoxW(g_hwndApp, lpwszErrorString);
    	}
    	return dwLoadCount;
    }
    


  • Warum zählst Du nicht eine Variable hoch/runter bei DLL_PROCESS_ATTACH/DLL_PROCESS_DETACH !?



  • @sapero:

    Vielen Dank für die Antwort. Werd ich mal ausprobieren.
    Brauche ich den ganzen Code, oder gibt es eine Kurzversion, wenn ich mich in der DLL befinde und nur den eigenen LoadCount wissen möchte.

    Habe auch gerade gelesen, dass "NtQueryInformationProcess" in Zukunft ggf. nicht mehr unterstützt wird und das man alternative Funktionen verwenden solle. Allerdings habe ich noch keine gefunden, welche die ProcessBasicInformation füllt! Gibts da was?

    Ein paar andere Fragen noch:

    Was bedeutet das sub im folgenden Fragement und das ",DWORD" hinter dem Prozedurnamen?

    sub GetDllLoadCount(opt BOOL interactive = false),DWORD
    

    Und was bedeutet das "L" hier vor dem String?

    lpwszErrorString = L"invalid HMODULE";
    

    @Jochen Kalmbach:

    Da muss ich einen gemeinsamen Speicherbereich innerhalb der DLL verwalten, oder?
    Es wird ja jede Instanz in einen eigenen Prozess geladen und daher muss diese Variable von allen Instanzen gemeinsam verwendet werden.
    Den Aufwand hätte ich mir gern gespart.

    Oder geht das mit einer Art globalen Variable? Wenn ja, dann wäre hier interessant, wie man den verteilten Zugriff aus den einzelnen Instanzen gegenseitig abschirmt.

    Ciao



  • WAS hast Du denn genau vor? Warum willst Du das wissen?
    Du kannst natürlich eine Variable deklarieren, welche dann im Shared-Memory landet... und dann von allen Instanzen der DLL verwendet werden kann.


  • Mod

    Du könntest auch einen Semaphore nehmen um die Zählung durchzuführen.

    Nur was nützt Dir die Info, wenn der Usage Count im Moment n ist. Genau in diesem Moment ist die Information schon wieder veraltet und ein Prozess kann Deine DLL geladen haben... 😉



  • Jochen Kalmbach schrieb:

    WAS hast Du denn genau vor? Warum willst Du das wissen?

    Muss ich kurz ausholen. Die DLL bietet neben weiteren 2 Funktionen an, die eine bestimmte Aktion anstarten bzw. wieder beenden.

    Sinnvoll wäre hier also wohl ein gemeinsamer Zähler, auf den alle geladenen DLL-Instanzen gemeinsam zugreifen können (statische Variable?).

    Ich möchte nun beim Aufruf der Funktion, welche die Aktion startet wissen, wie oft dies verteilt über alle geladenen DLL-Instanzen bereits passiert ist. Dazu wird der gemeinsame Zähler ausgelesen.

    Beim Aufruf der Funktion, welche die Aktion beendet soll der gemeinsame Zähler wieder dekrementiert werden.

    Die Frage ist nun, wie man diesen gemeinsamen Zähler innerhalb einer DLL programmiert und zwar auch so, dass nebenläufige Zugriffe sequenziert werden (nur eine DLL-Instanz soll zu einem Zeitpunkt den Zähler lesen oder schreiben können).

    Geht das denn, ohne dass man ein Risiko schafft, dass eine DLL-Instanz an dem Semaphor (oder was immer dann zum Einsatz kommt) ewig wartet, weil die Instanz, die gerade den Zugriff auf den gemeinsamen Zähler hat abgeschossen wurde oder abgestürzt ist oder andere Probleme hat?

    Ciao


  • Mod

    Es ist sicherlich einfach es so zu gewährleisten das nur ein Prozess inkrementiert oder ausliest.

    Aber das ist nicht Dein Problem. Du musst gewährleisten, dass für den Zeitraum in dem Du das ganze prüfst (als Lesen, Test und Reaktion) kein weiterer Prozess dazukommt.
    Da ist es aber längst dazu gekommen,dass ein anderer Prozess die DLL evtl. schon iweder geladen hat...

    IMHO ist das auf Low-Level Ebene in der DLL nicht zu erreichen.



  • Mit einem "named" Semaphore sollte das aber gehen...
    CreateSemaphore / WaitForSingleObject / ReleaseSemaphore



  • Eine noch nicht genannte Möglichkeit für einen Instanzenzähler können auch Mutex-Objekte bieten. Jede neue Instanz versucht der Reihe nach die namentlich festgelegten Mutex-Objekte einzurichten. Belegte Objekte liefern einen Fehler. Das erste freie Objekt ist dann der Instanzenzähler, den aber dann nur diese Instanz kennt. Ob dieser sehr einfache Weg ausreicht, kann ich nicht beurteilen. Für alles weitere braucht man in irgendeiner Form Shared Memory, notfalls in einer temporären Datei.
    Ich weiss, Mutex-Objekte sollen anderen Zwecken dienen. Da sie systemglobal sind, lassen sie ich aber durchaus auch hierfür problemlos einsetzen. Der erforderliche Aufwand ist gering.



  • lol



  • asdca schrieb:

    lol

    Du schon wieder! Hast du nichts anderes zu tun und was heisst 'lol' - 'Lasse Opel laufen'? Mein Hinweis ist geeignet und könnte dem Fragesteller vielleicht helfen. Jedenfalls geht es!



  • Mein Hinweis ist geeignet

    nein.



  • Dann probiere es oder verwende die von asdca vorgeschlagenen Funktion lol(...). Diese findet sich weder bei C noch in der WinApi.



  • bernie du bist mir ne frisbee ey.


Anmelden zum Antworten