![]() |
Umgebungsvariable eines anderen, laufenden Programms ändern
Hallo Gemeinde,
ich suche nach einer Lösung, eine Umgebungsvariable in einem schon laufenden Programm zu verändern. Ich meine mich daran erinnern zu können, dass ich irgendwo dazu schon mal Code gefunden hatte, habe aber keine Ahnung mehr, wo das war. Hintergrund: Ich starte aus meinem Programm zwei weitere Anwendungen, die asynchron miteinander kommuzieren. Mein Programm und Programm A werden dann irgendwann wieder beendet, Programm B läuft aber weiter. Wenn mein Programm nun wieder ausgeführt wird, möchte ich nicht Programm B erst abschießen und dann mit einer neuen Umgebungsvariable neu starten sondern einfach die Instanze beigehalten und den Wert der Variable XY in der Sitzung ändern. Es kann davon ausgegangen werden, dass sowohl mein Programm als auch das Programm B unter dem gleichen Benutzer mit dem gleichen Token laufen. Hat hierzu jemand eine Idee? Tausend Dank Tiemo |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Moin Tiemo,
bei der Konstellation wäre es vielleicht einfacher der laufenden Instanz von Programm B einfach auf anderem Wege, z.B., per WM_COPYDATA den gewünschten neuen Wert zu übergeben. Das Programm kann es dann, wenn's denn unbedingt eine Umgebungsvariable sein muss, auch in sein Environment eintragen. Das dürfte dann auch unter Vista funktionieren. Die Variante direkt das Environment eines fremden Prozesses zu manipulieren habe ich hier in der DP auch schon mal beschrieben, aber wenn alle beteiligten Programme von Dir stammen, lohnt sich der Aufwand hier wohl nicht. Für Vista habe ich da auch noch keine Lösung ;-) |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Bei so etwas weht auch immer ein leichter Hauch von Virus durch die Luft (zumindest für den Scanner) ;)
|
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Zitat:
Ausserdem gibt es für solche Vorgehensweisen auch legitime Anwendungen. ;-) |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Ich habe vergessen zu erwähnen, dass Programm A und B nicht von mir sind, so dass ich darauf leider keinen Einfluss nehmen kann.
|
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Und noch etwas: Ich möchte natürlich keinen Virus schreiben. Meine Applikation ist ein Konfigurationsprogramm für eine 3D CAD Anwendung. Dieses Konfigurationsprogramm setzt eine Reihe von Voreinstellungen und startet dann das CAD Programm. Abhängig von den Einstellungen zieht das CAD unterschiedliche Lizenzen. Es ist auch möglich, verschiedene Versionen des CAD Programms zu starten.
Programm B wiederum ist eine Helfer-Anwendung für ein dazugehöriges PDM System. B läuft asynchron zum CAD Programm, so dass beim Beenden des CAD Programmes die Daten trotzdem noch auf den Server hochgeschoben werden können. B braucht aber den Pfad zum CAD, der sich wiederum durch mein Programm beim Start auswählen lässt. Wenn B jetzt aber nicht gestartet wird, kann ich den Pfad nicht ändern. Abschießen und Neustarten ist auch Mist, da evtl. noch Daten zum Server geschoben werden. Das nur zur Beruhigung und Erklärung... |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Moin Tiemo,
das Du einen Virus schreiben willst, haben Detlef und ich auch nicht angenommen, aber die Techniken die erforderlich sind (Manipulation eines fremden Adressraumes) kann von einem Virenscanner durchaus als verdächtig angesehen werden. Um Umgebungsvariablen eines anderen Prozesses zu manipulieren, müsstest Du den Environmentblock dort überschreiben. Die einfachste Variante wäre es das eigene Environment zu ändern, und dann diesen Speicherbereich in den korrespondierenden Speicherbereich des Zielprozesses zu kopieren (Wichtig: Ab Windows 2000 muss man hierzu den Block mit Widestrings verwenden) Eine andere Möglichkeit wäre es, den Code der die Umgebungsvariablen setzt in den Zielprozess zu injizieren und dort zu starten, um gezielt die Umgebungsvariablen zu ändern (das habe ich allerdings noch nicht umgesetzt). Was ich mich allerdings die ganze Zeit über frage: Wann zieht das Programm eigentlich die Konfiguration? Erwarten würde ich, dass dieses bei Programmstart, was die Änderung der Konfiguration bei laufendem Programm natürlich unmöglich machen würde ;-) |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Hallo Christian,
vielen Dank für die Hilfestellung. Das mit dem EnvironmentBlock hatte ich schon mal probiert, bin aber gescheitert. Hast Du dafür vielleicht ein Beispiel? Wie übergebe ich den Env Block an das laufende Programm? Zum letzten Punkt, ob das Programm die Env Variable beim Start ausliest und dann als lokale Variable speichert oder ob die Umgebungsvariable a la GetEnvironmentString immer dann ausgelesen wird, wenn sie benötigt wird, weiß ich leider nicht. Das Risiko besteht natürlich, dass das Programm die Variable lokal speichert. Dann wäre ich mit dem Ansatz am Ende. Versuch macht Kluch. Gibt es vielleich ein Programm wie ProcessExplorer, womit ich die Umgebung eines laufenden Prozesses für diesen Test manipulieren kann, bevor ich es wirklich in meinen Code implementieren? Besten Dank Tiemo |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Moin Tiemo,
Zitat:
Es könnte auch sein, dass verschiedene Teile des Programmes sich den Wert unterschiedlich beschaffen. Der eine Teil liest immer den aktuellen Inhalt der Umgebungsvariablen (da könnte man etwas machen) ein andere Teil greift, z.B., auf einen beim Programmstart zwischengespeicherten Wert zu. Dann kann dann zu unvorhersehbaren Verhaltensweisen des Programmes kommen, da die Konfiguration inkonsistent ist. Ein kommentiertes Beispiel für die Manipulation des Environmentes kann ich Dir noch liefern. Ich muss es nur erst noch zusammenstellen ;-) |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Zitat:
|
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Moin Tiemo,
soweit hab' ich es fertig, allerdings ungetestet. Bislang habe ich das nur gebraucht, um das Environment des Parent-Prozesses zu manipulieren. Es könnte also das Problem geben, dass Dein Prozess nicht die Rechte hat, ein fremdes Environment zu ändern. Falls Du einen Virenscanner hast, wird der wahrscheinlich Alarm schlagen, wenn Du das Programm erzeugst ;-)
Delphi-Quellcode:
uses
TlHelp32,PsAPI; {$R *.dfm} const // 488 bis 499 werden nicht von der API belegt, können hier also benutzt werden. _ERR_DIFFERENT_SIZE = 488; _ERR_SIZE_CHANGED = 489; function csGetProcIDFromPath(const AsPath : string;var AdwLastError : DWORD) : Integer; // Die Prozess-ID aus dem Pfad ermitteln var hSnapShot : DWORD; pe32 : PROCESSENTRY32; hProcess : DWORD; pFilepath : PChar; sPath : string; begin Result := 0; hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if hSnapshot = INVALID_HANDLE_VALUE then begin AdwLastError := GetLastError; Exit; end; try sPath := AnsiLowerCase(Trim(sPath)); pe32.dwSize := SizeOf(pe32); if not Process32First(hSnapshot,pe32) then begin AdwLastError := GetLastError; Exit; end; repeat hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,False,pe32.th32ProcessID); try if hProcess <> 0 then begin pFilepath := AllocMem(MAX_PATH+1); try if GetModuleFileNameEx(hProcess,pe32.th32ModuleID,pFilePath,MAX_PATH+1) <> 0 then begin if AnsiLowerCase(Trim(pFilepath)) = sPath then begin Result := pe32.th32ProcessID; Exit; end; end; finally FreeMem(pFilepath,MAX_PATH+1); end; end; finally CloseHandle(hProcess); end; until not Process32Next(hSnapshot,pe32); finally CloseHandle(hSnapshot); end; end; function csReadProcessEnvironment(const AdwProcID : DWORD;var AdwEnvSize : DWORD;var ApEnvContent : Pointer;var AdwLastError : DWORD) : Boolean; // Den Speicher mit den WideString Umgebungsvariablen in Abhängigkeit // für eine Prozess-ID auslesen. var pEnvironment : Pointer; mbi : MEMORY_BASIC_INFORMATION; hProcess : DWORD; dwDummy : DWORD; begin Result := False; // Die Adresse ermitteln, an der das Environment liegt // Diese Adresse ist bei allen Prozessen gleich (bis incl. XP), weshalb man sich // hier nicht um den Prozess kümmern muss. pEnvironment := GetEnvironmentStringsW; hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,False,AdwProcID); if hProcess = 0 then begin AdwLastError := GetLastError; Exit; end; try // Eckdaten des Speicherbereiches holen, in dem das Environment liegt // prozessabhängig auslesen... if VirtualQueryEx(hProcess,pEnvironment,mbi,SizeOf(mbi)) <> SizeOf(mbi) then begin AdwLastError := GetLastError; Exit; end; // und den Speicherinhalt lesen ApEnvContent := AllocMem(mbi.RegionSize); AdwEnvSize := mbi.RegionSize; if not ReadProcessMemory(hProcess,mbi.BaseAddress,ApEnvContent,AdwEnvSize,dwDummy) then begin AdwLastError := GetLastError; FreeMem(ApEnvContent,AdwEnvSize); Exit; end; Result := True; finally CloseHandle(hProcess); end; end; function csWriteProcessEnvironment(const AdwProcID : DWORD;const ApEnvContent : Pointer;var AdwLastError : DWORD) : Boolean; var hProc : DWORD; mbi : MEMORY_BASIC_INFORMATION; dwOldProtect : DWORD; dwDummy : DWORD; pEnvironment : Pointer; begin Result := False; hProc := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_WRITE or PROCESS_VM_OPERATION,False,AdwProcID); if hProc = 0 then begin AdwLastError := GetLastError; Exit; end; try pEnvironment := GetEnvironmentStringsW; if VirtualQueryEx(hProc,pEnvironment,mbi,SizeOf(mbi)) <> SizeOf(mbi) then begin AdwLastError := GetLastError; Exit; end; // Den Zielspeicher zum Schreiben vorbereiten if not VirtualProtectEx(hProc,pEnvironment,mbi.RegionSize,PAGE_READWRITE,dwOldProtect) then begin AdwLastError := GetLastError; Exit; end; try // Das alte Environment mit dem neuen überschreiben if not WriteProcessMemory(hProc,pEnvironment,ApEnvContent,mbi.RegionSize,dwDummy) then begin AdwLastError := GetLastError; end; finally // Den Einstellungen für den Speicherschutz wieder herstellen if not VirtualProtectEx(hProc,pEnvironment,mbi.RegionSize,dwOldProtect,dwOldProtect) then begin AdwLastError := GetLastError; end else begin Result := True; end; end; finally CloseHandle(hProc); end; end; function csChangeProcessEnvironment(const AsPath : string;const AsEnvVariable : string;const AsValue : string;var AdwLastError : DWORD) : Boolean; // AsPath: Der Pfad des Programmes, dessen Enviroment geändert werden soll // AsEnvVariable: Name der Umgebungsvariablen // AsValue: Der Wert, den die Variable bekommen soll // AdwLastError: Falls Result = false der Fehlercode var dwProcessIDSelf : DWORD; dwProcessID : DWORD; pEnvironmentOldSelf : Pointer; dwEnvSizeOldSelf : DWORD; pEnvironmentNewSelf : Pointer; dwEnvSizeNewSelf : DWORD; pEnvironment : Pointer; dwEnvSize : DWORD; begin Result := False; dwProcessIDSelf := GetCurrentProcessId; dwProcessID := csGetProcIDFromPath(AsPath,AdwLastError); if dwProcessID = 0 then Exit; pEnvironmentOldSelf := nil; pEnvironmentNewSelf := nil; pEnvironment := nil; try // Das aktuelle eigene Environment auslesen if not csReadProcessEnvironment(dwProcessIDSelf,dwEnvSizeOldSelf,pEnvironmentOldSelf,AdwLastError) then Exit; // Das aktuelle Zielenvironment auslesen if not csReadProcessEnvironment(dwProcessID,dwEnvSize,pEnvironment,AdwLastError) then Exit; // Stimmen die Grössen nicht überein, können wir nicht weitermachen // da die Adressen nicht übereinstimmen werden if dwEnvSizeOldSelf <> dwEnvSize then begin AdwLastError := _ERR_DIFFERENT_SIZE; exit; end; // Die gewünschte Variable im eigenen Environment ändern if not SetEnvironmentVariable(PChar(AsEnvVariable),PChar(AsValue)) then begin AdwLastError := GetLastError; Exit; end; // Jetzt das geänderte eigene Enviroment auslesen if not csReadProcessEnvironment(dwProcessIDSelf,dwEnvSizeNewSelf,pEnvironmentNewSelf,AdwLastError) then Exit; // Wenn sich die Grösse geändert hat, können wir nicht weitermachen, da sich die Adressen // geändert haben if dwEnvSizeNewSelf <> dwEnvSize then begin AdwLastError := _ERR_SIZE_CHANGED; Exit; end; // Zielenviroment mit dem eigenen geänderten überschreiben if not csWriteProcessEnvironment(dwProcessID,pEnvironmentNewSelf,AdwLastError) then Exit; Result := true; finally // Aufräumen if Assigned(pEnvironmentOldSelf) then FreeMem(pEnvironmentOldSelf,dwEnvSizeOldSelf); if Assigned(pEnvironmentNewSelf) then FreeMem(pEnvironmentNewSelf,dwEnvSizeNewSelf); if Assigned(pEnvironment) then FreeMem(pEnvironment,dwEnvSize); end; end; procedure TForm1.btn1Click(Sender: TObject); var dwLastError : DWORD; begin if csChangeProcessEnvironment('<HIER DEN PFAD ZUR EXE ÜBERGEBEN','NAME DER ENVIRONMENTVARIABLENN','ZU SETZENDER WERT',dwLastError) then begin ShowMessage('Erledigt.'); end else begin case dwLastError of _ERR_DIFFERENT_SIZE : ShowMessage('Die Environments stimmen in der Grösse nicht überein.'); _ERR_SIZE_CHANGED : ShowMessage('Die Grösse des Environments hat sich geändert.'); else ShowMessage(IntToStr(dwLastError)+#13#10+SysErrorMessage(dwLastError)); end; end; end; |
Re: Umgebungsvariable eines anderen, laufenden Programms änd
Danke, Christian. Wirklich super. Ich werde es probieren.... Tausend Dank!!!
|
Re: Umgebungsvariable eines anderen, laufenden Programms änd
wäre es da nicht einfacher das CAD-Programm direkt mit den gewünschten Umgebungsvariablen zu starten, als diese im Nachinein zu ändern?
nicht das dieses CAD-Programm sich noch 'ne Kopie dieser Variablen erstellt und damit arbeitet ... dan kann man da ja ändern was man will und nix passiert. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz