Trainers Tutorials by Xylitol - Débuter en game-hacking

Select your platform and your letter

0-9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Become a Patron!   Amazon.com    Amazon Prime    Gamesplanet Shop

Trainers Tutorials by Xylitol - Débuter en game-hacking

Introduction:


On va reverse un jeu, faire nos triches, et coder un trainer.


Dead Space est un jeu vidéo de tir à la troisième personne dans le genre survival horror dans un univers de science-fiction.
C'est développé par EA game et le jeu est sorti en 2008.
Personnellement, j'ai apprécié y jouer, et c'est aussi avec ce jeu que j'ai découvert Sigur Rós, notamment avec l'utilisation de Dauðalagið dans le trailer du jeu.


Les outils:



I.a: Trouver un pointeur pour les munitions:


Lancez Dead Space, puis allez dans votre partie.
En parallèle, lancez Cheat Engine, puis sélectionnez le processus de Dead Space et cliquez sur Open.


1

Une fois le processus sélectionné, on va lancer un premier scan avec notre valeur actuelle pour les munitions qu'on a pour l'arme. Pour moi c'est '10'


1

On retourne dans le jeu pour tirer une balle, puis on retourne dans Cheat Engine pour insérr notre nouvelle valeur (9, pour moi) et on clique sur Next scan. Après le scan, la liste des valeurs a diminué, mais ce n’est pas encore assez dégrossi, on va donc recommencer.


1

Maintenant il ne reste plus qu'une seule adresse !
On double clique dessus pour envoyer notre valeur dans le volet de la table de triche.


1

On double clique sur notre valeur (8) dans le volet de la table de triche.
Une fenêtre d'édition s'ouvre, on remplace notre valeur par '1337' pour voir si ça change quelque chose dans le jeu.


1

On retourne dans le jeu et effectivement, on peut voir que notre manipulation de la valeur a fonctionné


1

Maintenant qu'on a la bonne adresse, il faut trouver d'où est ce qu'elle est lu/qui l'écrit.
Clic droit sur notre adresse et on clique sur "Find out what accesses this address"
On pourrait aussi faire "find out what writes to this address" mais on va déjà voir si ça donne quelque chose comme ça.


1

Une fenêtre nous prévient que l'on va attacher le débogueur au processus.
On clique sur Yes.
Ce qu'il y a de bien avec le débogueur de Cheat Engine c'est qu'on peut le détacher sans devoir terminer la cible avec comme dans Olly.


1

La fenêtre des opcodes apparaît.
On constate que 004F9101 semble y accéder avec insistance.
004F9101 - 8B 88 84060000 - mov ecx,[eax+00000684]

Si on retourne dans le jeu et que l'on passe en mode visée pour mettre en joue, d'autres adresses apparaissent:
004F88A3 - 8B 86 84060000 - mov eax,[esi+00000684]
004F8E9A - 8B 87 84060000 - mov eax,[edi+00000684]
011BA650 - 8B 86 84060000 - mov eax,[esi+00000684]
004F8EF9 - 83 BF 84060000 00 - cmp dword ptr [edi+00000684],00
004F8F29 - 8B 87 84060000 - mov eax,[edi+00000684]

004F88A3 semble y accéder pendant toute la durée du maintien de notre clique droit dans le jeu.
Le reste est accédé une seule fois pendant l'action.
Si on met le jeu en pause, toutes les adresses arrêtent de lire le pointeur.

004F9101 semble digne d'intérêt pour nous vu que le code passe tout le temps dessus.
On pourrait réécrire notre pointeur à cet endroit, comme ça, même si on tire des munitions, cette boucle de lecture va remettre notre valeur dans le compteur.


1

Ok, maintenant qu'on a les adresses là on click sur le bouton Stop, puis on reclique sur le même bouton qui et devenu 'Close'


I.b: Faire un codecave pour les munitions


On parle souvent de codecave dans le game-hacking, car contrairement au cracking où généralement les remplacements sont minimes en taille et consistent juste à changer un JUMP ou un registre.
Dans le game-hacking on a souvent besoin de rajouter du code "en plus", et on n’a pas la place sans écraser les instructions dans dessous.
Du coup, on redirige ailleurs, où il y a de la place, et on revient de la procédure à la fin.
Enfin, vous aller voir.

Fermez Cheat Engine et ouvrez Ollydbg, puis attachez-le au process de Dead Space.

