A propos de Paint Shop Pro 5.0 FINAL RELEASE (fichier psp.exe -> 3 612 672 octets)
La version finale étant sortie, je me suis donc attelé à la tâche...

Je passe rapidement sur le crack de la partie Time Limit, c'est facile et CyberBobJr a déjà détaillé le processus...
Pour info, j'ai personnellement patché en : 

585C84 : PUSH 02  (6a 02)
         POP EDI  (5f)
	 DEC EDI  (4f)

Manipulation visant à fixer EDI à 01 (et à remplir tous les octets remplacés).
Soit 1 jour d'utilisation pour l'éternité.
(enfin jusqu'à la version 5.01 qui va sortir dans 3 jours n'en doutont pas...ptet même avant la fin de ce texte).
Bon maintenant le NAG SCREEN, le morceau de choix du crack...
J'ai donc lu avec attention le tutorial d'+ORC sur le crack des différents PSP. (recommandé par Ethan je crois).

Personnellement, shunter le NAG SCREEN me paraît très difficile ici, 
car d'importantes routines nécessaires à l'initialisation de PSP sont incluses dans la routine d'affichage du NAG...
Un peu en dessous d'ailleurs de l'endroit où l'on a patché pour le Time Limit 
(la vérif s'effectuant juste avant affichage des infos dans la boîte de dialogue). 
Donc shunter le NAG, c'est forcément ne pas exécuter ces routines. y'aura donc un manque quelque part...

Je me suis donc orienter vers la bonne veille méthode de simulation d'action sur le (faux) bouton START 
(cf version 4.14 de PSP).
Je ne vais pas détailler ici la procédure car on s'aperçoit vite qu'elle ne sert à rien !
Le NAG se ferme bien mais après impossible d'ouvrir le moinde fichier 
(les extensions de files dans la boite OpenFileName sont vierges), 
ou même d'en créer un nouveau (pas assez de mémoire me dit le prog ;)...

Bref, il y a en plus une vérif quelque part...

Réfléchissons : le NAG est ouvert, affiché et fermé comme si j'appuyais sur le bouton START. 
Pourquoi ça ne marche pas ?
Il se passe visiblement quelque chose entre le moment où le NAG est affiché et celui où 
l'utilisateur est censé le fermer par START.
Humm c'est ici que je suis parti du postulat suivant : PSP doit déclarer un TIMER pour la fenêtre du NAG, 
et ce TIMER va exécuter une (ou plusieurs) routines indispensables par la suite. 
Le fait de forcer la fermeture du NAG par "simulation" du bouton START ne permet pas 
à ces fonctions d'être exécutées puisque le TIMER n'a pas eu matériellement le temps d'envoyer l'info...
(en fait ce n'est pas vraiment ce qui se passe, on le verra plus loin mais j'ai gardé ce passage 
pour montrer le raisonnement de départ).

Donc à partir de là, que fait-on ?

On repère le HANDLE de la fenêtre du NAG (je vous conseille WINSIGHT pour ce genre de truc).
Après soit on pose un BMSG Handle-du-Dessus WM_TIMER, et on galère...
Soit on utilise encore WINSIGHT pour étudier justemment les MESSAGES WINDOWS envoyés vers le NAG.
On sélectionne WM_TIMER comme message (non ce n'est pas un hasard ;) et on regarde ce qui se passe...
Et surprise, on a juste UN et UN SEUL WM_TIMER d'envoyer à la fenêtre NAG même si on ne la ferme pas...

Donc la routine appelée lorsque le NAG reçoit le WM_TIMER va contenir un KILLTIMER, 
API Windows servant à détruise un Timer.
Pourquoi est-ce important ? 
Tout simplement parce que maintenant nous connaissons une API sur laquelle poser un bPX 
et contenue dans la routine que l'on cherche....

NOTE : Habituellement les KILLTIMER sont plutôt exécutés dans la fonction gérant la fermeture de la fenêtre. 
Voilà pourquoi, il n'était pas forcément évident d'avoir un KILLTIMER dans la routine exécuté par le TIMER même...
(c'était pour la petit histoire).

Vous allez avoir plusieurs break dû à votre BPX KILLTIMER 
(Plusieurs modules de windows utilisant en permanence les Timers eux-aussi).
Mais avec un peu de pot (qu'est que la chance vient foutre là, on se le demande), 
vous attérirez en 586240.
Allez pour une fois, je détaille (un peu) la routine :

:00586240 8B442404                mov eax, dword ptr [esp+04]
:00586244 83EC18                  sub esp, 00000018
:00586247 83F807                  cmp eax, 00000007
:0058624A 56                      push esi
:0058624B 57                      push edi
:0058624C 8BF1                    mov esi, ecx
:0058624E 0F8518010000            jne 0058636C <-- celui là ne nous intéresse pas, on s'en tape...
:00586254 A178306300              mov eax, dword ptr [00633078]
:00586259 8B5620                  mov edx, dword ptr [esi+20]
:0058625C 8B4874                  mov ecx, dword ptr [eax+74]
:0058625F 51                      push ecx
:00586260 52                      push edx  <- HANDLE de la fenêtre de NAG SCREEN
:00586261 FF1528CB6300            Call USER32.KillTimer  <-- notre fameux KILLTIMER
:00586267 A170306300              mov eax, dword ptr [00633070]   <- première vérif 
:0058626C 85C0                    test eax, eax
:0058626E 0F85DF000000            jne 00586353   <-- c'est le mauvais chemin ça...

* Possible StringData Ref from Data Obj ->"5000"  <-- ici début d'une jolie vérif qui va regarder si on est bien arriver là	
                                 
:00586274 68A0EC6200              push 0062ECA0	 <-- après 5 secondes et pas avant...
:00586279 C7057030630001000000    mov dword ptr [00633070], 00000001
:00586283 FF15ECC76300            Call MSVCRT.atoi
:00586289 8B0D7C306300            mov ecx, dword ptr [0063307C]
:0058628F 83C404                  add esp, 00000004
:00586292 8D3C08                  lea edi, dword ptr [eax+ecx]
:00586295 FF15A8B56300            Call GetTickCount
:0058629B 3BC7                    cmp eax, edi
:0058629D 0F82B0000000            jb 00586353		<-- sinon bye bye 
:005862A3 8B5620                  mov edx, dword ptr [esi+20]
:005862A6 52                      push edx
:005862A7 FF15B4C96300            Call IsWindowVisible <-- Haha...ici on vérifie si la fenêtre du NAG est toujours visible
:005862AD 85C0                    test eax, eax
:005862AF 0F849E000000            je 00586353		<-- sinon bye bye
:005862B5 8D442408                lea eax, dword ptr [esp+08]
:005862B9 C74424109B010000        mov [esp+10], 0000019B
:005862C1 50                      push eax
:005862C2 C744241859010000        mov [esp+18], 00000159

Après on a la gestion du cursor par rapport à la fenêtre (bouton START avec Sablier et cie)

:005862CA C744241CF4010000        mov [esp+1C], 000001F4
:005862D2 C744242074010000        mov [esp+20], 00000174
:005862DA FF15F4C96300            Call GetCursorPos
:005862E0 8B5620                  mov edx, dword ptr [esi+20]
:005862E3 8D4C2408                lea ecx, dword ptr [esp+08]
:005862E7 51                      push ecx
:005862E8 52                      push edx
:005862E9 FF153CCB6300            Call USER32.ScreenToClient
:005862EF A170306300              mov eax, dword ptr [00633070]
:005862F4 85C0                    test eax, eax
:005862F6 753A                    jne 00586332
:005862F8 8B44240C                mov eax, dword ptr [esp+0C]
:005862FC 8B4C2408                mov ecx, dword ptr [esp+08]
:00586300 50                      push eax
:00586301 8D542414                lea edx, dword ptr [esp+14]
:00586305 51                      push ecx
:00586306 52                      push edx
:00586307 FF1570CB6300            Call USER32.PtInRect
:0058630D 85C0                    test eax, eax
:0058630F 7421                    je 00586332
:00586311 E81E540500              Call MFC42.MFC42:NoName0884
:00586316 68027F0000              push 00007F02
:0058631B 6A00                    push 00000000
:0058631D FF1520CA6300            Call USER32.LoadCursorA
:00586323 50                      push eax
:00586324 FF1510CB6300            Call USER32.SetCursor
:0058632A 5F                      pop edi
:0058632B 5E                      pop esi
:0058632C 83C418                  add esp, 00000018
:0058632F C20400                  ret 0004

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:005862F6(C), :0058630F(C)
|
:00586332 E8FD530500              Call MFC42.MFC42:NoName0884
:00586337 68007F0000              push 00007F00
:0058633C 6A00                    push 00000000
:0058633E FF1520CA6300            Call USER32.LoadCursorA
:00586344 50                      push eax
:00586345 FF1510CB6300            Call USER32.SetCursor
:0058634B 5F                      pop edi
:0058634C 5E                      pop esi
:0058634D 83C418                  add esp, 00000018
:00586350 C20400                  ret 0004


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0058626E(C), :0058629D(C), :005862AF(C)
|
:00586353 C7057030630000000000    mov dword ptr [00633070], 00000000   <-- ici donc la fameuse routine 
:0058635D E8D2530500              Call MFC42.MFC42:NoName0884  		1) faisant planter PSP 
:00586362 8B4004                  mov eax, dword ptr [eax+04] 		2) empêchant ouverture et creation fichiers
:00586365 8BC8                    mov ecx, eax
:00586367 8B10                    mov edx, dword ptr [eax]
:00586369 FF5270                  call [edx+70]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0058624E(C)
|
:0058636C 5F                      pop edi
:0058636D 5E                      pop esi
:0058636E 83C418                  add esp, 00000018
:00586371 C20400                  ret 0004

Bien c'est pas tout ça mais koikon fait donc ?
Bon on sait que cette routine s'exécute, que si le NAG Screen n'est pas affiché au moment de son éxecution 
(entre autre), on a un saut en 586353 provoquant des erreurs par la suite...
On pourrait donc empêcher les sauts et simuler le bouton START...
Mais pourquoi se faire chier ailleurs puisqu'on a tout sous la main.
Cette routine est exécuté, profitons-en...
Rajoutons à la fin un jolie SENDMESSAGEA(HandleNagScreen, WM_CLOSE, NULL, NULL) 
et elle se fermera toute seule :)
En plus, on a de la chance, y'a de la place à partir de 586374

D'où rajout du code suivant :
586374 : mov edi,[esi + 20]   <-- correspond au HANDLE du NAG...regardez la routine plus haut 
si vous me croyez pas
	 PUSH 0    (LPARAM de SendMessageA = NULL)
	 PUSH 0    (WPARAM de SendMessageA = NULL)
         PUSH dword ptr 10 (WM_CLOSE = 0x10)
	 PUSH EDI  (Handle du Nag, récupéré à l'instant)
         CALL DWORD PTR [0063CA54]  (adresse récupérée dans WDASM correspondant au 
CALL USER32!SENDMESSAGEA
         
         POP EDI
	 POP ESI
         ADD ESP,18
         RET 04
Et on n'oublie pas de mettre en 58632A et 58634B un JMP 586374 pour terminer la routine par notre code...
Voilà maintenant, on relance, si tout a été fait correctement, plantage monstre !!! 
(non je rigole normalement ça passe)...
Mais bon voilà que l'on doit attendre quand même 5 secondes avant que notre NAG SCREEN se ferme tout seul...
Solution : on va réduire le délai du TIMER...
Vous avez remarqué plus haut la chaîne 5000 (5000 ms = 5 secondes)...C'est pas un hasard non plus...
ATTENTION : ne faisont pas une erreur de logique : CE N'EST PAS ICI que le programme déclare son 
TIMER sur 5 secondes.
Si on retrouve les 5000 ms ici, ils sont du à une vérif et non à la déclaration du TIMER 
(d'ailleurs vous ne voyez pas de focntion SetTimer).
Je fais cette précision car en fait, la chaîne "5000" est utilisée pour la vérif de notre routine mais aussi ailleurs 
pour la déclaration du TIMER...
En fait PSP convertit cette chaine en nombre...
La déclaration du TIMER en lui-même se fait en 584FF8 (avec WDASM c'est facile de s'en rendre compte, 
grâce au référencement de String, avec SoftIce un peu moins ;).  Perso, je n'ai désassembler 
que pour vous filer le SOURCE. 
J'ai retrouvé la routine de SETTIMER par une autre méthode (utilisation de SmartCheck entre autre mais ça 
c'est une autre histoire :). 
Comme quoi, on le néglige souvent à partir d'un certain niveau 
(en toute modestie !! Ne me faite pas dire ce que je n'ai pas voulu dire...) 
mais un bon vieux DEAD Listing permet souvent de gagner du temps.

Bref concluons... on transforme le 5000 en 500 ce qui parait être une bonne valeur...
(modifier la chaine dans l'exe avec un Editeur Hexa - en d'autres termes : remplacer le 30 du dernier "0" par un 00)

Juste un petit mot pour conclure : j'ai présenté ici "ma" méthode, bonne ou mauvaise, peu importe car 
elle permet finalement de passer en revue pas mal de chose. Et finalement, le crack d'un programme en lui-même 
n'a que peu d'importance, ce qui compte c'est le savoir (oui mais dans ce cas, on peut dire ça pour 
chaque crack et on tourne en rond...ouais...c'est vrai tiens...je vais y réfléchir finalement ;).

J'espère que tous ceux ayant utilisé une autre méthode nous la ferons partager.

A+

Mister X  (04/98)
RETOUR