Lecture et écriture en mémoire [Résolu]

Signaler
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010
-
cs_PHIL63
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010
-
Bonjour à tous et à toutes,
Mon souci :
J'ai des adresses mémoire pour un logiciel donné et j'aurais besoin d'accèder directement à ces zones mémoire en lecture (pour en lire le contenu) et en écriture (pour y injecter de nouvelles données en lieu et place de celles existantes). Je sais, c'est pas simple.
Ce que je cherche donc à faire c'est dans un premier temps un petit programme de test avec un TEdit où rentrer l'adresse à lire/modifier, un Tlabel pour afficher le contenu en mémoire, un autre TEdit pour saisir les nouvelles valeurs à injecter, deux boutons, un pour lire et un pour écrire les valeurs.

Qui pourrait me donner un gros coup de main car je n'ai encore jamais utilisé de fonctions/API manipulant la mémoire d'un logiciel. Pour le reste ça devrait aller .
Merci d'avance.

Philippe DROUET

13 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
Entraîne toi sur un processus fait par toi même pour bien comprendre le procédé.

C'est juste une histoire de pointeurs.


Voilà une tentative de traduction :

J'ai sûrement fait pas mal d'erreurs...
var
rbrWnd: HWND; // Handle de la fenêtre
dwProcessId: DWORD; // ID du processus à modifier
hProcess: HANDLE; // Handle du processus à modifier
OldProtect: DWORD; // Récupération de la protection précédente
damageBlockAddress: DWORD; // Calcul de l'adresse des dégats
value: DWORD; // Valeur que l'on écrira dans le processus distant
firstAddress: DWORD; // On va déterminer les autres adresses à partir de celle-ci
bytesWritten: DWORD; // Nombre d'octets écrits par WriteProcessMemory
leftDoorAddress: DWORD; // Adresse des dégats de la portière gauche
begin
// Recherche de la fenêtre
rbrWnd:= FindWindow('D3D Window', nil);
if rbrWnd = 0 then RaiseLastOSError;

// Récupération de l'ID du processus à partir du handle de fenêtre
GetWindowThreadProcessId(rbrWnd, dwProcessId);

// Récupération d'un handle sur le processus à partir de son ID
hProcess:= OpenProcess(PROCESS_ALL_ACCESS, False, dwProcessId);
if hProcess = 0 then RaiseLastOSError;

// Lecture de 4 octets à l'adresse $008EF660
address:= $008EF660;
VirtualProtectEx(hProcess, Pointer(address), 4, PAGE_READWRITE, OldProtect);
ReadProcessMemory(hProcess, Pointer(address), @damageBlockAddress, 4, nil);

// L'adresse des dégats se trouve à l'offset $620 de l'adresse située à l'adresse $008EF660.
// On vient de récupérer l'adresse située à l'adresse $008EF660.
// Il faut lui ajouter $620.
damageBlockAddress:= damageBlockAddress + $620;

// On récupère l'adresse des dégats
VirtualProtectEx(hProcess, Pointer(damageBlockAddress), 4, PAGE_READWRITE, OldProtect);
ReadProcessMemory(hProcess, Pointer(damageBlockAddress), @damageBlockAddress, 4, nil);

// Pour ouvrir la porte, il faut écrire 0 à l'adresse des dégats + $36C
value:= 0;
leftDoorAddress:= damageBlockAddress + $36C;

VirtualProtectEx(hProcess, Pointer(leftDoorAddress), 4, PAGE_READWRITE, OldProtect);
WriteProcessMemory(hProcess, Pointer(leftDoorAddress), @value, 4, bytesWritten);

CloseHandle(hProcess);
end;
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
 Déclare un :

bytesRead: DWORD;


ReadProcessMemory(hProcess, Pointer(address), @damageBlockAddress, 4, bytesRead);

ReadProcessMemory(hProcess, Pointer(damageBlockAddress), @damageBlockAddress, 4, bytesRead);
Messages postés
991
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
5
bah un simple cast devrait suffire, a partir du moment ou tu sais quel type y mettre (=quelle taille memoire)
par exemple

edit1.text vaut "12345"

var
    addr: Pointer;
