ษอออออออออออออออออออออออออออออออออออป บ KeygenMe hccc #5 บ ศอออออออออออออออออออออออออออออออออออผ Protections: Anti-Softice et Serial Number Materiel:Softice et un compilateur Win32asm(protools.cjb.net et win32asm.cjb.net) Protocole : 1)La protection SoftIce ~~~~~~~~~~~~~~~~~~~~~~~ On lance le programme KeygenMe.exe, une boite de message s'afiche "Vilain Garcon, Softice detecte" ;) Ca a tout l'air d'une MessageBox, donc on pose un point d'arret sur l'API MessageBoxa (Avec Ctrl+D, puis bpx MessageBoxa). On ferme, puis on relance le prog, Softice s'affiche.On appuie une fois sur F12 jusqu'a apercevoir le nom du prog en bas en vert. On remonte le code de quelques lignes(Ctrl+fleche haut) jusqu'a trouver un saut conditionnel je: :00401317 B443 mov ah, 43 :00401319 CD68 int 68 ;Fonction 43 de l'interruption 68 : detecte softice(voir le tut de :0040131B 663D86F3 cmp ax, F386 ;christal a ce sujet sur assembly.citeweb.net) :0040131F 7405 je 00401326 ;si softice, saute :00401321 E9CC000000 jmp 004013F2 ;donne la main au prog(si pas sice) [...] :00401348 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"Vilain Gar" | :0040134A 6804614000 push 00406104 * Possible StringData Ref from Data Obj ->"Softice Detected ;(" | :0040134F 68F0604000 push 004060F0 :00401354 8B4D08 mov ecx, dword ptr [ebp+08] :00401357 51 push ecx * Reference To: USER32.MessageBoxA, Ord:01BEh | :00401358 FF15B8504000 Call dword ptr [004050B8] ;Messagebox d'avertissement que sice est detecte :0040135E E98F000000 jmp 004013F2 ;donne la main au prog (Copier/Coller de WDasm(URSoft)) Il suffit donc de patcher le je, soit en le changeant en jne, donc en changeant le 74 en 75 en 40131F, soit en le changeant en 2 nops, donc en changeant 7405 en 9090. Pour ce faire, tapez e 40131F, et taper le code en hexadecimal, ou tapez a 40131F, et tapez le code en asm. Fermez, puis rouvrez le prog, et hop!...Emballez, c'est pese. Pour le patch, cherchez a l'offset 131F du fichier. 2)Serial Fishing ~~~~~~~~~~~~~~~~ Qd vs desirez faire un keygen, il est tjs preferable de commencer par un bon serial fishing. Le serial fishing consiste a intercepter la routine de verification du serial(qd le prog compare le serial que vs avez entre au vrai). Certains esprits mal tournes seraient tente d'expliquer cela par un certain egoisme du cracker, qui pense d'abord a lui, puis aux autres, mais il ne s'agit en fait que de pouvoir verifier ulterieurement si son keygen fonctionne. On entre donc le nom et le serial, ceux que vs voulez, mais faites en sorte de pouvoir les reperer plus tard. Le bpx MessageBoxa doit tjs etre actif,clickez sur le bouton: softice s'affiche, appuyez sur F12, la messagebox s'affiche.Clickez OK, puis: Remontez le code, on apercoit aisement un autre appel vers une MessageBoxa, la bonne cette fois.Ca donne : :004012B4 8945E4 mov dword ptr [ebp-1C], eax ;eax->[ebp-1C] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004012AD(U) | :004012B7 8B4DE4 mov ecx, dword ptr [ebp-1C] ;[ebp-1C]->ecx :004012BA 894DE0 mov dword ptr [ebp-20], ecx ;etc... :004012BD 8B55E0 mov edx, dword ptr [ebp-20] :004012C0 8915906A4000 mov dword ptr [00406A90], edx :004012C6 833D906A400000 cmp dword ptr [00406A90], 00000000 ;not zero? :004012CD 7518 jne 004012E7 ;jump to bad guy(vilain garcon ;p) :004012CF 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"KeyGeNMe" | :004012D1 68B4614000 push 004061B4 * Possible StringData Ref from Data Obj ->"Bien jou" | :004012D6 6840604000 push 00406040 :004012DB 8B4508 mov eax, dword ptr [ebp+08] :004012DE 50 push eax * Reference To: USER32.MessageBoxA, Ord:01BEh | :004012DF FF15B8504000 Call dword ptr [004050B8] ;messagebox Good guy bien, pour savoir si le serial est bon,le prog test si ecx==0.Il faut trouver le moment ou il met 0 ds ecx(ou ds [ebp-1C]) On remonte a peine, et on a la routine de comparaison: :00401264 C745F0046B4000 mov [ebp-10], 00406B04 ;faux serial->[ebp-10] :0040126B C745EC9C6A4000 mov [ebp-14], 00406A9C ;vrai serial->[ebp-14] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004012A4(C) | :00401272 8B45EC mov eax, dword ptr [ebp-14] ;comparaison... :00401275 8A08 mov cl, byte ptr [eax] :00401277 884DEB mov byte ptr [ebp-15], cl :0040127A 8B55F0 mov edx, dword ptr [ebp-10] :0040127D 3A0A cmp cl, byte ptr [edx] :0040127F 752E jne 004012AF :00401281 807DEB00 cmp byte ptr [ebp-15], 00 :00401285 741F je 004012A6 :00401287 8B45EC mov eax, dword ptr [ebp-14] :0040128A 8A4801 mov cl, byte ptr [eax+01] :0040128D 884DEA mov byte ptr [ebp-16], cl :00401290 8B55F0 mov edx, dword ptr [ebp-10] :00401293 3A4A01 cmp cl, byte ptr [edx+01] :00401296 7517 jne 004012AF :00401298 8345EC02 add dword ptr [ebp-14], 00000002 :0040129C 8345F002 add dword ptr [ebp-10], 00000002 :004012A0 807DEA00 cmp byte ptr [ebp-16], 00 :004012A4 75CC jne 00401272 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401285(C) | :004012A6 C745E400000000 mov [ebp-1C], 00000000 ;zero ds [ebp-1C] :004012AD EB08 jmp 004012B7 ;et on jump Voila, pour avoir le serial, bpx en 40126B, et arrive la, on fait d 406a9c. Pour moi, ca donne : Nom : NostraDamus Serial : 8754-2349-69 3)KeyGenning ~~~~~~~~~~~~ bon, si on cherche qd le serial est mis en 406a9c, on a des chances de trouver la routine de generation, on remonte un peu ds le code...Pas tres parlant...On entre un nom et 1 serial, et on bpx hmemcpy.Click sur le bouton, sice s'affiche.PLusieurs fois F12 juska avoir le nom du prog(keygenme) a la ligne verte en bas. Et on arrive la: :004010A1 FF15C8504000 Call dword ptr [004050C8] ;on get le nom :004010A7 6A32 push 00000032 :004010A9 68046B4000 push 00406B04 :004010AE 68E9030000 push 000003E9 :004010B3 8B4D08 mov ecx, dword ptr [ebp+08] :004010B6 51 push ecx * Reference To: USER32.GetDlgItemTextA, Ord:0104h | :004010B7 FF15C8504000 Call dword ptr [004050C8] ;on get le serial :004010BD 0FBE155C6A4000 movsx edx, byte ptr [00406A5C] :004010C4 85D2 test edx, edx ;nom[0]==0? :004010C6 751B jne 004010E3 ;non, on saute :004010C8 6A00 push 00000000 ;oui, on affiche "Vous devez entrer un nom" * Possible StringData Ref from Data Obj ->"KeyGeNMe" | :004010CA 68B4614000 push 004061B4 * Possible StringData Ref from Data Obj ->"Vous devez entrer un nom" | :004010CF 6898614000 push 00406198 :004010D4 8B4508 mov eax, dword ptr [ebp+08] :004010D7 50 push eax * Reference To: USER32.MessageBoxA, Ord:01BEh | :004010D8 FF15B8504000 Call dword ptr [004050B8] :004010DE E92F020000 jmp 00401312 ;sortie de la routine * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010C6(C) | :004010E3 0FBE0D046B4000 movsx ecx, byte ptr [00406B04] :004010EA 85C9 test ecx, ecx ;serial[0]==0? :004010EC 751B jne 00401109 ;non, on saute :004010EE 6A00 push 00000000 ;oui, on affiche... * Possible StringData Ref from Data Obj ->"KeyGeNMe" | :004010F0 68B4614000 push 004061B4 * Possible StringData Ref from Data Obj ->"Vous devez entrer un s" | :004010F5 687C614000 push 0040617C :004010FA 8B5508 mov edx, dword ptr [ebp+08] :004010FD 52 push edx * Reference To: USER32.MessageBoxA, Ord:01BEh | :004010FE FF15B8504000 Call dword ptr [004050B8] :00401104 E909020000 jmp 00401312 ;sortie * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004010EC(C) | :00401109 BF5C6A4000 mov edi, 00406A5C ;debut de routine_compliquee_de_calcul_longueur_serial :0040110E 83C9FF or ecx, FFFFFFFF :00401111 33C0 xor eax, eax :00401113 F2 repnz :00401114 AE scasb :00401115 F7D1 not ecx :00401117 83C1FF add ecx, FFFFFFFF ;fin :0040111A 890D586A4000 mov dword ptr [00406A58], ecx :00401120 833D586A400004 cmp dword ptr [00406A58], 00000004 ;strlen(serial) => 4 :00401127 7D1B jge 00401144 ;oui, on saute :00401129 6A00 push 00000000 ;non, affiche pas assez de caracteres * Possible StringData Ref from Data Obj ->"KeyGeNMe" | :0040112B 68B4614000 push 004061B4 * Possible StringData Ref from Data Obj ->"Le nom doit comprendre au moins " ->"4 caract" | :00401130 684C614000 push 0040614C :00401135 8B4508 mov eax, dword ptr [ebp+08] :00401138 50 push eax * Reference To: USER32.MessageBoxA, Ord:01BEh | :00401139 FF15B8504000 Call dword ptr [004050B8] :0040113F E9CE010000 jmp 00401312 ;sortie * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401127(C) | * Possible StringData Ref from Data Obj ->"KeygenMe" | :00401144 68E4604000 push 004060E4 ;KeygenMe :00401149 685C6A4000 push 00406A5C ;nom entre * Possible StringData Ref from Data Obj ->"Hccc" | :0040114E 68DC604000 push 004060DC ;Hccc * Possible StringData Ref from Data Obj ->"%s%s%s" ;filtre wsprintf string1+string2+string3(Hcccnom_entre_par_userKeygenMe) | :00401153 6844614000 push 00406144 :00401158 68386B4000 push 00406B38 ;buffer ou stocker le resultat :0040115D E80E030000 call 00401470 ;routine similaire a wsprintf :00401162 83C414 add esp, 00000014 :00401165 C705506A400000000000 mov dword ptr [00406A50], 00000000 :0040116F EB0F jmp 00401180 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011E5(U) | :00401171 8B0D506A4000 mov ecx, dword ptr [00406A50] :00401177 83C101 add ecx, 00000001 :0040117A 890D506A4000 mov dword ptr [00406A50], ecx * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040116F(U) | :00401180 8B15506A4000 mov edx, dword ptr [00406A50] ;[406A50]->edx :00401186 0FBE82386B4000 movsx eax, byte ptr [edx+00406B38] ;nom[edx] ds eax :0040118D 85C0 test eax, eax ;eax==0? :0040118F 7456 je 004011E7 ;oui,saute :00401191 8B0D506A4000 mov ecx, dword ptr [00406A50] :00401197 0FBE91386B4000 movsx edx, byte ptr [ecx+00406B38] ;nom[ecx] ds edx :0040119E 8915946A4000 mov dword ptr [00406A94], edx :004011A4 A1946A4000 mov eax, dword ptr [00406A94] ;ds eax :004011A9 83C009 add eax, 00000009 ;eax= eax + 9 :004011AC A3946A4000 mov dword ptr [00406A94], eax :004011B1 8B0D946A4000 mov ecx, dword ptr [00406A94] ;result ds ecx :004011B7 6BC90E imul ecx, 0000000E ;ecx= ecx * 0Eh :004011BA 890D946A4000 mov dword ptr [00406A94], ecx :004011C0 A1946A4000 mov eax, dword ptr [00406A94] ;result ds eax :004011C5 99 cdq ;utile? *** :004011C6 83E203 and edx, 00000003 ;?? edx=0 tjs :004011C9 03C2 add eax, edx ;?? :004011CB C1F802 sar eax, 02 ;eax=sar(eax,2) :004011CE A3946A4000 mov dword ptr [00406A94], eax ;eax ds [406A94] :004011D3 8B15006B4000 mov edx, dword ptr [00406B00] ;somme de tous les resultats ds edx :004011D9 0315946A4000 add edx, dword ptr [00406A94] ;on ajoute celui qu'on vient de trouver :004011DF 8915006B4000 mov dword ptr [00406B00], edx ;on stocke la somme ds n1 :004011E5 EB8A jmp 00401171 ;et on boucle... ***rappel sur l'instruction cdq : transforme le dword(32) ds eax en qword(64) ds edx:eax.Resultat, edx est tjs a zero pisque le high word de eax est tjs a zero(qd on utilise des lettres et des chiffres) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040118F(C) | :004011E7 C705506A400000000000 mov dword ptr [00406A50], 00000000 :004011F1 EB0D jmp 00401200 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401242(U) | :004011F3 A1506A4000 mov eax, dword ptr [00406A50] :004011F8 83C001 add eax, 00000001 :004011FB A3506A4000 mov dword ptr [00406A50], eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004011F1(U) | :00401200 8B0D506A4000 mov ecx, dword ptr [00406A50] ;nombre de caracteres lus ds ecx :00401206 0FBE91386B4000 movsx edx, byte ptr [ecx+00406B38] ;nom[ecx] ds edx :0040120D 85D2 test edx, edx ;edx==0? :0040120F 7433 je 00401244 ;saute :00401211 A1506A4000 mov eax, dword ptr [00406A50] :00401216 0FBE88386B4000 movsx ecx, byte ptr [eax+00406B38] :0040121D 890D946A4000 mov dword ptr [00406A94], ecx :00401223 8B15946A4000 mov edx, dword ptr [00406A94] :00401229 83F209 xor edx, 00000009 ;nom[eax]=nom[eax] xor 9 :0040122C 8915946A4000 mov dword ptr [00406A94], edx :00401232 A1986A4000 mov eax, dword ptr [00406A98] :00401237 0305946A4000 add eax, dword ptr [00406A94] ;rajoute a la somme finale :0040123D A3986A4000 mov dword ptr [00406A98], eax ;eax ds n2 :00401242 EBAF jmp 004011F3 ;boucle * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040120F(C) | :00401244 8B0D986A4000 mov ecx, dword ptr [00406A98] ;2eme numero n2 :0040124A 51 push ecx :0040124B 8B15006B4000 mov edx, dword ptr [00406B00] ;1er numero n1 :00401251 52 push edx * Possible StringData Ref from Data Obj ->"%d-%d-69" | :00401252 6838614000 push 00406138 ;filtre wsprintf n1-n2-69 :00401257 689C6A4000 push 00406A9C :0040125C E80F020000 call 00401470 ;procedure=wsprintf :00401261 83C410 add esp, 00000010 Vala vala, il nous reste plus qu'a ecrire une jolie procedure: D'abors, on change la chaine de depart du nom en rajoutant Hccc au debut et KeygenMe a la fin Puis, la routine calcule la somme n1 de tous les caracteres transformes.Il ont subi la transformation suivante: char=char+9 char=Char*E char=sar(char,2) Ensuite, un deuxieme nombre n2 est calcule, tjs une somme des caracteres transformes cette fois ci par: char=xor(char,9) ensuite on accole ls deux nombres de la facon suivante: n1-n2-69 Le 69 de la fin est donc inevitable. Vous avez tous les elements en main pour ecrire une procedure d'encodage, dont voici un exemple(sans pretention, je sais qu'il est mal code, mais il marche bien et c'est tout ce qui compte): GetSerial PROC ;on fait "Hccc"+nom+"KeyGenMe" invoke wsprintf, addr buffer, addr filter1, addr name_entre pushad xor eax,eax xor ebx,ebx xor ecx,ecx xor edx,edx ;adresse de la chaine a traiter ds esi mov esi,offset buffer ;calcul du 1er nombre nombre1: xor eax,eax lodsb cmp eax,0 je fin_nombre1 add eax,9 imul eax,eax,0Eh sar eax,2 add ebx,eax jmp nombre1 fin_nombre1: mov esi,offset buffer ;calcul du second nombre nombre2: xor eax,eax inc ecx lodsb cmp eax,0 je fin_calcul xor eax,9 add edx,eax jmp nombre2 fin_calcul: ;longueur du texte ds ecx dec ecx mov textlong,cl ;on fait n1-n2-69 invoke wsprintf, addr buffer, addr filter2, ebx,edx popad ret GetSerial endp