1

Olly met en pause le processus une fois celui-ci attaché.
Allez dans la fenêtre des modules de l'exécutable (ALT+E), sélectionnez Dead Space.exe, click droit et cliquez sur follow entry.

1

On arrive maintenant sur la plage d'offset 011F, on va chercher un endroit en prévision pour poser notre code.
Donc la c'est à vous de voir, soit vous scrollez directement en bas avec le désassembleur pour voir si y'a de la place.
Soit vous pouvez aussi chercher des "zéros" en faisant un clic droit>search for binary string (CTRL+B)

1

Pour ma part, je vais établir un codecave sur cette zone:

1

Il y a de la place, et cette zone mémoire ne semble pas être protégée/réécrite par dessus.

On note l'offset pour s'en rappeler plus tard: 011F631D

Revenons à nos munitions, on a trouvé avec Cheat Engine l'adresse 004F9101, allons-y faire un tour avec Olly. (CTRL+G)
MOV ECX,DWORD PTR DS:[EAX+684]
On a un pointeur (EAX+684) son contenue est placé dans ECX.
Si on pose un breakpoint dessus et qu'on lance, on rebreak directement sur notre instruction, on presse F8 un coup et on remarque que ECX contient le nombre de munitions.

1

On a juste à remplacer l'adresse du pointeur par une valeur fixe, mais on n’a pas la place en terme de taille pour faire ça.
C'est pour ça qu'on a chercher un peu plus tôt 'une zone libre' on remplace l'instruction MOV ECX,DWORD PTR DS:[EAX+684] par un JMP sur notre zone.

1

Juste la place pour! ça n'aurait pas été un problème si on avait tapé dans la ligne du CMP (on l'aurait juste déplacé dans notre cave).

Maintenant pour le code cave c'est simple:

MOV DWORD PTR DS:[EAX+684],539
On place 539 (1337) dans le pointeur.

MOV ECX,DWORD PTR DS:[EAX+684]
C'est l'instruction originale en 004F9101, on place le contenu du pointeur dans ECX.

JMP 004F9107
On resaute pour revenir en 004F9107 (sur CMP ECX,DWORD PTR DS:[EAX+68C])

Une fois ça fait on et bon, y'a plus qu'a enlever notre breakpoint, appuyez sur F9 pour relancez l'exécution et testez notre modification.

1

II.a: Trouver le pointeur pour la vie


On ne connait pas notre valeur de santé, rien ne nous l'indique dans le jeu.
On a juste des jauges posées dans la partie dorsale de notre armure.

De manière générale dans les jeux, la valeur de la santé a tendance à être en float, on va partir du principe qu'on a la vie pleine donc à 100, on lance un premier scan avec 100 en valeur.

1

Ensuite on va prendre des dégâts dans le jeu, et on relance un scan avec 'Decreased value'

1

Il y en a de trop, on recommence, plus que 20, on continue.

1

Plus que 11 résultats.

1

Vu que les valeurs qui restent semblent toutes descendre, on va essayer de monter.
Hop, on va se soigner dans le jeu avec un medikit puis on rescanne, mais avec Increased value.
Plus que 5:

1

Bon, à ce stade, soit vous continuez, où soit vous commencez à regarder manuellement la valeur des adresses.
Pour ma par je l'ai refait un coup avec Decreased Value, puis j'ai regardé ce que j'avais.


1

Une valeur avec "55"
Une autre avec -2
Une autre à zéro.

La plus probable étant celle avec la valeur de 55, je l'ai juste remis a 100 et regardé ce qu'il se passait dans le jeu.
Ma jauge de santé et revenue à 100%, c'est bien la bonne valeur.


Si on n’avait rien eu: peut-être que notre valeur initiale n'était pas à 100.
Dans ce cas on aurait refait le premier scanne, mais avec 'Unknown initial value' puis reappliqué la stratégie Decreased/Increased value pour les scannes suivants.


Il faut trouver qui lit/écrit dans cette adresse maintenant.
On fait pareil que tout à l'heure pour les munitions et on attache le débogueur de Cheat Engine pour savoir qui accède au pointeur.


1

On a:
00526FE9 - 0F2F 80 20010000 - comiss xmm0,[eax+00000120]
Qui semble lire constamment.

