****************************************************** * 1 - Tut "faire la peau à Windev 5.5" (Thetoucs) * ****************************************************** Details sur la protection Hardware de PcSoft Windev 5.0 et comment le reverser Par Thetoucs Bon je sais que je vais attirer le courou de Pcsoft sur moi mais je vais ici vous detailler la protection de Windev. Et bien sur comment le cracker.Y'a pas besoin d'être un cracker excellent mais il faut avoir quelques notions sur l'assembleur et aussi sur les dongles de types Aladdin. Pour l'assembleur je vous conseille un excellent bouquin qui est "assembleur facile" de chez marabout et pour les dongles je vous conseille de lire fortement la doc au format pdf disponible chez Aladdin(ya une en version francaise sur mon site http://www.multimania.com/thetoucs/, section dongle) Bon commencons : Sommaire : I ) Intro sur Windev II ) Petit recapitulatif sur les dongles III ) Etude de la protection et patch à realiser IV ) Conclusion I ) Intro sur Windev Bon comme je l'ai dit plus haut je vais prendre comme exemple la version 5.0 de Windev(pour les connaisseurs, ne me demandez pas le N° de la LST je ne la connais pas!!). Bon apres l'installation de Windev, lorsqu'on le lance y'a un message qui apparait qui nous dit : "La clé de protection n'a pas été reconnue, veuillez le brancher ou verifiez que votre imprimante soit allumé". Bref on voit tout de suite qu'il faut un dongle pour le faire fonctionner. Le seul probleme c'est qu'il y'a différent types et marques de dongles sur le Net(par exemple Sentinel de chez Rainbow technologie ou encore Hasp de chez aladdin software). Comment connaitre le type de dongle avec lequel windev est protégé ? en fait a plusieurs moment vous avez pu le voir si vous avez été attentifs, lors de l'installation par exemple lorsqu'il lance le programme d'installation du driver du dongle. Ou encore en regardant un peu dans le repertoire ou plus simple encore dans les Docs fournies avec Windev.Vous avez touvé ? Le mot que l'on retrouve le plus souvent c'est HASP(NETHASP,HINSTALL ETC...). Donc on sais maintenant que Windev est protégé par un dongle de type HASP(plus d'informations sur ce type de dongle plus bas) Oui mais ensuite, il faut trouver quels sont les executables (et pourquoi pas les DLL) protégés par Dongle.Car vous ne croyez pas que les developpeurs de PCSOFT soient assez stupides pour protéger leurs logiciels aussi simplement. Bon essayez un peu tous les autres éxécutables et vous verrez. Vous avez trouvé ? Oui il y'a 4 executables protégés par dongle : - Windev5.exe (ca on s'en doutait) - Wdedit5.exe (Module qui complete Windev5.exe) - Wdetat5.exe (Pour créer ses etats) - Wdana5.exe (Pour créer ses analyses) - Wdgen.exe (Complete wdana5.exe) Tous ces fichiers affichent le même message "vous n'avez pas branché cette put.... de clé". Bon maintenant qu'on connait quels sont les modules protégés par dongle on va pouvoir commencer. Mais juste avant, un petit rappel sur ces dongles de type HASP. II ) Petit recapitulatif sur les dongles Bon ici je vais pas detailler le fonctionnement de tous les types de dongles.. Juste un petit rappel(pour ceux qui ont luent la doc au format pdf sur les HASP). Et aussi quelques notions qui n'apparaissent pas dans cette doc, comme par exemple la protection d'un logiciel par dongle avec le langage assembleur. Bref nous allons etudier quelque peu le dongle Hasp.(juste pour info, ces informations sont issues d'un cours de +zafer dispo sur le site de +Fravia, et aussi de la doc officiel. En fait il y'a plusieurs types de dongles Hasp(MemoHasp, NetHasp, TimeHasp etc..). bon ici je ne vais detailler tres succintement que les MemoHasp et les NetHasp, car windev n'utilise que ces 2 types de dongles. # MemoHASP ---------- Il y'a 2 différent types de MemoHasp: - Tout d'abord le Memohasp-1 qui a 112 byte de lecture/ecriture memoire - Et le Memohasp-4 qui a 496 byte de lecture/ecriture memoire.(Celui que windev utilise) # NetHASP --------- NetHasp est en fait Memohasp-4 et en connectant seulement 1 NetHasp a un Serveur, vous pouvez utiliser le logiciel tout en etant sur n'importe quel station de travail relié à ce serveur (les utilisateurs sont bien sur limités). Il a 496 byte de lecture/ecriture memoire. Comment l'application fait t'il appel à la clé ? Il faut savoir aussi que le dialogue entre le logiciel et le dongle s'execute grace a un driver qui a été installé au préalable par cette même application.(Hasp95.vxd pour Win95 et Haspnt pour Winnt) Oui mais encore ? En fait pour appeller la clé, il existe une API par lequel s'instaure le dialogue. Regardons de plus pres cette API : Hasp (Service, SeedCode/IdleTime, LptNum/ProgNum, Password1, Password2, Par1, Par2, Par3, Par4) Cette API verifie la presence d'une Clé sur votre port paralelle, renvoie des Return codes pour un SeedCode et permet d'acceder à la mémoire des clés Hasp à memoire pour des opérations de lecture/ecriture. La routine HASP accepte 9 parametres : Le 1er,Service, determine le type d'operation effectué par la routine. PAR1,PAR2,PAR3,PAR4 sont des pointeurs sur des entiers. Utilisation en assembleur : call: bh=service ax=SeedCode/IdleTime bl=LptNum/ProgNum cx=Password1 dx=Password1 di=address si=data es=buffer segment (Pour les fonctions Read/WriteBlock, Set* ; ax=buffer offset) retourne: ax=Par1 bx=Par2 cx=Par3 dx=Par4 Bien que ce ne soit pas comprehensible pour certains, vous comprendrez plus tard la signication de ces parametres lorsque nous etudierons la protection de Windev. Ce que nous devons retenir c'est que l'appel API se fait en plusieurs temps c.a.d qu'il appelle pour savoir par exemple s'il y'a un dongle sur le port parallèle puis verifie le type de dongle et ainsi de suite. Comment fait t'il pour differentier les differents appels ? Simple, le parametre "Service" lui dit quel verification(SERVICE) à effectuer. Bon ci-dessous je vais détailler les services de bases utilisé par les MemoHasp et les NetHasp : Service Nom Operation ---------------------------------------------------------------------------------------------------------------------------- 1 IsHasp Verifie si un Hasp est connecté à l'ordinateur retourne Par1 0 pas de hasp 1 HASP de n'importe quel type ---------------------------------------------------------------------------------------------------------------------------- 2 HaspCode Vérifie si une clé Hasp specifique est connecté à l'ordinateur en verifiant les Returns Code pour un Seed Code donné. retourne Par1/2/3/4 retourne Code1/2/3/4 ---------------------------------------------------------------------------------------------------------------------------- 3 ReadWord Lit un mot de donné dans la memoire Hasp retourne Par2 1 Mot Par3 Status (Lisez les statuts plus bas) ---------------------------------------------------------------------------------------------------------------------------- 5 HaspStatus Verifie le type de clé Hasp connecté à l'ordinateur,verifie sur quel port paralelle est connecté la clé Hasp, verifie la taille memoire d'une clé Hasp a memoire. retourne Par1 1 MemoHasp-1 4 MemoHasp-4 0 Autres Types Par2 0 HASP-3 1 MemoHasp-1/MemoHasp-4 3 TimeHasp 5 TimeHasp-4 Par3 Paralel port # ---------------------------------------------------------------------------------------------------------------------------- 6 HaspID Recupere le N° d'identification de la clé retourne Par1 IDLow : Mot de poid faible de l'identification Par2 IDHigh : Mot de poid fort de l'identification (ID Number = IDLow+65536 * IDHigh) Par3 Statut (Lisez les statuts plus bas) ou IDLow et IDHigh sont des entiers non signés ---------------------------------------------------------------------------------------------------------------------------- 50(32h) Readblock Lit un bloc de données dans la mémoire Hasp retourne Par1 Adresse de depart Par2 Longueur du blos Par3 Statut (Lisez les statuts plus bas) ---------------------------------------------------------------------------------------------------------------------------- Les deux sevices qui suivent concerent le NetHasp(je n'ai pas trouvé necessaire d'en inclure d'autres) : ---------------------------------------------------------------------------------------------------------------------------- 42(2Ah) Login Effectue un login NetHasp.l'application protégé accede au gestionnaire de licence NetHasp et requiert une licence. retourne Par1 Return code 1 Par2 Return code 2 Par3 Return code 3 Par4 Return code 4 ---------------------------------------------------------------------------------------------------------------------------- 40(28H) Laststatus Verifie l'etat du precedent appel a la routine Hasp().(Service effectue apres chaque appel Nethasp) retourne Par1 Etat Nethasp: Retourne 1 si l'appel a été un succes sinon une autre valeur. Ce service retourne d'autres valeurs mais qui ne nous intéresse pas. ---------------------------------------------------------------------------------------------------------------------------- Details de différents statuts : code Details 0 Operation reussie -1 Time-out : echec de l'operation(qui se traduira par un FFFF en hexa) -2 L'adresse est hors zone -3 Impossible de trouver une clé hasp avec les mots de passe spécifiés -4 Une clé Hasp est trouvé mais ce n'est pas une clé MemoHasp -5 Echec de l'opeération d'écriture -999 Service invalide Voila je pense que ce sera tout pour les Hasp.Maintenant si vous voulez en savoir plus(car ce que j'ai ecrit n'est vraiment qu'un minimum!!) reportez vous à la Doc officielle ou au Tut de +Zafer(dispo sur le site de +Fravia) Maitenant que les recapitulatifs sont terminé, commencons les festivités. III ) Etude de la protection et patch à realiser Bon nous allons commencer par l'étude de la protection de windev. Commencons par desassembler le premier executable. Comme c'est une application 16bit mieux vaut le desassembler avec la version 6 de Wdasm. Même en trouvant le message d'erreur qui dit que la clé n'est pas présente dans les string data reference de l'exe cela ne servira a rien. En fait le plus dur est de trouver où se trouve la routine Hasp et ensuite regarder le deroulement de la protection. Autant vous le dire de suite, il est presque impossible de trouver la routine sous Win95 ou Win98. en fait je l'ai fait sous NT, j'ai posé un breakpoint avec softice sur l'acces au port paralelle : Bpio 378 r(en fait cela bloquera l'application si cette derniere tentait de lire sur le port lpt 378 et redonnerais la main a softice). En le faisant sous NT lorsque je relance windev je me retrouve dans softice, dans le driver du dongle (haspnt.vxd).Quelques coups de F12 pour revenir au programme appelant et je me retrouve dans le module windev5.exe dans le segment de code N°1 à l'adresse 0001.007D. En fait on vient de trouver la routine Hasp de windev qui commence en 0001.0000.(ci dessous j'ai recopié toute la routine) : //********************** Start of Code in Segment: 1 ************** :0001.0000 55 push bp <--- debut de la routine Hasp :0001.0001 8BEC mov bp, sp :0001.0003 06 push es :0001.0004 57 push di :0001.0005 56 push si :0001.0006 52 push dx :0001.0007 51 push cx :0001.0008 53 push bx :0001.0009 50 push ax :0001.000A C47610 les si, [bp+10] :0001.000D 268B3C mov di, es:[si] :0001.0010 8B5E06 mov bx, [bp+06] <--- la fonction passe le numero de service dans bx :0001.0013 86FB xchg bl , bh <--- Passage du service qui se trouve dans bl en bh :0001.0015 035E0A add bx, [bp+0A] <--- met bh a 0 donc on a bx = xx00 où xx correspond au :0001.0018 8B4608 mov ax, [bp+08] N° de service :0001.001B 8B4E0C mov cx, [bp+0C] :0001.001E 8B560E mov dx, [bp+0E] :0001.0021 837E0632 cmp word ptr [bp+06], 0032 :0001.0025 7206 jb 002D :0001.0027 C4761C les si, [bp+1C] :0001.002A 268B04 mov ax, es:[si] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0001.0025(C) | :0001.002D C47614 les si, [bp+14] :0001.0030 268B34 mov si, es:[si] :0001.0033 837E0632 cmp word ptr [bp+06], 0032 Jusqu'a l'adresse 0001.0077 la routine :0001.0037 7436 je 006F fait quelques verifs qui ne nous interesse :0001.0039 837E0633 cmp word ptr [bp+06], 0033 pas vraiment, mais il modifie aussi les :0001.003D 7430 je 006F registres pour y mettre les parametres de la :0001.003F 837E0634 cmp word ptr [bp+06], 0034 routine Hasp. :0001.0043 742A je 006F :0001.0045 837E0635 cmp word ptr [bp+06], 0035 :0001.0049 7424 je 006F :0001.004B 837E0637 cmp word ptr [bp+06], 0037 :0001.004F 741E je 006F :0001.0051 837E0638 cmp word ptr [bp+06], 0038 :0001.0055 7418 je 006F :0001.0057 837E064D cmp word ptr [bp+06], 004D :0001.005B 7412 je 006F :0001.005D 837E064C cmp word ptr [bp+06], 004C :0001.0061 740C je 006F :0001.0063 837E0651 cmp word ptr [bp+06], 0051 :0001.0067 720E jb 0077 :0001.0069 837E0663 cmp word ptr [bp+06], 0063 :0001.006D 7708 ja 0077 * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0001.0037(C), :0001.003D(C), :0001.0043(C), :0001.0049(C), :0001.004F(C), |:0001.0055(C), :0001.005B(C), :0001.0061(C) | :0001.006F 56 push si :0001.0070 C47618 les si, [bp+18] :0001.0073 268E04 mov es, es:[si] :0001.0076 5E pop si * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0001.0067(C), :0001.006D(C) | :0001.0077 55 push bp :0001.0078 9A0000FFFF call 0003.0000 <----- Appel Hasp qui renvoie les differentes valeurs dans ax,bx,cx,dx :0001.007D 5D pop bp :0001.007E C47E10 les di, [bp+10] :0001.0081 268905 mov es:[di], ax <-----Copie le contenu de ax dans es:[di] :0001.0084 C47E14 les di, [bp+14] :0001.0087 26891D mov es:[di], bx <-----Copie le contenu de bx dans es:[di] :0001.008A C47E18 les di, [bp+18] :0001.008D 26890D mov es:[di], cx <-----Copie le contenu de cx dans es:[di] :0001.0090 C47E1C les di, [bp+1C] :0001.0093 268915 mov es:[di], dx <-----Copie le contenu de dx dans es:[di] :0001.0096 58 pop ax :0001.0097 5B pop bx :0001.0098 59 pop cx :0001.0099 5A pop dx :0001.009A 5E pop si :0001.009B 5F pop di :0001.009C 07 pop es :0001.009D 5D pop bp :0001.009E CB retf D'apres ce que nous avons vu dans le chapitre précedent, l'appel au service Hasp se fait par l'intermediaire du registe bh. C'est le cas ici en 0001.0013 ensuite viennent des verifications qui ne nous interesse pas vraiment jusqu'a l'adresse : 0001.0078 call 0003.0000 En fait c'est ici vraiment que se fera le dialogue entre la clé et le logiciel par l'intermediaire des registres ax,bx,cx,dx Le tout est maintenant de savoir où est appellé ce call , pour ça pas d'autre solution faite un serach dans wdasm et entrez la ligne suivante : call 0001.0000 La première recherche s'arrêtera en 0003.A419. En effet c'est ici que commence la verification de la clé et on verra que la partie de code qui suit n'est autre que la suite de la verification. J'ai separé ci dessous les différentes verifications pour mieux les commenter; On commence par la première verification : :0003.A404 683000 push 0030 :0003.A407 FF36E202 push word ptr [02E2] :0003.A40B FF36E002 push word ptr [02E0] :0003.A40F FF36E602 push word ptr [02E6] <----- les autres push ci dessus correspondent :0003.A413 FF36E402 push word ptr [02E4] au parametres de la routine hasp() :0003.A417 6A01 push 0001 <----- Push du service 1 :0003.A419 9A00005BA4 call 0001.0000 <----- Appel de verification :0003.A41E 83C41A add sp, 001A :0003.A421 8E063600 mov es, [0036] :0003.A425 26833E300001 cmp word ptr es:[0030], 0001 <---- Compare la valeur de es:[0030] a 1 :0003.A42B 7403 je A430 <---- Saute si Egale sinon :0003.A42D E93403 jmp A764 <---- Bye bye Ici c'est le service 1 qui est appelle et d'après le chapitre précedent on sait que si une clé est connecté la valeur renvoyé dans ax est 1 sinon 0. Or avant la sortie du call 0001.0000 on sait que le contenu de ax a été copié dans un emplacement mémoire ici c'est es:[0030], c'est pourquoi windev verifie si cette emplacement memoire est égale à 1, et si c'est le cas il saute en A430 sinon il saute en A764. Donc le patch devrait se faire comme ceci : :0003.A425 26C70630000100 mov word ptr es:[0030], 0001 :0003.A42C 90 nop :0003.A42D 90 nop :0003.A42E 90 nop :0003.A42F 90 nop Passons à la suite : :0003.A443 683000 push 0030 :0003.A446 FF36E202 push word ptr [02E2] :0003.A44A FF36E002 push word ptr [02E0] :0003.A44E FF36E602 push word ptr [02E6] :0003.A452 FF36E402 push word ptr [02E4] :0003.A456 6A05 push 0005 <--- push du service 5 :0003.A458 9A0000A1A4 call 0001.0000 <--- appel de verification :0003.A45D 83C41A add sp, 001A :0003.A460 8E063600 mov es, [0036] :0003.A464 26833E300001 cmp word ptr es:[0030], 0001 <--- compare si la valeur de es:[0030] 1 :0003.A46A 7403 je A46F <--- saute si c'est égale sinon :0003.A46C E9F502 jmp A764 <--- re bye bye Même chose qu'au dessus , appel du service 5 qui doit renvoyer 1 si une clé est connecté sinon 0 ,donc le patch se fait de la même façcon : :0003.A464 26C70630000100 mov word ptr es:[0030], 0001 :0003.A46B 90 nop :0003.A46C 90 nop :0003.A46D 90 nop :0003.A42E 90 nop Suite de la verification : On voit directement que les modifications ci dessus ne servent à rien car juste en dessous on voit que es:[0030] est remise a 0, on aurait pu juste changer le je en jmp mais c'est mieux de prendre de bonnes habitudes. :0003.A46F 26C70630000000 mov word ptr es:[0030], 0000 <--- remise a zero de es:[0030] :0003.A476 687DA4 push SEG ADDR of Segment 0006 j'ai sauté une partie de code inutile: :0003.A49C 6A03 push 0003 <--- push du service 3 :0003.A49E 9A00000CA5 call 0001.0000 <--- appel de verification :0003.A4A3 83C41A add sp, 001A :0003.A4A6 8E063800 mov es, [0038] :0003.A4AA 26833E340000 cmp word ptr es:[0034], 0000 <--- verifie si es:[0034] est egale a 0 :0003.A4B0 7403 je A4B5 <--- saute si c'est le cas sinon :0003.A4B2 E9AF02 jmp A764 <--- mauvais garçon * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0003.A4B0(C) | :0003.A4B5 8E063A00 mov es, [003A] :0003.A4B9 26A13200 mov ax, word ptr es:[0032] <--- copie es:[0032] dans ax :0003.A4BD 8946F2 mov [bp-0E], ax <--- puis copie ax dans [bp-0e] :0003.A4C0 0BC0 or ax, ax <--- un OU logique qui verifie si ax n'est pas null :0003.A4C2 7407 je A4CB <--- sinon il saute :0003.A4C4 8AC4 mov al , ah <--- copie le contenu de ah dans al :0003.A4C6 98 cbw <--- le transforme en un mot(Word) :0003.A4C7 26A33200 mov word ptr es:[0032], ax <--- et le rebalance dans es:[0032] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0003.A4C2(C) | :0003.A4CB 26F606320010 test byte ptr es:[0032], 10 <--- teste si c'est egale à 10h :0003.A4D1 7503 jne A4D6 <--- bien :0003.A4D3 E98E02 jmp A764 <--- pas bien La c'est un peu plus subtil mais pas vraiment dur. En effet le service 03 est appellé, or d'après le chapitre précedent on sait que l'appel au service 3 renvoie deux valeurs : il renvoie un mot(Word) dans bx et le statut de la clé dans cx(ici le statut devrait être 0) De plus on sait que dans le call 0001.0000 bx et cx sont copié dans des emplacement mémoires. Bon revenons aux verifs : en 0003.A4AA on verifie si es:[0034] est egale à 0 or si on réflechi un peu on devine que cx à été copié dans cet emplacement mémoire et que cet emplacement mémoire devrait être égale a 0 donc le patch pour cette partie devrait être: :0003.A4AA 26C70634000000 mov word ptr es:[0034], 0000 :0003.A4B1 90 nop :0003.A4B2 90 nop :0003.A4B3 90 nop :0003.A4B4 90 nop Ensuite cela devient un petit peu plus subtil en 0003.A4B5 L'emplacement memoire es:[0032] doit contenir le mot qui etait auparavant dans bx, il est copié dans ax puis le contenu de ax est copié dan [bp-0E], ensuite on verifie que ax n'est pas null sinon il saute plus bas ce qu'il ne devrait pas faire s'il y avait une clé . Ensuite ah est copié dans al et transformé en un mot puis il est recopié dans es:[0032], pour être comparé a 10h et si ça colle on saute en A4D6 sinon on saute en A764. Jusqu'a 0003.A4C2 ax contient le mot et après quelques modifications il doit être égale a 10h donc nous allons retrouver sa valeur initiale: AX = 0010 en A4C6 Ax = 1010 en A4C4 AX = 1000 juste avant En effet en A4C2 ax=1000 puis al recoit ah donc ax=1010 puis il est transformé en mot avex CWD donc ax=0010 et enfin viennent les test.Donc voici la façcon dont j'ai patché cette partie: :0003.A4B5 8E063A00 mov es, [003A] :0003.A4B9 B80010 mov ax, 1000 <----en fait la valeur de bx dans la routine hasp etait a l'origine inséré :0003.A4BC 90 nop dans ax, autant lui adresser la bonne valeur. :0003.A4BD 8946F2 mov [bp-0E], ax :0003.A4C0 0BC0 or ax, ax :0003.A4C2 7407 je A4CB :0003.A4C4 8AC4 mov al , ah :0003.A4C6 98 cbw :0003.A4C7 26A33200 mov word ptr es:[0032], ax Ensuite on passe directement en 0003.A5DE.D'autres appels à la clé sont éxécutées juste avant mais il n'y a pas vraiment de verification. | :0003.A5DE 6A03 push 0003 <--- Appel une seconde fois le service 3 :0003.A5E0 9A000073A6 call 0001.0000 <--- appel de verification (comme c'est le deuxième appel au service3 :0003.A5E5 83C41A add sp, 001A DI est incrémenté pour différencier le deuxième appel de la 1ère) :0003.A5E8 FF76F0 push word ptr [bp-10] :0003.A5EB FF76F2 push word ptr [bp-0E] :0003.A5EE 9AAC00F8A5 call 0004.00AC <--- call qui renvoie un mot(explication ci-dessous) :0003.A5F3 52 push dx :0003.A5F4 50 push ax :0003.A5F5 9AD20285A6 call 0004.02D2 <--- Call qui renvoie un serail dans AX :0003.A5FA 83C408 add sp, 0008 :0003.A5FD 8E063800 mov es, [0038] :0003.A601 26A33400 mov word ptr es:[0034], ax ---| :0003.A605 8E063A00 mov es, [003A] | :0003.A609 26A13200 mov ax, word ptr es:[0032] | :0003.A60D 8E063800 mov es, [0038] |> ici se font les verifications :0003.A611 2639063400 cmp es:[0034], ax |> :0003.A616 740E je A626 |> :0003.A618 26A13400 mov ax, word ptr es:[0034] | :0003.A61C 8E063E00 mov es, [003E] | :0003.A620 26A32A00 mov word ptr es:[002A], ax | :0003.A624 EB0B jmp A631 ---| On voit que le service 3 est appelé une seconde fois et on sait qu'il renvoie 2 valeurs dans bx et cx. De plus on sait maintenant que es:[0034] correspond a cx et que es:[0032] correspond a bx. on voit qu'a la sortie du call en A5F5 le contenu de ax est copie dans es:[0034] puis que le contenu de es:[0032] est copié dans ax et enfin le contenu de es:[0034] est comparé a ax et si c'est egale le programme suit son petit bonhomme de chemin sinon splash. En fait ici le N° de serie de windev est calculé dans les call juste avant les verifs et est stocké dans ax. Puis il copie ax dans l'emplacement qui contenait cx(le statut)pour moi le serial est 5858h. Puis l'emplacement ou etait copié BX(le mot) est copié dans AX. Enfin il compare le serail généré par les call au serial renvoyé par la clé. Pas la peine de se fatiguer avec tout ça on met ax a 0 et le reste aussi. J'ai modifié donc ce court passage de cette façon : :0003.A5F3 52 push dx :0003.A5F4 50 push ax :0003.A5F5 9AD20285A6 call 0004.02D2 :0003.A5FA 83C408 add sp, 0008 :0003.A5FD 8E063800 mov es, [0038] :0003.A601 90 nop :0003.A602 B80000 mov ax, 0000 :0003.A605 8E063A00 mov es, [003A] :0003.A609 26A33200 mov word ptr es:[0032], ax :0003.A60D 8E063800 mov es, [0038] :0003.A611 26A33400 mov word ptr es:[0034], ax :0003.A615 90 nop :0003.A616 EB0E jmp A626 :0003.A618 26A13400 mov ax, word ptr es:[0034]--------- :0003.A61C 8E063E00 mov es, [003E] |>cette partie de code ne sera jamais executé :0003.A620 26A32A00 mov word ptr es:[002A], ax |> :0003.A624 EB0B jmp A631 --------- Verification suivante : :0003.A66E 6A03 push 0003 --->toujours le service 3 :0003.A670 9A0000EFA6 call 0001.0000 --->appel de verification :0003.A675 83C41A add sp, 001A :0003.A678 FFB67EFE push word ptr [bp+FE7E] :0003.A67C FF76F0 push word ptr [bp-10] :0003.A67F FF76F2 push word ptr [bp-0E] :0003.A682 9AAC008CA6 call 0004.00AC --->call qui modifie les valeurs retourné par la cle :0003.A687 52 push dx :0003.A688 50 push ax :0003.A689 9A460373A2 call 0004.0346 --->call qui modifie les valeurs retourné par la cle :0003.A68E 83C40A add sp, 000A :0003.A691 8E063800 mov es, [0038] :0003.A695 26A33400 mov word ptr es:[0034], ax :0003.A699 8E063A00 mov es, [003A] :0003.A69D 26A13200 mov ax, word ptr es:[0032] :0003.A6A1 8E063800 mov es, [0038] :0003.A6A5 2639063400 cmp es:[0034], ax :0003.A6AA 740C je A6B8 :0003.A6AC 26A13400 mov ax, word ptr es:[0034] :0003.A6B0 8E063E00 mov es, [003E] :0003.A6B4 26A32A00 mov word ptr es:[002A], ax Je ne vais pas redetailler cette partie c'est le même type de verification qu'au dessus donc je vous donne directement le patch que j'ai effectué : :0003.A687 52 push dx :0003.A688 50 push ax :0003.A689 9A460373A2 call 0004.0346 :0003.A68E 83C40A add sp, 000A :0003.A691 8E063800 mov es, [0038] :0003.A695 90 nop :0003.A696 B80000 mov ax, 0000 :0003.A699 8E063A00 mov es, [003A] :0003.A69D 26A33200 mov word ptr es:[0032], ax :0003.A6A1 8E063800 mov es, [0038] :0003.A6A5 26A33400 mov word ptr es:[0034], ax :0003.A6A9 90 nop :0003.A6AA EB0C jmp A6B8 :0003.A6AC 26A13400 mov ax, word ptr es:[0034] :0003.A6B0 8E063E00 mov es, [003E] :0003.A6B4 26A32A00 mov word ptr es:[002A], ax Enfin la dernière verification : :0003.A6E0 B80200 mov ax, 0002 <--- ax reçoit 2 :0003.A6E3 8E063600 mov es, [0036] :0003.A6E7 26A33000 mov word ptr es:[0030], ax :0003.A6EB 50 push ax <--- push du service ax qui est egale a 2 :0003.A6EC 9A0000B8A7 call 0001.0000 <--- call de verification Hasp :0003.A6F1 83C41A add sp, 001A :0003.A6F4 8E063600 mov es, [0036] :0003.A6F8 26813E30000436 cmp word ptr es:[0030], 3604 <---comparaison des valeurs retournés :0003.A6FF 7527 jne A728 <---bad guy :0003.A701 8E063A00 mov es, [003A] :0003.A705 26813E32004003 cmp word ptr es:[0032], 0340 <---comparaison des valeurs retournés :0003.A70C 751A jne A728 <---bad guy :0003.A70E 8E063800 mov es, [0038] :0003.A712 26813E34002260 cmp word ptr es:[0034], 6022 <---comparaison des valeurs retournés :0003.A719 750D jne A728 <---bad guy :0003.A71B 8E063C00 mov es, [003C] :0003.A71F 26813E3600CB91 cmp word ptr es:[0036], 91CB <---comparaison des valeurs retournés :0003.A726 741D je A745 <---good guy Appel du service 2 qui renvoie normalement 4 valeurs dans les registres ax,bx,cx,dx or on sait que : ax correspond es:[0030] bx correspond es:[0032] cx correspond es:[0034] donc ça ne devrait pas être difficille de deviner que : dx correspond es:[0036] De plus on n'a pas a chercher les valeurs ,elles nous sont données. Donc le patch devrait se faire comme ceci : :0003.A6E0 B80200 mov ax, 0002 :0003.A6E3 8E063600 mov es, [0036] :0003.A6E7 26A33000 mov word ptr es:[0030], ax :0003.A6EB 50 push ax :0003.A6EC 9A0000B8A7 call 0001.0000 :0003.A6F1 83C41A add sp, 001A :0003.A6F4 8E063600 mov es, [0036] :0003.A6F8 26C70630000436 mov word ptr es:[0030], 3604 :0003.A6FF 90 nop :0003.A700 90 nop :0003.A701 8E063A00 mov es, [003A] :0003.A705 26C70632004003 mov word ptr es:[0032], 0340 :0003.A70C 90 nop :0003.A70D 90 nop :0003.A70E 8E063800 mov es, [0038] :0003.A712 26C70634002260 mov word ptr es:[0034], 6022 :0003.A719 90 nop :0003.A71A 90 nop :0003.A71B 8E063C00 mov es, [003C] :0003.A71F 26C7063600CB91 mov word ptr es:[0036], 91CB :0003.A726 EB1D jmp A745 On voit qu'ensuite il ne sert plus a rien de patcher car : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0003.A726(C) | :0003.A745 8E063A00 mov es, [003A] :0003.A749 26A13200 mov ax, word ptr es:[0032] <--- es:[0032]=0340 est copié dans ax :0003.A74D 2D4003 sub ax, 0340 <--- ax est soustrait a 0340 pour une verification plus tard :0003.A750 8E063E00 mov es, [003E] :0003.A754 2601062A00 add es:[002A], ax :0003.A759 8E063600 mov es, [0036] :0003.A75D 26C70630000100 mov word ptr es:[0030], 0001 <--- es:[0030] recoit 0001 * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0003.A42D(U), :0003.A46C(U), :0003.A4B2(U), :0003.A4D3(U), :0003.A743(U), | :0003.A764 8E063600 mov es, [0036] :0003.A768 26833E300001 cmp word ptr es:[0030], 0001 <--- on compare si es:[0030] est egale a 1 or c'est le cas :0003.A76E 7503 jne A773 <--- sinon adieu :0003.A770 E92C09 jmp B09F <--- merci d'avoir acheté windev Le jmp B09F marque la fin de la verification de la clé.Donc on a fini de patcher windev5.exe mais les verifications ne se terminent pas la car bien sur cela aurait été trop facile. Après avoir effectué toutes les modifications avec un editeur hexa on verra qu'il y'aura toujours un problème de clé. Et oui il faut ensuite passer aux autres modules. En fait lorsqu'on lance windev apres avoir patché correctement le module windev5.exe avec un editeur hexa on remarque que le nouveau message d'erreur qui dit que la clé n'est pas présente, provient de Wdedit5.exe.(comment je le sais ? Et bien c'est simple , le dans le libéllé du message on voit appraitre Wdedit.) En fait Wdedit5.exe est surement le module le plus difficille a cracker. Car il ne se contente pas de simples verfification comme le faisait windev5.exe. On desassemble wdedit5.exe avec notre desassembleur favoris. Et la on recherche la partie de code qui verifie si une clé est présente(C'est la même que windev5.exe) En effet elle commence au debut du 1er segment de code en 0001.0000 Cette fois ci au lieu de patcher le fichier a chaque verif, on va émuler la clé.(et oui faut changer un peu) Mais avant d'émuler quoi que ce soit il faut savoir quelles valeurs renvoyer et où placer le code qui nous servira à l'emulation. Si vous faites un search encore vous verrez que cette routine est appelle au moin une bonne douzaine de fois. Comment savoir quel est la premiere routine qui verifie le 1er ? Bon on remet notre bpio 378 r et on relance Windev. La on attend et pof, nous revoila dans softice. Quelques coups de F12 et nous sommes dans le module Wdedit5.exe dans la routine Hasp en 0001.007D. Encore un coup de F12 pour savoir où il est appellé et la on arrive en 0007.6DDC. Je ne vais pas ici redetailler comme je l'ai fait pour le 1er module. En fait il n'ya que 2 verifs : 0007.6DDC push 01 0007.6DDE call 0001.0000 Bon nous sommes arrêtes a l'appel du 1er service et on sait qu'il doit renvoyer 01 dans ax(la verif qui suit le montre bien). Notons cela quelque part. Et juste en dessous la seconde verif : 0007.6E1C push 05 0007.6E1E call 0001.0000 Le service 5 est appellé or on sait que l'appel du service 5 doit renvoyer 01 dans ax(la verif qui suit le montre bien). Donc retenons cela aussi. Si on force les registres dans la routine Hasp et qu'on mettre AX a 1 pour ces 2 verifs on voit que Windev se lance. Il y'a toujours un message d'erreur de la clé, mais cette fois cela ne provient pas de Wdedit5.exe ni de Windev5.exe. Mias alors d'ou cela peut il provenir ? Ben on recommence avec notre bpio et le F12 et la on se retrouve dans la routine Hasp d'une Dll : wd501std.dll et si on fait encore F12 on voit que cette routine est apellé par une autre Dll : wd501exe.dll Nom d'une pipe, quand est ce que ils s'arreteront? Donc il faut cracker ces dll maintenant.. Mais n'avons nous rien oublié ? Wdedit5.exe , on avait trouvé beaucoup de reference pour l'appel de la routine Hasp et j'avais dit que c'etait le module le plus dure a cracker et alors ? Ca viendra, pour l'instant occupons nous de ces 2 DLL tout en retenant les 2 verifs qu'on avait trouvé dans Wdedit. En fait je vais vous dire ce qui se passe pour les deux DLL: Wd501exe.dll fait appel à wd501std pour appeler la clé , puis elle recupère les valeurs pour faire la comparaison. J'ai mis un break juste avant que wd501std ne soit appelé donc dans wd501exe et je vois qu'il n'ya qu'une occurence de recherche de la clé. En effet wd501exe push le N° de service puis appelle wd501std pour appeler la clé. De plus le N° du service n'est pas explicite : Le N° de service varie selon si l'appel précedente a été un succes. Alors pour voir je regarde les services qui sont appelé et je force quelques fois les valeurs retournés par wd501std pour que ce soient de bonnes valeurs et j'ai vu que les services suivant sont appelé et les valeurs qu'ils doivent renvoyer dans les registres pour que windev puisse fonctionner : (si dans les valeurs retourné vous voyez XXXX c'est qu'ont s'en fout de ces valeurs.) N° Service AX BX CX DX 01 01 05 01 06 xxxx xxxx 0000 32 xxxx xxxx 0000 03 avec di=0 1000 0000 03 avec di=1 xxxx 0000 03 avec di=2 5858 0000 Comment j'ai retoruvé ces valeurs, et bien rassurez vous je me suis pas amusé à tracer dans la dll pour les retrouver, en fait je les avait déja sous la main. On a déjà cracké windev5.exe et wdedit5.exe et dans ces fichiers plusieurs services ont été appelé.Ce sont ces mêmes services qui sont appelé dans ces dll On sait par exemple que le service 01 doit retourner 01 dans ax, puis que le service 5 doit renvoyer 01 dans ax. Le service 06 n'a pas été appellé dans aucun des executables mais si vous regardez un peu le premier chapitre sur les dongles vous verrez que le serice 06 renvoie 3 valeurs : Le N° D'identification dans AX et BX, et le statut de la clé dans CX. Ici on s'enfout du N° d'ID de la clé car les valeurs renvoyé dans ax et bx vont être multiplié par 65535 pour generer je crois un serial. En fait dans le service 06 c'est cx qui nous interesse et qui doit être a 0( regarder les differents statuts dans le chapitre 1). Le service 32h c'est a peu de choses près la même chose que le service 06. Le plus chiant en fait c'est le service 03. en effet, les valeurs renvoyé sont dans BX et CX. Il lit une valeur sur la clé la renvoie dans BX et renvoie le statut de la clé dans CX. Donc on sait déjà que CX doit toujours être égale a 0. Pour ce qui est de bx c'est autre chose : Sa valeur varie en effet selon DI, en fait avant l'appel de la clé DI recoit l'adresse où aller rechercher la valeur dans la clé ( et DI varie souvent). Mais pas de problème, car windev5.exe appelle ce service 3 fois avec di ayant respectivent les valeurs 00,01,02. On sait (si vous avez regarder la première partie) que windev5.exe avec di=00 ,la cle doit renvoyer 1000, puis avec di=01 la valeur de BX n'est pas vraiment important( autant le mettre a 0000). Enfin la dernière valeur avec di=02, là il suffit de voir la verif que fait windev lorsqu'il compare la valeur retourné par une valeur qu'il a généré.(en fait c'est cette valeur que le service 03 avec di=02 que BX doit renvoyer). La solution serait maintenant d'emuler la clé comme on l'a fait dans la seconde partie de ce Tut. Mais je vais vous montrer un truc que j'ai decouvert et qui est vraiment plus rapide. En fait c'etait par hasard que je l'ai remarqué, lorsque wd501exe.dll appel le service 1 je ne force pas les registres, et ensuite je vois que le service 2Ah est appellé. Ce service demande en fait l'autorisation de l'utilsation d'une clé reseau. Il renvoie 4 valeurs dans les 4 registres. Je n'ai qu'a tracer que quelques lignes de codes pour voir la verif et recuperer les valeurs : AX=A367 BX=5A8A CX=BD5A DX=6E41 Juste après, le service 28h est appellé(service qui est appellé pour voir si le dernier appel de la clé reseau a reussi) et je sais que ce service doit renvoyer 0000 dans ax, donc je modifie ax et la que vois je? Plus de verifs, alors autant prendre la seconde verif, ce sera plus court a émuler non ? Ci dessous les lignes de code que j'ai modifié pour emuler la clé dans wd501std.dll : :0003.DC8A 55 push bp :0003.DC8B 8BEC mov bp, sp :0003.DC8D 06 push es :0003.DC8E 57 push di :0003.DC8F 56 push si :0003.DC90 52 push dx :0003.DC91 51 push cx :0003.DC92 53 push bx :0003.DC93 50 push ax :0003.DC94 C47610 les si, [bp+10] :0003.DC97 268B3C mov di, es:[si] :0003.DC9A 8B5E06 mov bx, [bp+06] :0003.DC9D 86FB xchg bl , bh :0003.DC9F 80FF01 cmp bh, 01 <----- Est ce que c'est le service 01 :0003.DCA2 7505 jne DCA9 <----- Sinon on va en DCA9 :0003.DCA4 B80000 mov ax, 0000 <----- si c'est le service 01 alors ax recoit 0000 car on va emuler le nethasp :0003.DCA7 EB5F jmp DD08 <----- jmp fin * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0003.DCA2(C) | :0003.DCA9 80FF2A cmp bh, 2A <----- Est ce le service 2Ah :0003.DCAC 750E jne DCBC <----- sinon on va en DCBC :0003.DCAE B867A3 mov ax, A367 <-----| :0003.DCB1 BB8A5A mov bx, 5A8A <-----|> On met les bonnes valeurs dans les registres :0003.DCB4 B95ABD mov cx, BD5A <-----|> :0003.DCB7 BA416E mov dx, 6E41 <-----| :0003.DCBA EB4C jmp DD08 <-------- Et on termine * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0003.DCAC(C) | :0003.DCBC B80000 mov ax, 0000 <------- Sinon si ce n'est pas le service 01 ni le service 2A :0003.DCBF EB47 jmp DD08 le service 28 qui doit renvoyer 00 dans ax Ici j'ai sauté toute une partie de code qui ne sera jamais executé. * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0003.DCA7(U), :0003.DCBA(U), :0003.DCBF(U) | :0003.DD08 C47E10 les di, [bp+10] :0003.DD0B 268905 mov es:[di], ax :0003.DD0E C47E14 les di, [bp+14] :0003.DD11 26891D mov es:[di], bx :0003.DD14 C47E18 les di, [bp+18] :0003.DD17 26890D mov es:[di], cx :0003.DD1A C47E1C les di, [bp+1C] :0003.DD1D 268915 mov es:[di], dx :0003.DD20 58 pop ax :0003.DD21 5B pop bx :0003.DD22 59 pop cx :0003.DD23 5A pop dx :0003.DD24 5E pop si :0003.DD25 5F pop di :0003.DD26 07 pop es :0003.DD27 5D pop bp :0003.DD28 CB retf En fait maitenant on lance Windev et tout se lance correctement, aucun message d'erreur au demmarrage...Au demmarrage oui mais essayez de créer une fenetre ou autre chose et vous verrez ...Message d'erreur.En fait il y'a toujours des verifs, lorsque vous créer des fenetres ou des controles ou lorsque vous enregistrez ou lors des test de fenetres etc etc.. Vous vous rappellez des reference trouvé dans Wdedit et bien voila d'aou sortes ces verifs.J'avais dit qu'on allait emuler la clé et bien c'est ce que nous allons faire .. Si on fait un bpio machin chouette et qu'on essaie de créer une fenetre ou autre chose on voit que l'appel Hasp se fait a plusieurs endroits.En fait si vous desassemblez Wdedit, vous verrez que tous ces appels Hasp s'executent dans une même routine et qu'elles se ressemblent. Cela commence en 0007.5A7F. Je ne detaillerais qu'un seul appel car tout ce qui suivra sera la même chose. :0007.5A7F FF76F4 push word ptr [bp-0C] <------- appel d'un service dont on ne connait pas la valeur :0007.5A82 9A0000C35A call 0001.0000 <------- appel de verif du dongle :0007.5A87 83C41A add sp, 001A :0007.5A8A C45EC0 les bx, [bp-40] :0007.5A8D 26833F00 cmp word ptr es:[bx], 0000 <------- ici ce n'est pas vraiment une verif du dongle mais :0007.5A91 7435 je 5AC8 il verifie si c'est un appel reseau ou non et si oui :0007.5A93 689A5A push SEG ADDR of Segment 0040 alors il continue sinon il saute en 5AC8 :0007.5A96 680C00 push 000C :0007.5A99 68A05A push SEG ADDR of Segment 0040 :0007.5A9C 680C00 push 000C :0007.5A9F 688D5B push SEG ADDR of Segment 0040 :0007.5AA2 680C00 push 000C :0007.5AA5 66FF76B8 push word ptr [bp-48] :0007.5AA9 C45EB4 les bx, [bp-4C] :0007.5AAC 26FF37 push word ptr es:[bx] :0007.5AAF C45EB0 les bx, [bp-50] :0007.5AB2 26FF37 push word ptr es:[bx] :0007.5AB5 FF76C8 push word ptr [bp-38] :0007.5AB8 C45EC4 les bx, [bp-3C] :0007.5ABB 26FF37 push word ptr es:[bx] :0007.5ABE 6A28 push 0028 <------- verifie si l'appel reseau a été un succes, mais cela :0007.5AC0 9A0000E65B call 0001.0000 ne nous interresse pas car en 5A91 on saute obligatoirement :0007.5AC5 83C41A add sp, 001A en 5AC8 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0007.5A91(C) | :0007.5AC8 C45EB8 les bx, [bp-48] :0007.5ACB 26833F00 cmp word ptr es:[bx], 0000 <------- de même que cette verif ne nous interresse pas car :0007.5ACF 0F8579FF jne 5A4C elle se rapporte a service 28 plus haut qu'on a pas executé C'est ici que commence la verif , les explication sont decrites plus bas :0007.5AD3 C45EBC les bx, [bp-44] :0007.5AD6 268B07 mov ax, es:[bx] :0007.5AD9 3946F0 cmp [bp-10], ax :0007.5ADC 752B jne 5B09 :0007.5ADE 8E06640D mov es, [0D64] :0007.5AE2 26A10600 mov ax, word ptr es:[0006] :0007.5AE6 3946EE cmp [bp-12], ax :0007.5AE9 751E jne 5B09 :0007.5AEB 26A10800 mov ax, word ptr es:[0008] :0007.5AEF 3946EC cmp [bp-14], ax :0007.5AF2 7515 jne 5B09 :0007.5AF4 26A10A00 mov ax, word ptr es:[000A] :0007.5AF8 3946EA cmp [bp-16], ax :0007.5AFB 750C jne 5B09 :0007.5AFD 26A10600 mov ax, word ptr es:[0006] :0007.5B01 2B46EE sub ax, [bp-12] :0007.5B04 05381C add ax, 1C38 :0007.5B07 EB06 jmp 5B0F Un service est appele mais on ne sait pas lequel. En fait le service n'est pas explicitement ecrit car il change selon si c'est un dongle en reseau ou en locale. Mettez un breakpoint avec softice en 0007.5A7F et regardez le service appelé pour le dongle en locale et vous verrez que c'est le service 2 qui est appelé. Et c'est en 0007.5AD3 que commence les verifs. Mais si on se reporte a la première partie du tut on verra qu'on a les valeurs pour le service 2, et ben non car si on trace dans le call 0001.0000 on verra que la valeur de AX est différent de l'appel du service 2 dans windev5.exe. En effet, dans windev5.exe avant l'appel de verif du dongle ax etait egale à 0 et dans wdedit5.exe ax est different de 0(En fait ax se voit affecté d'un nombre qui varie selon ce que vous faite, creation de fenêtre ou autre).En fait Ax contient un des parametres de Hasp() et s'il change, les valeurs retour changent. On sait que le service 2 renvoie 4 valeurs dans ax,bx,cx,dx et que ces registres sont copié dans des emplacements mémoire. Voyons la verif qu'il fait en 0007.5AE2 : :0007.5AE2 26A10600 mov ax, word ptr es:[0006] :0007.5AE6 3946EE cmp [bp-10], ax :0007.5AE9 751E jne 5B09 dans le call 0001.000 ax avait été copié dans un emplacement memoire , ici cet emplacement mémoire est recopié dans ax pour être comparé a une valeur stocke dans la pile : [BP-12](En assembleur pour acceder aux valeurs de la pile, une routine utilise le registre BP, revoyez vos cours sur l'assembleur) .Et si c'est egale alors on continue. Ainsi de suite les valeurs renvoyées sont comparé aux valeurs de la pile suivantes : [bp-12], [bp-14], [bp-16]. Donc on voit que des emplacements dans la pile contient les bonnes valeurs. Avec softice, vous verrez que ces valeurs varient souvent , donc qu'il est inutile de recopier ces valeurs. Mais prenons soin d'écrire quelque part la valeur du registre BP(Nous verrons son utilité plus tard). En fait avec le Bpio softice se bloque 2 fois. La 1ere vous l'avez vue juste au dessu et la seconde c'est ce qui suit : :0007.5BE0 FF76F2 push word ptr [bp-0E] :0007.5BE3 9A0000245C call 0001.0000 :0007.5BE8 83C41A add sp, 001A :0007.5BEB C45EC0 les bx, [bp-40] :0007.5BEE 26833F00 cmp word ptr es:[bx], 0000 :0007.5BF2 7435 je 5C29 :0007.5BF4 68FB5B push SEG ADDR of Segment 0040 :0007.5BF7 680C00 push 000C :0007.5BFA 68015C push SEG ADDR of Segment 0040 :0007.5BFD 680C00 push 000C :0007.5C00 683E5C push SEG ADDR of Segment 0040 :0007.5C03 680C00 push 000C :0007.5C06 66FF76B8 push word ptr [bp-48] :0007.5C0A C45EB4 les bx, [bp-4C] :0007.5C0D 26FF37 push word ptr es:[bx] :0007.5C10 C45EB0 les bx, [bp-50] :0007.5C13 26FF37 push word ptr es:[bx] :0007.5C16 FF76C8 push word ptr [bp-38] :0007.5C19 C45EC4 les bx, [bp-3C] :0007.5C1C 26FF37 push word ptr es:[bx] :0007.5C1F 6A28 push 0028 :0007.5C21 9A00006158 call 0001.0000 :0007.5C26 83C41A add sp, 001A * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0007.5BF2(C) | :0007.5C29 C45EB8 les bx, [bp-48] :0007.5C2C 26833F00 cmp word ptr es:[bx], 0000 :0007.5C30 0F8579FF jne 5BAD Même chose on ne connait pas le service appelé donc breakpoint avec softice et on voit que le service 32 est appelé. Le service 32 renvoie 3 valeurs dans ax,bx,cx. ax et bx ne nous intresse pas car le seul registre verifié est cx qui doit être egale a 0. Retenons cette valeur. Ensuite les verifs se repentent donc on a tous les renseignements necessaire pour emuler la clé : Le service 1 et 5 sont appelés et doivent renvoyer 0001 dans ax. le service 2 est appelé avec ax en paramètre qui doit renvoyer 4 valeurs dans ax,bx,cx,dx et qui doivent être égaux à des emplacements dans la pileque sont [bp-10], [bp-12], [bp-14], [bp-16] . Et on connait la valeur de bp au moment de la verif donc on va nous aussi utiliser le registre BP pour notre emulation . Et enfin le service 32h est appelé et doit renvoyer au moins 0000 dans cx. //********************** Start of Code in Segment: 1 ************** :0001.0000 55 push bp :0001.0001 8BEC mov bp, sp :0001.0003 06 push es :0001.0004 57 push di :0001.0005 56 push si :0001.0006 52 push dx :0001.0007 51 push cx :0001.0008 53 push bx :0001.0009 50 push ax :0001.000A C47610 les si, [bp+10] :0001.000D 268B3C mov di, es:[si] :0001.0010 8B5E06 mov bx, [bp+06] :0001.0013 86FB xchg bl , bh <---- bh recoit le service :0001.0015 80FF02 cmp bh, 02 <---- est ce que le service 02 est appelé :0001.0018 750E jne 0028 <---- sinon on saute en 0028 :0001.001A 8B466A mov ax, [bp+6A] <---- si oui alors on copie les bonnes valeurs dans les registres :0001.001D 8B5E68 mov bx, [bp+68] on connaissait la valeur de bp et le problème c'est que :0001.0020 8B4E66 mov cx, [bp+66] sa valeur changeait en entrant dans ce call alors il fallait :0001.0023 8B5664 mov dx, [bp+64] modifier quelques peu la syntaxe :0001.0026 EB56 jmp 007E <---- jmp fin * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0001.0018(C) | :0001.0028 80FF32 cmp bh, 32 <---- est ce le service 32 qui est appelé :0001.002B 7505 jne 0032 <---- si non alors on saute en 0032 :0001.002D 6A00 push 0000 <---- si oui alors cx recoit 0000 :0001.002F 59 pop cx :0001.0030 EB4C jmp 007E <---- jmp fin * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0001.002B(C) | :0001.0032 B80100 mov ax, 0001 <--- reste les services 01 et 05, qui doivent renvoyer 01 dans ax :0001.0035 EB47 jmp 007E <--- et on saute a la fin. * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0001.0026(U), :0001.0030(U), :0001.0035(U) | :0001.007E C47E10 les di, [bp+10] <----- c'est ici que le registres vont être recopiés dans des :0001.0081 268905 mov es:[di], ax emplacements mémoires pour les verifications ultérieures :0001.0084 C47E14 les di, [bp+14] :0001.0087 26891D mov es:[di], bx :0001.008A C47E18 les di, [bp+18] :0001.008D 26890D mov es:[di], cx :0001.0090 C47E1C les di, [bp+1C] :0001.0093 268915 mov es:[di], dx :0001.0096 58 pop ax :0001.0097 5B pop bx :0001.0098 59 pop cx :0001.0099 5A pop dx :0001.009A 5E pop si :0001.009B 5F pop di :0001.009C 07 pop es :0001.009D 5D pop bp :0001.009E CB retf Juste une pointe d'explication pour le service 02. en fait je savais que la pile contenait les bonnes valeurs, et je connassais aussi la valeur du registre BP, or pour acceder a la pile il faut utiliser le registre BP, et alors je me suis dit pourquoi ne pas recopier directement les bonnes valeurs dans les registres. Le seul probleme c'est que BP changeait lors de l'entrée dans la routine Hasp donc il a fallu changer quelque peu l'adressage de la pile.. (si vous ne comprenez pas reportez vous a votre cours sur l'assembleur). Voila la c'est vraiemnt terminé, enfin presque. Il reste juste les modules de rajouts : Wdgen.exe Wdetat5.exe wdetat5.exe. En fait si vous etes arrivé jusqu'ici alors vous pourrez cracker tres facilement ces modules(ils ont tous les 3 la même protection, donc si vous en avez cracké un vous pourrez le faire pour les 2 autres). Je vais mettre juste a titre d'exemple le patch a faire pour l'un d'eux et essayer ensuite de le faire pour les autres : Je ne detaille rien car c'est en fait les mêmes services qui sont appelé ,mais il y'a quand même quelques petits commentaires La modification est le même pour les modules. Ici je n'emule la clé que pour wdana5.exe mais pour les autres c'est la même chose. En effet, pour ces modules il n'ya que les services 01,05 et 03 qui sont appellé : :0011.9666 55 push bp :0011.9667 8BEC mov bp, sp :0011.9669 06 push es :0011.966A 57 push di :0011.966B 56 push si :0011.966C 52 push dx :0011.966D 51 push cx :0011.966E 53 push bx :0011.966F 50 push ax :0011.9670 C47610 les si, [bp+10] :0011.9673 268B3C mov di, es:[si] :0011.9676 8B5E06 mov bx, [bp+06] :0011.9679 86FB xchg bl , bh :0011.967B 80FF01 cmp bh, 01 <------ Service 01 qui renvoie 1 dans ax :0011.967E 7505 jne 9685 :0011.9680 B80100 mov ax, 0001 :0011.9683 EB5F jmp 96E4 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0011.967E(C) | :0011.9685 80FF05 cmp bh, 05 <------ Service 05 qui renvoie 01 dans ax :0011.9688 7505 jne 968F :0011.968A B80100 mov ax, 0001 :0011.968D EB55 jmp 96E4 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0011.9688(C) | :0011.968F B90000 mov cx, 0000 <------- sinon il reste le service 03 qui renvoie 1000 dans bx :0011.9692 BB0010 mov bx, 1000 et 0000 dans cx :0011.9695 EB4D jmp 96E4 * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:0011.9683(U), :0011.968D(U), :0011.9695(U) | :0011.96E4 C47E10 les di, [bp+10] :0011.96E7 268905 mov es:[di], ax :0011.96EA C47E14 les di, [bp+14] :0011.96ED 26891D mov es:[di], bx :0011.96F0 C47E18 les di, [bp+18] :0011.96F3 26890D mov es:[di], cx :0011.96F6 C47E1C les di, [bp+1C] :0011.96F9 268915 mov es:[di], dx :0011.96FC 58 pop ax :0011.96FD 5B pop bx :0011.96FE 59 pop cx :0011.96FF 5A pop dx :0011.9700 5E pop si :0011.9701 5F pop di :0011.9702 07 pop es :0011.9703 5D pop bp :0011.9704 CB retf IV ) Conclusion Voila le crack de windev est enfin terminé, c'etait long même tres long.Je ne sens plus mes doigts. Bref ceci pour montrer qu'il n'ya pas vraiment de protection inviolable(il se peut qu'il y'en ai quand meme) mais en fait ne prenez pas ce cours que pour cracker windev, en fait essayez de l'appliquer sur d'autres application protégés par dongle et vous verrez que ces parasites ne sont aussi inviolables qu'ils n'y paraissent. Juste un conseil : Lisez les différents tuts sur la section dongle du site de +Fravia ou des miroirs ce ne sera pas une perte de temps, ca je vous l'assure. Voila j'espere que le cours n'etait pas trop deplaisant(car des fautes peuvent subsister) et si vous avez quelques remarques vous pouvez le faire a : thetouc@yahoo.fr