begin  addr :Pointer(StrToInt(edit1.Text)); //addr vaut l'adresse memoire 12345 ( $3039 en hexa)
  integer(addr^) := 5; //ecrira "5" sur 4 octets (taille d'un integer) a l'adresse $3039
end;
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Hummm,
je pensais plutot avoir à utiliser des fonctions comme VirtualProtectEx(), ReadProcessMemory(), etc...
je dois lire et écrire dans des zones mémoire d'un processus déjà connu (cette partie fonctionne).

En fait j'ai déjà essayé ce qui suit mais j'ai une erreur.
Trouver le processus :
HRBRWindow := FindWindow(Nil,'Richard Burns Rally - DirectX9');
Label3.Caption := IntToStr(HRBRWindow);
dwProcessId := 0;
GetWindowThreadProcessId(HRBRWindow, dwProcessId);
Label4.Caption := IntToStr(dwProcessId);

Lire :
function Tform1.LitDomages(adresse:dword): float;
var debBlock : dword;
begin
 debBlock : = 0;
 asm
   push eax
   mov eax, $008EF660
   mov eax, [eax]
   add eax, adresse     //$620
   mov eax, [eax]
   mov debBlock, eax
   pop eax
 end;
 LitDomages := debBlock;
end;
.......
.......
Ecrire (ça ça ne fonctionne pas) :
procedure TForm1.bButton1Click(Sender: TObject);
begin
  OldProtect : = 0;
  BlockAddressDomages := 0;
  MA := $008EF660;
  // change la protection de la zone mémoire Read/Write
  NumberOfBytes := 4;
  VirtualProtectEx(HRBRWindow, Ptr(MA),NumberOfBytes,PAGE_READWRITE,OldProtect);
  ReadProcessMemory(HRBRWindow, Ptr(MA), Ptr(BlockAddressDomages), NumberOfBytes, Wrtpr);

  BlockAddressDomages := BlockAddressDomages + $620;
  VirtualProtectEx(HRBRWindow, Ptr(BlockAddressDomages),NumberOfBytes,PAGE_READWRITE,OldProtect);
  ReadProcessMemory(HRBRWindow, Ptr(BlockAddressDomages), Ptr(BlockAddressDomages), NumberOfBytes, Wrtpr);

end;

Merci quand même.

Philippe DROUET
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
27
FindWindow(Nil,'Richard Burns Rally - DirectX9');

ça sens le trainer a pleins nez ça ... :)


Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Salut  f0xi,
Ca sent surtout une mise en place de gestion des dommages entre deux courses pour des championnats. :-))
Et là... ben je galère... je ne m'était jamais penché sur des manip comme celle-ci.
Il faudrait que je puisse récupérer les dommages en fin de course pour pouvoir les ré-injecter juste avant le départ de la suivante.

Philippe DROUET
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
Salut,


Ta LitDomages fonctionne ????


Ce n'est pas parce que c'est de l'assembleur que ça ira lire le processus voisin...


Il faut que ce code soit executé dans le processus cible pour qu'il ait
une chance de fonctionner : les processus ne partagent pas de mémoire.


Tu peux cependant sans problème traduire ce code avec du ReadProcessMemory.


Ton "Ecrire" ne fait que lire : il n'utilise pas WriteProcessMemory. Il
faut visiblement commencer par un Read mais le deuxième doit être un
Write.


Ptr(MA) -> Renvoie l'adresse de MA, alors que c'est l'adresse MA qui t'intéresse -> Pointer(MA).


Pour l'écriture, pareil, ta source doit être l'adresse d'un entier
contenant tes nouveaux dommages (Ptr()), mais l'adresse de destination
doit être la valeur de BlockAddressDomages (Pointer()).
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Je n'arrive à rien et ça m'agace...
Un gars programmant en C ou C++ m'avait passé ça mais je n'arrive pas à le traduire en Delphi....

HWND rbrWnd = ::FindWindow("D3D Window", NULL);
if(!rbrWnd)
{
return;
}
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(rbrWnd, &dwProcessId);
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessId);
if(!hProcess)
{
return;
}
DWORD OldProtect = 0;
DWORD damageBlockAddress = 0;
VirtualProtectEx(hProcess,(LPVOID)0x008EF660,4,PAGE_READWRITE,&OldProtect);
ReadProcessMemory(hProcess,(LPCVOID)0x008EF660, &damageBlockAddress, 4, NULL);

