Récupérer les variables d'environnement de n'importe quel processus

Soyez le premier à donner votre avis sur cette source.

Vue 8 774 fois - Téléchargée 567 fois

Description

Bonjour,

voilà (encore) une source orientée système qui permet de récupérer (lecture seule uniquement) les variables d'environnement d'un processus quelconque.

Pour récupérer les variables du processus courant c'est on ne peut plus trivial avec Environment.GetEnvironmentVariables() :-)

Mais pour les autres processus, c'est une autre histoire...

Il existe deux méthodes pour les obtenir :

La première : "Méthode injection"
- Injecter une dll dans le processus dont on veut connaitre les variables d'environnement
- Ouvrir un nouveau thread dans le processus (CreateRemoteThread)
- Appeler GetEnvironmentStrings() qui récupère les variables du processus courant
- Libérer la dll

C'est très très moche et il faut le privilège Debug !

Du coup ici je vous propose une seconde méthode : il s'agit de lire les informations dans le PEB du processus.

Explication : plusieurs informations d'environnement sont stockées dans un espace mémoire de chacun des processus. Ces informations sont stockées dans le "PEB" (process environment block).
Il convient donc de lire dans la mémoire du processus désiré pour récupérer ces précieuses informations (via ReadProcessMemory).

Toute la difficulté est donc de récupérer l'emplacement mémoire à lire, puisqu'il n'est pas le même pour chacun des processus...

Voici donc comment procéder :
a) on récupère l'adresse du PEB, qui, contrairement à ce qu'on peut souvent lire sur Internet, N'EST PAS TOUJOURS la même (non, ce n'est pas toujours 0x7ffdf000 !!!). Du coup on appelle NtQueryInformationProcess pour obtenir cette info.

b) Le PEB possède plein d'informations inutiles pour nous, il faut donc trouver les bonnes. Il faudra donc dans un premier temps récupérer l'adresse mémoire d'un second block, appelé "ProcessParameters block". En effet, les variables d'environnement sont situées physiquement à une adresse variable, qui elle, est fixée à une adresse fixe dans le PEB.
On récupère donc l'adresse du "ProcessParameters block".

c) On récupère les variables d'environnement à proprement parler.
Elle sont situées à l'offset 0x48 (72) dans le "ProcessParameters block" pour tous les systèmes Windows NT. Toute la (nouvelle) difficulté est de récupérer la taille qu'elles occupent en mémoire.

Voilà comment elles sont architecturées en mémoire :
var1=val1@var2=val2@....@varn=valn@@ , avec le signe '@' représentant deux octets 0.
En effet, les informations sont codées au format Unicode, et donc chaque caractère prend 2 octets.

Les variables sont donc séparées par 00 00, et la fin de la liste est marqué par 00 00 00 00 (4 null bytes).

Donc on lit la mémoire jusqu'à trouver 00 00 00 00, on calcule la taille, ensuite on récupère dans un buffer la liste complète des variables, et on parse le tout pour que ce soit lisible par le commun des mortels (un tableau de shorts c'est moyen ^^).

Voilà pour le principe, la réalisation est dans le fichier zip.

Rappels divers :
- ANSI : caractères codés sur un octet (on voit ABCD dans un éditeur hexa)
- UNICODE : caractères codés sur 2 octets (on voit A.B.C.D. dans un éditeur hexa)
- Integer : 4 octets
- Short : 2 octets
- Byte : 1 octet
- Une adresse mémoire est codée sur 4 octets sur un système 32 bits
- Byte = Octet en anglais (rien à voir avec bit).

NB : pour le changement des variables d'environnement, par contre, il faudra forcément passer par de l'injection. Cf : http://www.codeproject.com/KB/threads/DynEnvVar.aspx

Voilà !!

@+

Conclusion :


Si j'ai fait quelques erreurs d'explication, n'hésitez pas à me corriger !

J'ai mis tous les commentaires en anglais, mais c'est compréhensible je pense (en plus je viens de détailler la méthode).

@+

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

violent_ken
Messages postés
1822
Date d'inscription
mardi 31 mai 2005
Statut
Membre
Dernière intervention
26 octobre 2010

Ok merci !

Par contre, pour les droits, administrateur ne suffit pas pour accéder à tout : contrairement à ce que j'ai dit dans la description par rapport à l'injection, il faut également le droit DebugPrivilege pour accéder au processus système pour faire un ReadProcessMemory.

@+
PWM63
Messages postés
127
Date d'inscription
lundi 11 octobre 2004
Statut
Membre
Dernière intervention
18 mai 2016

Ok merci, je testerai de nouveau ça demain.

Pour info, je suis administrateur de mon propre PC.

@+
violent_ken
Messages postés
1822
Date d'inscription
mardi 31 mai 2005
Statut
Membre
Dernière intervention
26 octobre 2010

J'ai corrigé tous les bugs (normalement).


Sinon pour le processus ou il n'y a pas de données, _size = 2 indique que le bloc mémoire contenant la liste des variables est vide (du coup c'est normal qu'il retrouve rien).

Plusieurs raisons :
- soit le processus n'a pas de variables (très peu probable)
- soit l'accès est refusé (processus système et droits non suffisants ?)
- soit je sais pas ??

@+
PWM63
Messages postés
127
Date d'inscription
lundi 11 octobre 2004
Statut
Membre
Dernière intervention
18 mai 2016

Alors, pour les lignes vides, la petite correction n'a à priori rien amélioré...
J'ai toujours 1 ou 2 lignes vides à la fin.

Et pour les processus où il n'y a pas de données (sauf 2 lignes vides) :
_size = 2
violent_ken
Messages postés
1822
Date d'inscription
mardi 31 mai 2005
Statut
Membre
Dernière intervention
26 octobre 2010

Version 32 bits ? Hum, bah de toutes façons même en 64 bits le problème aurait été des plus bizarre. Bref, question ouverte en suspend.
Avec la nouvelle fonction çà marche, mais çà reste franchement étrange que j'ai du apporter la modification du dessus.


Je vais mettre à jour le zip.


Alors sinon pour les lignes vides, effectivement j'ai fait une erreur d'index, il faut lire :
sBuf2.CopyTo(sBuf, CInt(size / 2)) (pas de -1) ^^


Pour =::=::\, ben honnêtement c'est pas de ma faute :-)

En mémoire il y a une chaine de ce type (vérifié avec un editeur hexa) :
::=::\@ (ou @ est un nullchar). Du coup lors du parsing, je prend ce qui est à gauche du premier '=' (c'est à dire rien) et c'est le nom de la variable.
Sa valeur est à droite du premier '=', c'est donc =::=::\.

Bref, du coup c'est "un bug de Windows" (une variable d'environnement qui n'a pas de nom et qui a une valeur pourrie). Le plus simple est de les filtrer en n'affichant que celles dont NomVariable.Length > 0 (nom de variable non nul).


Pour les processus sans données, tu pourrais s'il te plait juste mettre un point d'arrêt dans le code et me donner la valeur de _size juste avant ReadBytesAS ?
Ainsi que le nom du process, parce qu'un process avec plus de 4K de variables d'environnement... OUCH !!


Merci
@+

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.