CONFidence ESET crackme (Le vrai, pas le tout pourri pour les pauvres étudiants francais)
Par Baboon le jeudi, juillet 29 2010, 21:19 - Lien permanent
Mdlolkikoodr tout le monde !
Tout d'abord désolé pour le silence prolongé, mon stage ne m'a pas laissé beaucoup de temps mais j'ai fait 2-3 trucs lolilols (ca a beau ne pas être français, respectons tout de même l'accord)...
Pour ce qui est de armadillo je n'ai toujours pas eu l'occasion de me pencher à nouveau dessus. Pour me faire pardonner, nous allons aujourd'hui parler du crack me proposé par ESET (lien qui pour une raison complètement inconnue ne fonctionne pas avec Opéra ...) lors de la série de la conférence CONFidence.
Ce challenge a été remporté par Gynvael Coldwind et j00ru qui n'a toujours pas publié sa solution malgré mes menaces de mort répétées donc je le fais à sa place, tant pis pour lui.
Le crack-me en question est packé avec UPX et commence par un petit layer avec des instructions SSE 2 qui embêtent bien olly mais pas le fourbe que je suis qui n'a même pas pris le temps de les étudier mais s'est contenté de lancer le binaire puis de le mettre en pause.
Pas d'anti-debuggers particuliers (aucun ne s'est manifesté avec HideDebugger).
Passons au vif du sujet, la routine de vérification se trouve à l'adresse 00401342 du crack-me qui commence par récupérer le serial, vérifier que sa taille est bien de 32 caractères et enfin le mettre en majuscule.
Le nom est ensuite récupéré et doit faire au moins 3 lettres (pourquoi 3... je ne sais pas ... surement pour faire chier les jB et autres crackers aux pseudos atrophiés (meuh non s'pas méchant)). Enfin le nom est hashé à l'aide de MD2 et des APIs cryptographiques de windows (CryptAcquireContext / CryptCreateHash / CryptHashData / CryptGetHashParam).
Le serial est transformé en hexadécimal à l'aide de la routine en 00401771, rien de spécial.
Une transformation du hash du nom est créé à l'aide de l'algo suivant :
DWORD hh[4]; DWORD h[4] = MD2(Name); d = 0x4E4F44 for (i = 0; i < 4; i++) { d = ROR(d,0xC); hh[i] = ((~(0x45534554^d))&0x455353) | h[i]; }
Et là on entre dans le vif du vif du sujet. Le serial est en effet accepté ou non après l'exécution d'une VM et par la comparaison de sa sortie avec le hash du nom.
La VM est exécutée en 004015C4 et son byte code est situé en 0040305C.
Cette VM n'est pas très compliquée à étudier et on trouve rapidement le format de ses instructions :
grp_1 : *format de l'instruction* aaa ---- ccc --- bbb a==0 => retn a==1 => call if flag(b) a==2 => InvFlag(b) a==3 => SetFlag(b) a==4 => flag(c) = flag(c) & flag(b) a==5 => flag(c) = flag(b) grp_2 : *format de l'instruction* aaa ddddd ccccc bbb a==6 => flag(b) = bit(regs[d], c) a==7 => bit(regs[d], c) = flag(b)
Comme on le voit ici le nombre d'instruction est très réduit, par contre le nombre d'instructions et quand à lui TRES élevé (195,545 instructions, rien que ca).
J'ai donc commencé à coder plusieurs émulateurs en python,
Le premier se contentait de garder en mémoire l'ensemble des opérations faites sur chacun des bits : FAIL python arrivait très vite à bout de mémoire
Le deuxième comportait un simplificateur d'équations booléennes plutôt pas mal foutu mais hélas re FAIL, la complexité des équations explose très vite et mon émulateur n'avance plus.
Pensant que le problème venait de mon simplificateur, je me suis rabattu sur une lib en python implémentant l'algorithme de Quine-McCluskey et ai créé dans la foulée une petite interface de debug mais re-FAIL : la complexité reste trop élevée.
J'ai enfin bridé mon émulateur pour arrêter la simplification des équations à partir d'une certaine complexité et amélioré mon interface de debug et enfin j'ai pu étudier le code exécuté par la VM (tout en sachant que mon émulateur a continué à être modifié / customisé tout au long de l'étude pour effectuer différents tests etc.).
Mon émulateur est disponible à la fin de l'article en pièce jointe et les différentes commandes utilisables sont détaillées ici :
- d : désassemble la ligne courante
- d1 : toutes les instructions exécutées seront affichées
- d0 : annule la commande précédente
- r : entre et quitte le mode pas à pas
- c : continue l'exécution
- g : affiche l'état des différentes variables (ghh affiche le hash modifié, gss le serial modifié, gh le hash etc.)
- q : termine l'émulation
- y/n : prend le saut ou non
- p : permet l'exécution de commandes python (ex : pgetRepr(flags[1]))
Après un certain temps d'analyse, on arrive enfin à comprendre le fonctionnement du code :
s[0] ^= h[1]; s[2] ^= h[3]; ss[1] = s[1]*hh[2]; ss[3] = s[3]*hh[0]; ss[0] = s[0]*hh[3]; ss[2] = s[2]*hh[1]; ss[1] ^= h[0]; ss[3] ^= h[2];
la multiplication est effectuée à l'aide de la technique de multiplication dans l'Égypte antique.
A la fin de l'exécution, le serial modifié (DWORD ss[4]) doit être égal au hash du nom (DWORD h[4]), l'algorithme est donc simplement inversé à l'aide de l'algo suivant :
DWORD findMagic(h,hh) { DWORD ss = 0, s = 0; int i; for (i = 0; i < 32; i++) { if (getbit(h,i) != getbit(ss,i)) { if (!getbit(hh,i)) { exit(EXIT_FAILURE); } ss += hh; s += 1 << i; } hh <<= 1; } return s; } s[0] = h[1]^findMagic(h[0], hh[3]); s[2] = h[3]^findMagic(h[2], hh[1]); s[1] = findMagic(h[1]^h[0], hh[2]); s[3] = findMagic(h[3]^h[2], hh[0]);
Et enfin comme je me suis bien fait chier à résoudre ce crackme, je me suis dit que j'allais coder un petit keygen (en pièce jointe à la fin de l'article encore une fois), j'espère que vous apprécierai le graphisme et la musique
Bon, je sais que ce crackme est hyper spécifique et que vous n'aurez pas appris grand chose aujourd'hui si ce n'est comment trouver l'inverse d'un entier modulo 0x100000000 (supaire !) mais j'espère avoir le temps de vous pondre un truc un peu plus intéressant dans les jours / semaines / mois à venir
Commentaires
Salut baboon, bah moi j'ai quand même appris des choses sur l'Egypte antique avec ton article :p
Merci pour cette petite explication...non qui n'est pas inutile! C'est même une sacrée lanterne pour le newbie, que je suis, qui n'avait pas trouvé son serial.
Et moi,personnellement, moi-même, l'esthétique du keygen, j'adore. Et la musique aussi!
Si je comprends bien , le stage est fini... donc les articles vont pleuvoir?!!
A+
cool, je suis encore dessus, j'ai l'espoir de finir mon code pour simplifier tout ça - on peut toujours rêver :p
++ pour ton mignon keygen
Merci pour vos commentaires et bon courage Ange pour ton outil
J'en ai pas mal bavé pour faire un script python qui aille bien :p
Sinon pour la pluie d'article eh bien elle attendra un peu, je suis actuellement en pleine recherche d'appart (qui sera suivit d'un déménagement ...) / rédaction de rapport / finition d'outils etc.
Mais j'ai aussi un jeu protégé par securom 7 sous le coude donc à voir