![]() |
COURS
ETUDE DE WINACE 1.2
PROTECTIONS ASPACK KEYFILE CRC |
DATE
01/02/2000 Maj 25/02/2000 |
Salut à tous,
Petite étude de WinAce.exe Version 1.2
Alors on s'équipe de tout ce qu'il
faut : Jus de fruits, barres de céréales...
(certains pour la frime disent : Alcool, drogueS
et autres accélérateurs de particules...)
(Essayez de faire
une nuit de debug en vous aidant d'un litre de Vodka et vous verrez...)
Il s'agit d'un prog Delphi compacté
par AsPack (c'est écrit ds le PE ;o] ).
| Donc 1ère manipulation : le décompactage |
On prend un éditeur de PE header et
on vérifie les infos des sections
surtout celles qui contiennent le code et
le point d'entrée.
CODE : C0000040
=> problèmes = pas de Désassemblage, pas de Debug...
On corrige par un E0000020.
On trace un peu de code avec un Debgr (style SoftICE ou TRW2000)
Première remarque un PUSHAD => il y
a de forte chance d'avoir un POPAD à la fin.
| 00648001 PUSHAD *******=Push
EDI, ESI, EBP, EBX, EDX, ECX, EAX
00648002 CALL 00648542 00648007 JMP 00648051 00648051 MOV EBX,00442994 00648056 ADD EBX,EBP 00648058 SUB EBX,[EBP+004429C1] ...... On UnPack... ...... 006484BC POPAD ******* He Oui 006484BD JNZ 006484C7 006484C7 PUSH 005802E4 Adresse du prog 006484CC RET On y va 005802E4 PUSH EBP On y est ;) 005802E5 MOV EBP,ESP 005802E7 ADD ESP,-10 005802EA PUSH EBX |
Donc l'adresse de l'exe est 005802E4
En 006484CC on place un JMP EIP
pour faire une boucle infinie...
On prend son meilleur dumper (SDump ou ProcDump
ou autre)
On fait un Full Dump de l'exe WinAce (J'aime
bien ProcDump).
Ensuite on Kill la tâche WinAce.exe
(il y a une boucle infinie)
On prend son meilleur éditeur de PE
(ProcDump par exemple ;) et on corrige le point d'entrée :
005802E4 - 00400000 = 001802E4 et voila...
On obtient un exe non compressé qui
tourne correctement !
Bien sur on peut attendre d'avoir un prog
qui fait du UnAsPack directement
mais bon il faut qd même un minimum
de savoir faire pour ne pas être trop dépendant !
| Petit
complément pour un bon Dead Listing :
La restitution de la table d'import. |
Dans l'éditeur de PE en trouve :
idata : VAdrs = 0x001B9000 , VSize = 0x00004000
Donc on peut en conclure que la table se trouvera
là en mémoire
(0x00400000 + 0x001B9000 = 0x005B9000) à
un moment ou un autre.
On va donc faire un BP sur la zone mémoire
indiquée et attendre...
On regarde l'état de la zone mémoire
: il s'agit d'adresse mémoire
sur des chaînes (on regarde qq centaines
d'octets plus bas si on ni
connait rien et c'est bon si l'on voit des
noms de fonctions en clair).
OK on a les infos : Gardons les ds un coin
(du Disque dur ;o)
Dump mémoire de 0x005B9000 à
0x005BCFFFF (=x005B9000 + 0x4000 -1).
Nous voilà avec une belle table sur
disque.
ASTUCE: Si AUCUN DUMPER ne le fait pour
vous, il suffit de le
faire sous le debugger et de convertir le
fichier texte en binaire...
(Voir en fin de fichier : le code source Pascal
d'un convertisseur)
On prend notre meilleur éditeur Hexa
et on lui demande d'ajouter ce
fichier à l'exe décompacté
! On fait un build PE amélioré et on se retrouve
avec un beau prog bien lisible (du moins c'est
mieux que sans !).
Pour ajouter la table ds WinAce : (exp avec
Soft Ice comme débuggeur)
> BPM 005B9000 W
Break
> F10 (jusqu'à avoir une table import
correcte)
> WD OFF
> D 005B9000 4000
> F5
Ds le loader : Fichier | Save History As...
"TableImp.log"
Conversion des lignes du fichier .log en binaire
"TableImp.bin"
(il faut bien sur épurer le fichier
log pour ne garder que le dump)
Prendre un éditeur de fichier.
Ouvrir les fichiers : WinAceDump.exe et TableImp.bin.
Sélectionner tout le fichier binaire.
Sélectionner la zone 001b9000:001bc540
ds WinAceDump.
Coller (remplacer) ds WinAceDump.
Sauver WinAceDump.exe
Avec un éditeur de PE vous modifiez
le "section directory"
au niveau de l'Import table pour y placer
les bonnes valeurs.
(Adresse: 001B9000 size: 4000). Vous pouvez
aussi reconstruire
le fichier mais pas l'import table (en tout
cas moi je ne le fais pas).
Vous voilà avec un bel exécutable
bien lisible !
Object01: CODE RVA: 00001000 Offset: 00000600
Size: 0017F5CC Flags: E0000020
Object02: DATA RVA: 00181000 Offset: 0017FC00
Size: 0000E480 Flags: C0000040
Object03: BSS RVA: 00190000 Offset: 00190000
Size: 00000000 Flags: C0000040
Object04: .idata RVA: 001B9000 Offset:
0018E200 Size: 00003538 Flags: C0000040
Object05: .edata RVA: 001BD000 Offset: 00191800
Size: 0000012C Flags: C0000040
Object06: .tls RVA: 001BE000 Offset: 001BE000
Size: 00000000 Flags: C0000040
Object07: .rdata RVA: 001BF000 Offset: 00191A00
Size: 00000010 Flags: C0000040
Object08: .reloc RVA: 001C0000 Offset: 00191C00
Size: 00000000 Flags: C0000040
Object09: .rsrc RVA: 001D7000 Offset: 00191C00
Size: 000703BC Flags: C0000040
Object10: .aspack RVA: 00248000 Offset: 00202000
Size: 00001B10 Flags: E0000020
Object11: .rsrc RVA: 0024A000 Offset: 00203C00
Size: 00000000 Flags: C0000040
IMPORTED FUNCTIONS: Imported Modules = 24 (decimal)
Import Module 001: kernel32.dll
Import Module 002: user32.dll
Import Module 003: advapi32.dll
Import Module 004: oleaut32.dll
Import Module 005: kernel32.dll
Import Module 006: advapi32.dll
Import Module 007: kernel32.dll
Import Module 008: mpr.dll
Import Module 009: version.dll
Import Module 010: gdi32.dll
Import Module 011: user32.dll
Import Module 012: ole32.dll
Import Module 013: oleaut32.dll
Import Module 014: comctl32.dll
Import Module 015: winspool.drv
Import Module 016: shell32.dll
Import Module 017: comdlg32.dll
Import Module 018: shell32.dll
Import Module 019: ole32.dll
Import Module 020: cabinet.dll
Import Module 021: shell32.dll
Import Module 022: ace.dll ***
Import Module 023: Shell32.dll
Import Module 024: winmm.dll
Pour le dump on peut essayer avec ProcDump
mais ca ne marche pas tjrs.
| Enregistrement d'un utilisateur Oui mais OU ?? |
Après qq tests (plus ou moins longs
en fonction du niveau du testeur ;)
On galère un peu dans AceTools.Dll
(en fait il n'y a que les formulaires)
On passe dans Ace.Dll et on revient dans WinAce.exe
etc...
Pour les nouveaux : Y a pas de secret on fait
de façon classique :
Un bp sur un call et on le passe si Code non
Valide alors il faut étudier ce call !
(on procède un peu par dichotomie)
// bien sur on peut
être plus Zen et voir que ds Ace.Dll il y a des noms de fonctions
// qui sont très
explicites donc on y met un BP ;) et hop Glop Glop !
Donc dans WinAce on tombe ici :
| 00558DBD
FFD3 call ebx
00558DBF 84C0 test al, al 00558DC1 0F847B010000 je 00558F42 00558DC7 33C0 xor eax, eax 00558DC9 A348625800 mov dword ptr [00586248], eax 00558DCE 8D95F0FDFFFF lea edx, dword ptr [ebp+FFFFFDF0] 00558DD4 8D85F0FCFFFF lea eax, dword ptr [ebp+FFFFFCF0] 00558DDA E8459EEAFF call 00402C24 00558DDF BAA48F5500 mov edx, 00558FA4 00558DE4 8D85F0FCFFFF lea eax, dword ptr [ebp+FFFFFCF0] 00558DEA E8DD9DEAFF call 00402BCC 00558DEF 8D95F0FCFFFF lea edx, dword ptr [ebp+FFFFFCF0] 00558DF5 B884625800 mov eax, 00586284 00558DFA B132 mov cl, 32 00558DFC E83F9EEAFF call 00402C40 00558E01 8D45F0 lea eax, dword ptr [ebp-10] 00558E04 BA84625800 mov edx, 00586284 00558E09 E8CAB0EAFF call 00403ED8 00558E0E 8D85ECFCFFFF lea eax, dword ptr [ebp+FFFFFCEC] 00558E14 8D95F0FEFFFF lea edx, dword ptr [ebp+FFFFFEF0] 00558E1A E8B9B0EAFF call 00403ED8 00558E1F 8B85ECFCFFFF mov eax, dword ptr [ebp+FFFFFCEC] 00558E25 8D55F8 lea edx, dword ptr [ebp-08] 00558E28 E81BF9EAFF call 00408748 00558E2D BB01000000 mov ebx, 00000001 00558E32 EB21 jmp 00558E55 00558E34 8B45F8 mov eax, dword
ptr [ebp-08]
|
Appel
du TRegForm (saisie du code)
Bouton Cancel ? Oui on annule... Sinon on test les résultats Taille de la AVString (UserName)
On transforme la chaîne
en une 0Ended
edx = Code
*eax = Code
eax = 17h = length(Code)
Nettoyage du code
eax = code ss les '-'
eax=Code
Renvoie
une erreur de code!!
RegUser OK si [00586248]=0
OK si [00586248]=0
OK si [00586248]=0
Affiche Reg OK
|
On voit donc que l'on peut forcer l'enregistrement
de l'utilisateur à Vrai !
MAIS MAIS : cela ne ce fait pas complètement
car il y a un KeyFile (Ace.KEY)
qui n'est pas écrit...
Pourrait-on forcer cette écriture ?
;-)
Pourquoi ne pas simplement chercher le flag
qui dit Reg OK et le fixé ?
| On étudie de plus près : call 004B211C |
Et l'on fini par arriver dans Ace.Dll avec
un décalage de 00250000 à ajouter
(en fct de l'adresse de chargement)
On a un JMP [005B9B74] = JMP 0066241C
| Exported Function
: ACERegister Vu
le nom de la fct on ne pouvait pas se tromper !
:0041241C 56 push esi
|
| On étudie de plus près : call 00409C76 |
| :00409C76 51
push ecx
:00409C77 52 push edx :00409C78 56 push esi :00409C79 57 push edi :00409C7A E8F5FCFFFF call 00409974 :::test du code :00409C7F 833D9813440000 cmp dword ptr [00441398], 00000000 :00409C86 0F85BD000000 jne 00409D49 ::: ERREUR 221 :00409C8C 833D86F0440000 cmp dword ptr [0044F086], 00000000 :00409C93 742D je 00409CC2 . . . . . . . . :00409CE3 C70598134400FF000000 mov dword ptr [00441398], 000000FF :00409CED 5F pop edi :00409CEE 5E pop esi :00409CEF 5A pop edx :00409CF0 59 pop ecx :00409CF1 C3 ret |
| On étudie de plus près : call 00409974 |
C'est là que l'on s'amuse !
| :00409974 53
push ebx
...... :00409979 C8200000 enter 0020, 00 :::un peu de mémoire locale :0040997D 8D7DF0 lea edi, dword ptr [ebp-10] :00409980 BE28104000 mov esi, 00401028 :00409985 A5 movsd :00409986 A5 movsd :00409987 A5 movsd :00409988 A5 movsd :00409989 B910000000 mov ecx, 00000010 :0040998E BED1F04400 mov esi, 0044F0D1 :00409993 8D7DE0 lea edi, dword ptr [ebp-20] :::esi= code - les 3 1er lettres :00409996 31C0 xor eax, eax :00409998 57 push edi :00409999 F2 repnz :0040999A A4 movsb :0040999B 5F pop edi :::fin de copie ds edi en 008FF830 :0040999C 8B0D38AB4200 mov ecx, dword ptr [0042AB38] :::"34679ACDEFHKLMNPQRSTWXY" :004099A2 EB06 jmp 004099AA ::: appelons cette chaîne GrpA ...... :004099AC EB06 jmp 004099B4 ...... :004099B4 8A5C28E0 mov bl, byte ptr [eax+ebp-20] :::bl = 1ere lettre ...... On vérifie si les lettres du Code sont dans le GrpA : "34679ACDEFHKLMNPQRSTWXY" sinon il y a une erreur : Donc le code ne peut être composé que de ces lettres là! ...... :004099C1 83FA17 cmp edx, 00000017 ::: bl pas ds GrpA :004099C4 75DE jne 004099A4 :004099C6 C7059813440021020000 mov dword ptr [00441398], 00000221 ::: ERREUR 221 :004099D0 E950360000 jmp 0040D025 ::: bad Code ....... si OK on se retrouve avec edi qui pointe sur la liste des index des lettres du code par rapport à la position ds GrpA (exp : A ds le code donne 05 ds la zone ptée par edi) ....... Qq calculs sur le code ainsi modifié ....... :004099E3 6B442AF017 imul eax, dword ptr [edx+ebp-10], 00000017 :004099E8 83C204 add edx, 00000004 :004099EB 89442AEC mov dword ptr [edx+ebp-14], eax :004099EF 83FA0C cmp edx, 0000000C :004099F2 75EF jne 004099E3 ....... Qq calculs sur le code ....... :00409A3E 7407 je 00409A47 :00409A40 B801000000 mov eax, 00000001 :00409A45 EB02 jmp 00409A49 :00409A47 31D8 xor eax, ebx :00409A49 BB03000000 mov ebx, 00000003 :::compteur pour un calcul :00409A4E BACEF04400 mov edx, 0044F0CE :::adrs mémoire :00409A53 A386F04400 mov dword ptr [0044F086], eax :::init :00409A58 B8FFFFFFFF mov eax, FFFFFFFF :::init :00409A5D E87C580000 call 0040F2DE :::Calcul de CRC?? :00409A62 0FB6C0 movzx eax, al :::on garde AL (doit être = à C3) :00409A65 A38AF04400 mov dword ptr [0044F08A], eax :::on sauve en mémoire :00409A6A 89C2 mov edx, eax :00409A6C B8E2F04400 mov eax, 0044F0E2 :::Adresse :00409A71 E891DC0000 call 00417707 :::Calcul de CRC?? :00409A76 E9AA350000 jmp 0040D025 :::on s'en va!!! enfin |
Donc tout ca, est-ce bien le calcul de vérif
code !! // Non il en manque encore bcp !
Quel B....L de M...E !!!
Ca multiplie, ca décale, ca tourne,
ca appel et allons-y ne nous privons pas c'est du Pascal !
Mais pensez donc à ceux qui regarde
ca sous un autre œil !
En assembleur c'est moins amusant ce genre
de chose !
Là il y a un choix à faire :
Soit il y a une routine qui calcule le bon
code soit on utilise tjrs cette routine pour vérifier.
Qd le prog se lance il doit vérifier
si l'on est inscrit donc si l'on passe ds le coin au démarrage
c'est qu'il y a vérification du code
saisie (donc stockage qq part - ds Ace.key pour ceux qui on bien lu)...
On va qd même vérifier en regardant
un peu le code source du prog et des Dlls (Ace.dll)...
A plus tard...
Bon comme on a trouver la routine de calcul
c'est plus simple mais on se balade d'un call à l'autre en
dead listing c'est dur dur.
Là on arrête
tout et on fait une pause kitkat !
(qq mn plus tard...)
Soyons plus Zen et réfléchissons
un peu :
Données du pb => une AVstring (username)
et un code
Solutions possibles => (il n'y en a pas 36)
1- le username donne un code mémoire
qui est comparé à celui saisie ?
2- le username donne un CRC qui est comparé
à celui du code saisie ?
Soluce 1: le code fishing => il doit y avoir
ds le prog une comparaison de chaîne
Soluce 2: on fait un (ou plusieurs) calcul(s)
avec le username et
un (ou plusieurs) calcul(s) avec le code ensuite
on compare le résultat (généralement un entier)...
On a vu en 00409974 que le 1er calcul est
fait sur le code donc on peut
imaginer qu'il s'agit d'un calcul de CRC !
On remarque ds le code (:00409A2D et :00409A6C)
que le résultat est placé en 0044F0E2.
Donc on va utiliser une vieille ruse de Sioux
: suivre le gibier à la trace !
On passe donc sous debuger et on surveille
la zone mémoire 0044F0E0:0044F0F0
On prend une zone
un peu plus large pour les 1ers tests...
Petite promenade...Remarque importante on
lit/écrit aussi en 0044F080:0044F090 donc
on regarde aussi cette zone mémoire...
Résultats:
1°) Calcul de CRC avec le code, écriture
en 0044F0E2:0044F0E8 (adrs:00409a2d)
2°) Copie du résultat en 008ff4bc
(adrs:00417794)
3°) Copie d'une valeur calculée
de 008ff6fc vers 0044F0E2 (adrs:004177ab)
4°) Calcul de CRC avec la AVString (username),
écriture en 0044F082 (adrs:00409c45)
5°) Test important 0044F082=0044F0E2 ???
OUI alors le code est bon !!!
On sait que :0040999C nous indique que les
lettres composant le code sont ds
"34679ACDEFHKLMNPQRSTWXY"
Un indice on remarque que le CRC calculé
en 0040f2de des 3 1eres lettres du code
doit faire eax=??????C3. Un peu de Zen et
on se dit que comme ds tous les progs
il doit s'agir des initiales du prog. On fait
un test avec "ACE" et c'est gagner!!!
Il devient maintenant très simple de
patcher le code du programme (en mémoire pour tester)
en regardant la zone mémoire de 0044F080:0044F0EF
et en répondant aux interrogations du prog !
qqs exemples mais pas tous : il faut aussi
que vous travailliez un peu
| :00409C7F 833D9813440000
cmp dword ptr [00441398], 00000000
:00409C86 0F85BD000000 jne 00409D49 ::: devient EB049090 :00409C8C 833D86F0440000 cmp dword ptr [0044F086], 00000000 :00409C93 742D je 00409CC2 ::: devient EB2D :00409C3D E89C560000 call 0040F2DE :00409C42 8B55BC mov edx, dword ptr [ebp-44] :00409C45 8902 mov dword ptr [edx], eax :00409C47 3B4260 cmp eax, dword ptr [edx+60] :00409C4A 7521 jne 00409C6D ::: devient 9090 :00409C59 E880560000 call 0040F2DE :00409C5E 8B55BC mov edx, dword ptr [ebp-44] :00409C61 3A4266 cmp al, byte ptr [edx+66] :00409C64 7507 jne 00409C6D ::: devient 9090 |
etc... il y a en tout 8 adresses et 17 octets à changer........
PETIT COMPLEMENT (pour les puristes du patch ;o)
On peut réduire cela à 2 octets
en modifiant deux "jmp si EAX=1"... ;o))
En fait la protection vérifie 2 fois
que le CRC du Code est égal au CRC de l'AVString (userName).
Donc en forcant le passage à 2 endroits
différents on obtient un code valide et un fichier clef.
Une autre méthode : (relative au point
5°)
S'arranger pour que la routine qui compare
les CRCs renvoie toujours EAX=1 !
Attention : cela peut-être dangereux
si le prog utilise la routine de CRC pour valider certaines archives ZIP...
Pourquoi ne pas l'avoir dit plutôt ??
Simplement parceque le
but de l'étude est un KeyGen, donc je n'ai pas cherché à
améliorer le patch du prog.
Si votre but est juste
de vous enregistrer, avec un debugger et 1 break point sur Ace.Dll vous
pouvez
générer
un keyFile. Ensuite vous utilisez le prog de façon normale. Il n'y
a aucun problème...
Donc une suggestion
pour le programmeur : vérifier la validité des valeurs à
chq chargement.
Pour que l'on soit au
moins obligé de faire un Patch du prog ;)
Ceux qui se demandent comment on fait pour
savoir si l'on "jump" ou pas doivent faire un peu plus de "dead listing".
On y remarque très bien si l'on part vers une erreur ou un affichage
de msgbox
(sinon on test et on prend des notes ;o)
Ensuite on saisie un Username et un code "ACEDT....DT"
et on s'enregistre...Bingo !!
(en fait on doit prendre des lettres ds :
"34679ACDEFHKLMNPQRSTWXY"
Parce Que ca ne sert à rien de mettre
des patchs ds tous les coins -
sinon on peut aussi patcher ce test ?-).
Le fichier Ace.Key est généré
et l'utilisateur est le bon et on peut en changer qd on veut !
Tous ceci serait très sympa mais d'après
vous : Pourquoi avoir Aspacker l'exe et laisser les Dlls en clair ???
Réponse : Tout simplement car
il y a un test de validité de la Dll dans le prog !!!
Donc on peut tjrs utiliser un patcher mémoire
ou trouver la routine de contrôle et la modifier (tjrs patch mémoire)
on peut aussi garder le prog unAspaked (on
l'a fait au début) et le patcher en direct !
IL Y A AUSSI UNE AUTRE SOLUTION : (moins élégante)
Une version de la Dll patchée et une
non patchée. On utilise une fois la Dll patchée pour l'enregistrement
ensuite on utilise la classique. Comme ca
pas besoin de unAspack ni de patcheur mémoire...
Mais on doit pouvoir faire mieux !
| Etudions la routine de contrôle de la Dll |
En première réflexion on pense
à un calcul de CRC sur la Dll (un octet de modifié et hop
perdu !!)
Ensuite on peut imaginer qu'il y a un test
des octets cruciaux (un octet de modifié et hop perdu !!)
Comment le savoir me direz-vous : Très
simple on prend la Dll et on modifie un octet très en dehors des
"zones sensibles"... Si un message s'affiche => c'est un CRC sur le fichier
complet !!
Résultat : On cherche un texte ds la
Dll et on le modifie => ERREUR de Dll !!!
On a donc un CRC sur toute la Dll. On ne peut
donc rien modifier même en équilibrant le poids des octets.
Il y a d'autre possibilité de tester
le code :
- somme des octets (contournable par équilibrage
du code)
- somme des octets pondérée
(octet1*1 + ... + octet9*9 + octet10*1 + ... + octet19*9)
- Vérification du nombre de NOP (Au
lieu de mettre 2 NOP on met un DEC + un INC)
- Etc...
Une chose à faire si vous ne maîtrisez
pas les CRC : aller sur le Web et trouver des codes sources de routines
de calcul de CRC (freeWare). Vous apprendrez comment en 2 ou 3 ligne de
prog on fait une solide vérification. Vous remarquerez qu'il y a
un tableau d'entiers 32 bits qui est utilisé (intéressant
à chercher avec un Editeur hexa). Vous apprendrez que l'entier recevant
le résultat est initialisé à FFFFFFFF au début
du calcul. Ensuite vous compilez le code source et vous en étudiez
l'assembleur cela vous donne une idée du type d'instructions utilisées
(shr résult..xor index..shl index..xor résu,tableau[index])...
Juste avec ces infos vous pouvez trouver la
routine de calcul ds le prog ;o))
Calculons les CRCs de la Dll correcte =>
E0/chk8 22E0/chck16 0092/crc16 56BF/ccitt
DEC8F3A0/crc32 (valeur en complément à 1)
Pour ceux qui ne
manient pas les calculs : HexWorkShop fait ca très bien !
ATTENTION : Suivant les algos on
trouve des valeurs à +/- 1.
On gardera en mémoire la valeur D3C8F3A0 qui est un CRC32 (bien ds le style du prog)
Là il y a plusieurs voies possibles
:
- recherche en dead listing d'une
routine de calcul de CRC (facile)
- recherche en dead listing d'un test
sur la valeur du CRC (il faut de la chance)
- live Debug et recherche de lecture
du fichier (ace.dll)
Supposition : Au feeling on va dire
qu'il y a ouverture du fichier, lecture et comptage...
Donc cherchons les ouvertures de fichiers.
Plaçons les pts d'arrêts
sur : CreateFileA, ReadFile, LoadLibraryA
(pour faire la différence avec
le chargement de Ace.Dll)
INFO: Avec ces routines le nom du
file sera ds EDI.
On tombe sur :
1°) CreateFileA pour Ace.Dll
2°) ReadFile pour Ace.Dll ( bon
début )
3°) On trace en pas à pas
( on passe qd même au dessus des routines )
On regarde les Registres..
4°) Tient en retour de fonction
EAX=DEC8F3A0 !!!!!! Ca nous dit qq chose cette valeur.
(On vient donc de passer la routine
de calcul du CRC)
5°) On continue en prenant des
notes sur les adresses d'exécution...
6°) Tient cmp EAX, DEC8F3A0 !!!!
Joli test de CRC valide
si OK alors EAX=0 et Ret
7°) He hop : test AL, AL si OK
alors goto somewhere...
Voilà, voilà : Donc plusieurs
possibilités =>
1°) On remplace la valeur DEC8F3A0
par celle du CRC32 de la DLL modifiée
2°) On force la comparaison par
un mov EAX,00000000
3°) On force le test AL par un
Jump SomeWhere
4°) On force une comparaison avec
le fichier de la Dll non modifiée
| Etudions la façon de placer les modifications |
1°) On change ds la Dll (pas de problème
particuliers)
2°a) On patch l'exe décompressé
simple et efficace
2°b) On ajoute du code au prog compressé
pour faire un patch mémoire de l'exe !
Regardons cette solution 2°b :
Où, quand, comment et pourquoi ????
1°) OU : Simplement là où
il y a de la place ds le code ;o)
On va prendre le PE header du prog compressé
(ProcDump, Hiew...) et l'on regarde les sections.
La plus sympa est .aspack on voit qu'elle
a une taille physique < à la taille virtuelle (alignement de
code)
donc on se dit qu'il y a de la place par là.
Pour en être sur on regarde et l'on
voit que le prog ne passe pas 00649BFF en adresse
alors que l'on voulait justement écrire
entre 00649C000 et 00649FFF ! ! !
(Adrs = Image (00400000) + VirtualOffset (00248000)
+ PhysiqSize (1C000) = 00649C000)
Mais on remarque qu'il y a pas mal de 00 après
00649B11 donc un petit test en lecture/écriture
mémoire va nous dire si le programme
se sert de cette zone mémoire.
Réponse NON donc on peut utiliser cet
espace pour mettre du code machine !
2°) QUAND : Simplement quand le compacteur
a fini son travail ;o)
Nous avons vu au départ (lors de la
phase de Dump) que la fin du travail se situe en 006484CC
en remontant un peu on voit MOV [adrs], EAX
voilà un bel endroit pour détourner l'attention du programme
et le modifier qq peu (car EAX contient le
point d'entré du prog décompressé).
| 006484B3 5B POP
EBX
006484B4 0BDB OR EBX,EBX 006484B6 89855C2E4400 MOV [EBP+00442E5C],EAX (EAX=EntryPt) 006484BC 61 POPAD 006484BD 7508 JNZ 006484C7 006484BF B801000000 MOV EAX,00000001 006484C4 C20C00 RET 000C 006484C7 6800000000 PUSH 00000000 (le pt d'entré est placé ici) |
3°) COMMENT : Bonne question ;o)
En 006484B6 on va faire un JUMP 00649B20 et
à cette adresse nous allons placer
le code manquant pour une bonne étude
du programme...
| 006484B6 JMP
00649B20 : Adresse du patch
... 00649B20 MOV BYTE PTR [Adrs1],EB 00649B27 MOV BYTE PTR [Adrs2],EB 00649B2E MOV [EBP+00442E5C],EAX on écrit le point d'entré; 00649B35 JMP 006484BC On retourne d'où on vient... |
He voilà on lance le prog original (un
peu modifié) et tout va bien on peut s'enregistrer,
changer qd on veut de nom utilisateur et bénéficier
de l'ensemble des fonctions...
| Voilà
donc les secrets de la protection de WinAce 8-)
Bon prog, tout n'est pas l'un en dessous de l'autre, on a une bonne segmentation du code qui balade bien le cracker de base... Le checksum et le prog Aspaked compliquent un peu les choses... Une bonne surprise pour un shareWare bien sympa ! - MAIS comme tjrs avec un peu de Zen on arrive au bout ! Pour ceux qui se demandent comment être ZEN ? Réponse : Faite une pose de temps à autre, ayez l'esprit clair... Ensuite devant un problème particulier demandez-vous comment vous auriez programmé cela. Si vous êtes bon le prog sera certainement comme vous le pensez ! Pour la prochaine fois : LE KEYGEN
Pour aider ceux qui veulent faire qq recherches
:
|
Pour ceux qui se demandent pourquoi il n'y
a pas toutes les adresses à patcher ?
Réponse : Le tutorial est fait pour
apprendre pas pour faire un crack en direct !
Avec ce tut pour faire un crack il vous faudra
travailler un peu, vous avez le chemin
à suivre, la technique à utiliser,
il ne vous reste plus qu'à pratiquer !
PAS DE SITE PAS D'ADRESSE EMAIL :
Question ? => posez-les sur les forums français...
|
Comme toujours : VOUS NE DEVEZ PAS
UTILISER CE COURS POUR OBTENIR ILLEGALEMENT DES PROGRAMMES.
|
| CODE SOURCE (Dump mémoire style Sice vers fichier binaire) |
(non optimisé mais qui fonctionne bien...)
| procedure
Raw2Bin;
var fi : textfile; fo : file; barray : array[1..16] of byte; ph : string; i,j : integer; function hextobyte(a,b : char) : byte;
begin
|