Et les autres, qui lisent (ou pas) selon vos actions:
00525971 - 0F2F 86 20010000 - comiss xmm0,[esi+00000120]
00527026 - D9 80 20010000 - fld dword ptr [eax+00000120]
0045D393 - 0F2F 80 20010000 - comiss xmm0,[eax+00000120]

II.b: Faire le codecave pour la vie


On n'a plu qu'a mettre 1337 (c'est un float donc en hexa: 44A72000) dans le pointeur et voir ce que ça donne.
On a déjà un emplacement pour la cave, autant continuer derrière notre dernière modification de code.
Aller hop, on reattache Olly, on va sur 00526FE9 avec CTRL+G, et on remplace l'instruction qui lit le plus pour l'envoyer sur notre cave à la place.
Assurez-vous que le jeu soit en pause ou que le processus soit en pause avant de faire ça, sinon il va partir directement sur votre jump et crasher dans le champ des 000000

1

Ensuite un peu de code:

MOV DWORD PTR DS:[EAX+120],44A72000
COMISS XMM0,DWORD PTR DS:[EAX+120]
JMP 00526FF0

1

Il n'y a plus qu'à tester:

1


III: Faire un trainer


On aurait pu utiliser Cheat Engine qui a une fonctionnalité pour générer un trainer, mais c'est toujours mieux d'avoir du code pour comprendre comment ça marche.
Du coup voilà une solution bricolée en assembleur.
Celui-là possède un peu plus d'options que simplement munitions illimitées et vies illimitées, mais les offsets sont tout aussi simples à trouver que ce qu'on a fait.
Pour le code il y a de la gestion de touches de raccourcie, et on écrit le processus en regardant le titre de la fenêtre et ça classe. (histoire de ne pas écrire dans l’explorateur Windows bêtement si le titre de la fenêtre contient 'Dead Space')

trainer.asm:

.486
.model	flat, stdcall
option	casemap :none   ; case sensitive

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\comctl32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\comctl32.lib

DlgProc       PROTO :DWORD,:DWORD,:DWORD,:DWORD
TrainerEngine PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD

.const
IDD_DIALOG      equ 1000
IDB_HEALTH      equ 1001
IDB_AMMO        equ 1002
IDB_KILL        equ 1003
IDB_MONEY       equ 1004
IDB_NODES       equ 1005
IDB_SHIPLIFE    equ 1006
IDB_VELOCITY    equ 1007
IDC_STATIC1005  equ 1008
IDC_STATIC1006  equ 1009
IDC_STATIC1007  equ 1010
IDC_STATIC1008  equ 1011
IDC_STATIC1009  equ 1012
IDC_STATIC1010  equ 1013
IDC_STATIC1011  equ 1014
IDC_STATIC1012  equ 1015
.data
;Dialog details
szTitle         db "Dead Space v1.0.0.222 Trainer +7",0 
szIDBCheatON    db "[ENABLE]",0
szIDBCheatOFF   db "[DISABLE]",0
szErrorCaption  db "ERROR", 0
szErrorMessage  db "Game is not Running",0ah 
                db "You need to run the game",0ah
                db "So You can Use the trainer",0
szHotkeyHelp    db "Hotkeys", 0
szHotkeyF12     db "F12 - Unlimited health and stasis", 0
szHotkeyF11     db "F11 - Unlimited Ammo", 0
szHotkeyF10     db "F10 - One Hit Kill", 0
szHotkeyF9      db "F9   - Unlimited credits", 0
szHotkeyF8      db "F8   - Unlimited nodes", 0
szHotkeyF7      db "F7   - Unlimited Ship health", 0
szHotkeyF6      db "F6   - Super speed", 0

;Game patching details
;Tested with Dead.Space-RELOADED
GameCaption     db "Dead Space",0 ; The window name of game
GameClass       db "DeadSpaceWndClass",0 ;game class

Offset1         dd 4F9101h ; Unlimited ammunition
bytes2write1    db 0E9h,017h,0D2h,0CFh,000h,090h ; JMP 011F631D
bytes2Restore1  db 08Bh,088h,084h,006h,000h,000h ; MOV ECX,DWORD PTR DS:[EAX+684]
Offset2         dd 011F631Dh ; Unlimited ammunition (codecave)
bytes2write2    db 0C7h,080h,084h,006h,000h,000h,039h,005h,000h,000h, ;MOV DWORD PTR DS:[EAX+684],539
                   08Bh,088h,084h,006h,000h,000h,                     ;MOV ECX,DWORD PTR DS:[EAX+684]
                   0E9h,0D5h,02Dh,030h,0FFh                           ;JMP 004F9107

Offset3         dd 526FE9h ; Unlimited health
bytes2write3    db 0E9h,044h,0F3h,0CCh,000h,090h,090h ; JMP 011F6332
bytes2Restore3  db 00Fh,02Fh,080h,020h,001h,000h,000h ; COMISS XMM0,DWORD PTR DS:[EAX+120]
Offset4         dd 011F6332h ; Unlimited health (codecave)
bytes2write4    db 0C7h,080h,020h,001h,000h,000h,000h,020h,0A7h,044h, ;MOV DWORD PTR DS:[EAX+120],44A72000
                   00Fh,02Fh,080h,020h,001h,000h,000h,                ;COMISS XMM0,DWORD PTR DS:[EAX+120]
                   0E9h,0A8h,00Ch,033h,0FFh                           ;JMP 00526FF0

Offset5         dd 005808E7h ; Unlimited credits
bytes2write5    db 0E9h,05Ch,05Ah,0C7h,000h,090h ; JMP 011F6348
bytes2Restore5  db 08Bh,082h,0E4h,00Ch,000h,000h ; MOV EAX,DWORD PTR DS:[EDX+CE4]
Offset6         dd 011F6348h ; Unlimited credits (codecave)       
bytes2write6    db 0C7h,082h,0E4h,00Ch,000h,000h,0F9h,0C7h,004h,000h, ;MOV DWORD PTR DS:[EDX+CE4],4C7F9
                   08Bh,082h,0E4h,00Ch,000h,000h,                     ;MOV EAX,DWORD PTR DS:[EDX+CE4]
                   0E9h,090h,0A5h,038h,0FFh                           ;JMP 005808ED

Offset7         dd 00521610h ; Unlimited nodes
bytes2write7    db 0E9h,048h,04Dh,0CDh,000h,090h ; JMP 011F635D
bytes2Restore7  db 08Bh,081h,094h,005h,000h,000h ; MOV EAX,DWORD PTR DS:[ECX+594]
Offset8         dd 011F635Dh ; Unlimited nodes (codecave)
bytes2write8    db 0C7h,081h,094h,005h,000h,000h,0F9h,0C7h,004h,000h, ;MOV DWORD PTR DS:[ECX+594],04C7F9
                   08Bh,081h,094h,005h,000h,000h,                     ;MOV EAX,DWORD PTR DS:[ECX+594]
                   0E9h,0A4h,0B2h,032h,0FFh                           ;JMP 00521616

; Used only in Chapter 4 with the Asteroid Defense System cannon shooting/minigame
; No codecave here, just a dumb patch.
Offset9           dd 005BE9ACh ; Unlimited Ship health
Offset10          dd 005BE9F6h ; Unlimited Ship health (offset2)
bytes2write0910   db 090h,090h,090h,090h,090h,090h,090h,090h ; NOPS
bytes2Restore0910 db 0F3h,00Fh,011h,083h,094h,007h,000h,000h ; MOVSS DWORD PTR DS:[EBX+794],XMM0

Offset11          dd 004518DEh ; one hit kill
bytes2write11     db 0E9h,07Ah,04Ah,0DAh,000h,090h,090h,090h ; JMP 011F635D
bytes2Restore11   db 0F3h,00Fh,010h,087h,020h,001h,000h,000h ; MOVSS XMM0,DWORD PTR DS:[EDI+120]
Offset12          dd 011F6389h ; one hit kill (codecave)
bytes2write12     db 0C7h,087h,020h,001h,000h,000h,000h,000h,000h,000h, ;MOV DWORD PTR DS:[EDI+120],0
                     0F3h,00Fh,010h,087h,020h,001h,000h,000h,           ;MOVSS XMM0,DWORD PTR DS:[EDI+120]
                     0E9h,072h,0B5h,025h,0FFh                           ;JMP 004518E6

Offset13          dd 005471C4h ; Unlimited Stasis
bytes2write13     db 0E9h,0A9h,0F1h,0CAh,000h,090h,090h,090h ; JMP 011F6372
bytes2Restore13   db 0F3h,00Fh,010h,089h,028h,001h,000h,000h ; MOVSS XMM1,DWORD PTR DS:[ECX+128]
Offset14          dd 011F6372h ; Unlimited Stasis (codecave)
bytes2write14     db 0C7h,081h,028h,001h,000h,000h,000h,000h,0C8h,042h, ;MOV DWORD PTR DS:[ECX+128],42C80000
                     0F3h,00Fh,010h,089h,028h,001h,000h,000h,           ;MOVSS XMM1,DWORD PTR DS:[ECX+128]
                     0E9h,043h,00Eh,035h,0FFh                           ;JMP 005471CC
                     
Offset15          dd 004644A0h ; Super speed
bytes2write15     db 0E9h,0FBh,01Eh,0D9h,000h,090h ; JMP 011F63A0
Offset16          dd 011F63A0h ; Super speed (codecave)
bytes2write16     db 0C7h,081h,080h,000h,000h,000h,000h,000h,000h,040h, ;MOV DWORD PTR DS:[ECX+80],50000000
                     0D9h,081h,080h,000h,000h,000h,                     ;FLD DWORD PTR DS:[ECX+80]
                     0E9h,0F1h,0E0h,026h,0FFh                           ;JMP 004644A6
;Normal speed is bytes2write17
bytes2write17     db 0C7h,081h,080h,000h,000h,000h,000h,000h,080h,03Fh, ;MOV DWORD PTR DS:[ECX+80],3F800000
                     0D9h,081h,080h,000h,000h,000h,                     ;FLD DWORD PTR DS:[ECX+80]
                     0E9h,0F1h,0E0h,026h,0FFh                           ;JMP 004644A6

.data?
hInstance       dd ?
windhand        dd ? ; Window handle
hwnddlg         dd ? ; Window handle
phandle         dd ? ; Process handle of game
pid             dd ? ; Process id of game
status1         dd ? ; on/off
status2         dd ? ; on/off
status3         dd ? ; on/off
status4         dd ? ; on/off
status5         dd ? ; on/off
status6         dd ? ; on/off
status7         dd ? ; on/off

.code
start:
    invoke GetModuleHandle, NULL
    invoke DialogBoxParam, hInstance, IDD_DIALOG, 0, ADDR DlgProc, 0
    invoke ExitProcess, eax
; -----------------------------------------------------------------------
DlgProc	proc    hWin    :DWORD,
        uMsg    :DWORD,
        wParam  :DWORD,
        lParam  :DWORD

	.if uMsg == WM_INITDIALOG
        pushad ; Saving registry is needed... the program will crash if you omit this
        ; Set the dialog controls texts. Done here in the code instead of resource
        ; file to reduce the required bytes (strings in the rc file are UNICODE not ANSI)
        invoke SetWindowText,hWin,ADDR szTitle ; Set the window title text
        invoke SetDlgItemText,hWin,IDB_HEALTH,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_AMMO,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_KILL,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_MONEY,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_NODES,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_SHIPLIFE,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDB_VELOCITY,ADDR szIDBCheatON
        invoke SetDlgItemText,hWin,IDC_STATIC1005,ADDR szHotkeyHelp
        invoke SetDlgItemText,hWin,IDC_STATIC1006,ADDR szHotkeyF12
        invoke SetDlgItemText,hWin,IDC_STATIC1007,ADDR szHotkeyF11
        invoke SetDlgItemText,hWin,IDC_STATIC1008,ADDR szHotkeyF10
        invoke SetDlgItemText,hWin,IDC_STATIC1009,ADDR szHotkeyF9        
        invoke SetDlgItemText,hWin,IDC_STATIC1010,ADDR szHotkeyF8        
        invoke SetDlgItemText,hWin,IDC_STATIC1011,ADDR szHotkeyF7      
        invoke SetDlgItemText,hWin,IDC_STATIC1012,ADDR szHotkeyF6 
        mov hwnddlg, eax
        invoke SetTimer,hWin,0,90, 0 ;set the timer for monitoring action keystrokes
        mov status1,0
        mov status2,0
        mov status3,0
        mov status4,0
        mov status5,0
        mov status6,0
        mov status7,0
	.elseif	uMsg == WM_COMMAND ; Did the user press a button
        .if wParam == IDB_HEALTH
            @HEALTH:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status1 == 1
                  mov status1,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset3,offset bytes2Restore3,NULL,NULL,7
                  ;stasis:
                  invoke TrainerEngine,offset GameCaption,Offset13,offset bytes2Restore13,NULL,NULL,8
                  invoke SetDlgItemText,hWin,IDB_HEALTH,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status1,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset3,offset bytes2write3,NULL,NULL,7
                  invoke TrainerEngine,offset GameCaption,Offset4,offset bytes2write4,NULL,NULL,22
                  ;stasis!
                  invoke TrainerEngine,offset GameCaption,Offset13,offset bytes2write13,NULL,NULL,8
                  invoke TrainerEngine,offset GameCaption,Offset14,offset bytes2write14,NULL,NULL,23
                  
                  invoke SetDlgItemText,hWin,IDB_HEALTH,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_AMMO
            @AMMO:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status2 == 1
                  mov status2,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset1,offset bytes2Restore1,NULL,NULL,6
                  invoke Beep,1000,30
                  invoke SetDlgItemText,hWin,IDB_AMMO,ADDR szIDBCheatON
                .else
                  mov status2,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset1,offset bytes2write1,NULL,NULL,6
                  invoke TrainerEngine,offset GameCaption,Offset2,offset bytes2write2,NULL,NULL,21
                  invoke SetDlgItemText,hWin,IDB_AMMO,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_KILL
            @KILL:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status3 == 1
                  mov status3,0 ; Disable
                  invoke TrainerEngine, offset GameCaption, Offset11, offset bytes2Restore11, NULL, NULL,8
                  invoke SetDlgItemText,hWin,IDB_KILL,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status3,1 ; Enable
                  invoke TrainerEngine, offset GameCaption, Offset11, offset bytes2write11, NULL, NULL,8
                  invoke TrainerEngine, offset GameCaption, Offset12, offset bytes2write12, NULL, NULL,23
                  invoke SetDlgItemText,hWin,IDB_KILL,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_MONEY
            @MONEY:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status4 == 1
                  mov status4,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset5,offset bytes2Restore5,NULL,NULL,6
                  invoke SetDlgItemText,hWin,IDB_MONEY,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status4,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset5,offset bytes2write5,NULL,NULL,6
                  invoke TrainerEngine,offset GameCaption,Offset6,offset bytes2write6,NULL,NULL,21
                  invoke SetDlgItemText,hWin,IDB_MONEY,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_NODES
            @NODES:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status5 == 1
                  mov status5,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset7,offset bytes2Restore7,NULL,NULL,6
                  invoke SetDlgItemText,hWin,IDB_NODES,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status5,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset7,offset bytes2write7,NULL,NULL,6
                  invoke TrainerEngine,offset GameCaption,Offset8,offset bytes2write8,NULL,NULL,21
                  invoke SetDlgItemText,hWin,IDB_NODES,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_SHIPLIFE
            @SHIPLIFE:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status6 == 1
                  mov status6,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset9,offset bytes2Restore0910,NULL,NULL,8
                  invoke TrainerEngine,offset GameCaption,Offset10,offset bytes2Restore0910,NULL,NULL,8
                  invoke SetDlgItemText,hWin,IDB_SHIPLIFE,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status6,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset9,offset bytes2write0910,NULL,NULL,8
                  invoke TrainerEngine,offset GameCaption,Offset10,offset bytes2write0910,NULL,NULL,8
                  invoke SetDlgItemText,hWin,IDB_SHIPLIFE,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
        .if wParam == IDB_VELOCITY
            @VELOCITY:
            ; Find the game window
            invoke FindWindow,addr GameClass,addr GameCaption
            ; The game is running
            .if eax != NULL
                .if status7 == 1
                  mov status7,0 ; Disable
                  invoke TrainerEngine,offset GameCaption,Offset16,offset bytes2write17,NULL,NULL,21
                  invoke SetDlgItemText,hWin,IDB_VELOCITY,ADDR szIDBCheatON
                  invoke Beep,1000,30
                .else
                  mov status7,1 ; Enable
                  invoke TrainerEngine,offset GameCaption,Offset15,offset bytes2write15,NULL,NULL,6
                  invoke TrainerEngine,offset GameCaption,Offset16,offset bytes2write16,NULL,NULL,21
                  invoke SetDlgItemText,hWin,IDB_VELOCITY,ADDR szIDBCheatOFF
                  invoke Beep,5000,30
                .endif
            ;If game is not running
            .else
                invoke Beep,100,30
                ; Show the error message
                invoke MessageBox,hWin,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
            .endif
        .endif
	.elseif uMsg == WM_TIMER
    invoke GetAsyncKeyState, VK_F12 ; Was F12 pressed?
      .if eax != 0 ; If yes
         jmp @HEALTH
      .endif
     invoke GetAsyncKeyState, VK_F11 ; Was F11 pressed?
      .if eax != 0 ; If yes
         jmp @AMMO
      .endif
     invoke GetAsyncKeyState, VK_F10 ; Was F10 pressed?
      .if eax != 0 ; If yes
         jmp @KILL
      .endif
     invoke GetAsyncKeyState, VK_F9 ; Was F9 pressed?
      .if eax != 0 ; If yes
         jmp @MONEY
      .endif
     invoke GetAsyncKeyState, VK_F8 ; Was F8 pressed?
      .if eax != 0 ; If yes
         jmp @NODES
      .endif
     invoke GetAsyncKeyState, VK_F7 ; Was F7 pressed?
      .if eax != 0 ; If yes
         jmp @SHIPLIFE
      .endif
     invoke GetAsyncKeyState, VK_F6 ; Was F6 pressed?
      .if eax != 0 ; If yes
         jmp @VELOCITY
      .endif
	.elseif	uMsg == WM_CLOSE
        invoke AnimateWindow,hWin,300,AW_BLEND+AW_HIDE 
        invoke EndDialog,hWin,0
	.endif
	xor	eax,eax
	ret
DlgProc	endp

TrainerEngine PROC lpWindCap:DWORD, lpAdress:DWORD, lpNewValue:DWORD, nAdd:DWORD, lpBuffer:DWORD, _byteSize:DWORD
       ; Find the game window (again)
       invoke FindWindow,addr GameClass,lpWindCap
       ; The game is running
       .if eax != NULL
           ; Move the handle to windhand
           mov windhand, eax
           ; Get the process ID and save it to pid
           invoke GetWindowThreadProcessId, windhand, offset pid
           ; Open the process
           invoke OpenProcess, PROCESS_ALL_ACCESS,NULL, pid
           ; Move our process handle to phandle
           mov phandle, eax
           ; Prepare the ground for writing
           invoke VirtualProtectEx, phandle, lpAdress, _byteSize, PAGE_EXECUTE_READWRITE, 00
           ; Write the new value
           invoke WriteProcessMemory,phandle, lpAdress, lpNewValue, _byteSize, NULL
           ; Close handle
           invoke CloseHandle, phandle
       ; If game is not running
       .else
           invoke Beep,100,30
           ; Show the error message
           invoke MessageBox,hwnddlg,addr szErrorMessage,addr szErrorCaption,MB_ICONERROR
       .endif
ret ; Return
TrainerEngine ENDP

end start

base.rc:

;This Resource Script was generated by WinAsm Studio.

#define IDD_DIALOG 1000
#define IDB_HEALTH 1001
#define IDB_AMMO 1002
#define IDB_KILL 1003
#define IDB_MONEY 1004
#define IDB_NODES 1005
#define IDB_SHIPLIFE 1006
#define IDB_VELOCITY 1007
#define IDC_STATIC1005 1008
#define IDC_STATIC1006 1009
#define IDC_STATIC1007 1010
#define IDC_STATIC1008 1011
#define IDC_STATIC1009 1012
#define IDC_STATIC1010 1013
#define IDC_STATIC1011 1014
#define IDC_STATIC1012 1015

IDD_DIALOG DIALOGEX 0,0,227,129
FONT 8,"Tahoma"
STYLE 0x80c80880
EXSTYLE 0x00000000
BEGIN
	CONTROL "",IDB_HEALTH,"Button",0x50010000,163,22,61,13,0x00000000
	CONTROL "",IDB_AMMO,"Button",0x50010000,163,37,61,13,0x00000000
	CONTROL "",IDB_KILL,"Button",0x50010000,163,52,61,13,0x00000000
	CONTROL "",IDB_MONEY,"Button",0x50010000,163,68,61,13,0x00000000
	CONTROL "",IDB_NODES,"Button",0x50010000,163,83,61,13,0x00000000
	CONTROL "",IDB_SHIPLIFE,"Button",0x50010000,163,98,61,13,0x00000000
	CONTROL "",IDB_VELOCITY,"Button",0x50010000,163,114,61,13,0x00000000
	CONTROL "",IDC_STATIC1005,"Static",0x50000000,10,6,44,10,0x00000000
	CONTROL "",IDC_STATIC1006,"Static",0x50000000,23,22,134,10,0x00000000
	CONTROL "",IDC_STATIC1007,"Static",0x50000000,23,37,134,10,0x00000000
	CONTROL "",IDC_STATIC1008,"Static",0x50000000,23,52,134,10,0x00000000
	CONTROL "",IDC_STATIC1009,"Static",0x50000000,23,68,134,10,0x00000000
	CONTROL "",IDC_STATIC1010,"Static",0x50000000,23,83,134,10,0x00000000
	CONTROL "",IDC_STATIC1011,"Static",0x50000000,23,98,134,10,0x00000000
	CONTROL "",IDC_STATIC1012,"Static",0x50000000,23,114,134,10,0x00000000
END

make.bat:

@echo off
\masm32\bin\rc /v base.rc
\masm32\bin\ml.exe /c /coff /Cp /nologo trainer.asm
\masm32\bin\link.exe /SUBSYSTEM:WINDOWS /RELEASE /VERSION:4.0 /OUT:DS_Trainer.exe trainer.obj base.res
del base.res
del trainer.obj
pause

Une fois compilé, ça ressemble à ça:

1


Vu que le code du jeu passe très rapidement sur certaines boucles, il peut arriver que le trainer écrit pendant que le code passe dessus, cela ferra crasher l’exécutable du jeu.
Vu que les boucles sont à l’arrêt quand le jeu et en pause, c’est mieux de le mettre en pause, d’activer nos options et de reprendre la partie.


IV: Idées de hack:


Il est possible de faire beaucoup d'autres choses dans le jeu, voici quelques idées.

- Enlever la collision avec les ennemies quand ils vous touchent pour que le personnage ne bronche pas: Il faut désactiver le segment de code qui détecte que l'on a pris un coup.

- Enlever le recule quand on tir avec une arme: Désactiver le segment qui fait le recule après tir.

- Oxygene illimité : Désactiver le segment qui gère le timer quand le personnage entre dans une zone sans atmosphère respirable.

- Droper par terre des objets en x1337 exemplaires : Trouver le segment qui gère la quantité des objets.

- Geler les ennemis : Désactiver le segment de code qui détermine quand les monstres se déplacent. Ou bien trouver la variable qui affecte si un monstre a vu le joueur ou non, modifiez le code autour de cela afin que les monstres ne se mettent jamais en état d'alerte.

- Tuer les monstres en 1 coup: Trouvez la ligne de code qui soustrait la santé du monstre, faites-lui soustraire un registre différent avec une grosse valeur à la place, ou bien remplacez leur compteur de vie à zéro.
Parfois certains jeux possèdent aussi des registres partagés, où circule dans le registre votre vie puis celle des ennemies (cyberpunk 2077 par exemple). Du coup, trouver un point de référence fixe dans le registre pour votre joueur au moment du segment partagé, et faites une comparaison avec cette valeur dans la cave pour savoir si la boucle en cours concerne votre joueur ou l'ennemie, en général c'est facile de faire un 'one hit kill' couplé d'un cheat vies illimitées pour le joueur une fois qu'on a nos références.

- Méga dommages: Trouvez la ligne qui fait les dégâts de votre arme et augmentez-là.

- Fly hack/coordonnées du joueur: Pour un flyhack, trouvez le registre qui donne la hauteur de votre personnage dans l'espace et augmentez-là.
(increase/decrease en se déplaçant dans un escalier par exemple pour trouver le pointeur)

- Wallhack: en général quand le personnage entre en collision avec un objet, on a affaire à un booléen, la méthode commune consiste a rentrer dans un mur, mettre le jeu en pause cherchez 0, ou 1, sortir du mur et répétez.
Parfois il faut aussi trouver la valeur de collision avec la caméra, car notre personnage peut traverser le mur, mais c'est encore un autre booléen pour la caméra qui ne traversera pas le mur.



Voilà, il y a encore d'autres trucs rigolos à faire auxquels je n'ai surement pas pensé avec ce jeu.



Xylitol, 02/05/2021




Partners