Zvolume 3.1


 
 



Outils

Softice v4.01
Hiew 6.04
Procdump v1.6
Icedump v6


HowTo


Avant Propos :

Je previens que c'est une protection très longue et pénible pour en venir à bout. En effet ce prog est protégé avec la version 0.9 d'asprotect.
Quand on lance le prog il y a un nag qui nous indique le temps qui reste à l'utiliser et si on dépasse cette date le même nag nous dit que c'est fini et on ne peut plus utiliser le prog. Il n'est pas possible de désassembler le prog ni de le tracer en utilisant le symbol loader. Le prog doit donc être compressé/crypté. Pour savoir si il utilisait une protection commercial, je l'ai ouvert avec un éditeur hexa pour voir s'il n'y avait pas la marque d'une compression. Dans la version 3.1 il n'y a rien.
Cependant dans la version 3.04 il y avait .aspr signature de la protection asprotect. Ceci permet juste de savoir quelle est la protection utilisé dans ce prog même si ce n'est pas vital de le savoir.
 

1ère partie : Asprotect

Pour pouvoir tracer le programme ou obtenir un dump du programme j'ai d'abord changer toutes les caractéristiques des sections du prog à l'aide de pe-editor de procdump. J'ai mis E0000020 (readable, writeable..). Mais là surprise quand on lance le prog il y a le message suivant qui apparait : file corrupted. et on quitte le prog. Je m'attendais à trouver un antisoftice comme dans d'autres progs protégés avec asprotect mais là on dirait bien que l'on a droit à un cheksum. Pour en être certain je suis aller sur le site d'asprotect et voilà ce qu'il disent :

Ca fait pas mal de truc. En tout cas une chose est sur il y a bien un checksum. Donc il faut le virer. Pour cela le checksum doit surement utilisé la fonction CreateFileA pour vérifier le fichier où en créer un autre. J'ai donc mis sous softice un pnt d'arrêt : bpx createfilea. et on lance le prog. Softice break et on remonte le code avec F12 et on trace un peu pour trouver cela :

015F:0049C2BB  5E                  POP       ESI
015F:0049C2BC  5B                  POP       EBX
015F:0049C2BD  C3                  RET
015F:0049F9E0 894304              MOV       [EBX+04],EAX
015F:0049F9E3  837B0400            CMP       DWORD PTR [EBX+04],00
015F:0049F9E7  7D23                JGE       0049FA0C                (JUMP )
015F:0049FA0C  807DFF00            CMP       BYTE PTR [EBP-01],00
015F:0049FA10  740A                JZ        0049FA1C                (NO JUMP)
015F:0049FA12  648F0500000000      POP       DWORD PTR FS:[00000000]
015F:0049FA19  83C40C              ADD       ESP,0C
015F:0049FA1C  8BC3                MOV       EAX,EBX
015F:0049FA1E  5F                  POP       EDI
015F:0049FA1F  5E                  POP       ESI
015F:0049FA20  5B                  POP       EBX
015F:0049FA21  8BE5                MOV       ESP,EBP
015F:0049FA23  5D                  POP       EBP
015F:0049FA24  C20400              RET       0004
015F:004A9496  8945E8              MOV       [EBP-18],EAX
015F:004A9499  33D2                XOR       EDX,EDX
015F:004A949B  55                  PUSH      EBP
015F:004A949C  68EB944A00          PUSH      004A94EB
015F:004A94A1  64FF32              PUSH      DWORD PTR FS:[EDX]
015F:004A94A4  648922              MOV       FS:[EDX],ESP
015F:004A94A7  8BC3                MOV       EAX,EBX
015F:004A94A9  E8FE04FFFF          CALL      004999AC
015F:004A94AE  8BF0                MOV       ESI,EAX
015F:004A94B0  8BD6                MOV       EDX,ESI
015F:004A94B2  8BCB                MOV       ECX,EBX
015F:004A94B4  8B45E8              MOV       EAX,[EBP-18]
015F:004A94B7  8B38                MOV       EDI,[EAX]
015F:004A94B9  FF17                CALL      [EDI]
015F:004A94BB  8B463C              MOV       EAX,[ESI+3C]
015F:004A94BE  8BD3                MOV       EDX,EBX
015F:004A94C0  2BD0                SUB       EDX,EAX
015F:004A94C2  03C6                ADD       EAX,ESI
015F:004A94C4  E89FE2FFFF          CALL      004A7768
015F:004A94C9  8945EC              MOV       [EBP-14],EAX
015F:004A94CC  8BD3                MOV       EDX,EBX
015F:004A94CE  8BC6               MOV       EAX,ESI
015F:004A94D0  E8EF04FFFF          CALL      004999C4
015F:004A94D5  33C0                XOR       EAX,EAX
015F:004A94D7  5A                  POP       EDX
015F:004A94D8  59                  POP       ECX
015F:004A94D9  59                  POP       ECX
015F:004A94DA  648910              MOV       FS:[EAX],EDX
015F:004A94DD  68F2944A00          PUSH      004A94F2
015F:004A94E2  8B45E8              MOV       EAX,[EBP-18]
015F:004A94E5  E8CA08FFFF          CALL      00499DB4
015F:004A94EA  C3                  RET
015F:004A94F2  8B45EC              MOV       EAX,[EBP-14]
015F:004A94F5  3B45F0              CMP       EAX,[EBP-10]
015F:004A94F8  7443                JZ        004A953D          <-- on inverse
015F:004A94FA  8A154CEA4A00        MOV       DL,[004AEA4C]
015F:004A9500  8B45F8              MOV       EAX,[EBP-08]
015F:004A9503  E858EBFFFF          CALL      004A8060
015F:004A9508  8945F4              MOV       [EBP-0C],EAX
015F:004A950B  837DF400            CMP       DWORD PTR [EBP-0C],00
015F:004A950F  742C                JZ        004A953D                (NO JUMP)
015F:004A9511  8D85E4FEFFFF        LEA       EAX,[EBP-011C]
015F:004A9517  8D95E9FEFFFF        LEA       EDX,[EBP-0117]
015F:004A951D  B9FF000000          MOV       ECX,000000FF
015F:004A9522  E8ED11FFFF          CALL      0049A714
015F:004A9527  8B85E4FEFFFF        MOV       EAX,[EBP-011C]
015F:004A952D  E83A14FFFF          CALL      0049A96C
015F:004A9532  8B55F4              MOV       EDX,[EBP-0C]
015F:004A9535  8B5205              MOV       EDX,[EDX+05]
015F:004A9538  E8CBF7FFFF          CALL      004A8D08
 

