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 :
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 :
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 :
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 :
Amicalement,
LuTiN NoIR