Cel     : StrongDisk v2.8.2.5
Opis    : Program umozliwia stworzenie wirtualnych dyskow twardych
URL     : http://www.phystechsoft.com
Toolz   : SoftIce,IDA

W katalogu z glownym programem znajdziemy plike regwiz.exe, ktory
umozliwia zarejestrowanie programu, do wyboru mamy 3 opcje 
rejestracji:

 - Register legally purchased copy in Full mode
 - Try different configurations in Demo mode
 - Register in Read-only mode

Opcja pierwsza umozliwia wprowadzenie numeru seryjnego, wiec 
zaznaczamy ja i klikamy dalej, naszym patrzalkom ukazuja sie 4 pola 
edycyjne umozliwiajace wpisanie numeru seryjnego, wpisujemy byle shit 
ale przycisk dalej jest wylaczony, z tego wniosek, ze program sprawdza
numer podczas wpisywania go do editow.Wpisujemy wszystkie cyfy seriala,
zakladamy standardowa pulapke na GetDlgItemTextA i modyfikujemy jakas
cyfre naszego seriala.Jest, SoftIce zatrzymal nas w:

00401330        sub     esp, 14h
00401333        lea     eax, [esp+14h+var_14]
00401337        push    ebx
00401338        push    ebp
00401339        mov     ebp, [esp+1Ch+arg_0]
0040133D        push    esi
0040133E        mov     esi, ds:GetDlgItemTextA
00401344        push    edi
00401345        push    5       <-- max dlugosc pobieranego ciagu
00401347        push    eax     <-- bufor gdzie zostana zapisane dane 
                                z edita
00401348        push    3F2h    <-- id edita
0040134D        push    ebp     <-- uchwyt okna glownego
0040134E        xor     bl, bl
00401350        call    esi ; GetDlgItemTextA
00401352        lea     ecx, [esp+24h+var_10]
00401356        push    5
00401358        push    ecx
00401359        push    3F3h
0040135E        push    ebp
0040135F        call    esi ; GetDlgItemTextA
00401361        lea     edx, [esp+24h+var_C]
00401365        push    5
00401367        push    edx
00401368        push    3F4h
0040136D        push    ebp
0040136E        call    esi ; GetDlgItemTextA
00401370        lea     eax, [esp+24h+var_8]
00401374        push    5
00401376        push    eax
00401377        push    3F5h
0040137C        push    ebp
0040137D        call    esi ; GetDlgItemTextA
0040137F        lea     edi, [esp+24h+var_14]   <-- bufor gdzie zostal 
                                                    odczytany serial
00401383        or      ecx, 0FFFFFFFFh         <-- przygotuj ecx
00401386        xor     eax, eax                <-- szukaj zera w
                                                    ciagu
00401388        repne scasb
0040138A        not     ecx
0040138C        dec     ecx
0040138D        cmp     ecx, 10h                <-- sprawdz rozmiar 
                                                    numeru seryjnego
00401390        jnz     short loc_4013FA

Jesli przesledzimy kod pod SI zobaczymy, ze program odczytuje wszystkie
czesci seriala do jednego bufora, nastepnie oblicza dlugosc tego bufora
i jesli nasz serial nie bedzie mial 16 bajtow nastapi wyjscie z
procedury sprawdzajacej ten serial, ale wystarczy, ze wypelnimy wszystkie
4 pola edycyjne aby przejsc do nastepnych sprawdzen:


00401392        mov     dl, [esp+24h+var_12]
00401396        xor     ecx, ecx
00401398 
00401398 loc_401398:                            ; CODE XREF: sub_401330+C6j
00401398        mov     al, [esp+ecx+24h+var_14]<-- pierwszy bajt z seriala
0040139C        cmp     al, '0'                 <-- jesli jest mniejszy od 30h sprawdz czy to znak
0040139E        jl      short loc_4013A4
004013A0        cmp     al, '9'
004013A2        jle     short loc_4013AE
004013A4 
004013A4 loc_4013A4:                            ; CODE XREF: sub_401330+6Ej
004013A4        cmp     al, 'A'
004013A6        jl      short loc_4013AC
004013A8        cmp     al, 'Z'
004013AA        jle     short loc_4013AE
004013AC 
004013AC loc_4013AC:                            ; CODE XREF: sub_401330+76j
004013AC        mov     bl, 1
004013AE 
004013AE loc_4013AE:                            ; CODE XREF: sub_401330+72j
004013AE                                        ; sub_401330+7Aj
004013AE        test    ecx, ecx                <-- po 2 kolejce odczytywania ecx=1
004013B0        jnz     short loc_4013C4
004013B2        mov     al, [esp+24h+var_14]    <-- jeszcze raz wez pierwszy bajt seriala
004013B6        cmp     al, 'S'                 <-- czy to 'S'?
004013B8        jz      short loc_4013F2
004013BA        cmp     al, 'W'                 <-- czy to 'W'?
004013BC        jz      short loc_4013F2
004013BE        cmp     al, 'P'                 <-- czy to 'P'?
004013C0        jz      short loc_4013F2
004013C2        jmp     short loc_4013F0        <-- ustaw bl na 1