damageBlockAddress += 0x620;
VirtualProtectEx(hProcess,(LPVOID)damageBlockAddress,4,PAGE_READWRITE,&OldProtect);
ReadProcessMemory(hProcess,(LPCVOID)damageBlockAddress, &damageBlockAddress, 4, NULL);
/*
the damage data starts at "damageBlockAddress"
you have to do some tests to determine which offsets means what
in example if you write zero at (damageBlockAddress + 0x36C) you will get the left door opened,
or if you write zero at (damageBlockAddress + 0x384) you open the bonet.
*/
DWORD value = 0;
DWORD bytesWritten = 0;
DWORD leftDoorOffset = damageBlockAddress + 0x36C;
VirtualProtectEx(hProcess,(LPVOID)leftDoorOffset,4,PAGE_READWRITE,&OldProtect);
WriteProcessMemory(hProcess, (LPVOID)leftDoorOffset, &value, 4, &bytesWritten);
DWORD bonetOffset = damageBlockAddress + 0x384;
VirtualProtectEx(hProcess,(LPVOID)bonetOffset,4,PAGE_READWRITE,&OldProtect);
WriteProcessMemory(hProcess, (LPVOID)bonetOffset, &value, 4, &bytesWritten);
CloseHandle(hProcess);

Tout ce que j'essaie me renvoie une erreur "violation de partage lecture adresse 008EF660 etc...".
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Je te remercie pour cette traduction.
Ben justement les histoires pointeurs ce n'est pas mon fort....
J'obtiens l'erreur suivante "Les types des paramètres VAR originaux et formels doivent être identiques" avec les lignes
  ReadProcessMemory(hProcess, Pointer(address), @damageBlockAddress, 4, nil);
et
  ReadProcessMemory(hProcess, Pointer(damageBlockAddress), @damageBlockAddress, 4, nil);
lors de la compilation.
Je savais bien que ça allait être coton ce prog...

Merci quand même pour ton aide.
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

YES


ça marche, le logiciel arrive à ouvrir la portière, ce qui veux dire que la partie "écriture" fonctionne (heu ... celle pour la lecture aussi puisque après on peut écrire à cette adresse )
C'est vraiment génial.
Je te remercie encore pour le temps que tu as passé à m'aider c'était vraiment sympa car je ne pense pas que j'aurais réussi sans ton aide.

Philippe DROUET
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Une dernière question idiote, comment je peux récupérer le contenu de "@damageBlockAddress" dans une variable ?

Philippe DROUET
Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
Pour cela, il faut commencer par connaître la taille de ce qui se
trouve à cette adresse. On sait que la porte est en +$36C et le "bonet"
(?) en +$384. Donc ça fait de la place... On va essayer de copier $500
par exemple.

var
lpDamageBlocBuffer: array [0..$500] of Byte;
begin
...
VirtualLocEx
VirtualProtectEx(hProcess, Pointer(damageBlockAddress), $500, PAGE_READWRITE, OldProtect);
ReadProcessMemory(hProcess, Pointer(damageBlockAddress), @lpDamageBlocBuffer[0], $500, nil);
Messages postés
76
Date d'inscription
dimanche 9 février 2003
Statut
Membre
Dernière intervention
10 août 2010

Bonjour,
En fait pour la taille, je peux être un peu plus précis car je sais qu'en $36C j'ai "Porte G ouverte" et en $370 j'ai "Porte G dégondée" donc je peux réduire la taille à 4 au lieu de $500.
Il faut maintenant que je me fasse une petite fonction qui me renvoie le contenu du bloc mémoire avant que j'injecte le 0.

En fait, comme tu as du le comprendre, j'ai besoin dans un premier temps de trouver à quoi correspondent tout un tas d'adresses mémoire dans le processus du jeu pour établir une liste en injectant un 0 à chaque emplacement puis en vérifiant ce que ça fait merd** au niveau de la voiture.
Un fois que j'aurais fais au moins une liste sommaire, je pourrais réinjecter les dégats dans la partie suivante ce qui sera plus réaliste.
Grâce à toi j'ai énormément avancé et je t'en remerci encore.
@+

Philippe DROUET