TUTORIAL 0
Autor: zoomek
Grupa: Seven Team
WWW: www.7team.z.pl
Kontakt: zoomek@interia.pl
Temat: Teleport pro V1.29: opis złamania+przykład stworzenia kompletnego keygeneratora w Win32asm
Data ukończenia: 08.05.2000
Potrzebne narzędzia: SoftICE v4.05; W32Dasm v8.93; Ms Visual C++ 6.0; Tasm 5.0(Tasm32.exe, Tlink32.exe)+pliki:Import32.lib, rlink32.dll


Głównym celem tego tutorka nie jest złamanie programu Teleport pro, bo jest to sprawą bardzo prostą , a jedynie pokazanie na przykładowym programiku jak napisać w pełni funkcjonalny keygenerator w Win32asm zaczynając od elementarnych podstaw. Keygenerator jest uniwersalny, i po wpisaniu odpowiedniej procedurki wyliczającej serial dla swojego programu, szablon ten można wykorzystać pisząc własnego keygeneratorka.

Spis treści
  • Opis zabezpieczenia
  • Keygen - stworzenie okienka głównego programu w edytorze zasobów
  • Keygen - właściwy kod w asemblerze
  • Opcje kompilacji i konsolidacji


  • Opis zabezpieczenia
    Jeżeli mamy już zarejestrowany program, to musimy coś zrobić, żeby znowu był niezarejestrowany. Teleport umieszcza swoje dane o rejestracji w następującym kluczu rejestru (można to łatwo wykryć regmonem):

    HKEY_CURRENT_USER\SOFTWARE\Tennyson Maxwell\Teleport Pro\User

    Teraz wystarczy coś zmienić w wartościach Name lub Registration (Company nie ma znaczenia), i program znowu będzie UNREGISTERED.
    Program ten łamie się bardzo szybko za pomocą debugera SI. Opiszę to teraz w wielkim skrócie. Uruchamiamy Teleport. Wchodzimy do Help/Register. Wypełniamy pola dowolnymi danymi, np. zoomek/Seven Team/012345. Zakładamy pułapkę na funkcji GetWindowTextA (bpx getwindowtexta). Wciskamy OK. Jesteśmy w SI (pobranie Name). Dajemy F5 i znowu lądujemy w SI (pobranie Company), F5 i ponownie jesteśmy w SI (pobranie seriala). Wciskamy F10 aż zobaczymy linię:
    :00425648 3945E8 CMP[EBP-18],EAX
    Dalej już nie wciskamy. Wpisujemy ?eax i mamy prawidłowy serial na nasze Name (hex i dec). Naszym zadaniem jest jednak stworzenie keygeneratora na dowolne Name.

    Uruchamiamy W32Dasm'a i disassemblujemy plik Pro.exe. Po disassemblacji klikamy na przycisk String Data References, i szukamy podejrzanego komunikatu. Po drodze znajdujemy komunikat informujący o tym, że wpisaliśmy błędne dane: "We're sorry! The registration number you entered appears to".
    Znajdujemy wreszcie coś konkretnego: "Thank you! Your copy of Teleport Pro is now registered. Al". Klikamy to dwa razy i dostajemy:

    * Possible StringData Ref from Data Obj ->"User"
    |
    :00425632 BE88A94700 mov esi, 0047A988
    :00425637 0F8406010000 je 00425743
    :0042563D FFB7D5000000 push dword ptr [edi+000000D5]
    :00425643 E890090000 call 00425FD8<--ważny call (PROCEDURKA GENERACJI SERIALA)
    :00425648 3945E8 cmp dword ptr [ebp-18], eax<-- porównanie prawidłowego seriala z tym wpisanym przez nas
    :0042564B 59 pop ecx <-- pobranie ecx ze stosu
    :0042564C 753A jne 00425688<-- skok jeśli nieprawidłowy serial
    :0042564E A174B34700 mov eax, dword ptr [0047B374]
    :00425653 8945F0 mov dword ptr [ebp-10], eax

    * Possible Reference to String Resource ID=07152: "Thank you! Your copy of Teleport Pro is now registered. Al"
    |
    :00425656 68F01B0000 push 00001BF0<-- tu lądujemy
    :0042565B 8D4DF0 lea ecx, dword ptr [ebp-10]

    Jak widać pod adres 00425648 można było od razu skoczyć (Goto/Goto Code Location) wykorzystując poprzednią metodę złamania z SI.
    UWAGA!!!!!! W zależności od wersji build listing może wyglądać nieco inaczej, ale różnice te nie są zbytnio istotne (dotyczą m.in. adersów jumpów i calli, ale nie tylko). Ja sprawdzałem dla wersji build 933 i 1107(najnowsza - tą tutaj opisuję) i różnią się. Wersja 1.29 build 1107 jest obecnie do pobrania na stronie www.tenmax.com.
    Klikamy na call 00425FD8 (podświetli się na zielono) i wciskamy przycisk Execute Call. Dostajemy:

    :00425FD8 57 push edi<-- tu lądujemy POCZĄTEK PROCEDURY GENERACJI SERIALA
    :00425FD9 8B7C2408 mov edi, dword ptr [esp+08]<-- wpisanie Name do edi
    :00425FDD 85FF test edi, edi
    :00425FDF 7409 je 00425FEA
    :00425FE1 57 push edi
    :00425FE2 E879560000 call 0042B660<-- call_pom POMOCNICZY
    :00425FE7 59 pop ecx
    :00425FE8 EB02 jmp 00425FEC
    ............
    :00425FEC 83F805 cmp eax, 00000005<-- czy Name >= 5 chars?
    :00425FEF 7304 jnb 00425FF5<-- skok jeśli Name < 5 chars
    ............
    :00425FFE 85FF test edi, edi
    :00426000 7409 je 0042600B
    :00426002 57 push edi
    :00426003 E858560000 call 0042B660<-- call_pom
    :00426008 59 pop ecx
    :00426009 EB02 jmp 0042600D
    ............
    :00426020 8BC6 mov eax, esi<-- prawidłowy serial jest kopiowany do eax
    :00426022 5E pop esi
    :00426023 5B pop ebx
    :00426024 5F pop edi
    :00426025 C3 ret<-- KONIEC PROCEDURY GENERACJI SERIALA

    Teraz klikamy na call 0042B660( podświetli się na zielono) i wciskamy przycisk Execute Call. Dostajemy:

    :0042B660 8B4C2404 mov ecx, dword ptr [esp+04]<-- tu lądujemy POCZĄTEK PROCEDURY call_pom
    * Possible Reference to Dialog: DialogID_00CA, CONTROL_ID:0003, "Autoconfigure"
    |
    :0042B664 F7C103000000 test ecx, 00000003
    :0042B66A 7414 je 0042B680
    ............
    :0042B6D1 8D41FC lea eax, dword ptr [ecx-04]
    :0042B6D4 8B4C2404 mov ecx, dword ptr [esp+04]
    :0042B6D8 2BC1 sub eax, ecx
    :0042B6DA C3 ret<-- KONIEC PROCEDURY call_pom

    Pełny listing wyciętych, ważnych części kodu umieściłem w pliku rip.txt (dołączony do tutoriala). Cechą charakterystyczną jest tutaj, że wygenerowany serial jest tylko i wyłącznie na podstawie Name, a nie zależy wogóle od tego co wpiszemy do pola Company, a sama procedura generowania seriala jest "idealnie wycięta" z W32Dasm'a (no może z niewielkimi przeróbkami kosmetycznymi).


    Keygen - stworzenie głównego okna programu w edytorze zasobów
    Uruchamiamy Ms Visual C++. Wybieramy File/New i w oknie, które się pojawi wybieramy zakładkę Files. Następnie wybieramy Resource Template i w polu File name wpisujemy nazwę pliku zasobów z rozszerzeniem .res, ja wpisałem tp.res. W polu Location podajemy ścieżkę dostępu, gdzie ma być umieszczony ww plik. Wybieramy Insert/Resource. W oknie, które się pojawi wybieramy Dialog (okienko dialogowe)i klikamy dwukrotnie na IDD_FORMVIEW. Pojawia się nam piękne okienko. Usuwamy z niego element TODO: layout formview (Select & Cut). Kliknijmy na Dialog prawym przyciskiem i wybierzmy Properties. W oknie Language wybieramu Neutral. Klikając na Dialog dwukrotnie otrzymujemy okienko z jego właściowościami: Dialog Properties. Ustawiamy tam w zakładkach odpowiednie dane: Zakładka General: w polu ID wpisujemy 1, w polu Caption: "Teleport pro V1.29 keygenerator by zoomek", w polu X Pos:10, a w polu Y Pos: 10; Zakładka Styles: zaznaczamy: Title bar, System menu i Minimize box, w polu Styles wybieramy : Popup, a w polu Border: Dialog Frame; Zakładka More Styles zaznaczamy: Absolute align, Visible, Set foreground, 3D-look, No fail create i Local Edit. Nasze operacje będą widoczne i można dostosować okno do naszych wymagań. Rozciągamy okienko dialoge do odpowiednich rozmiarów. Z okna Controls wybieramy i umieszczamy na Dialogu dwa pola tekstowe typu Edit Box, dwa pola textowe typu Static Text i dwa przyciski typu Button. Klikamy na te elementy dwukrotnie i wpisujemy odpowiednie dane. Nie będę tego dokładnie opisywał, tylko podam numery ID poszczególnych elementów. ID Edit Box 1: 101; ID Edit Box 2: 102; ID Button 1: 1; ID Button 2: 2. Dla okienka edycyjnego Edit Box 2 należy ustawić w Properties\Styles Read-only (tylko do odczytu). Powyższe czynności mające na celu stworzenie okienka keygeneratora nie są trudne, wymagają jednak wprawy. Po wykonaniu powyższych czynności okienko naszego kegena powinno wyglądać mniej więcej tak:


    Zasoby nie są jeszcze kompletne. Trzeba dodać ikonkę programu. Klikamy na Insert/Resource i w oknie które się pojawi wybieramy Icon, następnie Import i podajemy nazwę pliku z naszą ikoną. Ja wybrałem ikona.ico . Po utworzeniu zasobu klikamy na Icon prawym przyciskiem i wybieramy Properties. W polu ID wpisujemy 103, a w polu Language wybieramy Neutral. I to już wszystko.

    Keygen - właściwy kod w asemblerze
    Jak wiadomo(lub też nie) program windowsowy, to "okno" + procedura obsługi komunikatów (wciśnięcia przycisków, pobranie textu z EDIT BOX'a , zakończenie programu,... ). Aby nie zaciemniać kodu niektóre rzeczy umieściłem w pliku tp.inc. Oto jego postać:

    
    ;deklaracje funkcji API uzytych w programie 
    Extrn	 GetModuleHandleA:PROC
    Extrn    DialogBoxParamA:PROC
    Extrn	 MessageBoxA:PROC
    Extrn	 SendDlgItemMessageA:PROC
    Extrn	 SetDlgItemTextA:PROC
    Extrn    TranslateMessage:PROC
    Extrn    ExitProcess:PROC
    Extrn    GetMessageA:PROC
    Extrn    DispatchMessageA:PROC
    Extrn    GetDlgItemTextA:PROC
    Extrn    DefWindowProcA:PROC
    Extrn    DispatchMessageA:PROC
    Extrn    GetMessageA:PROC
    Extrn _wsprintfA:PROC
    
    UINT    EQU 
    ;zmienna 4 bajtowa(32 bity),ang. Define Doubleword ULONG EQU
    ;zmienna 32 bitowa ;struktura klasy okna (Window Class Structure) WNDCLASS struc clsStyle UINT ? clsLpfnWndProc ULONG ? clsCbClsExtra UINT ? clsCbWndExtra UINT ? clsHInstance UINT ? clsHIcon UINT ? clsHCursor UINT ? clsHbrBackground UINT ? clsLpszMenuName ULONG ? clsLpszClassName ULONG ? hIconSm UINT ? WNDCLASS ends ;struktura komunikatu (message) MSGSTRUCT struc msHWND UINT ? msMESSAGE UINT ? msWPARAM UINT ? msLPARAM ULONG ? msTIME ULONG ? msPT ULONG 2 dup(?) MSGSTRUCT ends ;przyciski typu BUTTON IDD_GREETZ equ 1 IDD_EXIT equ 2 ;pola tekstowe typu EDIT BOX IDD_BOX1 equ 101 IDD_BOX2 equ 102 ;okno glowne (DIALOG) IDD_DLG equ 1 ;komunikat okna(Windows Message) WM_SETTEXT = 000Ch ;zmiana okna WM_CLOSE = 0010h ;komunikat ten jest wysylany do procedury obslugi okna wtedy gdy uzytkownik probuje zamknac okno WM_INITDIALOG = 0110h ;komunikat przesylany do procedury dialogu podczas tworzenia okna WM_COMMAND = 0111h ;operacje na obiektach sterujacych (np. BUTTON) ;Class Style CS_VREDRAW = 0001h ;okno bedzie odmalowane po kazdej zmianie jego wys. CS_HREDRAW = 0002h ;okno bedzie odmalowane po kazdnej zmianie jedo szer. CS_GLOBALCLASS = 4000h ;umozliwia tworzenie globalnych klas dostepnych dla innych aplikacji

    W kodzie głównym umieściłem wiele komentarzy pozwalających (mam taką nadzieję) zrozumieć kod. Kod programu wyglada nastepujaco (tp.asm):

    
    .386P
    Locals
    jumps
    
    include tp.inc
    
    .Model Flat, StdCall
    
    .Data
    box_1_text   db "zoomek [Seven Team]",0  ;domyslne Name 
    
    warning  db "You Name must be >= 5 chars",0 ; tresc komunikatu, gdy Name < 5 chars
    
    
    caption   db "http://www.7team.z.pl",0  ; pasek w Greetz
    
    greetz   db 'Greetz to: R!SC & all members of CrackPl',10,0
             
    
    msg     MSGSTRUCT    ;struktura komunikatu(message)
    wc      WNDCLASS     ;struktura klasy okna (Window Class Structure)
    hIce    dd 0 ;uchwyt okna
    
         	
    my_name       db 30h dup (?)       ;dla Name
    serial        db 10 dup (0)        ;dla wyliczonego seriala
    format        db "%lu",0           ;format pobrania seriala (dec)
    ;===============================================================
    .Code
     
    Start:
        jmp glowny  ;skok do glownego programu
    
    getit:          
        push    040              ;rozmiar bufora
        push    offset my_name   
        push    IDD_BOX1         
        push    hwnd             
        call    GetDlgItemTextA 
    setit:
        cmp     eax, 05         
        jl      warning_box2     ;jezeli Name lt&; 5 chars
        call    call_00425FD8   ;procedurka wyliczajaca serial
      
        
    ;wypisanie seriala w EDIT BOX 2
    print_serial_into_box_2:    
        push offset my_name
        push    0
        push    WM_SETTEXT       
        push    IDD_BOX2        
        push    hwnd             
        call    SendDlgItemMessageA
        mov     eax, 1
        jmp     WMfinish      
        
    
    ; procedurka generujaca serial wyrippowana z W32Dasm'a (rip.txt)
    
    call_00425FD8:
              push edi
              mov edi, offset my_name
              test edi, edi
              je j_00425FEA
              push edi
              call call_0042B660
              pop ecx
              jmp j_00425FEC
    
    j_00425FEA:
              xor eax, eax
    j_00425FEC:
              cmp eax, 00000005h ;sprawdzenie, czy Name >= 5 chars
              jnb j_00425FF5          
              xor eax, eax
              pop edi
              ret
    j_00425FF5:
              push ebx
              push esi
              mov esi, 5DFEE4A4h
              xor ebx, ebx
    j_00425FFE:
              test edi, edi
              je j_0042600B
              push edi
              call call_0042B660
              pop ecx
              jmp j_0042600D
    j_0042600B:
              xor eax, eax
    j_0042600D:
              add eax, 00FFFFFFFCh
              cmp ebx, eax
              jnb j_00426020
              xor esi, dword ptr [ebx+edi]
              test bl, 40h
              je j_0042601D
              inc ebx
    j_0042601D:
              inc ebx
              jmp j_00425FFE
    
    j_00426020:
              mov eax, esi
              pop esi
              pop ebx
              pop edi
              
              ;pobranie zawartosci rejestru eax (w odpowiednim formacie) do my_name
              push eax 
              push offset format 
              push offset my_name 
              call _wsprintfA 
              ;odtworzenie zawartosci rejestru eax (sprytne!)
              pop eax 
              pop eax 
              pop eax
    
              ret
    
    call_0042B660:
    
              mov ecx, offset my_name
              test ecx, 00000003h
              je j_0042B680
    j_0042B66C:
              mov al, byte ptr [ecx]
              inc ecx
              test al, al
              je j_0042B6B3
                                   
              test ecx, 00000003h
              jne j_0042B66C
              add eax, 00000000h
    
    j_0042B680:
              mov eax, dword ptr [ecx]
              mov edx, 007EFEFEFFh
              add edx, eax
              xor eax, 00FFFFFFFFh
              xor eax, edx
              add ecx, 00000004h
              test eax, 81010100h
              je j_0042B680
              mov eax, dword ptr [ecx-04]
              test al, al
              je j_0042B6D1
              test ah, ah
              je j_0042B6C7
              test eax, 00FF0000h
              je j_0042B6BD
              test eax, 00FF000000h
              je j_0042B6B3
              jmp j_0042B680
    
    j_0042B6B3:
              lea eax, dword ptr [ecx-01]
              mov ecx, dword ptr [esp+04]
              sub eax, ecx
              ret
    
    j_0042B6BD:
              lea eax, dword ptr [ecx-02]
              mov ecx, dword ptr [esp+04]
              sub eax, ecx
              ret
    
    j_0042B6C7:
              lea eax, dword ptr [ecx-03]
              mov ecx, dword ptr [esp+04]
              sub eax, ecx
              ret
    
    j_0042B6D1:
              lea eax, dword ptr [ecx-04]
              mov ecx, dword ptr [esp+04]
              sub eax, ecx
              ret
    
    warning_box2:
        push    offset warning   ;zabezpieczenie przed Name < 5 chars
        push    0
        push    WM_SETTEXT
        push    IDD_BOX2
        push    hwnd
        call    SendDlgItemMessageA
        mov     eax, 1
        jmp     WMfinish
    
    ;===============================================================
    
    glowny:             ;glowne okno
        push    0
        call    GetModuleHandleA
        mov     [hIce], eax ;pobranie uchwytu okna
    
        ;wypelnienie pol struktury okna
        mov     [wc.clsStyle], CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS
        mov     [wc.clsLpfnWndProc], offset WndProc
        mov     [wc.clsCbClsExtra], 0
        mov     [wc.clsCbWndExtra], 0
        mov     eax, [hIce]
        mov     [wc.clsHInstance], eax
    
        push    0              
        push    offset Main_DlgProc    
        push    0
        push    IDD_DLG
        push    [hIce]
        call    DialogBoxParamA
        jmp     finish
    
    ;glowna procedura        
    Main_DlgProc proc hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
    
        push    ebx
        push    esi
        push    edi
        
        ;sprawdzenie jaka message i odpowiednia reakcja(skok)
        cmp     [wmsg], WM_COMMAND      
        jz      WMcommand
        cmp     [wmsg], WM_INITDIALOG   
        jz      WMinit
        cmp     [wmsg], WM_CLOSE        
        jz      WMdlgdestroy
        mov     eax, 0
    
    WMfinish:
        pop     edi
        pop     esi
        pop     ebx
        ret
    
    ;petla obslugi komunikatow
    msg_loop:
    
        push    0
        push    0
        push    0
        push    offset msg
        call    GetMessageA
    
        cmp     eax, 0
        jz      end_loop
    
        push    offset msg
        call    TranslateMessage
    
        push    offset msg
        call    DispatchMessageA
    
        jmp     msg_loop
    
    end_loop:
        push    [msg.msWPARAM]
        call    ExitProcess
    
    Main_DlgProc    endp
    
    
    ;procedura obslugi komunikatow
    WndProc proc hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
        push    esi
        push    edi
        push    ebx
    
    defwndproc:
        push    [lparam]
        push    [wparam]
        push    [wmsg]
        push    [hwnd]
        call    DefWindowProcA
    
    finish:
        pop     ebx
        pop     edi
        pop     esi
        ret
    
    WndProc          endp
    
    
    
    WMgreetz:             
        push    0
        push    offset caption
        push    offset greetz
        push    0
        call    MessageBoxA
        mov     eax, 1
        jmp     WMfinish
    
        
    WMinit:          
        push    offset box_1_text
        push    0
        push    WM_SETTEXT
        push    IDD_BOX1
        push    hwnd
        call    SendDlgItemMessageA
    
        jmp     getit   
    
    
    WMcommand:
        cmp     [wparam], IDD_GREETZ           ; wcisnieto przycisk Greetz
        jz      WMgreetz
        cmp     word ptr [wparam],IDD_BOX1     ; zmiana textu w EDIT BOX 1
        jz      getit
        cmp     [wparam], IDD_EXIT             ; wcisnieto przycisk Exit 
        jz      WMdlgdestroy
    
        mov     eax, 0
        jmp     WMfinish
        
    WMdlgdestroy:
        call    ExitProcess
    
    End Start
    


    Opcje kompilacji i konsolidacji
    Aby nie wpisywać odpowiednie linie komend za każdym razem kiedy chcemy dokonywać kompilacji lub konsolidacji najlepiej jest stworzyć plik z rozszerzeniem .bat. Wygląda on następująco:

    @echo off
    tasm32 /mx /m3 /z /q tp
    tlink32 -x /Tpe /aa /c tp,tp,,import32.lib,,tp.res
    Del tp.obj
    :End




    ©Copyright by zoomek@interia.pl 2000
    Wszelkie prawa zastrzeżone!