Bases de l'Auto Assembler : comprendre les scripts d'injection AOB dans Cheat Engine
Qu'est-ce qu'une entrée de script, comment fonctionnent [ENABLE] et [DISABLE], et analyse ligne par ligne du modèle d'injection AOB de Cheat Engine : aobscanmodule, alloc, labels, symboles et jokers.
La plupart des entrées utiles des tables de triche partagées ne sont pas de simples valeurs, mais des scripts : santé infinie, pas de rechargement, fabrication gratuite. Ils sont écrits dans l'Auto Assembler de Cheat Engine, un petit format de script qui combine l'assembleur x86 avec des commandes pour trouver et modifier du code. Ce guide explique ce que fait un tel script, détaille le modèle d'injection AOB que Cheat Engine génère pour vous, et présente les règles qui rendent un script fiable.
Vous en tirerez plus de profit si vous savez déjà trouver une valeur et ce qu'est un pointeur ; le guide d'analyse de pointeurs aborde ces notions. Les scripts modifient le code d'un jeu en cours d'exécution : utilisez-les uniquement dans des jeux solo et hors ligne, sauvegardez avant de tester et conservez des copies de vos fichiers de sauvegarde.
Qu'est-ce qu'une entrée de script
Une entrée de script est un élément de la liste d'adresses dont la colonne Valeur affiche <script>. Au lieu de pointer vers une valeur, elle contient du code Auto Assembler. Cocher la case Actif de l'entrée exécute la section [ENABLE] du script ; la décocher exécute la section [DISABLE]. Le guide sur comment utiliser une table de triche présente cela du côté de l'utilisateur.
Un script typique ne modifie pas une valeur une seule fois. Il modifie l'instruction du jeu qui écrit la valeur, de sorte que l'effet est permanent tant que le script est actif. Par exemple, l'instruction qui enregistre votre nouvelle santé après des dégâts peut être redirigée vers du code qui enregistre plutôt le maximum.
Les scripts ont un gros avantage sur les simples adresses : ils localisent leur cible en cherchant un motif d'octets dans le code du jeu, et fonctionnent donc après un redémarrage sans aucun pointeur. En contrepartie, ils dépendent de la stabilité de ce code, ce qui les lie à une version du jeu.
[ENABLE] et [DISABLE]
Chaque script activable possède ces deux sections. [ENABLE] trouve le code, alloue de la mémoire pour le nouveau code et écrit un saut depuis l'instruction du jeu vers ce nouveau code. [DISABLE] annule tout : il réécrit les octets d'origine, supprime les noms enregistrés et libère la mémoire. Un [DISABLE] bien écrit laisse le jeu exactement tel qu'il était. S'il est absent ou incorrect, décocher l'entrée laisse le jeu modifié ou instable jusqu'à son redémarrage.
Trouver l'instruction et générer le modèle
- Trouvez la valeur que vous voulez contrôler et ajoutez-la à la liste d'adresses.
- Faites un clic droit dessus et choisissez Find out what writes to this address. Faites changer la valeur dans le jeu. Une ou plusieurs instructions apparaissent dans la liste.
- Sélectionnez l'instruction et ouvrez-la dans le désassembleur (Memory Viewer).
- Avec cette instruction sélectionnée dans le Memory Viewer, ouvrez Tools → Auto Assemble.
- Dans la fenêtre Auto Assemble, choisissez Template → AOB Injection. Confirmez l'adresse et acceptez ou modifiez le nom du symbole, qui est
INJECTpar défaut. - Modifiez le script, puis utilisez le menu Fichier de la fenêtre pour l'assigner à la table de triche actuelle. Il apparaît dans la liste d'adresses comme une nouvelle entrée de script.
Le modèle d'injection AOB, ligne par ligne
Voici un exemple de structure produite par le modèle. Le nom du processus, le symbole et les octets sont inventés à titre d'illustration ; ce n'est pas du code d'un vrai jeu.
{ EXAMPLE STRUCTURE ONLY - not code for a real game.
Process: game.exe Symbol: INJECT Bytes: made up }
[ENABLE]
aobscanmodule(INJECT,game.exe,89 83 F0 00 00 00 48 8B 5C 24 ??) // should be unique
alloc(newmem,$1000,INJECT)
label(code)
label(return)
newmem:
mov eax,#999 // your change: store 999 instead
code:
mov [rbx+000000F0],eax // the original instruction
jmp return
INJECT:
jmp newmem
nop
return:
registersymbol(INJECT)
[DISABLE]
INJECT:
db 89 83 F0 00 00 00 // original bytes: mov [rbx+000000F0],eax
unregistersymbol(INJECT)
dealloc(newmem)
aobscanmodule
aobscanmodule(INJECT,game.exe,...) recherche le motif d'octets dans la mémoire du module game.exe et, s'il le trouve, définit le nom INJECT comme l'adresse où il commence. Limiter la recherche à un module est plus rapide et évite les fausses correspondances ailleurs. Des commandes voisines existent : aobscan recherche dans toute la mémoire, et aobscanregion recherche entre deux adresses. Si le motif est introuvable, le script ne s'active pas et affiche une erreur, ce qui est le symptôme habituel après une mise à jour du jeu.
alloc
alloc(newmem,$1000,INJECT) réserve 0x1000 octets de mémoire pour votre code et l'appelle newmem. Le troisième paramètre demande à Cheat Engine de l'allouer près de INJECT. Dans les jeux 64 bits, c'est important : un court jmp de 5 octets ne peut atteindre qu'environ 2 Go dans chaque direction, et allouer à proximité permet de garder un saut assez petit pour remplacer l'instruction d'origine.
label
label(code) et label(return) déclarent des noms pour des positions définies plus bas. code indique où l'instruction d'origine est rejouée ; return indique l'instruction située juste après celle modifiée, où l'exécution continue.
newmem et code
Tout ce qui se trouve sous newmem: est votre code, suivi de l'instruction d'origine sous code:. Dans l'exemple, mov eax,#999 met le registre à 999 (le # indique un nombre décimal), puis l'instruction d'origine mov [rbx+000000F0],eax l'enregistre, de sorte que la valeur écrite est toujours 999. Enfin, jmp return revient dans le code du jeu.
INJECT: jmp newmem
À l'adresse trouvée, le script écrase l'instruction d'origine par jmp newmem. Le saut occupe 5 octets mais l'instruction d'origine en faisait 6 ici, donc un nop comble l'octet restant ; sinon le processeur tenterait d'exécuter une demi-instruction. Le modèle fait ce calcul pour vous. return: est placé juste après, et marque donc la prochaine instruction intacte.
registersymbol et unregistersymbol
registersymbol(INJECT) rend le nom INJECT connu globalement dans Cheat Engine. C'est ce qui permet à la section [DISABLE], exécutée plus tard et séparément, de retrouver la même adresse sans nouvelle analyse. Cela permet aussi à d'autres entrées d'y faire référence. unregistersymbol(INJECT) dans [DISABLE] supprime le nom.
Restaurer les octets d'origine, et dealloc
Dans [DISABLE], INJECT: suivi de db 89 83 F0 00 00 00 réécrit les octets d'origine par-dessus le saut, ce qui restaure exactement l'instruction du jeu. Ensuite, dealloc(newmem) libère la mémoire qui contenait votre code. L'ordre compte : restaurez d'abord le saut, afin que le jeu n'utilise plus newmem au moment de sa libération.
Jokers et importance des signatures uniques
Le motif d'octets dans aobscanmodule s'appelle une signature. Elle doit remplir deux conditions :
- Elle doit être unique. Si le motif apparaît plusieurs fois, le script modifie la première correspondance, qui peut être une fonction complètement différente. C'est ainsi que des scripts font planter des jeux ou modifient la mauvaise chose. Le modèle ajoute le commentaire « should be unique » comme rappel.
- Elle doit résister aux petits changements. Certains octets changent facilement entre les versions du jeu, voire entre deux lancements : décalages dans les instructions, adresses relatives des appels et des sauts, constantes intégrées. Remplacer ces octets par des jokers
??permet au motif de continuer à correspondre quand seuls ces détails changent.
Ces deux objectifs s'opposent. Trop peu d'octets et le motif correspond à de nombreux endroits ; trop de jokers et il redevient générique. Une approche pratique consiste à garder les octets d'opcode, remplacer par des jokers les décalages et adresses variables, et inclure quelques octets des instructions suivantes pour le contexte. Vérifiez ensuite que le motif est unique : dans la fenêtre principale, réglez Value Type sur Array of byte, collez le motif et lancez l'analyse avec les options de mémoire incluant la mémoire exécutable. Vous voulez obtenir exactement un résultat. Le générateur de signatures AOB vous aide à transformer des octets copiés en motif avec jokers et à repérer les octets susceptibles de changer.
Tester un script
- Sauvegardez la partie et gardez une copie de votre sauvegarde avant le premier test.
- Activez le script, vérifiez l'effet, puis désactivez-le et confirmez que le jeu se comporte à nouveau normalement.
- Activez-le et désactivez-le plusieurs fois. Un script qui échoue à la deuxième activation a généralement une section
[DISABLE]qui n'annule pas entièrement[ENABLE]. - Faites attention aux instructions partagées. L'instruction qui écrit votre santé peut aussi écrire celle des ennemis ; dans ce cas, votre modification affecte tout le monde, et vous devrez distinguer les cas avant de modifier quoi que ce soit.
Une fois qu'un script fonctionne, donnez à l'entrée une description claire et enregistrez la table. Quand le jeu est mis à jour et que le script ne s'active plus, la signature est la première chose à vérifier.
Commentaires
Aucun commentaire pour le moment
Soyez le premier à donner votre avis.