merci a bouh2 pour ce tuto
Créer un Cheat
Bonjour,
Voici le tutoriel tant attendu par certain, je vais vous expliquer comment exploiter la structure de WoW et ainsi faire un "mini WEH".
Ce sera à vous de créer votre cheat à partir des adresses et offset déjà donné ;)
I. Le Playerbase
Le Playerbase est l'adresse dites de "base" du joueur. C'est une adresse qui désigne l'endroit ou est stocké toutes les informations sur le joueur (que l'on joue).
On ajoute un offset à l'adresse obtenu pour trouver la donnée que l'on veux (vitesse de déplacement, positions ...)
Cette adresse est dynamique, elle change à chaque lancement et à chaque chargement dans WoW, on doit donc la trouver en lisant des pointeurs spécifiques.
Le schéma du playerbase est :
Note : StaticAdress est disponible dans le post des Pointer&Offset. Cette adresse est la même à chaque lancement de WoW mais change à chaque Mise à jour. Il faut donc la modifier dans ce cas là.
Ce qui donne en faites :
Bien sûr il faut remplacer ####### par l'adresse statique selon la version
Il faut ensuite ajouter un offset qui correspond à la donnée que l'on veut (voir sujet sur les Pointer&Offset).
Exemple avec 0x7D0 (Coordonnés X du personnage)
Et pareil pour la modification
Note : La notation "ptr" indique une valeur pointeur, celle-ci n'est pas obligatoire on peut théoriquement la remplacer par "int" ou "dword" mais évite toute erreur.
L'AutoIt contrairement à d'autre langage comme le C/C++ accepte sans problème cette différence.
Il arrive en lisant la mémoire (ex : pos du perso) que vous ayez un résultat de ce genre : "3.03434E4", cela signifie que la valeur n'est pas float donc que ce n'est pas la bonne adresse ou que celle ci ai changer (ex : lors d'un chargement)
Il faut donc rechargez la playerbase de cette façon :
On peut aussi envisager de recharger WoW si on l'avait quitter, mais ce sera à vous de le faire xD
II. L'object Manager
L'Object manager est une fonction qui permet de renvoyer tout les objets que WoW a chargé (PNJ, Joueur, GO, Items, Cadavres et sacs). Cette fonction que l'on doit créer doit être une boucle qui renvoie des informations sur un objet de la même façon que le playerbase en ajoutant un offset à l'adresse obtenu.
J'expliquerais quels sont ces offsets par la suite.
Tout d'abords on doit trouver l'adresse base de l'Object manager qui est dynamique :
Note : Client connexion est une adresse statique qui est toujours la même au lancement de WoW au contraire de l'Object Manager Base qui lui change à chaque chargement.
A partir de là les objets seront à la suite, le premier sera :
Et le prochain sera :
Puis
Etc ...
Note : C'est à ces adresse obtenus que l'on ajoute un offset.
On va donc faire une boucle qui les fasse tous et qui en sort quand le résultat est 0 ou n'est pas pair et à chaque fois on incrémentera l'adresse base de l'object actuel de 0x3C
Note : Pour savoir si un nombre est pair on dois faire une division par 2 et voir si sont reste est égale à 0. Il est existe un opérateur qui donne le reste d'un division : le modulo ( signé % en C/C++, C#, Java et autres). En autoit c'est une fonction, la fonction Mod(dividende, diviseur).
Mod(4,3) donne 1 car il y a 1 fois 3 dans 4 et il reste 1. Bon je ne vais pas revenir sur la division, mieux vaut le savoir ;)
Voici à quoi notre boucle ressemble :
Note : J'ai fait en sortes de faire le code le plus propre possible, je vous conseille fortement de faire de même. (Adresse au début du code, espacer le code, faire des fonctions pour bien délimiter...)
Chaque objet à un type, il y a 7 types :
1 - Objets dans votre sac (Items)
2 - Conteneurs
3 - Unités (Monstre & PNJ)
4 - Joueurs
5 - GameObjects
6 - DynamicObjects (Sorts & équipements)
7 - Cadavres
Pour différencier les types d'objets on utilise l'offset 0x14 qui correspond au type
Voici comment on pourrais organisé ça :
Note : Le switch empêche de faire des "if" inutiles, de plus ça évite de lire 7 fois la mémoire au lieu d'une ce qui est considérable pour l'autoit
On va d'abords s'intéresser aux type joueur et unités qui sont les plus simples
On va juste lire la position de chaque
Les offsets sont simples ce sont les mêmes que ceux du joueur local (playerbase) soit 0x7D0, 0x7D4 et 0x7D8 pour la 3.0.3 - 3.0.9
On va organiser un maximum le code, une seul fonction suffit. En retournant un tableau on évite de déclarer trop de variables inutiles
Mais il faut bien l'avouer avec ça on fait pas grand chose
Alors on va pousser un peu et utiliser les "champs de descriptions" (DescriptorFields)
Voici la liste complète de ceux-là : Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris! (Dumper by Kynox)
Il faut avouer que cette liste est bien intrigante et incompréhensible
Nous allons par exemple trouver la position des GameObject
Il y a 2 offset à ajouter à l'objet :
-DescriptorFieldsOffsets (qui correspond à 0x08)
-L'offset que l'on désire (ici 0x10, 0x11, 0x12) multiplier par 4
Pourquoi multiplier par 4 ? Car le dumper donne juste l'ordre des offset, étant coder sur 4 octets il faut multiplier par 4 pour avoir le bonne offset
Note : Il me semble que le dumper de Cypher donne l'offset exact, déjà avec les valeurs multipliées, il est bon de vérifier ;)
Voici donc ce que l'on obtient :
Soit :
On peux donc modifier notre fonction :
Et voilà notre fonction qui donne la pos d'un objet est complète, à vous de faire d'autre fonction du même genre.
Note : Je vous conseille d'ajouter l'include (Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris!) au début du script. Ça évite des lignes pour rien.
Note : Attention la version 3.1.0 à beaucoup changé, pour avoir la position des GameObject ce n'est plus [CurrentObject + 0x8] GAME_OBJECT_POS_X * 4 mais CurrentObject + 0xE8 (E8, EC, F0) voir code ci-dessous
Maintenant, dernière complication, on va lire le nom de l'objet. Le moyen le plus (mais pas pour nous) et d'utiliser l'injection de code pour appeler la fonction (VMT) GetNameByObject()
Nous ne sommes pas encore à ce stade, on va se contenter de lire la mémoire
On va d'abords lire le nom d'un joueur, c'est le plus dure. En effet car il faut faire une fonction pour lire le nom à partir du GUID (Nombre unique donné par le serveur pour chaque object = Global Unique ID)
Je vous épargne les explications incompréhensible, voici le code :
Note : Pour lire une chaîne de caractères on utilise le symbole "char[#]" en remplaçant # par le nombre de caractères à lire. Ici on met 20 car on sait que le nombre d'un joueur ne fait pas plus de 20 caractères.
L'offset du Guid de l'objet est 0x30
On appelle la fonction de cette manière :
Maintenant lire le nom des GameObject et des PNJ est relativement simple :
Unit Name :
[[Object + 0x970] + 0x3C]
GameObject Name :
[[Object + 0x1FA] + 0x78]
Donc notre fonction finale donne :
Note : J'ai ajouté la fonction _String_To_StringUTF8($string) elle permet de convertir les caractères ASCII en UTF8 ainsi pouvoir afficher les caractères spéciaux (é, à, ê, ô...) sinon vous aurez des @/, €( etc...
Donc enfin voici le code complet qui affiche les résultat dans une ListView qui est en faite un tableau(avec de la couleur !)
Je l'ai commenté autant que j'ai pu et ajouté les changements pour la 3.1.1
Voilà la partie sur l'ObjectManager est fini, c'est un très gros bout mais c'est très important, je vous conseille de le relire plusieurs fois et de modifier le code que j'ai donner pour comprendre comment ça fonctionne
fin
Créer un Cheat
Bonjour,
Voici le tutoriel tant attendu par certain, je vais vous expliquer comment exploiter la structure de WoW et ainsi faire un "mini WEH".
Ce sera à vous de créer votre cheat à partir des adresses et offset déjà donné ;)
I. Le Playerbase
Le Playerbase est l'adresse dites de "base" du joueur. C'est une adresse qui désigne l'endroit ou est stocké toutes les informations sur le joueur (que l'on joue).
On ajoute un offset à l'adresse obtenu pour trouver la donnée que l'on veux (vitesse de déplacement, positions ...)
Cette adresse est dynamique, elle change à chaque lancement et à chaque chargement dans WoW, on doit donc la trouver en lisant des pointeurs spécifiques.
Le schéma du playerbase est :
Code:
Playerbase = [[StaticAdress]+0x30]+0x28
Ce qui donne en faites :
PHP:
$PlayerBase = _MemoryRead((_MemoryRead((_MemoryRead(0x#######, $Processus, "ptr") + 0x30), $Processus, "ptr") + 0x28), $Processus, "ptr")
Il faut ensuite ajouter un offset qui correspond à la donnée que l'on veut (voir sujet sur les Pointer&Offset).
Exemple avec 0x7D0 (Coordonnés X du personnage)
PHP:
$PlayerBase = _MemoryRead((_MemoryRead((_MemoryRead(0x#######, $Processus, "ptr") + 0x30), $Processus, "ptr") + 0x28), $Processus, "ptr")
$PosX = _MemoryRead($PlayerBase + 0x7D0, $Processus, 'float')
PHP:
$PlayerBase = _MemoryRead((_MemoryRead((_MemoryRead(0x#######, $Processus, "ptr") + 0x30), $Processus, "ptr") + 0x28), $Processus, "ptr")
$PosX = _MemoryRead($PlayerBase + 0x7D0, $Processus, 'float')
_MemoryWrite($PlayerBase + 0x7D0, $Processus,$PosX + 10, 'float')
L'AutoIt contrairement à d'autre langage comme le C/C++ accepte sans problème cette différence.
Il arrive en lisant la mémoire (ex : pos du perso) que vous ayez un résultat de ce genre : "3.03434E4", cela signifie que la valeur n'est pas float donc que ce n'est pas la bonne adresse ou que celle ci ai changer (ex : lors d'un chargement)
Il faut donc rechargez la playerbase de cette façon :
PHP:
HotKeySet("{F4}","Reload");reload appelé lorsque la touche F4 est pressé
... ; chargement de wow
$PlayerBase = _MemoryRead((_MemoryRead((_MemoryRead(0x#######, $Processus, "ptr") + 0x30), $Processus, "ptr") + 0x28), $Processus, "ptr")
$PosX = _MemoryRead($PlayerBase + 0x7D0, $Processus, 'float') ;valeur non significative et improbable
Func Reload() ;fonction appelé par exemple par un raccourci
$PlayerBase = _MemoryRead((_MemoryRead((_MemoryRead(0x#######, $Processus, "ptr") + 0x30), $Processus, "ptr") + 0x28), $Processus, "ptr")
EndFunc
II. L'object Manager
L'Object manager est une fonction qui permet de renvoyer tout les objets que WoW a chargé (PNJ, Joueur, GO, Items, Cadavres et sacs). Cette fonction que l'on doit créer doit être une boucle qui renvoie des informations sur un objet de la même façon que le playerbase en ajoutant un offset à l'adresse obtenu.
J'expliquerais quels sont ces offsets par la suite.
Tout d'abords on doit trouver l'adresse base de l'Object manager qui est dynamique :
Code:
[Client Connexion]+CurMgrOff = Object Manager Base
A partir de là les objets seront à la suite, le premier sera :
Code:
Object Manager Base + 0xAC = Premier Objet
Code:
Premier Objet + 0x3C = Objet suivant
Code:
Objet suivant + 0x3C = Objet suivant
Note : C'est à ces adresse obtenus que l'on ajoute un offset.
On va donc faire une boucle qui les fasse tous et qui en sort quand le résultat est 0 ou n'est pas pair et à chaque fois on incrémentera l'adresse base de l'object actuel de 0x3C
Note : Pour savoir si un nombre est pair on dois faire une division par 2 et voir si sont reste est égale à 0. Il est existe un opérateur qui donne le reste d'un division : le modulo ( signé % en C/C++, C#, Java et autres). En autoit c'est une fonction, la fonction Mod(dividende, diviseur).
Mod(4,3) donne 1 car il y a 1 fois 3 dans 4 et il reste 1. Bon je ne vais pas revenir sur la division, mieux vaut le savoir ;)
Voici à quoi notre boucle ressemble :
PHP:
#include <NomadMemory.au3> ;obligatoire
;On déclare toutes les adresses et offset
;Le fait de mettre Const empêche une modifications des donnés
;Cela évite des erreurs bêtes et permet d'etre plus clair
Global Const $staticClientConnection = 0x011CB310
Global Const $offFirstObject = 0xAC, $offNextObject = 0x3C
Global Const $offObjectManager = 0x28A4
;On déclare les variables
Local $CurrentObject
Local $LocalGuid
Global $ObjectManagerBase
;Ne pas oublier d'ouvre le processus de wow
LoadAdresses() ;on initiale l'ojectmanager
$CurrentObject = _MemoryRead($ObjectManagerBase + $offFirstObject, $Processus, 'int') ;On lit le premiere objet
While ($CurrentObject <> 0) And (Mod($CurrentObject, 2) == 0) ;si différent de 0 ou si pair on continu la boucle
;-----------------------
;On ajoutera le code ici
;-------------------------
$CurrentObject = _MemoryRead($CurrentObject + $offNextObject, $Processus, 'int') ;On lit l'objet suivant
WEnd
Func LoadAdresses()
$ObjectManagerBase = _MemoryRead(_MemoryRead($staticClientConnection, $Processus, 'int') + $offObjectManager, $Processus, 'int')
EndFunc
Chaque objet à un type, il y a 7 types :
1 - Objets dans votre sac (Items)
2 - Conteneurs
3 - Unités (Monstre & PNJ)
4 - Joueurs
5 - GameObjects
6 - DynamicObjects (Sorts & équipements)
7 - Cadavres
Pour différencier les types d'objets on utilise l'offset 0x14 qui correspond au type
Voici comment on pourrais organisé ça :
PHP:
Global Const $offTypeObject = 0x14
While ($CurrentObject <> 0) And (Mod($CurrentObject, 2) == 0) ;si différent de 0 ou si pair on continu la boucle
Switch (_MemoryRead($CurrentObject + $offTypeObject, $Processus, 'int')
case 1
;Item
case 2
;Conteneur
case 3
;Unité
case 4
;Joueur
case 5
;GameObject
case 6
;Sort ou équipement
case 7
;Cadavre
EndSwitch
$CurrentObject = _MemoryRead($CurrentObject + $offNextObject, $Processus, 'int') ;On lit l'objet suivant
WEnd
On va d'abords s'intéresser aux type joueur et unités qui sont les plus simples
On va juste lire la position de chaque
Les offsets sont simples ce sont les mêmes que ceux du joueur local (playerbase) soit 0x7D0, 0x7D4 et 0x7D8 pour la 3.0.3 - 3.0.9
On va organiser un maximum le code, une seul fonction suffit. En retournant un tableau on évite de déclarer trop de variables inutiles
PHP:
Global Const $offTypeObject = 0x14
Global Const $offPosX = 0x7D0
Global Const $offPosY = 0x7D4
Global Const $offPosZ = 0x7D8
Global Const $offRot = 0x7DC
local $ObjectPosition[4]
While ($CurrentObject <> 0) And (Mod($CurrentObject, 2) == 0) ;si différent de 0 ou si pair on continu la boucle
Switch (_MemoryRead($CurrentObject + $offTypeObject, $Processus, 'int'))
case 1
;Item
case 2
;Conteneur
case 3
;
$ObjectPosition = GetObjectPos($CurrentObject, 3) ;donne la pos de l'unité
case 4
;JoueurUnité
$ObjectPosition = GetObjectPos($CurrentObject, 4) ;donne la pos du joueur
case 5
;GameObject
case 6
;Sort ou équipement
case 7
;Cadavre
EndSwitch
$CurrentObject = _MemoryRead($CurrentObject + $offNextObject, $Processus, 'int') ;On lit l'objet suivant
WEnd
Func GetObjectPos($Object, $Type)
local $returnPos[4]
Switch ($Type)
Case 1 ;On retourne 0 car les items et conteneur n'ont pas de pos
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
case 2
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
Case 3 ;Si c'est une unité ou un joueur...
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
case 4
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
case 5
;On va voir plus tard
case 6
;On va vois plus tard
case 7
;on va voir plus tard
EndSwitch
Return $returnPos ;on retourne le résultat sous forme de tableau
EndFunc
Alors on va pousser un peu et utiliser les "champs de descriptions" (DescriptorFields)
Voici la liste complète de ceux-là : Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris! (Dumper by Kynox)
Il faut avouer que cette liste est bien intrigante et incompréhensible
Nous allons par exemple trouver la position des GameObject
Il y a 2 offset à ajouter à l'objet :
-DescriptorFieldsOffsets (qui correspond à 0x08)
-L'offset que l'on désire (ici 0x10, 0x11, 0x12) multiplier par 4
Pourquoi multiplier par 4 ? Car le dumper donne juste l'ordre des offset, étant coder sur 4 octets il faut multiplier par 4 pour avoir le bonne offset
Note : Il me semble que le dumper de Cypher donne l'offset exact, déjà avec les valeurs multipliées, il est bon de vérifier ;)
Voici donc ce que l'on obtient :
Code:
[CurrentObjet +0x8]+0x10*4 = Position X du gameobject
PHP:
_MemoryRead(_MemoryRead($CurrentObject + 0x8, $Processus, 'int') + 0x10 *4, $Processus, 'float')
Code:
Global Const $offDescriptorFields = 0x8
Global Const $GAMEOBJECT_POS_X = 0x10
Global Const $GAMEOBJECT_POS_Y = 0x11
Global Const $GAMEOBJECT_POS_Z = 0x12
Global Const $GAMEOBJECT_FACING = 0x13
Global Const $DYNAMICOBJECT_POS_X = 0xB
Global Const $DYNAMICOBJECT_POS_Y = 0xC
Global Const $DYNAMICOBJECT_POS_Z = 0xD
Global Const $DYNAMICOBJECT_FACING = 0xE
Global Const $CORPSE_FIELD_FACING = 0xA
Global Const $CORPSE_FIELD_POS_X = 0xB
Global Const $CORPSE_FIELD_POS_Y = 0xC
Global Const $CORPSE_FIELD_POS_Z = 0xD
PHP:
Func GetObjectPos($Object, $Type)
local $returnPos[4]
Switch ($Type)
Case 1 ;On retourne 0 car les items et conteneur n'ont pas de pos
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
case 2
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
Case 3 ;Si c'est une unité ou un joueur...
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
case 4
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
case 5 ;GameObject
$returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_X *4, $Processus, 'float')
$returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_Y *4, $Processus, 'float')
$returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_Z *4, $Processus, 'float')
$returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_FACING *4, $Processus, 'float')
case 6 ;Sort
$returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_X *4, $Processus, 'float')
$returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_Y *4, $Processus, 'float')
$returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_Z *4, $Processus, 'float')
$returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_FACING *4, $Processus, 'float')
case 7 ;cadavre
$returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_X *4, $Processus, 'float')
$returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_Y *4, $Processus, 'float')
$returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_Z *4, $Processus, 'float')
$returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_FACING *4, $Processus, 'float')
EndSwitch
Return $returnPos ;on retourne le résultat sous forme de tableau
EndFunc
Note : Je vous conseille d'ajouter l'include (Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris!) au début du script. Ça évite des lignes pour rien.
Note : Attention la version 3.1.0 à beaucoup changé, pour avoir la position des GameObject ce n'est plus [CurrentObject + 0x8] GAME_OBJECT_POS_X * 4 mais CurrentObject + 0xE8 (E8, EC, F0) voir code ci-dessous
Maintenant, dernière complication, on va lire le nom de l'objet. Le moyen le plus (mais pas pour nous) et d'utiliser l'injection de code pour appeler la fonction (VMT) GetNameByObject()
Nous ne sommes pas encore à ce stade, on va se contenter de lire la mémoire
On va d'abords lire le nom d'un joueur, c'est le plus dure. En effet car il faut faire une fonction pour lire le nom à partir du GUID (Nombre unique donné par le serveur pour chaque object = Global Unique ID)
Je vous épargne les explications incompréhensible, voici le code :
PHP:
Func GetPlayerNameByGuid($guid)
Local $mask, $base, $offset, $current, $shortGUID, $testGUID
$mask = _MemoryRead($nameStorePtr + $nameMaskOffset, $Processus, 'int')
$base = _MemoryRead($nameStorePtr + $nameBaseOffset, $Processus, 'int')
$shortGUID = BitAnd($guid, 0xffffffff)
if ($mask = 0xffffffff) Then Return ""
$offset = 12 * BitAND($mask, $shortGUID)
$current = _MemoryRead($base + $offset + 8, $Processus, 'int')
$offset = _MemoryRead($base + $offset, $Processus, 'int')
if (BitAND($current, 0x1) == 0x1) then Return ""
$testGUID = _MemoryRead($current, $Processus, 'int')
while ($testGUID <> $shortGUID)
$current = _MemoryRead($current + $offset + 4, $Processus, 'int')
if (BitAND($current, 0x1) = 0x1) then Return ""
$testGUID = _MemoryRead($current, $Processus, 'int')
WEnd
Return _MemoryRead($current + $nameStringOffset, $Processus, 'char[20]')
EndFunc
L'offset du Guid de l'objet est 0x30
On appelle la fonction de cette manière :
PHP:
GetPlayerNameByGuid(_MemoryRead($CurrentObjet + 0x30, $Processus, 'int'))
Unit Name :
[[Object + 0x970] + 0x3C]
GameObject Name :
[[Object + 0x1FA] + 0x78]
Donc notre fonction finale donne :
PHP:
Func GetObjectName($Object, $Type)
Switch ($Type)
Case 3;unité
Return _String_To_StringUTF8(_MemoryRead(_MemoryRead(_MemoryRead($CurrentObject + $offUnitName1, $Processus, 'int') + $offUnitName2, $Processus, 'int'), $Processus, 'char[128]'))
Case 4;joueur
Return _String_To_StringUTF8(GetPlayerNameByGuid(_MemoryRead($Object + $offGuid, $Processus, 'int')))
Case 5;gameobject
Return _String_To_StringUTF8(_MemoryRead(_MemoryRead(_MemoryRead($CurrentObject + $offGameObjectName1, $Processus, 'int') + $offGameObjectName2, $Processus, 'int'), $Processus, 'char[128]'))
EndSwitch
Return ""
EndFunc ;==>GetObjectName
Func _String_To_StringUTF8($String) ;Convertit une chaîne de charactère en chaîne UTF8
Return BinaryToString(StringToBinary($String, 1), 4)
EndFunc
Donc enfin voici le code complet qui affiche les résultat dans une ListView qui est en faite un tableau(avec de la couleur !)
PHP:
#include "DescriptorDump.au3" ;Dump de Kynox convertit en AutoIt
#include <NomadMemory.au3>
;Include pour la GUI
#include <GUIConstantsEx.au3>
#include <GUIConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
;On déclare toutes les adresses et offset
;Le fait de mettre Const empêche une modifications des donnés
;Cela évite des erreurs bêtes et permet d'etre plus clair
Global Const $staticClientConnection = 0x01132F60 ;3.0.9 : 0x011CB310
Global Const $offFirstObject = 0xAC, $offNextObject = 0x3C ;3.0.9 : 0xAC ;3.0.9 : 0x3C
Global Const $offLocalGuid = 0xC0 ;Guid du joueur ;3.0.9 : 0xC0
Global Const $offObjectManager = 0x2C24 ;3.0.9 : 0x28A4
;On déclare les variables
Local $CurrentObject
Local $ObjectPosition[4]
Local $LocalGuid
Global $ObjectManagerBase
Global $Processus
Global Const $offTypeObject = 0x14 ;3.0.9 : 0x14
Global Const $offGuid = 0x30 ;3.0.9 : 0x30
Global Const $offPosX = 0x798 ;3.0.9 : 0x7D0
Global Const $offPosY = 0x79C ;3.0.9 : 0x7D4
Global Const $offPosZ = 0x7A0 ;3.0.9 : 0x7D8
Global Const $offRot = 0x7A8 ;3.0.9 : 0x7DC
Global Const $offDescriptorFields = 0x8 ;3.0.9 : 0x8
Global Const $offGOPosX = 0xE8 ;3.0.9 : NOT
Global Const $offGOPosY = 0xEC ;3.0.9 : NOT
Global Const $offGOPosZ = 0xF0 ;3.0.9 : NOT
Global Const $offGORot = 0xF4 ;3.0.9 : NOT
Global Const $offUnitName1 = 0x968 ;3.0.9 : 0x970
Global Const $offUnitName2 = 0x54 ;3.0.9 : 0x03C
Global Const $offGameObjectName1 = 0x1A4 ;3.0.9 : 0x1F4
Global Const $offGameObjectName2 = 0x88 ;3.0.9 : 0x078
Global Const $nameStorePtr = 0x01137CE0 + 0x8;Nom du joueur dans la base de données ;3.0.9 : 0x011AF470 + 0x8
Global Const $nameMaskOffset = 0x024;offset qui correspond au mask pour trouver le nom dans la liste de noms ;3.0.9 : 0x024
Global Const $nameBaseOffset = 0x01c;offset qui correspond au début de la liste de nom ;3.0.9 : 0x01c
Global Const $nameStringOffset = 0x020;offset qui correspond à la chaine de charactere dans la structure de nom ;3.0.9 :0x020
;On déclare la gui en mémoire
$FormMain = GUICreate("Résultats...", 517, 308, 193, 125)
$LabelResult = GUICtrlCreateLabel("Résultat du dump :", 180, 8, 120, 17)
$List = GUICtrlCreateListView("", 8, 32, 497, 265, BitOR($WS_BORDER, $WS_HSCROLL, $WS_VSCROLL, 0xD), 0x200)
_GUICtrlListView_AddColumn($List, "Nom", 100)
_GUICtrlListView_AddColumn($List, "PosX", 100)
_GUICtrlListView_AddColumn($List, "PosY", 100)
_GUICtrlListView_AddColumn($List, "PosZ", 100)
_GUICtrlListView_AddColumn($List, "Rotation", 100)
SETPRIVILEGE("SeDebugPrivilege", 1) ;pour mettre le mode debug et pour pouvoir lire la mémoire (1 pour lactiver 0 pour le désactiver)
$Dll = DllOpen("user32.dll")
While 1
If ProcessExists("wow.exe") Then ;si il trouve le processus wow.exe on passe à la suite
$Processus = _MemoryOpen(WinGetProcess("World of Warcraft"))
ExitLoop
EndIf
WEnd
GUISetState(@SW_SHOW) ;On affiche la fenêtre
LoadAdresses() ;on initiale l'ojectmanager
$CurrentObject = _MemoryRead($ObjectManagerBase + $offFirstObject, $Processus, 'int') ;on trouve le premier objet
Local $i
While ($CurrentObject <> 0) And (Mod($CurrentObject, 2) == 0) ;si différent de 0 ou si pair on continu la boucle
Switch (_MemoryRead($CurrentObject + $offTypeObject, $Processus, 'int')) ;selon le type de l'objet
Case 1
$i += 1 ;on incrémente $i pour chaque objet trouvé
Case 2
$i += 1
Case 3
;Unité
$ObjectPosition = GetObjectPos($CurrentObject, 3) ;donne la pos de l'unité
GUICtrlCreateListViewItem(GetObjectName($CurrentObject, 3) & "|" & $ObjectPosition[0] & "|" & $ObjectPosition[1] & "|" & $ObjectPosition[2] & "|" & $ObjectPosition[3], $List)
GUICtrlSetBkColor(-1, 0x60ff0000) ;Fond rouge
$i += 1
Case 4
;Joueur
$ObjectPosition = GetObjectPos($CurrentObject, 4) ;donne la pos du joueur
GUICtrlCreateListViewItem(GetObjectName($CurrentObject, 4) & "|" & $ObjectPosition[0] & "|" & $ObjectPosition[1] & "|" & $ObjectPosition[2] & "|" & $ObjectPosition[3], $List)
If (_MemoryRead($CurrentObject + $offGuid, $Processus, 'int') = $LocalGuid) Then ;si le guid est égale à celui du joueur
GUICtrlSetBkColor(-1, 0x6000ffff) ;Fond Turquoise
Else ;sinon
GUICtrlSetBkColor(-1, 0x6000ff00) ;Fond vert
EndIf
$i += 1
Case 5
;GameObject
$ObjectPosition = GetObjectPos($CurrentObject, 5) ;donne la pos du GameObject
GUICtrlCreateListViewItem(GetObjectName($CurrentObject, 5) & "|" & $ObjectPosition[0] & "|" & $ObjectPosition[1] & "|" & $ObjectPosition[2] & "|" & $ObjectPosition[3], $List)
GUICtrlSetBkColor(-1, 0x600000ff) ;Fond bleu
$i += 1
Case 6
;Sort ou équipement
$i += 1
Case 7
;Cadavre
$i += 1
EndSwitch
$CurrentObject = _MemoryRead($CurrentObject + $offNextObject, $Processus, 'int') ;On lit l'objet suivant
WEnd
GUICtrlSetData($LabelResult, GUICtrlRead($LabelResult) & $i)
While 1 ;boucle infini pour attendre la fermeture de la fenerre
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Func GetObjectPos($Object, $Type)
Local $returnPos[4]
Switch ($Type)
Case 1 ;On retourne 0 car les items et conteneur n'ont pas de pos
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
Case 2
$returnPos[0] = 0
$returnPos[1] = 0
$returnPos[2] = 0
$returnPos[3] = 0
Case 3 ;Si c'est une unité ou un joueur...
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
Case 4
$returnPos[0] = _MemoryRead($Object + $offPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offRot, $Processus, 'float') ;Rotation
Case 5 ;GameObject
;~ WOW 3.0.9-
;~ $returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_X * 4, $Processus, 'float')
;~ $returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_Y * 4, $Processus, 'float')
;~ $returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_POS_Z * 4, $Processus, 'float')
;~ $returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $GAMEOBJECT_FACING * 4, $Processus, 'float')
;~ WOW 3.1.0+
$returnPos[0] = _MemoryRead($Object + $offGOPosX, $Processus, 'float') ;Pos X
$returnPos[1] = _MemoryRead($Object + $offGOPosY, $Processus, 'float') ;Pos Y
$returnPos[2] = _MemoryRead($Object + $offGOPosZ, $Processus, 'float') ;Pos Z
$returnPos[3] = _MemoryRead($Object + $offGORot, $Processus, 'float') ;Rotation
Case 6 ;Sort
;~ WOW 3.0.9-
;~ $returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_X * 4, $Processus, 'float')
;~ $returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_Y * 4, $Processus, 'float')
;~ $returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_POS_Z * 4, $Processus, 'float')
;~ $returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $DYNAMICOBJECT_FACING * 4, $Processus, 'float')
Case 7 ;cadavre
;~ WOW 3.0.9-
;~ $returnPos[0] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_X * 4, $Processus, 'float')
;~ $returnPos[1] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_Y * 4, $Processus, 'float')
;~ $returnPos[2] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_POS_Z * 4, $Processus, 'float')
;~ $returnPos[3] = _MemoryRead(_MemoryRead($CurrentObject + $offDescriptorFields, $Processus, 'int') + $CORPSE_FIELD_FACING * 4, $Processus, 'float')
EndSwitch
Return $returnPos ;on retourne le résultat sous forme de tableau
EndFunc ;==>GetObjectPos
Func GetObjectName($Object, $Type)
Switch ($Type)
Case 3;unité
Return _String_To_StringUTF8(_MemoryRead(_MemoryRead(_MemoryRead($CurrentObject + $offUnitName1, $Processus, 'int') + $offUnitName2, $Processus, 'int'), $Processus, 'char[128]'))
Case 4;joueur
Return _String_To_StringUTF8(GetPlayerNameByGuid(_MemoryRead($Object + $offGuid, $Processus, 'int')))
Case 5;gameobject
Return _String_To_StringUTF8(_MemoryRead(_MemoryRead(_MemoryRead($CurrentObject + $offGameObjectName1, $Processus, 'int') + $offGameObjectName2, $Processus, 'int'), $Processus, 'char[128]'))
EndSwitch
Return ""
EndFunc ;==>GetObjectName
Func GetPlayerNameByGuid($guid)
Local $mask, $base, $offset, $current, $shortGUID, $testGUID
$mask = _MemoryRead($nameStorePtr + $nameMaskOffset, $Processus, 'int')
$base = _MemoryRead($nameStorePtr + $nameBaseOffset, $Processus, 'int')
$shortGUID = BitAND($guid, 0xffffffff)
If ($mask = 0xffffffff) Then Return ""
$offset = 12 * BitAND($mask, $shortGUID)
$current = _MemoryRead($base + $offset + 8, $Processus, 'int')
$offset = _MemoryRead($base + $offset, $Processus, 'int')
If (BitAND($current, 0x1) == 0x1) Then Return ""
$testGUID = _MemoryRead($current, $Processus, 'int')
While ($testGUID <> $shortGUID)
$current = _MemoryRead($current + $offset + 4, $Processus, 'int')
If (BitAND($current, 0x1) = 0x1) Then Return ""
$testGUID = _MemoryRead($current, $Processus, 'int')
WEnd
Return _MemoryRead($current + $nameStringOffset, $Processus, 'char[20]')
EndFunc ;==>GetPlayerNameByGuid
Func LoadAdresses()
$ObjectManagerBase = _MemoryRead(_MemoryRead($staticClientConnection, $Processus, 'ptr') + $offObjectManager, $Processus, 'int') ;trouve l'objectmanagerbase
$LocalGuid = _MemoryRead($ObjectManagerBase + $offLocalGuid, $Processus, 'int') ;trouve le guid du joueur
EndFunc ;==>LoadAdresses
Func _String_To_StringUTF8($String) ;Convertit une chaîne de charactère en chaîne UTF8
Return BinaryToString(StringToBinary($String, 1), 4)
EndFunc ;==>_String_To_StringUTF8
Voilà la partie sur l'ObjectManager est fini, c'est un très gros bout mais c'est très important, je vous conseille de le relire plusieurs fois et de modifier le code que j'ai donner pour comprendre comment ça fonctionne
fin