004013C4                                        <-- 2 kolejka odczytywania bajtow z sn
004013C4 loc_4013C4:                            ; CODE XREF: sub_401330+80j
004013C4        cmp     ecx, 1                  <-- za 2 razem ecx=1
004013C7        jnz     short loc_4013D2
004013C9        cmp     [esp+24h+var_13], 'N'   <-- czy 2 bajt sn to 'N'
004013CE        jz      short loc_4013F2        <-- jesli tak zwieksz licznik i czytaj nastepne bajty
004013D0        jmp     short loc_4013F0        <-- ustaw bl na 1

004013D2 
004013D2 loc_4013D2:                            ; CODE XREF: sub_401330+97j
004013D2        cmp     ecx, 2                  <-- 3 kolejka odczytywania bajtow z sn
004013D5        jnz     short loc_4013F2        <-- za 3 razem ecx=2
004013D7        cmp     dl, 'E'                 <-- czy 3 bajt sn to 'E'?
004013DA        jz      short loc_4013F2
004013DC        cmp     dl, 'F'                 <-- czy 3 bajt sn to 'F'?
004013DF        jz      short loc_4013F2
004013E1        cmp     dl, 'G'                 <-- czy 3 bajt sn to 'G'?
004013E4        jz      short loc_4013F2
004013E6        cmp     dl, 'P'                 <-- czy 3 bajt sn to 'P'?
004013E9        jz      short loc_4013F2
004013EB        cmp     dl, 'R'                 <-- czy 3 bajt sn to 'R'?
004013EE        jz      short loc_4013F2
004013F0 
004013F0 loc_4013F0:                            ; CODE XREF: sub_401330+92j
004013F0                                        ; sub_401330+A0j
004013F0        mov     bl, 1                   <-- bad boy
004013F2 
004013F2 loc_4013F2:                            ; CODE XREF: sub_401330+88j
004013F2                                        ; sub_401330+8Cj
004013F2                                        ; sub_401330+90j
004013F2                                        ; sub_401330+9Ej
004013F2                                        ; sub_401330+A5j
004013F2                                        ; sub_401330+AAj
004013F2                                        ; sub_401330+AFj
004013F2                                        ; sub_401330+B4j
004013F2                                        ; sub_401330+B9j
004013F2                                        ; sub_401330+BEj
004013F2        inc     ecx                     <-- zwieksz ecx i odczytuj nastepne bajty
004013F3        cmp     ecx, 0Fh
004013F6        jl      short loc_401398
004013F8        jmp     short loc_4013FC

004013FA 
004013FA loc_4013FA:                            ; CODE XREF: sub_401330+60j
004013FA        mov     bl, 1                   <-- bad boy
004013FC 
004013FC loc_4013FC:                            ; CODE XREF: sub_401330+C8j
004013FC        neg     bl
004013FE        sbb     ebx, ebx
00401400        and     ebx, 0FFFFFFFEh
00401403        add     ebx, 3
00401406        push    ebx
00401407        push    0
00401409        push    470h
0040140E        push    ebp
0040140F        call    ds:GetParent
00401415        push    eax
00401416        call    ds:PostMessageA
0040141C        pop     edi
0040141D        pop     esi
0040141E        pop     ebp
0040141F        mov     eax, 1
00401424        pop     ebx
00401425        add     esp, 14h
00401428        retn
00401428 sub_401330      endp

Program sprawdza pierwsze 3 bajty seriala, jesli sa one poprawne a
reszta bajtow seriala stanowia cyfry 0..9 lub literki A..Z zostanie
uaktywniony przycisk dalej, klikamy wiec na niego i jesli wylaczylismy
bpx-y ukaze sie msg box z textem "Wrong serial number.Please, try to
reenter it.", jesli nie usunelismy bpx-ow wyladujemy w kodzie:

004014EC        mov     edi, [esp+7Ch]
004014F0        mov     esi, ds:GetDlgItemTextA
004014F6        lea     edx, [esp+8]
004014FA        push    5
004014FC        push    edx
004014FD        push    3F2h
00401502        push    edi
00401503        mov     byte ptr [esp+1Ch], 0
00401508        call    esi ; GetDlgItemTextA
...
00401564        lea     edx, [esp+8]
00401568        push    5
0040156A        push    edx
0040156B        push    3F5h
00401570        push    edi
00401571        call    esi ; GetDlgItemTextA
00401573        lea     eax, [esp+8]
00401577        push    4
00401579        push    eax
0040157A        push    offset dword_4078AC
0040157F        call    _strncpy
00401584        push    offset dword_4078A0     <-- serial
00401589        call    __strlwr                <-- do lower case
0040158E        mov     ecx, dword_4078A0
00401594        mov     edx, dword_4078A4
0040159A        push    8
0040159C        lea     eax, [esp+38h]
004015A0        push    offset byte_407054      <-- ciag ktory zostanie dodany
004015A5        push    eax                     <-- ciag zrodlowy
004015A6        mov     [esp+38h], ecx
004015AA        mov     [esp+3Ch], edx
004015AE        call    _strncpy                <-- polacz ciagi

Program odczytuje jeszcze raz numer seryjny, do pierwszej czesci numeru
(1 edit) zostaja "doklejone" bajty spod VA 407054:

00407054 byte_407054     db 64h, 0C0h, 0EBh, 19h, 8Bh, 44h, 50h, 0E8h, 4 dup(0)

Jakies smieci, ale lecimy dalej:

004015B3        mov     ecx, dword_4078A8
004015B9        mov     edx, dword_4078AC
004015BF        add     esp, 1Ch
004015C2        lea     eax, [esp+7Ch]          <-- po tym adresem zostanie zapisany hContext
004015C6        mov     [esp+10h], ecx
004015CA        mov     [esp+14h], edx
004015CE        push    0                       <-- ALGO
004015D0        push    0CBh                    <-- USER KEY
004015D5        push    eax                     <-- ptr --> hContext
004015D6        mov     byte ptr [esp+24h], 0
004015DB        mov     dword ptr [esp+88h], 0
004015E6        call    ds:_cryptCreateContext@12
004015EC        test    eax, eax
004015EE        jnz     loc_401767
004015F4        mov     edx, [esp+7Ch]          <-- hContext
004015F8        mov     esi, ds:_cryptEncrypt@12<-- adres funkcji szyfrujacej
004015FE        lea     ecx, [esp+1Ch]          <-- 1 czesc seriala polaczona z badziestwem
00401602        push    10h                     <-- rozmiar bufora do szyfrowania/hashowania
00401604        push    ecx                     <-- bufor
00401605        push    edx                     <-- hContext
00401606        call    esi ; _cryptEncrypt@12  <-- szyfruj/hashuj
00401608        test    eax, eax                <-- jesli eax!=0 to znaczy, ze wystapil blad
0040160A        jnz     loc_401767
00401610        mov     ecx, [esp+7Ch]          <-- hContext
00401614        push    eax                     <-- eax bedzie sie rownac 0
00401615        lea     eax, [esp+20h]          <-- 1 czesc seriala
00401619        push    eax                     <-- bufor
0040161A        push    ecx                     <-- hContext
0040161B        call    esi ; _cryptEncrypt@12  <-- szyfruj/hashuj
0040161D        test    eax, eax
0040161F        jnz     loc_401767
00401625        mov     eax, [esp+7Ch]          <-- hContext
00401629        lea     edx, [esp+2Ch]          <-- bufor w ktorym otrzymamy wyniki
0040162D        push    edx
0040162E        push    eax
0040162F        call    ds:_cryptQueryContext@8 <-- pobierz wyniki operacji przeprowadzonych na hContext
00401635        test    eax, eax                <-- jesli eax!=0 to znaczy, ze wystapil blad
00401637        jnz     loc_401767
0040163D        mov     ecx, [esp+7Ch]          <-- hContext
00401641        push    ecx                     <-- zapamietaj i zniszcz obiekt
00401642        call    ds:_cryptDestroyContext@4       

Program korzysta z biblioteki CL32.DLL, w version info tej biblioteki
pisze, ze jest to "cryptlib encryption library" v2.1 autorstwa Erica
Younga, mozecie poszukac sobie versje 2.1 ale ja znalazlem wersje 3.0
beta 4 ktora nie zawiera juz funkcji _cryptQueryContext@8 ale o tym
za chwile, jestesmy przy _cryptCreateContext@12, w dokumentacji v3.0
pisze, ze:

The cryptCreateContext function is used to create an encryption context
for a given encryption algorithm.

int cryptCreateContext( CRYPT_CONTEXT *cryptContext, const CRYPT_USER cryptUser,
const CRYPT_ALGO cryptAlgo );

Parameters:
cryptContext - The address of the encryption context to be created.
cryptUser    - The user who is to own the encryption context or
               CRYPT_UNUSED for the default, normal user.
cryptAlgo    - The encryption algorithm to be used in the context.
               See also cryptDestroyContext, cryptDeviceCreateContext.

Funkcja tworzy obiekt, ktory umozliwia szyfrowanie/hashowanie, wg
okreslonego algorytmu, w naszym przypadku program wylicza hash
uzywajac algorytmu SHA1(bpm na dane).Nastepnie zostaje wywolana
2 razy funkcja _cryptEncrypt@12:

int cryptEncrypt( const CRYPT_CONTEXT cryptContext, const void *buffer, const int length );
Parameters: 
cryptContext - The encryption context to use to encrypt or hash the data.
buffer       - The address of the data to be encrypted or hashed.
length       - The length in bytes of the data to be encrypted or hashed.

Funkcja hashuje 1 czlon numeru seryjnego(po dodaniu do niego ciagu bajtow),
po hashowaniu nastepuje odczytanie wynikow poprzez wywolanie funkcji
_cryptQueryContext@8.Po wszystkim obiekt hContext zostaje "zniszczony"

...
00401696 loc_401696:                            ; CODE XREF: .text:00401680j
00401696                                        ; .text:00401692j
00401696        add     cl, al                  <-- bajt z 3 okna edycyjnego(2 znaki)
00401698        mov     al, [esp+esi+58h]       <-- porownaj
0040169C        cmp     al, cl
0040169E        jnz     short loc_4016CE        <-- skok bad boy
004016A0        inc     esi
004016A1        add     edx, 2
004016A4        cmp     esi, 4
004016A7        jl      short loc_40164E
004016A9        mov     eax, dword_407904
004016AE        test    eax, eax
004016B0        mov     al, [esp+1Ch]
004016B4        jz      short loc_4016ED
004016B6        cmp     al, -8Dh
004016B8        jz      short loc_4016ED
004016BA        mov     eax, dword_407D10
004016BF        push    200h
004016C4        push    offset unk_407B0C
004016C9        push    71h
004016CB        push    eax
004016CC        jmp     short loc_40170E

W duzym streszczeniu, program zamienia na wartosci hexadecymalne bajty
wprowadzone do 3 i 4 edita z numerem seryjnym, nastepnie porowywane
sa one z bajtami zwroconymi w buforze po wywolaniu funkcji z CL32.DLL
_cryptQueryContext@8(hash SHA1) i jesli sa rozne nastepuje wyjscie z
procki, a jesli sa takie same...to chyba sie domyslacie, tak thnx za
zarejestrowanie, program ma 3 tryby "zarejestrowania" zalezne od 1
litery numeru seryjnego, pamietacie te piewsze sprawdzenia, pierwsza
litera byla porownywana z "P","W" i "S", literka "P" na poczatku
seriala okresla, ze program ma byc zarejestrowany w trybie PERSONAL
EDITION max ilosc miejsca na wirtualnym dysku to 30mb, "W" WORKSTATION
EDITION nieograniczona ilosc dyskow wirtualnych i "S" SERVER EDITION
umozliwia tworzenie i zarzadzanie dyskami na serwerach(tak pisze w
helpie).

Streszczenie algo:
 - pobierana jest 1 i 2 czesci seriala
 - do tych czeci dolaczane sa "magiczne" bajty
 - calosc jest konwertowana do lower case
 - po przekonwertowaniu calosc jest hashowana wg. SHA1
 - bajty hash-a stanowia 2 czesc numeru seryjnego

Program jest spakowany UPXem 0.94 wiec upx -d i potem zabawa z deadlistingiem...

PS.
W wersji asmowej keygena wykorzystalem biblioteke cryptlib w wersji 2.1.


bart^CrackPl
cryogen@box43.pl