-+[ jak zlamac Keygenme3 by PdriLI ]+-

Crackme zrodzil Microsoft Visual C++ 6.0, ktore mozna zassac z
http://cryptokg.cjb.net/
Prog uzywa miracl, tak wiec przyda sie minimalna wiedza jesli chodzi
o dzialanie tej jakze popularnej biblioteki.

-+[ disasembler & debug ]+-

Standardowo stawiamy pulapke na GetDlgItemTextA, pobierane sa: name i dwa
seriale, a nastepnie:

 loc_4010F8:
           cmp     esi, 1Eh
           mov     eax, esi
           jge     short loc_401124
           mov     edx, 1Eh
           lea     edi, _name[esi]
           sub     edx, esi
           mov     eax, 2A2A2A2Ah
           mov     ecx, edx
           mov     ebx, ecx
           shr     ecx, 2
           rep stosd
           mov     ecx, ebx
           and     ecx, 3
           rep stosb
           lea     eax, [edx+esi]
 
 loc_401124:
           mov     _name[eax], 0

30 bajtowy bufor na name zostaje uzupelniany name+'**...*', nastepnie 
tworzone sa zmienne miracl i prog sprawdza czy nasze seriale skladaja sie
wylacznie z '0'..'9' / 'a'..'z' / 'A'..'Z', ok a co dalej:

push    offset _serial1
           push    ebp
           call    _cinstr
           mov     edx, [esp+2Ch+arg_4]
           push    offset _serial2
           push    edx
           call    _cinstr
           mov     eax, [esp+34h+var_C]
           mov     ecx, [esp+34h+var_8]
           push    ebx
           push    offset _name
           push    ecx
           mov     dword ptr [eax+238h], 10h
           call    _bytes_to_big
           push    offset aAc2db4fec8c629 ; "AC2DB4FEC8C62992DB4F"
           push    esi                    ; prime
           call    _cinstr

trzeba zwrocic uwage, ze kawalek kodu dalej IOBASE bylo ustawione na 60, czyli
serial1 i serial2 beda wczytywane w systemie 60, dopiero name wczytane
zostanie w systemie hex.

           push    ebx
           push    esi
           push    2
           push    ebx
           call    _power                 ; name=name^2 mod prime

           push    offset aB54f430648c6b2 ; "B54F430648C6B2A10FFB"
           push    esi                    ; p
           call    _cinstr
           mov     edx, [esp+60h+var_10]
           push    offset a2e0c2db4fec8c6 ; "2E0C2DB4FEC8C6299A0C"
           push    edx                    ; g
           call    _cinstr
           mov     edi, [esp+68h+var_4]
           add     esp, 44h
           push    offset a4e0f2acad51c4c ; "4E0F2ACAD51C4CCDFB51"
           push    edi                    ; y
           call    _cinstr
           mov     eax, [esp+2Ch+var_14]
           mov     ecx, [esp+2Ch+var_10]
           push    eax
           push    esi
           push    ebx
           push    ecx
           call    _powmod                ;a=g^m mod p
           mov     edx, [esp+3Ch+arg_8]
           mov     eax, [esp+3Ch+arg_4]
           push    edx
           push    esi
           push    eax
           push    ebp
           push    ebp
           push    edi
           call    _powmod2               ;b=y^a*a^b mod p
           mov     ecx, [esp+54h+arg_8]
           mov     edx, [esp+54h+var_14]
           push    ecx
           push    edx
           call    _compare               ;a==b

jesli wartosci sa rozne to bad boy, jakby ktos jeszcze nie wiedzial, to jest
to ElGamal, deszyfrowanie przedstawia sie nastepujaco:

najpierw musimy znalezc x, ktore oblicza sie: y=g^x mod p, czyli problem
dyskretnych logarytmow, do obliczenia pomocny bedzie aplet java:
http://www.alpertron.com.ar/DILOG.HTM, albo prog DLPTool by figugegl, mi
wyszlo x=9A0CD8235134E88BEFD0h

Przyda sie jeszcze k, ktore musi byc wzglednie pierwsze z p-1
Ok w takim razie mozemy zajac sie deszyfrowaniem:

a=g^k mod p

b=(M-ax)*k^-1 mod p-1

Ok, no to jak wyglada rozwiazanie:

          power(m,2,pow,m);           //name=name^2 mod prime
          decr(p,1,p1);               //p-1
          l=GetTickCount();           //'losujemy' seed
          irand(l);                   //uruchamiamy system losowania
          do
          {
              bigrand(p1,k);          //losujemy k wzgledem p-1
          }
          while(egcd(p1,k,ki)!=1);    //czy jest wzglednie pierwsze? (NWD=1)
          
          powmod(g,k,p,a);            //a=g^k%p     - mamy serial1

/* niestety miracl nie ma funkcji, ktora od razu jest w stanie obliczyc
   b=(M-ax)*k^-1%(p-1), dlatego musimy to rozbic na czesci pierwsze */

	  multiply(x,a,x);            //a*x
          subtract(m,x,x);            //m-ax
          xgcd(k,p1,ki,ki,prime);     //k^-1
          multiply(x,ki,x);           //(m-ax)*k^-1
          power(x,1,p1,x);            //(m-ax)*k^-1 mod p-1
          add(x,p1,b);                //na wypadek jakby liczba byla ujemna
          
          mip->IOBASE=60;             //seriale byly przyjmowane w systemie 60
          
          cotstr(a,pass);             //serial1
          cotstr(b,pass1);            //serial2

-+[ podsumowanie ]+-

fane crackme, wpisz seriali dla danego name, no i elgamal ;)
jakby kogos interesowalo to keygen+src do zassania z mojej strony.

jopas/htb+rag
         mail: jopas@o2.pl
        web: http://www.jopas.prv.pl

-+[ end ]+-