Donc il y a un saut en 4A94F8 qui ne s'effectue pas. Ensuite il y a le même en 4A950F, et après un fonction affiche le message d'erreur. Mais si on force le saut en 4A94F8 le prog se lance :). Donc voilà où se vérifient l'intégrité du programme. Le seul problème c'est que les addresses mémoires où ce trouve cette partie du code ne sont jamais les même. Donc le programme doit décompressé en mémoire cette partie du code qui doit être crypté. Mais comme le cheksum fait partie de la protection d'asprotect et non du prog, en fait le loader chargé de décompressé le prog doit lui même être compressé/crypté. Et c'est le loader qui doit contenir le checksum. Attention ce ne sont que des suppositions. Pour vérifier il va falloir tracer le prog avec symbol loader et dès qu'une fonction (call xxxxxxxx) affiche le message d'erreur il faudra à nouveau rentrer dedans (f8) . Une autre particularité d'Asprotect c'est son code CCA (code changeant d'apparence). Ce type de code est expliqué dans un tut de christal et dans un exemple fait par pulsar, je n'y reviendrais donc pas. Pourtant c'est pénible à tracer car le code change constament sous softice. Bon le traçage est excessivement long, j'ai mis en tout 41 point d'arrêt sur les calls successifs qui affiche le message d'erreur :

43F142
43F1A1
43F1D1
43F23C
43F26C
43F29B
43F2CC
43F30A
43F33A
43F369
43F39E
43F3CD
43F3FE
43F474
43F4A4
43F4D3
43F503
 <--  décompression 1 : fin en 4402C9
43F560
43F595
43F5C4
43F5F5
43F6CB
43F6FB
43F743
43F773
43F85F
43F88F
43F8C4
43F8F4
43F923
43F954
43F983
43F9B4
43F9E3
43FA14
43FA43
43FA73
43FABA
43FAEA
43FB19
43FB49
43FB78
43FBA8
43FBD7
43FC0C   <-- va ensuite vers zone mémoire qui change tout le temps , puis autre décompression.

Donc il y a une première décompression et après le dernier point d'arrêt que j'ai mis il va vers cette zone mémoire décompressée. Le problème c'est qu'asprotect change constament (à chaque démarrage du prog) l'endroit où cette zone se verra décompressé. Ensuite quand on continue de tracer on trouve une deuxième décompression. Je rappel que pour passer plus vite au dessus d'une décompression, on repère les boucles (avec les sauts) et on met un point d'arrêt après, puis on fait F5.
On continue donc de tracer cette deuxième décompression et à la fin il nous envoie vers cette nouvelle zone mémoire qui elle aussi n'est jamais au même endroit. Voici l'endroit où il nous envoie vers la deuxième zone mémoire :

015F:004B6A36  E9EBFEFFFF          JMP       004B6926
015F:004B6A3B  8B                  MOV       EAX, [EBP+00442A29]   <-- valeur fixe pour les paramètres
015F:004B6A41  50                  PUSH      EAX
015F:004B6A42  0385A0304400        ADD       EAX,[EBP+004430A0]    <-- adresse mémoire nouvelle zone
015F:004B6A48  5B                  POP       EBX
015F:004B6A49  0BDB                OR        EBX,EBX
015F:004B6A4B  8985D92E4400        MOV       [EBP+00442ED9],EAX    <-- change 4B6A5C avec adresse memoire nouvelle
                                                                   <-- zone
015F:004B6A51  61                  POPAD                           <-- récupère les registres
015F:004B6A52  7508                JNZ       004B6A5C                (JUMP )

< -- il y a autre chose entre les deux (mais je ne l'est pas récupérer) : surement pour gérer une erreur de décompressions.

015F:004B6A5C  68D0934A00          PUSH      004A93D0              <-- met adresse mémoire nouvelle zone sur pile
015F:004B6A61  C3                  RET                             <-- et y va

En 4B6A4B il change le push 00000000 en push 004A93D0 (début de a zone mémoire).
Voici maintenant le début de cette zone mémoire où se trouve le checksum :
 

015F:004A93D0  55                  PUSH      EBP
015F:004A93D1  8BEC                MOV       EBP,ESP
015F:004A93D3  83C4F4              ADD       ESP,-0C
015F:004A93D6  E86502FFFF          CALL      00499640
015F:004A93DB  0F85FB10FFFF        JNZ       0049A4DC                (NO JUMP)
015F:004A93E1  E8B215FFFF          CALL      0049A998
015F:004A93E6  E8213EFFFF          CALL      0049D20C
015F:004A93EB  E8F85BFFFF          CALL      0049EFE8
015F:004A93F0  E87FB1FFFF          CALL      004A4574
015F:004A93F5  E8E210FFFF          CALL      0049A4DC             <-- message d'erreur

On continue de tracer et on rentre dans le 5ème call en 4A93F5. Je rappel que chez vous les adresses seront différentes et chez moi aussi car asprotect décompresse ces zones jamais au même endroit. Et ceci empêche de mettre des points d'arrêts sur cette partie. Donc à partir du point d'arrêt en 43FC0C on est obligé de tout tracer et de se retapper la décompressions. Voilà pourquoi c'est pénible à tracer :point d'arrêt impossible et on ne peut pas se repérer au adresses mémoires..
Donc il faut recomencer à tracer et arriver sur ce 5ème call. Là on rentre dedans (f8) on passe le premier call mais le second affiche le nag. Donc on recommence encore une fois on rentre dans le 5ème call, puis après dans le deuxième qui se présente à nous, là en tracant un peu on arrive ici :

015F:004A94F2  8B45EC              MOV       EAX,[EBP-14]
015F:004A94F5  3B45F0              CMP       EAX,[EBP-10]
015F:004A94F8  7443                JZ        004A953D                (NO JUMP)
015F:004A94FA  8A154CEA4A00        MOV       DL,[004AEA4C]
015F:004A9500  8B45F8              MOV       EAX,[EBP-08]
015F:004A9503  E858EBFFFF          CALL      004A8060
015F:004A9508  8945F4              MOV       [EBP-0C],EAX
015F:004A950B  837DF400            CMP       DWORD PTR [EBP-0C],00
015F:004A950F  742C                JZ        004A953D                (NO JUMP)
015F:004A9511  8D85E4FEFFFF        LEA       EAX,[EBP-011C]
015F:004A9517  8D95E9FEFFFF        LEA       EDX,[EBP-0117]
015F:004A951D  B9FF000000          MOV       ECX,000000FF
015F:004A9522  E8ED11FFFF          CALL      0049A714
015F:004A9527  8B85E4FEFFFF        MOV       EAX,[EBP-011C]
015F:004A952D  E83A14FFFF          CALL      0049A96C
015F:004A9532  8B55F4              MOV       EDX,[EBP-0C]

Ca à l'air d'être l'endroit du cheksum. Pour le vérifier on force le premier saut (e 4A94F8 et on met eb à la place de 74). Et là le prog se lance :) . Donc c'est bien l'endroit du checksum.
Maintenant il faut faire un patch pour changer définitivement le 74 en EB. Le problème c'est que cette valeur ne se trouve jamais au même endroit. Mais voilà en gros la démarche : on change en 43FC0C le saut vers la 1ère zone mémoire. Cette partie fait partie du prog donc on peut patcher ici. Mais à se niveau on ne peut pas patcher le 74 car il n'est pas encore décompresser en mémoire. Par contre on peut patcher la fin de la première zone mémoire : la où il nous envoie vers la deuxième zone mémoire où se trouve le checksum :

015F:004B6A36  E9EBFEFFFF          JMP       004B6926
015F:004B6A3B  8B                  MOV       EAX, [EBP+00442A29]
015F:004B6A41  50                  PUSH      EAX
015F:004B6A42  0385A0304400        ADD       EAX,[EBP+004430A0]
015F:004B6A48  5B                  POP       EBX
015F:004B6A49  0BDB                OR        EBX,EBX
015F:004B6A4B  8985D92E4400        MOV       [EBP+00442ED9],EAX    <-- on détourne ici

015F:004B6A51  61                  POPAD
015F:004B6A52  7508                JNZ       004B6A5C                (JUMP )

< -- il y a autre chose entre les deux (mais je ne l'est pas récupérer) : surement pour gérer une erreur de décompressions.

015F:004B6A5C  68D0934A00          PUSH      004A93D0              <-- met adresse mémoire nouvelle zone sur pile
015F:004B6A61  C3                  RET                             <-- et y va

On peut détourner à l'endroit où il change le push avec l'adresse mémoire de la zone deux . Pour cela il faut trouver de la place dans le prog. Or il y en a à la fin :

.00455A90:  F2 A4 22 E9-38 96 D9 5D-41 34 F1 5D-A3 8A 8D A1  ò¤"é8Ù]A4ñ]£¡
.00455AA0:  A5 70 3F 51-8D D4 DC 0B-6E E6 B7 67-BC 7E C6 39  ¥p?QÔÜ næ·g¼~Æ9
.00455AB0:  72 C6 35 81-56 91 D7 65-81 99 FF D3-B1 A6 EF 26  rÆ5V×eÿÓ±¦ï&
.00455AC0:  23 69 7F B7-86 4F BD 91-33 8C 91 A6-F5 B2 A8 D7  #i·O½3¦õ²¨×
.00455AD0:  F2 D8 DC 9C-13 66 66 5A-E7 69 3D AA-F7 7E AB 07  òØÜ ffZçi=ª÷~«
.00455AE0:  F6 42 9D E1-3C B5 BE 07-92 1C E1 80-F6 AD 9F 87  öBá<µ¾ á€ö­
.00455AF0:  48 B2 30 DA-F1 6F 42 AB-7E 64 D6 00-00 00 00 00  H²0ÚñoB«~dÖ
.00455B00:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B10:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B20:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B30:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B40:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B50:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B60:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B70:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B80:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455B90:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BA0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BB0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BC0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BD0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BE0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
.00455BF0:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00

Donc on peut détourner vers 00455B00. Le problème c'est qu'on ne peut pas détourner avec un jmp car pour revenir dans le code il faut connaitre l'adresse or comme je l'ai dit plus haut elle n'est jamais là même. Donc un call est plus approprié. En effet on met un ret à la fin pour retourner dans le prog. Cependant cela n'est pas suffisant car un   CALL 00455B00 n'aura pas les mêmes valeurs hexa en fonction de l'endroit où il se trouve dans le prog (je fais allusion au fait que se 2ème patch qu'on fait devra aussi être écrit à l'aide d'un 1er patch).
Donc il faut utiliser une petite astuce :

mov ebx, 00455B00
call  ebx

et le problème est résolu.

On c'est donc où mettre notre patch comment le dévié. Mais le problème c'est que l'on sait pas où il faut l'appliquer. D'accord il faut remplacer un 74 par eb mais l'adresse où il faut le faire n'est jamais la même. Comme solution j'ai pris l'adresse du début de la 2ème zone et l'adresse où se trouve le 74 à modifié. En mémoire il est avant le début (en fait c'est là que le prog nous envoie, mais de là à dire que c'est le début ...). La différence donne e6c. Comme avant d'arriver dans cette zone mémoire l'adresse de "début" est dans eax on pourra mettre le patch en faisant mov byte ptr [eax-e6c], eb . Y a plus qu'à :

015F:004AE271  50                  PUSH      EAX
015F:004AE272  0385A0304400        ADD       EAX,[EBP+004430A0]
015F:004AE278  5B                  POP       EBX
015F:004AE279  BB005B4500          MOV       EBX,00455B00  <-- endroit du patch
015F:004AE27E  FFD3                CALL      EBX           <-- on y go
015F:004AE280  90                  NOP                     <-- on réajuste le code
015F:004B6A51  61                  POPAD
015F:004B6A52  7508                JNZ       004B6A5C

< -- il y a autre chose entre les deux

015F:004B6A5C  68D0934A00          PUSH      004A93D0
015F:004B6A61  C3                  RET

Et voici l'allure du patch :

00455B00  8985D92E4400        mov dword ptr [EBP+00442ED9], eax    <-- on restaure le chgt du push
00455B06  668094F1FFFFEB   mov byte ptr [EAX-E6C], eb                    <-- patch du checksum
00455B0D C3                             ret                                                             <-- et on retourne d'où on vient

Il n'y a même pas a sauvé ebx car juste après il restaure les registres.

Maintenant il faut faire le patch 1 qui va créer le deuxième. Regardons ce qui ce passe en 43FC0C :
 

.0043FC0C: E803000000                   call     .00043FC14   -------- (1)
.0043FC11: EB01                         jmps     .00043FC14   -------- (2)
.0043FC13: E85BEB04E8                   call      0E8061173
.0043FC18: EB04                         jmps     .00043FC1E   -------- (3)
.0043FC1A: E9EBFBE95B                   jmp       06BDDFA18
.0043FC1F: EB04                         jmps     .00043FC25   -------- (4)
.0043FC21: E8EB04E9EB                   call      0EBEA2B11
.0043FC26: FB                           sti
.0043FC27: E9C3000000                   jmp      .00043FCEF   -------- (5)
.0043FC2C: 004765                       add       [edi][00065],al
.0043FC2F: 7454                         je       .00043FC85   -------- (6)
.0043FC31: 69636B436F756E               imul      esp,d,[ebx][0006B],06E756F43
.0043FC38: 7400                         je       .00043FC3A   -------- (7)
.0043FC3A: 0000                         add       [eax],al
.0043FC3C: 0000                         add       [eax],al
.0043FC3E: 0000                         add       [eax],al
.0043FC40: 0000                         add       [eax],al
.0043FC42: 8D85039D4500                 lea       eax,[ebp][000459D03]
.0043FC48: 50                           push      eax
.0043FC49: C3                           retn
.0043FC4A: 384D04                       cmp       [ebp][00004],cl
.0043FC4D: 00BB0C010000                 add       [ebx][00000010C],bh
.0043FC53: 2002                         and       [edx],al

On voit pas trop là mais en fait le ret qui nous envoie vers la 1ère zone mémoire est en 43FC28. Donc c'est pareil que pour le patch précédent , on dévit vers la fin du prog où l'on met notre patch et on a tjs l'adresse de "début" de la zone mémoire 1 dans eax. On note cette adresse et celle où l'on a fait les modifs (en une seule fois sinon les valeurs vont changées) on fait la différence et on obtient 5bc (cette fois il faut rajouter). Voilà le principe du patch 1 :

015F:0043FC0C  E800000000          CALL      00043FC11
015F:0043FC11  5B                  POP       EBX
015F:0043FC12  BB105B4500          MOV       EBX,00455B10
015F:0043FC17  FFD3                CALL      EBX          <-- va vers notre patch
015F:0043FC19  5B                  POP       EBX
015F:0043FC1A  C3                  RET

En fait normalement entre le call en 0043fc0c et le ret il y a 2 pop ebx, le reste c'est du CCA. Donc dans notre patch on met juste les 2 pop ebx et le ret.
 

015F:00455B10  C780BC050000BB005B45MOV       DWORD PTR [EAX+5BC], 455B00BB        <-- en mémoire on inverse
015F:00455B1A  C780C005000000FFD390MOV       DWORD PTR [EAX+000005C0],90D3FF00
015F:00455B24  C3                  RET

Or là ça marche pas !!!. Et bien oui j'ai fait une erreur, il faut bien détourner en 43fc0c mais pas pour faire le patch directement. Car ce n'est pas possible, il y a encore une décompression entre les deux que je n'avait pas vu (elle est toute petite). Voilà son allure :

015F:004B1C6C  6A00                PUSH      00
015F:004B1C6E  50                  PUSH      EAX
015F:004B1C6F  FF9541294400        CALL      [EBP+00442941]
015F:004B1C75  8D85152C4400        LEA       EAX,[EBP+00442C15]  <-- on détourne
015F:004B1C7B  50                  PUSH      EAX
015F:004B1C7C  C3                  RET

Donc il faut détourner en 4B1C7B (adresse non fixe) vers la fin du prog pour qu'il mette le patch 2 (le précédent), puis en 43fc0c faire qu'il fasse ce patch là.
On détourne donc en 4b1c7b :

015F:004A4F30  6A00                PUSH      00
015F:004A4F32  50                  PUSH      EAX
015F:004A4F33  FF9541294400        CALL      [EBP+00442941]
015F:004A4F39  53                  PUSH      EBX                <-- on détourne
015F:004A4F3A  BB305B4500          MOV       EBX,00455B30
015F:004A4F3F  FFD3                CALL      EBX
015F:004A4F41  5B                  POP       EBX
015F:004A4F42  50                  PUSH      EAX
015F:004A4F43  C3                  RET

Bon là c'est pas les mêmes adresses mais c'est pas grave. C'est le même principe que tout à l'heure. J'ai détourné en 455b30 car j'ai laissé ce que j'avais mis en 455b10 (cette place sera surement utile par la suite) . Enfin voilà ce qu'il faut en 455b30 :

015F:00455B10  8D85152C4400        LEA       EAX,[EBP+00442C15]         <-- on restaure
015F:00455B16  C780B0020000BB005B45MOV       DWORD PTR [EAX+000002B0],455B00BB    <-- et on patch
015F:00455B20  C780B402000000FFD390MOV       DWORD PTR [EAX+000002B4],90D3FF00
015F:00455B2A  C3                  RET
 

Maintenant il faut patcher en 43fc0c pour que ce patch soit présent en mémoire :

015F:0043FC0C  E800000000          CALL      00043FC11
015F:0043FC11  5B                  POP       EBX
015F:0043FC12  BB105B4500          MOV       EBX,00455B50  <-- nouveau patch
015F:0043FC17  FFD3                CALL      EBX          <-- va vers notre patch
015F:0043FC19  5B                  POP       EBX
015F:0043FC1A  C3                  RET

Et voilà le patch en 455b50 :

015F:00455B50  C7800001000053BB305BMOV       DWORD PTR [EAX+00000100],5B30BB53
015F:00455B5A  C780040100004500FFD3MOV       DWORD PTR [EAX+00000104],D3FF0045
015F:00455B64  C78008010000C350C300MOV       DWORD PTR [EAX+00000108],00C3505B
015F:00455B6E  C3                  RET

Et là ... ça ne marche toujours pas, le prog palnte. Je ne fais pas exprès d'indiquer de mauvaises piste, mais c'est le raisonnement que j'ai suivi pour faire le patch. Pourtant sur cette dernière partie la structure est bonne, seulement voilà asprotec n'avait pas dit son dernier mot. Une petite explication s'impose. Allons voir plus en détail le deuxième endroit que l'on veut patcher (celui après le 43fc0c, donc celui qui sera créé par le 43fc0c) :

015F:004BABB5  8BC8                MOV       ECX,EAX                 <-- nb de fois pour boucler le repz
015F:004BABB7  8DBD092A4400        LEA       EDI,[EBP+00442A09]      <-- met chaine pour 4babd9
015F:004BABBD  8BB539294400        MOV       ESI,[EBP+00442939]      <-- destination
015F:004BABC3  F3A4                REPZ MOVSB                        <-- copie la chaine
015F:004BABC5  8B8539294400        MOV       EAX,[EBP+00442939]
015F:004BABCB  6800800000          PUSH      00008000
015F:004BABD0  6A00                PUSH      00
015F:004BABD2  50                  PUSH      EAX
015F:004BABD3  FF9541294400        CALL      [EBP+00442941]
015F:004BABD9  8D85152C4400        LEA       EAX,[EBP+00442C15]      <-- cette partie là est créé au-dessus
015F:004BABDF  50                  PUSH      EAX
015F:004BABE0  C3                  RET

La 1ère raison du fait que ça ne marche est qu'il y a un call (je ne l'est pas mis dans le listing) qui s'occupe de manipuler des chaines et le fait que l'on est changé auparavant ne lui plait pas. Ensuite comme indiqué la partie où l'on a appliqué le patch est elle même modifié. Et on ne peut pas patcher l'endroit où c'est modifié car ça fout tout en l'air (pourquoi ?). Il y a pourtant un endroit où l'on peut détourner :

015F:004BABB5  8BC8                MOV       ECX,EAX
015F:004BABB7  8DBD092A4400        LEA       EDI,[EBP+00442A09]
015F:004BABBD  8BB539294400        MOV       ESI,[EBP+00442939]
015F:004BABC3  F3A4                REPZ MOVSB
015F:004BABC5  8B8539294400        MOV       EAX,[EBP+00442939]
015F:004BABCB  6800800000          PUSH      00008000    <------------là
015F:004BABD0  6A00                PUSH      00
015F:004BABD2  50                  PUSH      EAX
015F:004BABD3  FF9541294400        CALL      [EBP+00442941] <---------à là inclus
015F:004BABD9  8D85152C4400        LEA       EAX,[EBP+00442C15]
015F:004BABDF  50                  PUSH      EAX
015F:004BABE0  C3                  RET

Docn on peut détourner ici à condition de réécrire le code que l'on a détruit. Seulement il y a un deuxième pb : on ne peut pas utiliser un call - ret, soit ça met tout en l'air, soit on a une erreur au runtime.
La solution est d'utiliser un saut. Le pb c'est que que c'est une adresse variable. On peut faire le saut pour aller en 455b30, mais pour revenir de 455b30 à l'endroit du prog on ne peut pas faire jmp 00xxxxx car l'adresse change.
Pourtant il y a une méthode. Je vais d'abord écrire ce patch et j'expliquerai le pourquoi du comment après.

015F:004BABB5  8BC8                MOV       ECX,EAX
015F:004BABB7  8DBD092A4400        LEA       EDI,[EBP+00442A09]
015F:004BABBD  8BB539294400        MOV       ESI,[EBP+00442939]
015F:004BABC3  F3A4                REPZ MOVSB
015F:004BABC5  8B8539294400        MOV       EAX,[EBP+00442939]
015F:004BABCB  6800800000          PUSH      00008000
015F:004BABD0  6A00                PUSH      00
015F:004BABD2  B9305B4500          MOV       ECX,00455B30    <-- on détourne le prog
015F:004BABD3  FFE1                JMP       ECX
015F:004BABD9  8D85152C4400        LEA       EAX,[EBP+00442C15]
015F:004BABDF  50                  PUSH      EAX            <-- on revient ici
015F:004BABE0  C3                  RET

Et voilà ce qu'il y a en 455b30 :

015F:00455B30  50                  PUSH      EAX                  <-- on restaure
015F:00455B31  FF9541294400        CALL      [EBP+00442941]        <-- ce que l'on a détruit
015F:00455B37  8D85152C4400        LEA       EAX,[EBP+00442C15]        <-- on récupère adresse début zone mémoire
015F:00455B3D  C780B0020000BB005B45MOV       DWORD PTR [EAX+000002B0],455B00BB      <-- on patch
015F:00455B47  C780B402000000FFD390MOV       DWORD PTR [EAX+000002B4],90D3FF00
015F:00455B51  FF25605B4500        JMP       [00455B60]                    <-- et on retourne d'où l'on vient

Quel est donc ce jmp [00455b60]. En 00455b60 il y a l'adresse de retour. Comme ce patch est créé en 43fc0c il suffit d'ajuster l'adresse à l'endroit où l'on veut revenir et de la mettre dans 00455b60. Pour mieux comprendre voici le patch en 0043fc0c (j'ai refait le calcul du nb de byte entre le début de la zone mémoire et l'endroit où le patch doit être appliqué : F9) :

015F:0043FC0C  E800000000          CALL      00043FC11
015F:0043FC11  5B                  POP       EBX
015F:0043FC12  E9595F0100          JMP       00455B70      <-- va vers patch
015F:0043FC17  5B                  POP       EBX
015F:0043FC18  C3                  RET

Et voilà ce qu'il y a en 455b70 :

015F:00455B70  C780F9000000B9905B45MOV       DWORD PTR [EAX+000000F9],455B90B9
015F:00455B7A  66C780FD00000000FF  MOV       WORD PTR [EAX+000000FD],FF00
015F:00455B83  C680FF000000E1      MOV       BYTE PTR [EAX+000000FF],E1
015F:00455B8A  0506010000          ADD       EAX,00000106
015F:00455B8F  A3605B4500          MOV       [00455B60],EAX
015F:00455B94  2D06010000          SUB       EAX,00000106
015F:00455B99  E979A0FEFF          JMP       0043FC17                (JUMP )
015F:0043FC17  5B                  POP       EBX
015F:0043FC18  C3                  RET
 

Là on peut utiliser les adresses mémoires car pour cette partie elles sont fixes. Voilà en fait en 455b60, l'adresse de retour est mis en fonction du nb de byte qui sépare l'adresse du début zone mémoire (ds eax) et l'endroit où l'on veut revenir : il y a 106 byte.

Maintenant on fait les modifications avec un héditeur hexa :

On lance le prog et tout marche impeccable, on a droit au nag du prog qui nous indique le nombre de jours d'utilisation qui reste :) .
 
 

2ème partie : Le prog
 

Pour la protection du prog par elle même elle n'existe pas vraiment. Voilà ce qui est dit dans le fichier d'aide si on s'enregistre:

  You will never see the 'Nag' screen...
  The support of the command-line parameters will be available.
  Full technical support.
  All new versions and updates of ZVolume Pro will be free for you!
 

En gros le prog marche tout le temps même lorsque les trentes jours d'utilisation sont dépassés : il suffit d'appuyer sur try et le prog se lance. Pour trouver où le nag est affiché il faut continuer à tracer après le dernier patch qui est appliqué (celui qui va virer le checksum). Mais là il va encore falloir modifié ce dernier patch pour en faire un autre : en effet le prog est décompressé dans la même zone mémoire que le checksum . Mais avant de s'occuper de cela regardons comment virer ce nag.

Le nag est en fait une dialogbox, donc posons un point d'arrêt sur la fonction DialogBoxParamA. Softice break au démarrage du prog et en remontant avec F12 on arrive là :

015F:0040E331  C1E902              SHR       ECX,02
015F:0040E334  F3A5                REPZ MOVSD
015F:0040E336  8BCA                MOV       ECX,EDX
015F:0040E338  83E103              AND       ECX,03
015F:0040E33B  F3A4                REPZ MOVSB
015F:0040E33D  E86EF2FFFF          CALL      0040D5B0      <-- dialogox
015F:0040E342  A1D4B74100          MOV       EAX,[0041B7D4]
015F:0040E347  83C404              ADD       ESP,04
015F:0040E34A  3D00FA0000          CMP       EAX,0000FA00
015F:0040E34F  7312                JAE       0040E363              <-- saute si on a cliqué sur try
 

Comme il est nécessaire de revenir dans cette partie du prog pour l'étudier il faudrait non pas s'arrêter après l'affichage du prog, mais avant. Or cette zone mémoire où le prog est décompressé est constante. Cependant le traditionnelle bpx ne marche pas. Il faut utiliser le point d'arrêt suivant : bpm 0040e331 x et la c'est ok.
Donc en étudiant c'est partie du code et en rentrant dans le call 0040d5b0, on constate deux chose :

Donc pour m'occuper de virer le nag j'ai mis un ret au debut du call 0040d5b0 (il n'y a rien a craindre cette fonction affiche juste une dialogbox) et jai regardé comment s'effectuait le saut : or il a lieu donc il n'y a même pas à l'inverser. Normalement il ne devrait pas y avoir de problème pour le lancement du prog car la fonction en 0040d5b0 n'a pas un rôle vital. Et c'est le cas : le prog ce lance sans le nag. Donc pour patcher le prog il suffit de mettre un ret en 0040d5b0.
 

Comme je l'ai dit plus haut la décompression du prog a lieu dans le dernière zone mémoire (où se trouve le checksum). Donc il faut tracer dans softice pour reperer où il est appelé. En tracant on retrouve nos 5 calls successifs de la première partie, on rentre dans le 5ème puis on repère un autre call qui affiche le prog. Une fois ce call repéré on recommence l'opération mais cette fois ci on rentre dedans (f8), on continue de tracer jusqu'à arriver là (attention code cca donc c'est a peu près ca) :

015F:004A9E05  89041C              MOV       [EBX+ESP],EAX
015F:004A9E08  EB02                JMP       004A9E0C
015F:004A9E0C  61                  POPAD
015F:004A9E0D  EB01                JMP       004A9E10        <-- on détourne
015F:004A9E10  50                  PUSH      EAX
015F:004A9E11  EB02                JMP       004A9E15
015F:004A9E15  E802000000          CALL      004A9E1C
015F:004A9E1C  58                  POP       EAX
015F:004A9E1D  C3                  RET                       <-- va vers prog décompressé

Donc de 4A9E0D à 4A9E1C il fait des trucs qui n'ont aucune importance (code cca). Par contre en 4a9e1d, il va vers le début du vrai prog. Donc on peut détourner en 4a9e0d vers la fin du prog :

015F:004A7595  BBA05B4500          MOV       EBX, 00455BA0
015F:004A759A  FFE3                JMP       EBX

Maintenant voilà ce qu'il doit y avoir en 455BA0 :

015F:00455BA0  C605B0D54000C3      MOV       BYTE PTR [0040D5B0],C3  <-- patch pour virer nag
015F:00455BA7  FFE0                JMP       EAX                     <-- va vers début du vrai prog

Donc en 455BA0, on patch le nag, et on fit ensuite jmp eax, qui va vers le début du prog car son adresse se trouve à ce moment là dans eax.
Maintenant pour que ce patch est lieu il faut légèrement modifié le patch en 00455b00 qui modifié le checksum. Il fuat également qu'il ajoute celui là.
Pour ce faire il faut connaitre le nombre de byte séparant l'endroit où l'on va mettre le patch (sur l'ex en 4a9e0d) et le début de la zone mémoire. On fait comme dans la partie 1 et on obtient 111B bytes donc on peut modifier le patch en 00455b00 :

015F:00455B00  8985D92E4400        MOV       DWORD PTR [EBP+00442ED9], eax
015F:00455B06  C68094F1FFFFEB      MOV       BYTE PTR [EAX+FFFFF194],EB
015F:00455B0D  C780E5EEFFFFBBA05B45MOV       DWORD PTR [EAX+FFFFEEE5],455BA0BB  <-- nouveau patch
015F:00455B17  66C780E9EEFFFF00FF  MOV       WORD PTR [EAX+FFFFEEE9],FF00
015F:00455B20  C680EBEEFFFFE3      MOV       BYTE PTR [EAX+FFFFEEEB],E3
015F:00455B27  C3                  RET

Le patch en 455b00 va jusqu'en 455b27 : j'avais laissé la place en 455b10 auparavant, et la ca ne déborde pas en 455b30 donc c'est ok.
Il ne reste plus qu'à effectué les changements avec un editeur hexa. On lance le prog et là plus de nag au démarrage :) .
 
 

3ème partie : Conclusion

Je reconnais volontiers que ce n'est pas très optimisé. Il aurait fallu mettre les patchs dans l'ordre, pour avoir quelquechose de plus clair et plus structuré. Cela aurait aussi éviter le fait qu'il est fallu laisser de la place à un moment.
Je récapitule :

Enfin, voilà mon approche pour ce prog protégé avec la dernière version d'asprotect. Je sais c'est long et pénible et trouver (surtout à cause du code CCA et du changements des adresses memoires).
J'ai essayé de m'exprimer clairement mais je suis convaincu que c'est encore assez difficile à saisir. Si vous n'arriviez pas à comprendre envoyé moi un mail que je vous explique. (city_of_bitch@caramail.com)

Amicalement,

LuTiN NoIR