Help ! Compréhension de programme en assembleur

Help ! Compréhension de programme en assembleur - ASM - Programmation

Marsh Posté le 01-11-2004 à 01:17:51    

Salut à tous !
 
Je suis étudiant et je suis des cours de sécurité informatique. Dans le cadre d'un cours, je dois analyser un programme en assembleur(*) afin de trouver la clé correspondant à un login et de le "craquer".
 
* Le programme a été écrit en C, compilé, décompilé, puis des instructions en C ont été placées à côté de l'assembleur pour nous "aider".
 
Le programme fait tout simplement ceci :
- il demande un nom ;
- il demande un code ;
- si la clé est bonne, il affiche que le code est correst, sinon qu'il n'est pas correct.
 
Et mon exercice consiste à analyser le code pour trouver la clé correspondant, par exemple, à mon prénom (nicolas).
 
Important :
- il s'agit d'un exercice, ce n'est pas du tout pour cracker d'autres logiciels ;
- il ne s'agit pas de faire un générateur de clé, juste de trouver au moins une clé correspondant à un nom.
 
Bref, je bloque.
J'ai vu que le programme, dans le main(), appelait une première fonction en lui envoyant les adresses du nom et du code, puis que cette méthode appelait 3 fois (au maximum) une méthode qui effectue des opérations sur les lettres du code. Mais je ne vois pas trop le lien entre les lettres du code et nom.
 
Pourriez-vous m'aider s'il vous plaît ? Me donner des indications, des conseils ??
 
Merci d'avance ! :jap:  
 
J'ai mis le code et un exécutable ici (pas de virus, rien, c'est sans danger, je vous l'assure) : http://emacoq.free.fr/bazar/prgm.zip

Reply

Marsh Posté le 01-11-2004 à 01:17:51   

Reply

Marsh Posté le 01-11-2004 à 18:06:15    

Qu'est-ce que tu as fait/trouvé déjà ?
Je suis en train de la faire et ça m'a pas l'air très compliqué...

Reply

Marsh Posté le 01-11-2004 à 18:45:47    

Salut !
 
J'ai compris que :
 
- le main() demande le nom puis le code ; elle appelle la fonction f00401162() en lui donnant le nom et le code en paramètre
- la fonction f00401162() appelle f004010DF() en lui donnant le code et 0h10
 
J'ai vraiment du mal à voir ce qu'il fait avec la fonction f004010DF() :-?
 
Au retour de cette fonction, j'ai vu qu'il comparait le premier caractère du code à 0h2D (ligne 363).
Ensuite, il pointe vers la 2nde lettre du code, push 0h14 et rappelle f004010DF(). Au retour, il compare à nouveau avec 0h2D (ligne 393).
 
J'ai essayé de mettre un code qui commence par "--" (2D est le code ASCII du tiret), mais après avoir passé ces 2 étapes, il compare mon nom à quelque chose de vide...
 
Voilà. Pourrais-tu m'éclaircir au moins sur la structure générale du programme, me donner des conseils, savoir quand le nom intervient...
 
Merci beaucoup pour ton aide :-)
Nico.

Reply

Marsh Posté le 01-11-2004 à 21:02:43    

(je bosse direct en assembleur car le .c est quasi illisible)
 
Donc tu as compris que le code est en 3 parties (recherche des 2 tirets + appels à la fonction f004010DF() 3 fois).
 

Citation :


0040116E  |. 6A 10          PUSH 10                     |Arg2 = 00000010 puis 14h puis 24h
00401170  |. 8D4D F8        LEA ECX,DWORD PTR SS:[EBP-8]
00401173  |. 51             PUSH ECX                    |Arg1 = *code
00401174  |. E8 66FFFFFF    CALL crack.004010DF          
004011A5  |. 83C4 08        ADD ESP,8


 
En fait on a : int f004010DF(char *code, int diviseur);
 

Citation :


=> Point d'entrée de la fonction f004010DF() puis boucle avec :
- EBP-8 = adresse du code
- EBP+C = valeur du diviseur

004010F4  |> 8B55 F8        /MOV EDX,DWORD PTR SS:[EBP-8]
004010F7  |. 0FBE02         |MOVSX EAX,BYTE PTR DS:[EDX]
004010FA  |. 8945 F0        |MOV DWORD PTR SS:[EBP-10],EAX
004010FD  |. 8B4D F8        |MOV ECX,DWORD PTR SS:[EBP-8]
00401100  |. 83C1 01        |ADD ECX,1
00401103  |. 894D F8        |MOV DWORD PTR SS:[EBP-8],ECX
=> ^^ Avance dans le buffer ^^
 
00401106  |. 8B55 F0        |MOV EDX,DWORD PTR SS:[EBP-10]
=> ^^ recupère le caractère suivant du buffer ^^
 
00401109  |. C1EA 04        |SHR EDX,4
=> ^^ divise par 16 la valeur ASCII ^^
 
0040110C  |. 8B4D F0        |MOV ECX,DWORD PTR SS:[EBP-10]
=> ^^ recupère le caractère suivant du buffer ^^
 
0040110F  |. 83E1 0F        |AND ECX,0F
00401112  |. D1E1           |SHL ECX,1
=> ^^ multiplie par 2 la partie basse ^^
 
00401114  |. 8B0495 3060400>|MOV EAX,DWORD PTR DS:[EDX*4+406030]
=> ^^ recupère la valeur depuis un tableau ^^ = TAB1 (tableau de masques en fait) = {00000000h,00000000h,00000000h,55550500h,A8AAAAAAh,AAAA2A00h,FCFFFFFFh,FFFF3F00h,00000000h,00000000h,00000000h,00000000h,00000000h,00000000h,00000000h,00000000h};

0040111B  |. D3E8           |SHR EAX,CL
0040111D  |. 83E0 03        |AND EAX,3
=> ^^ recupère les 3 derniers bits (val = 0 à 3) ^^
 
00401120  |. 0FBE88 7060400>|MOVSX ECX,BYTE PTR DS:[EAX+406070]
=> ^^ recupère la valeur depuis un tableau ^^ = TAB2 = {00h, 30h, 37h, 57h};

00401127  |. 894D F4        |MOV DWORD PTR SS:[EBP-C],ECX
0040112A  |. 837D F4 00     |CMP DWORD PTR SS:[EBP-C],0
0040112E  |. 74 20          |JE SHORT crack.00401150
=> ^^ On veut que la valeur soit comprise entre le caractère ASCII 48 et 128 ^^

00401130  |. 8B55 F0        |MOV EDX,DWORD PTR SS:[EBP-10]
00401133  |. 2B55 F4        |SUB EDX,DWORD PTR SS:[EBP-C]
00401136  |. 8955 F0        |MOV DWORD PTR SS:[EBP-10],EDX
00401139  |. 8B45 F0        |MOV EAX,DWORD PTR SS:[EBP-10]
0040113C  |. 3B45 0C        |CMP EAX,DWORD PTR SS:[EBP+C]
0040113F  |. 73 0F          |JNB SHORT crack.00401150
=> ^^ Teste si la valeur recuperée est bien < 10h ^^
Donc on veut que 0,1,2,...,9,A,B,...,F, les parties de code ne doivent contenir que des caractères hexa

00401141  |. 8B4D FC        |MOV ECX,DWORD PTR SS:[EBP-4]
00401144  |. 0FAF4D 0C      |IMUL ECX,DWORD PTR SS:[EBP+C]
00401148  |. 034D F0        |ADD ECX,DWORD PTR SS:[EBP-10]
0040114B  |. 894D FC        |MOV DWORD PTR SS:[EBP-4],ECX
0040114E  |.^EB A4          \JMP SHORT crack.004010F4
=> ^^ Ajoute la valeur trouvée dans un buffer en multipliant par 10h la valeur d'avant ^^
Si l'on a rentré "0123F567-a-a" comme code, on a donc dans ce buffer :
0x00000001 au premier passage,
0x00000012 au deuxieme, ....
0x123F567 au dernier passage (avant le "-" qui n'est un caractère hexa)

00401150  |> 8B55 F8        MOV EDX,DWORD PTR SS:[EBP-8]
00401153  |. 83EA 01        SUB EDX,1
00401156  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00401159  |. 8910           MOV DWORD PTR DS:[EAX],EDX
0040115B  |. 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
0040115E  |. 8BE5           MOV ESP,EBP
00401160  |. 5D             POP EBP
00401161  \. C3             RETN
=> ^^ Remet en place le buffer contenant le code d'origine avant le dernier caractère lu ^^


 
Cette fonction ne fait que de la conversion en fait (en fonction du diviseur). L'analyse de cette fonction est faite de manière très succinte mais on a compris le fonctionnement (conversion par division).
 

Citation :


004011EB  |> 8B4D 08        MOV ECX,DWORD PTR SS:[EBP+8]
004011EE  |. 8B11           MOV EDX,DWORD PTR DS:[ECX]
=> ^^ recupère les 4 premiers caracères du code ASCII du nom ^^
ex: si nom = nikodan alors EDX = 6f6b696eh (6fh=o, 69h=i, 6eh=n, ...)

004011F0  |. 3B55 FC        CMP EDX,DWORD PTR SS:[EBP-4]
004011F3  |. 75 1F          JNZ SHORT crack.00401214
=> ^^ compare avec la premiere partie du code ^^
On en déduit que la première partie n'est qu'une simple conversion du nom ASCII.
 
004011F5  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
004011F8  |. 8B48 04        MOV ECX,DWORD PTR DS:[EAX+4]
=> ^^ recupère les 4 caracères suivant du code ASCII du nom ^^
ex: si nom = nikodan alors ECX = 006e6164h (64h=d, 61h=a, 6eh=n, ...)

004011FB  |. 3B4D F4        CMP ECX,DWORD PTR SS:[EBP-C]
004011FE  |. 75 14          JNZ SHORT crack.00401214
=> ^^ compare avec la deuxieme partie du code ^^
On en déduit que la deuxieme partie est le reste d'une division euclidienne de la deuxieme partie du nom.

00401200  |. 8B55 FC        MOV EDX,DWORD PTR SS:[EBP-4]
00401203  |. 0355 F4        ADD EDX,DWORD PTR SS:[EBP-C]
=> ^^ ajoute la premiere partie du code et la deuxieme ^^

00401206  |. 3955 F0        CMP DWORD PTR SS:[EBP-10],EDX
00401209  |. 75 09          JNZ SHORT crack.00401214
=> ^^ compare avec la troisieme partie du code ^^
On en déduit que la troisieme partie est le reste d'une division euclidienne de la somme des deux premieres parties.


 
Ex: nikodan = 6f6b696e-2544ec-V18uS2
 
Par contre pour les noms de moins de 7 caractères, ça doit être plus chaud car on joue avec l'aléatoire... :/


Message édité par BMenez le 01-11-2004 à 21:06:30
Reply

Marsh Posté le 01-11-2004 à 21:04:02    

Au fait merci pour ce petit exercice, ça fait du bien de faire chauffer les méninges :D

Reply

Marsh Posté le 01-11-2004 à 21:24:53    

BMenez a écrit :

Au fait merci pour ce petit exercice, ça fait du bien de faire chauffer les méninges :D

ouais mais bon, t'as pas l'impression d'être hors charte là ? parce que tu lui as carrément résolu son exo ! [:heink]


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 01-11-2004 à 21:35:13    

Harkonnen a écrit :

ouais mais bon, t'as pas l'impression d'être hors charte là ? parce que tu lui as carrément résolu son exo ! [:heink]


 
Non, j'ai pas l'impression d'être hors charte :/
Je m'excuse si je suis allé un peu loin :sweat:

Reply

Marsh Posté le 01-11-2004 à 22:07:25    

Merci beaucoup pour tes explications ! Je me penche dessus dès ce soir (je suis en cours... au Québec :-p ...)...
 
Et ne vous inquiétez pas, je suis vraiment pas du genre à résoudre un exercice sans le comprendre :-)
 
Merci encore,
A plus si j'ai encore des questions ;-)
 
Nico.

Reply

Marsh Posté le 02-11-2004 à 03:48:48    

Bon, ben j'avoue que j'ai quand même passé un peu de temps sur tes explications...  :sweat:  
En fait, ça peut paraître con, mais j'ai pas tout de suite compris qu'il comparait la 1ère partie du nom avec la première partie du code "multipliée" par 10h (pas habitué à ce genre de multiplication :s), puis qu'il comparait la 2ème partie du nom avec la deuxième partie du code "multipliée" par 14h, et pareil avec la somme des deux parties du nom, la 3ème partie du code et 24h.
 
J'ai aussi bloqué dans la division de la deuxième partie du nom. Je me retrouvais avec un reste de 19 et je savais pas quoi en faire :p (mais en fait c'était juste un "j"  :pt1cable: )  
Mais j'ai perséveré, et maintenant j'ai bien compris :)  
 
Merci beaucoup de ton aide !
 
Nico.
 
PS : pour "nicolas", "6f63696e-2753j0-v14n2y" :D


Message édité par nikodan le 02-11-2004 à 03:52:57
Reply

Marsh Posté le 02-11-2004 à 05:21:13    

Re !
 
Je voulais juste te demander pourquoi ça poserait problème pour les noms de moins de 7 caractères... ?
 
J'ai fait un test avec 1 nom de 6 lettres, et le calcul semble se faire aussi bien... Enfin, j'ai peut-être eu de la chance ?

Reply

Marsh Posté le 02-11-2004 à 05:21:13   

Reply

Marsh Posté le 02-11-2004 à 10:16:09    

En fait c'est cette instruction qui me gène :

Citation :


004011F8  |. 8B48 04     MOV ECX,DWORD PTR DS:[EAX+4]  


 
Si le nom fait moins de 7 caractères, on ne sait pas ce qu'il peut y avoir à EAX+4
Avec "HFR" par exemple :

Citation :


0012FF54  48 46 52 00 69 00 00 40  HFR.i..@


 
"69 00 00 40" <= c'est quelquechose qui est mis automatiquement à l'initialisation du programme (toutefois cette valeur semble constante...) donc je ne vois pas comment tu peux faire le calcul sans connaitre cette valeur à l'avance. Si tu me dis que ça marche je te crois mais je ne comprends pas pourquoi. :)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed