Ce soir nous allons étudier rapidement un keygen me "basique", c'est-à-dire sans aucunes obfuscation, anti-debugging ou autre "protections" particulières.
C'est un challenge du site Zenk-Sécurité, pour cette raison, je ne vais pas dévoiler mon keygen mais juste donner des pistes (fortement détaillées).
Seuls ceux qui auront résolu le challenge pourront avoir accès à mon keygen.
Ca forcera les "gens" à lire entièrement ce write-up et à taper dans le challenge un minimum ^^.
Le page du challenge se trouve : ici.
On nous dit que la page http://venom630.free.fr/keygenmefast/keygenmefast.php va nous envoyer un keygenme sous forme d'un fichier ELF (exécutable Linux donc).
Le pseudo dont il faut générer le sérial se trouve dans les entêtes HTTP:
X-Pseudo-Keygenmefast: Overclok (par exemple)
Et pour finir, nous devons envoyer notre solution concaténée au pseudo sous la forme d'un hash SHA1.
http://venom630.free.fr/keygenmefast/verifkeygenmefast.php?solution=sha1.
De ces informations, nous pouvons tirer plusieurs hypothèses:
- un binaire de base est utilisé
- certaines données vont changer
Pour vérifier ces hypothèses, c'est somme toute assez simple, on va faire usage de diff et hexdump comme ci-dessous:
$ diff -u <(hexdump -C ./keygenmefast1) <(hexdump -C ./keygenmefast2)
--- /dev/fd/63 2011-02-02 16:50:47.833079643 +0100 +++ /dev/fd/62 2011-02-02 16:50:47.833079643 +0100 @@ -91,25 +91,25 @@ 000005a0 00 00 bb 42 a0 04 08 01 c3 8a 13 8b 7c 24 08 81 |...B........|$..| 000005b0 c7 05 00 00 00 8a 37 38 f2 0f 85 ba fe ff ff 68 |......78.......h| 000005c0 83 a0 04 08 e8 a7 fd ff ff 31 c0 c9 c3 55 89 e5 |.........1...U..| -000005d0 8b 45 08 25 ff 00 00 00 34 49 25 3f 00 00 00 c9 |.E.%....4I%?....| +000005d0 8b 45 08 25 ff 00 00 00 34 13 25 3f 00 00 00 c9 |.E.%....4.%?....| 000005e0 c2 04 00 55 89 e5 81 ec 08 00 00 00 8b 4d 0c 8b |...U.........M..| 000005f0 75 08 01 ce 31 c0 e9 0b 00 00 00 4e 8a 16 81 e2 |u...1......N....| 00000600 ff 00 00 00 01 d0 49 81 f9 ff ff ff ff 75 ec 34 |......I......u.4| -00000610 08 25 3f 00 00 00 c9 c2 08 00 55 89 e5 b8 01 00 |.%?.......U.....| +00000610 84 25 3f 00 00 00 c9 c2 08 00 55 89 e5 b8 01 00 |.%?.......U.....| 00000620 00 00 8b 75 08 8b 4d 0c e9 0f 00 00 00 31 db 8a |...u..M......1..| 00000630 1e 80 e3 ff f7 e3 25 ff 00 00 00 46 49 81 f9 ff |......%....FI...| -00000640 ff ff ff 75 e8 34 7e 25 3f 00 00 00 c9 c2 08 00 |...u.4~%?.......| +00000640 ff ff ff 75 e8 34 2f 25 3f 00 00 00 c9 c2 08 00 |...u.4/%?.......| 00000650 55 89 e5 81 ec 04 00 00 00 8b 75 08 8a 06 8b 4d |U.........u....M| 00000660 0c e9 09 00 00 00 46 8a 1e 38 c3 76 02 88 d8 49 |......F..8.v...I| -00000670 81 f9 ff ff ff ff 75 ee 34 a7 50 e8 b0 fc ff ff |......u.4.P.....| +00000670 81 f9 ff ff ff ff 75 ee 34 ed 50 e8 b0 fc ff ff |......u.4.P.....| 00000680 e8 fb fc ff ff 25 3f 00 00 00 c9 c2 08 00 55 89 |.....%?.......U.| 00000690 e5 31 db 8b 75 08 8b 4d 0c 49 e9 1d 00 00 00 31 |.1..u..M.I.....1| 000006a0 d2 8a 16 51 53 68 02 00 00 00 52 e8 58 00 00 00 |...QSh....R.X...| 000006b0 5b 59 01 c3 81 e3 ff 00 00 00 46 49 81 f9 ff ff |[Y........FI....| -000006c0 ff ff 75 db 89 d8 34 46 25 3f 00 00 00 c9 c2 08 |..u...4F%?......| +000006c0 ff ff 75 db 89 d8 34 77 25 3f 00 00 00 c9 c2 08 |..u...4w%?......| 000006d0 00 55 89 e5 31 c0 8b 75 08 81 fe 00 00 00 00 74 |.U..1..u.......t| 000006e0 1e e8 9a fc ff ff 8b 4d 08 e9 07 00 00 00 51 e8 |.......M......Q.| -000006f0 8c fc ff ff 59 49 75 f6 25 ff 00 00 00 34 39 25 |....YIu.%....49%| +000006f0 8c fc ff ff 59 49 75 f6 25 ff 00 00 00 34 57 25 |....YIu.%....4W%| 00000700 3f 00 00 00 c9 c2 04 00 55 89 e5 8b 4d 0c b8 01 |?.......U...M...| 00000710 00 00 00 81 f9 00 00 00 00 74 0f 8b 5d 08 f7 e3 |.........t..]...| 00000720 e9 02 00 00 00 f7 e3 49 75 fb c9 c2 08 00 90 90 |.......Iu.......| @@ -145,11 +145,11 @@ 00001010 76 83 04 08 86 83 04 08 00 00 00 00 00 00 00 00 |v...............| 00001020 55 74 69 6c 69 73 61 74 69 6f 6e 20 3a 20 25 73 |Utilisation : %s| 00001030 20 3c 70 73 65 75 64 6f 3e 20 3c 63 6c 65 66 3e | <pseudo> <clef>| -00001040 0a 00 52 76 6e 64 35 56 78 4b 4e 44 45 6b 70 5a |..Rvnd5VxKNDEkpZ| -00001050 2b 31 67 71 53 54 2d 75 62 73 72 68 6d 43 42 33 |+1gqST-ubsrhmCB3| -00001060 63 61 30 38 6c 37 55 6f 46 32 66 69 50 79 77 4d |ca08l7UoF2fiPywM| -00001070 6a 7a 57 59 41 58 48 49 51 34 4c 47 65 74 36 39 |jzWYAXHIQ4LGet69| -00001080 4a 4f 00 42 72 61 76 6f 20 21 21 0a 00 00 00 00 |JO.Bravo !!.....| +00001040 0a 00 31 68 69 2b 59 42 65 56 61 4e 4c 33 44 4a |..1hi+YBeVaNL3DJ| +00001050 4d 45 58 7a 32 6c 74 50 5a 2d 78 6d 34 6f 47 53 |MEXz2ltPZ-xm4oGS| +00001060 75 76 71 77 49 55 66 79 43 36 6a 70 6b 62 4b 54 |uvqwIUfyC6jpkbKT| +00001070 35 6e 63 4f 57 73 46 39 72 67 38 64 52 48 37 30 |5ncOWsF9rg8dRH70| +00001080 51 41 00 42 72 61 76 6f 20 21 21 0a 00 00 00 00 |QA.Bravo !!.....| 00001090 47 43 43 3a 20 28 55 62 75 6e 74 75 2f 4c 69 6e |GCC: (Ubuntu/Lin| 000010a0 61 72 6f 20 34 2e 34 2e 34 2d 31 34 75 62 75 6e |aro 4.4.4-14ubun| 000010b0 74 75 35 29 20 34 2e 34 2e 35 00 00 2e 73 68 73 |tu5) 4.4.5...shs|
Ainsi on remarque qu'on a 6 octets qui changent et une chaîne de 64 caractères aussi qui est générée. Ca n'a pas l'air d'être de la base64 (ne finit pas par des =).
On récupère donc les différents offsets de ces diffs :
- offsets octets: 0x5d9, 0x610, 0x646, 0x679, 0x6c7, 0x6fe
- offset string: 0x1042
Et les valeurs correspondantes:
- octets: 0x13, 0x84, 0x2f, 0xed, 0x77, 0x57
- string:1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC6jpkbKT5ncOWsF9rg8dRH70QAs
On verra à quoi ils servent par la suite.
Analysons la routine principale:
.text:08048450 ; =============== S U B R O U T I N E ======================================= .text:08048450 .text:08048450 ; Attributes: bp-based frame .text:08048450 .text:08048450 main proc near ; DATA XREF: start+17 o .text:08048450 .text:08048450 argc = dword ptr 8 .text:08048450 argv = dword ptr 0Ch .text:08048450 .text:08048450 push ebp .text:08048451 mov ebp, esp .text:08048453 mov eax, [ebp+argc] .text:08048456 cmp eax, 3 .text:0804845B jnb short loc_8048485 .text:0804845D mov esi, [ebp+argv] .text:08048460 mov edi, [esi] .text:08048462 sub esp, 8 .text:08048468 mov esi, offset format ; "Utilisation : %s\n" .text:0804846D mov [esp], esi ; s .text:08048470 mov [esp+4], edi .text:08048474 call _printf .text:08048479 .text:08048479 main_exit: ; CODE XREF: main+6F j .text:08048479 ; main+9B j ... .text:08048479 mov eax, 1 .text:0804847E mov ebx, 1 ; status .text:08048483 int 80h ; LINUX - sys_exit .text:08048485 ; --------------------------------------------------------------------------- .text:08048485 .text:08048485 loc_8048485: ; CODE XREF: main+B j .text:08048485 sub esp, 0Ch .text:0804848B mov ebx, [ebp+argv] .text:0804848E mov edx, ebx .text:08048490 add edx, 4 .text:08048496 mov edx, [edx] .text:08048498 mov [esp+4], edx ; argv[1] <=> username .text:0804849C mov edx, ebx .text:0804849E add edx, 8 .text:080484A4 mov edx, [edx] .text:080484A6 mov [esp+8], edx .text:080484AA mov esi, [esp+8] ; argv[2] <=> usersserial .text:080484AE push esi ; userserial .text:080484AF call _strlen .text:080484B4 add esp, 4 .text:080484BA cmp eax, 6 .text:080484BF jnz short main_exit .text:080484C1 mov edi, [esp+4] .text:080484C5 push edi ; username .text:080484C6 call _strlen .text:080484CB add esp, 4 .text:080484D1 mov [esp], eax ; szUsername .text:080484D4 push eax .text:080484D5 call get_offset0 .text:080484DA mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:080484DF add ebx, eax .text:080484E1 mov dl, [ebx] .text:080484E3 mov edi, [esp+8] ; argv[2] <=> userserial .text:080484E7 mov dh, [edi] .text:080484E9 cmp dl, dh .text:080484EB jnz short main_exit .text:080484ED mov edi, [esp] ; szUsername .text:080484F0 push edi .text:080484F1 mov edi, [esp+8] ; argv[2] <=> userserial .text:080484F5 push edi .text:080484F6 call get_offset1 .text:080484FB mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:08048500 add ebx, eax .text:08048502 mov dl, [ebx] .text:08048504 mov edi, [esp+8] .text:08048508 inc edi .text:08048509 mov dh, [edi] .text:0804850B cmp dl, dh .text:0804850D jnz main_exit .text:08048513 mov edi, [esp] ; szUsername .text:08048516 push edi .text:08048517 mov edi, [esp+8] ; argv[2] <=> userserial .text:0804851B push edi .text:0804851C call get_offset2 .text:08048521 mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:08048526 add ebx, eax .text:08048528 mov dl, [ebx] .text:0804852A mov edi, [esp+8] .text:0804852E add edi, 2 .text:08048534 mov dh, [edi] .text:08048536 cmp dl, dh .text:08048538 jnz main_exit .text:0804853E mov edi, [esp] ; szUsername .text:08048541 push edi .text:08048542 mov edi, [esp+8] ; argv[2] <=> userserial .text:08048546 push edi .text:08048547 call get_offset3 .text:0804854C mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:08048551 add ebx, eax .text:08048553 mov dl, [ebx] .text:08048555 mov edi, [esp+8] .text:08048559 add edi, 3 .text:0804855F mov dh, [edi] .text:08048561 cmp dl, dh .text:08048563 jnz main_exit .text:08048569 mov edi, [esp] ; szUsername .text:0804856C push edi .text:0804856D mov edi, [esp+8] ; argv[2] <=> userserial .text:08048571 push edi .text:08048572 call get_offset4 .text:08048577 mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:0804857C add ebx, eax .text:0804857E mov dl, [ebx] .text:08048580 mov edi, [esp+8] ; argv[2] <=> userserial .text:08048584 add edi, 4 .text:0804858A mov dh, [edi] .text:0804858C cmp dl, dh .text:0804858E jnz main_exit .text:08048594 mov edi, [esp+4] ; argv[1] <=> username .text:08048598 xor edx, edx .text:0804859A mov dl, [edi] .text:0804859C push edx .text:0804859D call get_offset5 .text:080485A2 mov ebx, offset hash ; "1hi+YBeVaNL3DJMEXz2ltPZ-xm4oGSuvqwIUfyC"... .text:080485A7 add ebx, eax .text:080485A9 mov dl, [ebx] .text:080485AB mov edi, [esp+8] .text:080485AF add edi, 5 .text:080485B5 mov dh, [edi] .text:080485B7 cmp dl, dh .text:080485B9 jnz main_exit .text:080485BF push offset aBravo ; "Bravo !!\n" .text:080485C4 call _printf .text:080485C9 xor eax, eax .text:080485CB leave .text:080485CC retn .text:080485CC main endp ; sp-analysis failed
On remarque que des blocs ont le même pattern:
- appel d'une fonction qui calcule un dword
- ajout de ce dword à hash
- comparaison du caractère calculé et du caractère entré
-> si incorrect on sort du keygen
-> si correct on continue
- lorsqu'on arrive à la fin, on obtient un "Bravo !!\n" ^^
Maintenant, en analysant chaque fonction de calcul d'offset, on remarque les choses suivantes:
get_offset0:
.text:080485D8 xor al, 13h .text:080485DA and eax, 3Fh .text:080485DF leave .text:080485E0 retn 4 .text:080485E0 get_offset0 endpget_offset1:
.text:0804860F xor al, 84h .text:08048611 and eax, 3Fh .text:08048616 leave .text:08048617 retn 8 .text:08048617 get_offset1 endpget_offset2:
.text:08048645 xor al, 2Fh .text:08048647 and eax, 3Fh .text:0804864C leave .text:0804864D retn 8 .text:0804864D get_offset2 endpget_offset3:
.text:08048678 xor al, 0EDh .text:0804867A push eax ; seed .text:0804867B call _srand .text:08048680 call _rand .text:08048685 and eax, 3Fh .text:0804868A leave .text:0804868B retn 8 .text:0804868B get_offset3 endpget_offset4:
.text:080486C6 xor al, 77h .text:080486C8 and eax, 3Fh .text:080486CD leave .text:080486CE retn 8 .text:080486CE get_offset4 endpget_offset5:
.text:080486FF and eax, 3Fh .text:08048704 leave .text:08048705 retn 4 .text:08048705 get_offset5 endpVous vous souvenez de nos 6 octets "changeant"?
- octets: 0x13, 0x84, 0x2f, 0xed, 0x77, 0x57
Eh oui, ce sont les "clés" utilisées par les fonctions de calcul d'offset.
En fait, le keygenme va faire les choses suivantes:
- vérification de la longueur de l'username
- vérification de la longueur du serial
-> bye bye si pas égal à 6
- calculs des offsets en utilisant les 6 bytes
- calcul du sérial
- comparaison entre le serial rentré et le sérial calculé
- bravo ou exit
On se rend compte que pour calculer les différents offsets, le serial est utilisé.
Je suis parti dans l'idée d'utiliser l'username pour générer le serial.
Et voilà, reste plus qu'à coder un beau keygen ;).
Have fun,
m_101
- Mon keygen: Keygen
Hello,
RépondreSupprimerIl y a un password pr ton keygen.zip ??
Faut croire que oui :).
RépondreSupprimerJe me souviens plus du mdp par contre.
Ca doit être le mot de passe du challenge ;).