IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

OpenProcess & WriteProcessMemory


Sujet :

Windows

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut OpenProcess & WriteProcessMemory
    Bonsoir à tous,

    Dans le but de la création d'un trainer, je vais être amener à utiliser les fonctions OpenProcess & WriteProcessMemory. Auriez vous un tuto ou un exemple de code pour ces fonctions car je ne comprends pas comment les utiliser

    Merci beaucoup.

    Bonne soirée

  2. #2
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Sous Windows, chaque processus est identifié de manière unique grâce à son PID (Process Identifier). OpenProcess permet d'obtenir un handle vers un processus (handle qui pourra être passé à des fonctions comme TerminateProcess, WriteProcessMemory, etc.).

    WriteProcessMemory, comme son l'indique, permet d'écrire dans la mémoire d'un processus. Il faut cependant généralement avoir appelé VirtualAllocEx avec le flag MEM_COMMIT avant d'appeler WriteProcessMemory.

    A la fin, il faut libérer la mémoire allouée par VirtualAllocEx à l'aide de VirtualFreeEx avec le flag MEM_RELEASE et fermer le handle retourné par OpenProcess à l'aide de CloseHandle.

    Lire la doc de ces fonctions sur MSDN.

    D'autres questions ?

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    Pour le moment non, je vais aller lire la MSDN si j'arrive a retrouver la page ou il explique les fonctions quel b*rdel ce site quand même

    Merci à vous.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    Bonsoir, j'avance doucement mais surement :

    Mon programme me trouve le PID et m'ouvre un handle via OpenProcess, ça à l'air de fonctionner mais je me pose quelques questions tout d'abord mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <iostream>
    #include <windows.h>
    using namespace std;
    int main ()
    {
    	int PID = NULL;
    	HWND Jeu = NULL;
    	HANDLE valeurOP = NULL;
    	cout << "En attente du processus ..." << endl;
    	do
    	Jeu = FindWindow(0,TEXT("Calculatrice"));
    	while (Jeu == NULL);
    	GetWindowThreadProcessId(Jeu,(LPDWORD) &PID);
    	cout << "Le handle de la fenetre Calculatrice est : " << Jeu << endl;
    	cout << "Son PID est : " << PID << endl;
    	cout << "Tentative d'ouverture du processus" << endl;
    	valeurOP = OpenProcess (PROCESS_TERMINATE,true,PID);
    		if (valeurOP != NULL){
    			cout << "Le handle du processus est : " << valeurOP << endl;
    			if (CloseHandle(valeurOP) != 0)
    				cout << "Handle ferme "<< endl;
    			else
    				cout << "Erreur de Closehandle" << endl;}
    	else
    		cout << "Erreur à l'ouverture" << endl;
    	system("PAUSE");
    	return 0;
    }
    Tout d'abord quel est la différence entre HANDLE et HWND dans quel cas utilise t on l'un ou l'autre ?

    Est il possible de créer un char que j'utiliserai dans la fonction FindWindow et dans mon cout car VC++ me dit qu'il peut pas convertir char en LPCWSTR j'ai lu pas mal de chose sur le net j'ai voulu changer mon projet en MultiByte mais ca ne résoud pas le probléme

    Je ne comprend pas non plus le deuxieme argument de la fonction OpenProcess :
    If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
    même si je parle un peu anglais la j'avoue que je ne comprend pas du tout :s

    Je sais que le code n'est pas "propre" et je suis à votre écoute pour toute remarque .

    Merci à vous

    Bonne soirée

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Un HWND est un handle de fenêtre, valable dans tout le système tant que la fenêtre existe. Un HWND ne permet pas de maintenir une fenêtre en vie.

    Un HANDLE est un handle vers un objet du kernel (sauf dans certains cas, comme le type de retour de LoadImage()). Un objet du kernel existe jusqu'à ce que tous ses handles soient fermés (on considère qu'un processus garde un handle sur lui-même tant qu'il s'exécute).

    L'héritage de handle est un truc qui a un rapport avec la création de processus fils: En gros, ça dit si le handle sera valide dans un processus fils ou non.

    Au niveau propreté: Utilise directement un DWORD pour le PID, et ne caste pas le pointeur.

    Au niveau conversion, c'est assez compliqué à gérer si l'on ne bosse pas sous Visual Studio (et une version payante strictement supérieure à 6).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    Merci de m'avoir répondu.

    J'ai donc modifier comme suit et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	GetWindowThreadProcessId(Jeu,&PID);
    Ca fonctionne toujours Je reconnais ne pas savoir quand utiliser un DWORD un LPCWSTR et compagnie je m'y perd mais je persévère

    La fonction ReadProcessMemory() lit bien ce qu'il y a en RAM un peu comme fait Tsearch donc ?

    Car j'ai voulu essayer avec un programme fait pour s'entrainer à la création de trainer, j'ai donc trouver ma valeur en mémoire ( Je sais utiliser Tsearch ) :

    Adresse : 41D090 ( je ne ferme pas le programme pour être sur que ca change pas )
    Taille : Tsearch me l'a trouver en tant que 4bytes
    Valeur : 16 ( que je peux modifier via Tsearch ca fonctionne niquel )

    Le souci est que quand je veux le faire via
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ReadProcessMemory(valeurOP,"41D090",&INFO,4,NULL);
    Le résultat est 0 => fonction échoué, et quand j'utilise le 5 ème argument qui me renvoie la taille des données lu celle si est nulle donc ça coince quelque part .

    J'ai utilisé la fonction GetLastError() et celle si me retourne 299 à savoir : Seule une partie de la demande Lecture/Ecriture du processus mémoire a été effectuée.

    j'ai remarqué que le handle retourné par OpenProcess est toujours = 0 quelque sois le processus je précise que je suis sous W7 RC donc peut etre est ce du a cela ?

    Une idée ?

    Merci encore à vous !

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Citation Envoyé par geek-59600 Voir le message
    J'ai donc modifier comme suit et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	GetWindowThreadProcessId(Jeu,&PID);
    NULL, c'est pour les pointeurs. Initialise-le plutôt à zéro.

    La fonction ReadProcessMemory() lit bien ce qu'il y a en RAM un peu comme fait Tsearch donc ?

    Car j'ai voulu essayer avec un programme fait pour s'entrainer à la création de trainer, j'ai donc trouver ma valeur en mémoire ( Je sais utiliser Tsearch ) :

    Adresse : 41D090 ( je ne ferme pas le programme pour être sur que ca change pas )
    Taille : Tsearch me l'a trouver en tant que 4bytes
    Valeur : 16 ( que je peux modifier via Tsearch ca fonctionne niquel )

    Le souci est que quand je veux le faire via
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ReadProcessMemory(valeurOP,"41D090",&INFO,4,NULL);
    Le résultat est 0 => fonction échoué, et quand j'utilise le 5 ème argument qui me renvoie la taille des données lu celle si est nulle donc ça coince quelque part .

    J'ai utilisé la fonction GetLastError() et celle si me retourne 299 à savoir : Seule une partie de la demande Lecture/Ecriture du processus mémoire a été effectuée.[/quote]
    intptr_t remoteAddress = 0x0041D090;
    ReadProcessMemory(valeurOP, reinterpret_cast<void*>(remoteAddress), &INFO, 4, NULL);

    j'ai remarqué que le handle retourné par OpenProcess est toujours = 0 quelque sois le processus je précise que je suis sous W7 RC donc peut etre est ce du a cela ?
    Si OpenProcess() a retourné un handle nul, c'est que l'ouverture du processus a échoué.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    En effectuant vos corrections, ca fonctione ; OpenProcess me renvoyer 40 et non pas 0.

    Pourriez vous m'éclairer sur intptr_t et l'utilité du réinterpret cast svp ?

    Merci beaucoup

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    intptr_t : Un type entier assez grand pour contenir la valeur d'un pointeur.
    Le cast: Vu qu'on entre l'adresse sous forme d'un entier et que la fonction demande un pointeur (qui n'est pas forcément valide en local), il faut caster, on n'a pas le choix ici. Mais autant le faire correctement, donc on utilise le cast C++ le plus approprié pour ça.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    Grace à vos éclaircissement et avec un peu de recherche sur WriteProcessMemory, mon trainer est fini et fonctionnel

    Je me permets de vous poster mon code encore une fois au cas ou vous auriez quelque conseil d'optimisation à me procurer et me dire ce que vous pensez de mes commentaires.

    Ce trainer est mon premier véritable projet C++ ( j'avais déjà fais quelque petite "connerie" avant mais rien de très "sérieux)



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #include <iostream>     //Fichier d'en-tête necessaire au flux cout 
    #include <windows.h>    //Fichier d'en-tête neccesaire pour utiliser les fonctions FindWindow(),GetWindowThreadProcessId()
    						//OpenProcess(),ReadProcessMemory() et la fonction Sleep()
    
    using namespace std;
    int main ()
    {
    	BYTE patch[] = "\x90\x90\x90";						//Déclaration d'une variable BYTE qui contient le patch
    	intptr_t Adressememoire = 0x007C8F77;				//Adresse mémoire où appliquer le patch
    	LPCWSTR Titrefenetre = (L"Tom Clancy's H.A.W.X");	//Déclaration d'une variable LPCWSTR qui contient le nom de la fenêtre du jeu
    	DWORD Pid = 0;										//Déclaration d'une variable DWORD qui contiendra le PID du processus du jeu
    	SIZE_T Infolues = 0;								//Déclaration d'une variable size_t qui contiendra le nombre d'octets lu
    	SIZE_T Infoecrites = 0;								//Déclaration d'une variable size_t qui contiendra le nombre d'octets écrie
    	int Valeurlue = 0;									//Déclaration d'une variable int qui contiendra la valeur lue en mémoire
    	HWND Handlefenetre = 0;								//Déclaration d'un HWND qui contiendra un handle sur la fenêtre du jeu
    	HANDLE Handleprocess = 0;							//Déclaration d'un Handle qui contiendra un handle sur le processus du jeu
    
    	SetConsoleTitleA ("Tom Clancy's H.A.W.X V 1.02 trainer By NiCk.0"); //Changement du titre de l'application console
    	
    	cout << "Lancement du trainer " << endl;
    	cout << endl;
    	cout << "En attente du processus ..." << endl;
    
    	do{													//Boucle qui permetra de se mettre en standby si la fenetre n'est pas trouvee
    	
    	Sleep (500);										//On attend 500ms pour pas surcharger le processeur de facon inutile
    														//tant que le jeu n'est pas lancé
    
    	Handlefenetre = FindWindow(0,(Titrefenetre));		//Recherche de la fenetre par son nom, le nom doit être utiliser en tant que deuxieme
    														//argument de la fonction, cette fonction renvoie un handle sur la
    														//fenetre trouvée.
    	}
    	while (Handlefenetre == NULL);						//Tant que la fonction FindWindow() n'a pas renvoyé un handle la boucle se poursuit
    
    	GetWindowThreadProcessId(Handlefenetre,&Pid);		//On récupére le PID du processus cette fonction prend en argument un Handle sur fenetre
    														//et un pointeur sur une valeur DWORD qui recevra le PID
    	cout << "Fenetre trouvee ... "<< endl;
    	cout << "Tentative d'ouverture du processus" << endl;
    	Handleprocess = OpenProcess (PROCESS_ALL_ACCESS,true,Pid);	//La fonction renvoie un handle sur processus le premier argument
    															    //est le type d'acces désiré, le second permer de spécifier si on veut que il y est 
    															    //un héritage de l'handle et le dernier la variable contenant le PID
    
    	if (Handleprocess != NULL){									//Instruction à éxécuter dans le cas ou le processus est bien ouvert
    			cout << "Processus ouvert, HANDLE sur processus acquis " << endl;
    			cout << "Tentative de lecture de la memoire" << endl;
    			ReadProcessMemory(Handleprocess,reinterpret_cast<void*>(Adressememoire),&Valeurlue,3,&Infolues); // Lecture de la mémoire la fonction prend comme argument
    																									  // le handle sur processus retourné par OpenProcess(),l'adresse où lire dans la mémoire via
    																									  // un cast vers un void* ,un pointeur sur une variable qui recevra les données lues,le nombre d'octet à lire,
    																									  // et pour finir un pointeur sur une variable qui recevra le nombre d'octet lu.
    			if ((Infolues == 3)&&(Valeurlue == 0x286e01)) 	    //Instruction à éxécuter dans le cas ou on a bien lue 3 octets de données et que ca correspond à ce qui est attendu
    																//Cela peut être utile pour detecter l'utilisation du trainer sur une autre version du jeu que celle pour laquelle il a été codé
    			{
    			cout << "Ok " << endl;
    			cout << "Tentative d'injection des donnees" << endl;
    			WriteProcessMemory(Handleprocess,reinterpret_cast<void*>(Adressememoire),patch,sizeof(patch),&Infoecrites); //On écrit en mémoire la fonction utilise comme argument un handle sur processus,
    																													  //l'adresse ou écrire caster vers un void*,la variable contenant les données à écrire,
    																													 //la taille des données à écrire via sizeof et un pointeur vers une variable qui contiendra le nombre d'octets écrit
    			if (Infoecrites == sizeof(patch))					//Instruction à éxécuter si la taille des données écrites en mémoire est égale à la taille des données qui devrait être écrite .
    			cout << "Injection reussie" << endl;
    			else
    			cout << "Injection ratee" << endl ;						//Instruction à éxécuter si la taille des données écrites en mémoire est differente à la taille des données qui devrait être écrite.
    			}
    			else
    			cout << "Erreur de lecture en memoire, assurez vous d'utiliser la version 1.02 du jeu."<< endl;
    			CloseHandle(Handleprocess);	
    			}													//On ferme l'Handle sur processus la fonction prend pour argument l'handle à fermer			
    	else														//Instruction à éxécuter dans le cas ou le processus n'a pu être ouvert
    		cout << "Erreur a l'ouverture du processus" << endl;	
    	system("PAUSE");
    	return 0;
    }
    Il me reste un souci d'aprés la MSDN le flag PROCESS_ALL_ACCESS pose un probléme si on code sous vista/seven et qu'on utilise sous xp ou inférieur la msdn préconise d'utiliser uniquement les flags nécessaires donc je remplace PROCESS_ALL_ACCESS par PROCESS_VM_READ+PROCESS_VM_WRITE mais dans ce cas le read fonctionne mais pas le write .

    Je vais tenter de compiler sous xp et d'utiliser sous seven, si ca fonctionne je me cantonnerai à cette solution si pas je chercherai une autre solution : peut être utiliser 2 OpenProcess chacun avec un flag différent

    Si vous avez une idée je suis tout ouïe.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Août 2008
    Messages
    154
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 154
    Points : 84
    Points
    84
    Par défaut
    Solution trouvée en ajoutant le flag PROCESS_VM_OPERATION

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo