Protection | Compression maison | Les Protections Renforcées | ||
Outils | Hiew SoftIce | |||
Cible | Photo 1.0 |
By Christal |
Photo dÆEcran Ver 1.0 1er et 2ème version Infection : Ecran Shareware au lancement de l'application : Version Non Enregistrée, et date d'installation Time limit Boite d'enregistrement Avant propos : Photo d'Ecran est un logiciel qui se décompresse en mémoire, ce qui rend sa " lisibilité " beaucoup plus problématique en attaquant le programme bille en tête avec SoftIce. Et puis, au regard de la taille de photo.exe (32ko), il est peu probable que ce soit l'application maître en elle même, mais plutôt un Loader/décompresseur. Du coup, une recherche du call appelant l'écran Shareware , en traçant avec F10, devient délicate. Pourtant, celui ci, ou le message qu'il contient, doit très certainement être soumis à un drapeau utilisateur Enregistré/non-enregistré. La boite " A propos " réplique de l'écran Shareware, doit l'être égalementà Bien que l'exercice ne porte pas sur la recherche du numéro de série j'ai commencé par regarder comment réagissait Photo d'Ecran à l'entrée d'un sérial quelconque. Je tiens à signaler que, dans un premier temps, le programme mis à disposition par ATP TEAM n'était pas celui du VRAI exercice. Par manque de courage, je n'ai pas franchement eu envie de réécrire un texte complet. Je me contenterai de signaler les différences entre les deux versions quand il le faudra. Le Flag Utilisateur Reg/Unreg Après avoir rempli la boite d'enregistrement, je suis passé sous SoftIce pour poser un BPX HMEMCPY, avant de valider le champ de la boite de dialogue. POP ! Après 7 appuis sur la touche [F12], j'ai atterri en douceur dans REGDLL.dll. Si avant d'attaquer le Soft vous avez eu la curiosité de noter le nom des fichiers contenus dans le répertoire de Photo.exe, vous n'aurez pas été sans repérer cette dll de 241 ko , la seule laissant à supposer que l'application maître est en fait ce fichier. A partir de ce point d'entrée, j'ai commencé à tracer doucement avec [F10], à la recherche du nag screen " clé non valide " pour cerner ma zone de travail. (Les lignes qui suivent font parties de la Version 1) 0177:00B98932 8BC6 MOV EAX,ESI 0177:00B98934 E85B31FFFF CALL 00B8BA94 > saisie des champs 0177:00B98939 5E POP ESI 0177:00B9893A 5B POP EBX 0177:00B9893B C3 RET Vous verrez dans les lignes qui vont suivre que SoftIce et Wdasm ne donnent pas les mêmes offsets 0177:00B9F502 E889A5FEFF CALL 00B89A90 0177:00B9F507 8B45F4 MOV EAX,[EBP-0C] > notre code 0177:00B9F50A 8D55FC LEA EDX,[EBP-04] > rien 0177:00B9F50D E8BA5FFDFF CALL 00B754CC > contrôle validité 0177:00B9F512 8B45FC MOV EAX,[EBP-04] > notre code 0177:00B9F515 E8763FFDFF CALL 00B73490 > calcul de la longueur 0177:00B9F51A 83F810 CMP EAX,10 > 16(d) caractères ? 0177:00B9F51D 741A JZ 00B9F539 > si oui, saute 0177:00B9F51F 6A00 PUSH 00 0177:00B9F521 668B0D50F6B900 MOV CX,[00B9F650] > charge "clé non valide" 0177:00B9F528 B201 MOV DL,01 0177:00B9F52A B85CF6B900 MOV EAX,00B9F65C 0177:00B9F52F E8CCC3FFFF CALL 00B9B900 > 1er nag screen 0177:00B9F534 E9D7000000 JMP 00B9F610 snips 0177:00B9F54C 83F808 CMP EAX,08 0177:00B9F54F 741A JZ 00B9F56B > vers code OK 0177:00B9F551 6A00 PUSH 00 0177:00B9F553 668B0D50F6B900 MOV CX,[00B9F650] 0177:00B9F55A B201 MOV DL,01 0177:00B9F55C B85CF6B900 MOV EAX,00B9F65C 0177:00B9F561 E89AC3FFFF CALL 00B9B900 > 2eme nag screen snips 0177:00B9F59B 58 POP EAX 0177:00B9F59C E8FF3FFDFF CALL 00B735A0 0177:00B9F5A1 754F JNZ 00B9F5F2 > vers 3eme nag snips 0177:00B9F5AE B874F6B900 MOV EAX,00B9F674 0177:00B9F5B3 E848C3FFFF CALL 00B9B900 > merci de vous êtreà snips 0177:00B9F5DC B89CF6B900 MOV EAX,00B9F69C 0177:00B9F5E1 E87AD5FFFF CALL 00B9CB60 0177:00B9F5E6 C7050C18BA0001000000MOV DWORD PTR [00BA180C],00000001 0177:00B9F5F0 EB17 JMP 00B9F609 > Fin routine code OK 0177:00B9F5F2 6A00 PUSH 00 0177:00B9F5F4 668B0D50F6B900 MOV CX,[00B9F650] 0177:00B9F5FB B201 MOV DL,01 0177:00B9F5FD B85CF6B900 MOV EAX,00B9F65C 0177:00B9F602 E8F9C2FFFF CALL 00B9B900 > 3eme nag screen 0177:00B9F607 EB07 JMP 00B9F610 Ci dessus, vous avez trouvé un extrait de la routine de vérification du sérial. Le premier contrôle concerne la validité des caractères entrés : 8A02 mov al , [edx] > 1 caractère du code entré dans al 3C61 cmp al, 61 > comparaison avec la valeur ascii de " a " 7206 jb 004054F9 > saute si inférieur 3C7A cmp al, 7A > comparaison avec " z " 7702 ja 004054F9 > saute si supérieur Le second vérifie que le nombre de caractères entrés est égale
à 16 (ou 10 en hexadécimal), et continue, ou évite le premier écran " Clé
non valide ". Ensuite, chaque contrôle disposera de son call 00B9B900 -> nag screen. POP ! 0177:00B9F1BB 33DB XOR EBX,EBX 0177:00B9F1BD 33C0 XOR EAX,EAX 0177:00B9F1BF A30C18BA00 MOV [00BA180C],EAX > le Flag 0177:00B9F1C4 8D45E4 LEA EAX,[EBP-1C] 0177:00B9F1C7 E8F8D6FFFF CALL 00B9C8C4 Un rapide coup d'£il dans la fenêtre des Registres, EAX = 0. Changeons les
données en forçant EAX à 1 (r eax = 1). 0177:00B9F1BD 40 INC EAX > EAX = 1 0177:00B9F1BE 90 NOP > équilibrage du nb d'octets 0177:00B9F1BF A30C18BA00 MOV [00BA180C],EAX > Flag = 1 Et surtout à la trouver dans REGDLL.dllà 0177:00B9F1BB 33DB XOR EBX,EBX > ça 0177:00B9F1BD 33C0 XOR EAX,EAX > ça 0177:00B9F1BF A30C18BA00 MOV [00BA180C],EAX > mais là... Inutile de s'attendre à trouver une occurrence sur 00BA180C, par contre en cherchant une chaîne du type 33DB33C0A30C, j'ai de forte chance, en contrôlant suffisamment d'octets, de tomber dessus : :0042F1BB 33DB xor ebx, ebx :0042F1BD 33C0 xor eax, eax :0042F1BF A30C184300 mov [0043180C], eax :0042F1C4 8D45E4 lea eax, [ebp-1C] :0042F1C7 E8F8D6FFFF call 0042C8C4
:0042FC06 E85904FFFF call 00420064 :0042FC0B 833D0C18430001 cmp dword ptr [0043180C], 00000001 :0042FC12 0F8437020000 je 0042FE4F Je vous laisse le soin de faire l'opération, cette fois ci, pour trouver
la correspondance avec SoftIce. :00B9F340 E85B42FDFF call 00B735A0 :00B9F345 740D je 00B9F354 > saut conditionnel :00B9F347 837DE001 cmp [ebp-20], 00000001 :00B9F34B 7513 jne 00B9F360 :00B9F34D E8260D0000 call 00BA0078 :00B9F352 EB0C jmp 00B9F360 :00B9F354 B301 mov bl, 01 > pour ici... :00B9F356 C7050C18430001000000 mov dword ptr [00BA180C], 00000001 Pour la version 2, vous obtenez la correspondance en 00B9F2E5 pour 00B9F345 Je ne fais pas parti de ces privilégiés surdoués qui trouvent du premier coup l'endroit exacte à patcher. Parfois je trouve la réponse rapidement, parfois non. A la lecture d'un essai comme celui ci, on pourrait croire qu'il ne m'a fallu que quelques minutes pour cracker la cible. En fait, je n'ai pas vu immédiatement le Flag Utilisateur Enregistré (l'inconvénient de SoftIce et de sa petite fenêtre de codes), ça n'est qu'en y revenant, et en continuant à tracer après l'inversion du Zéro-Flag que j'ai eu la réponse à ma question : Pourquoi la boite " A propos " m'indiquait "Version Enregistrée " ? Avant de mettre la main sur ce Drapeau, j'ai regardé du coté de la base de registres, de la Time Limit, et dans le cas de cette dernière, j'avais trouvé une autre façon de rendre le Soft éternel en jouant sur la date. La Time Limit En posant un BPX GetLocalTime, vous allez revenir à REGDLL (en appuyant sur [F12]) : * Reference To: kernel32.GetLocalTime, Ord:0000h | :00B76354 E85FE3FFFF Call KERNEL 32 !GetLocalTime :00B76359 668B4C240E mov cx, [esp + 0E] > jour = 28 :00B7635E 668B54240A mov dx, [esp + 0A] > mois = 9 :00B76363 668B442408 mov ax, [esp + 08] > année = 1999 Avancez d'un jour votre date, et vous ferrez la valeur de CX se modifier. Il y a donc moyen de forcer la Time Limit a toujours se croire au premier jour de son installation en faisant : :00B76354 E85FE3FFFF Call KERNEL 32 !GetLocalTime :00B76359 66B91E00 mov cx, 1C > 28 hexa :00B7635D 90 nop :00B7635E 66BA0900 mov dx, 09 > 9 hexa :00B76362 90 nop :00B76363 66B8CF07 mov ax, 07C > 1999 hexa :00B76367 90 nop Par contre si il y a des fonctions limitées dans la version shareware, vous
ne les lèverez pas, et l'écran Shareware continuera à indiquer " version Non Enregistrée
" :0042FDB9 770D ja 0042FDC8 :0042FDBB 8B45EC mov eax, [ebp-14] > 19991027 > réfléchissez ! :0042FDBE 8B55F8 mov edx, [ebp-08] > 19991028 > idem :0042FDC1 E8DA37FDFF call 004035A0 > comparaison :0042FDC6 7371 jnb 0042FE39 > branchement si non inférieur Et si la date du jour [ebp-08] est inférieur à la date d'installation
+30 - 1 jour [ebp-14] ? :0042FDBB 8B45EC mov eax, [ebp-14] :0042FDBE 8B55EC mov edx, [ebp-14] > EC à la place de F8 Vous corrigerez ce " défaut " ! :0042FDAE 8B45F0 mov eax, [ebp-10] > date du jour :0042FDB1 8B55F8 mov edx, [ebp-08] > date install +30 :0042FDB4 E8E737FDFF call 004035A0 > comparaison :0042FDB9 770D ja 0042FDC8 > saut si supérieur Je pense que c'est assez parlant, non ? :0042FD59 8B45F0 mov eax, [ebp-10] > date du jour :0042FD5C 8B55F8 mov edx, [ebp-08] > date install +30 :0042FD5F E83C38FDFF call 004035A0 > comparaison -1 :0042FD64 7529 jne 0042FD8F
Pour faire plus sport, et parce que ça faisait parti de l'exercice, j'ai essayé de patcher REGDLL à partir de Photo.exe. En Vain pour la première version ! De toutes les adresses que j'avais trouvées, et qui pourraient permettre " d'améliorer " la protection, seule la routine de saisie de la date ne se décompressait pas APRES l'arrivée dans REGDLL.dll. Partant de là, je n'ai pas vu comment réussir à patcher une adresse à partir de l'exécutable ALORS QU'ELLE N'EXISTAIT PAS ENCOREà Photo.exe dans la deuxième version est le MEME exécutable que dans la première (pour autant que je n'en sois rendu compte), seul le point d'entrée sera différent, les adresses restant identiques. En traçant avec F10, j'avais mis la main sur le call qui faisait la bascule entre l'exécutable et la DLL : 004026C6 CALL [USER32 !RegisterHotKey] 004026CC CALL [0040D618] En faisant un d 40D618, j'ai obtenu BA085CB8 pour la 1er version et BA07FC pour la deuxième, soit l'entry point de REGDLL. Comme cette valeur n'est pas arrivée par hasard dans [0040D618], j'ai posé ensuite un BPM 40D618, pour arriver ici : 0137:00401FD7 8B35E0F24000 MOV ESI,[KERNEL32!GetProcAddress] 0137:00401FDD 68ACA14000 PUSH 0040A1AC 0137:00401FE2 50 PUSH EAX 0137:00401FE3 FFD6 CALL ESI 0137:00401FE5 85C0 TEST EAX,EAX 0137:00401FE7 A318D64000 MOV [0040D618],EAX > POP ! 0137:00401FEC 7502 JNZ 00401FF0 0137:00401FEE 5E POP ESI 0137:00401FEF C3 RET 0137:00401FF0 A1B8D54000 MOV EAX,[0040D5B8] Dans le Call ESI, eax va prendre la valeur BA07FC. A bien y réfléchir,
on devrait pouvoir récupérer un vingtaine d'octets dans ces paragesà (de 00401FDD à 00401FEF,
puisque le JNZ en 00401FEC saute toujours en 00401FF0). :004125CF 61 popad :004125D0 669D popf :004125D2 E9F904FFFF jmp 00402AD0 > fin de la zone compressée snips 0137:004125E9 0100 ADD [EAX],EAX 0137:004125EB 000C0F ADD [ECX+EDI],CL 0137:004125EE 0100 ADD [EAX],EAX Partant de l'idée que la routine de décompression se trouvait au dessus, j'ai cherché une zone qui semblait " clean " : 0137:0041255A 754B JNZ 004125A7 (JUMP) 0137:0041255C 3986E8B50000 CMP [ESI+0000B5E8],EAX snips 0137:004125A4 017D0C ADD [EBP+0C],EDI 0137:004125A7 8B4510 MOV EAX,[EBP+10] Et il m'a semblé qu'ici j'avais largement la place pour " m'exprimer
"à 01:00412557 39450C CMP [EBP+0C],EAX 02:0041255A 803DDD1F400068 CMP BYTE PTR [00401FDD],68 03:00412561 7544 JNZ 004125A7 04:00412563 C705DD1F4000C70518D6MOV DWORD PTR [00401FDD],D61805C7 05:0041256D C705E11F40004000FC07MOV DWORD PTR [00401FE1],07FC0040 06:00412577 C705E51F4000BA00C605MOV DWORD PTR [00401FE5],05C600BA 07:00412581 C705E91F4000E5F2B900MOV DWORD PTR [00401FE9],00B9F2E5 08:0041258B 66C705ED1F4000EB40 MOV WORD PTR [00401FED],40EB 09:00412594 C605EF1F400048 MOV BYTE PTR [00401FEF],48 10:0041259B EB0A JMP 004125A7 11:0041259D 90 NOP 12:0041259E 017DFC ADD [EBP-04],EDI 12:004125A1 83C40C ADD ESP,0C - Je commence à modifier en ligne 2 : La zone 00401FDD est elle décompressée
? (test de la valeur 68 qui est sensée s'y trouver après décompression). 0177:00401FD7 8B35E0F24000 MOV ESI,[KERNEL32!GetProcAddress] 0177:00401FDD C70518D64000FC07BA00MOV DWORD PTR [0040D618],00BA07FC 0177:00401FE7 C605E5F2B900EB MOV BYTE PTR [00B9F2E5],EB 0177:00401FEE 40 INC EAX 0177:00401FEF 48 DEC EAX 0177:00401FF0 A1B8D54000 MOV EAX,[0040D5B8] Pour les adeptes de listing Wdasm avec références, il y a moyen d'en
obtenir un: :004125CF 61 popad :004125D0 669D popf :004125D2 E9F904FFFF jmp 00402AD0 > fin de la décompression A partir de 00402AD0, vous n'aurez plus la possibilité de trouver des occurrences avec votre éditeur hexadécimal sur les codes relevés dans SoftIce. C'est ici que l'on va intervenir, et voici le Script que je vous propose: [Photo 1.0] L1=LOOK 61,66,9D > recherche la chaîne POPAD POPF L2=BP > pose un breakpoint (comme dans SI) L3=STEP > commence l'analyse du programme OPTL1=00000000 OPTL2=01000101 OPTL3=01010001 OPTL4=00030000 OPTL5=00000000 Sans oublier de rajouter le nom de votre bidouille dans l'index du fichier Script.ini de ProcDump
Que reste-t-il à faire? 0177:00401FD7 8B35E0F24000 MOV ESI,[KERNEL32!GetProcAddress] 0177:00401FDD C70518D64000FC07BA00MOV DWORD PTR [0040D618],00BA07FC > restore EAX 0177:00401FE7 C605E5F2B900EB MOV BYTE PTR [00B9F2E5],EB > patch REGDLL 0177:00401FEE 40 INC EAX > équilibre 0177:00401FEF 48 DEC EAX 0177:00401FF0 A1B8D54000 MOV EAX,[0040D5B8] |
Merci à toute l'équipe d'ATP Team pour nous avoir proposé cet exercice.
Bonne Journée