Zpět na seznam článků     Číst komentáře (4)     Verze pro tisk

Cracking4neWBies - Lekce č.18

Autor: DjH   
20.10.2007

Cracking pro začátečníky...poosmnácté :-)


Cracking4neWBies

Lekce č.18

Keygenning po druhé



Balík zde

Už se kolem CrackMe ze stránek Programujte.com a hry 3D Live Pool motáme pořád do kola, co říkáte? Víceméně se jedná o naučný seriál, a ne o nějakou „Jak se stát warezmanem“ :). Ale nebojte, postupně si toho crackneme více. Ale teďka se opět podíváme na CrackMe z první lekce, a vytvoříme si na něj keygen :). Pokusíme se o keygen v MASMu i v Delphi.
Nejdříve ale zapátráme, jak se vlastně s/n vypočítávalo:

00401167 . 33C0 XOR EAX, EAX //EAX=0
00401169 . 33C9 XOR ECX, ECX
//ECX=0
0040116B . A1 D3304000 MOV EAX, DWORD PTR DS:[4030D3]
//do EAX dej to, co je v EDITu (první 4 znaky)
00401170 . B9 5A415244 MOV ECX, 4452415A
//ECX=4452415Ah
00401175 . 33C1 XOR EAX, ECX
//Vyxoruj EAX s ECX
00401177 . 33D2 XOR EDX, EDX
//vynuluj EDX
00401179 . BB 77770100 MOV EBX, 17777
//EBX=17777h
0040117E . F7F3 DIV EBX
//vyděl EBX
00401180 . 35 86140000 XOR EAX, 1486
//Vyxoruj EAX s 1486h
00401185 . /75 1E JNZ SHORT crackme_.004011A5
//Jestli není s/n správné skoč na badboy
00401187 . |6A 00 PUSH 0
00401189 . |68 CC304000 PUSH crackme_.004030CC 
0040118E . |68 6A304000 PUSH crackme_.0040306A………

Oživíme si trochu paměť z první lekce:
Jak může fungovat funkce DIV jen s jednou zdrojovou proměnnou? Stačí se mrknout do IronScrewa popisu ASM instrukcí (v balíku), a zjistíte, že DIV přesně znamená (a používá se…):
DIV zdroj - AL:=AX div zdroj; AH:=AX mod zdroj

kde 
- DIV – početní operace; dělení bez lomítka
- MOD – početní operace, která zjistí zbytek po dělení

Tudíž, už v první lekci bylo řečeno:
Libovolné číslo z intervalu <1E19D44A, 1E1B4BC0> stačí xornout hodnotou 4452415Ah a vyjde nám číslo, které převedeme odzadu na ASCII a vyjde nám správný string…
Proč takový interval jsem taky vysvětloval:
1E19D44A – toto je vlastně 1486h * 17777h…
1E1B4BC0 – toto je 1E19D44A + 17776h, takový může být vlastně maximální zbytek v EDX, který s hodnotou 1486h v EAX nemá nic společného.

Stačí tedy deklarovat číslo 1E19D44Ah a k tomu přičíst hodnotu „Random($17777);“ (Delphi - $17776 ne, protože čísla v závorce se stejně nikdy nedosáhne, maximální číslo je tedy $17777 – 1, tedy $17776, mohli bysme tedy napsat $17776 + 1 ale je to zbytečné :)), no a tuto hodnotu xornout 4452415Ah a pomocí vkládaného assembleru vypsat string. Keygen v Delphi by vypadal asi takto:

program Keygen;
uses
Windows,DjH;

var
    Serial :int64;
//sn musi byt int64, aby mel pro sebe 8bytu (integer ma 4, a nemel by ukonceny string hexnulou)
   
PtrSn :pointer; //Pointer na Serial (push addr serial)
 
   Caption:pchar; //Caption MsgBoxu
begin
    Randomize;
    Caption := 'Keygen4CMe1-Programujte.com';
    serial := ((($1E19D44A) + Random($17777)) xor $4452415A);
    PtrSn := Addr(Serial);
asm
    push 0
    push caption
    push PtrSn
    push 0
    call messagebox
end;
end.


Po každém spuštění se Vám zobrazí platné sériové číslo. To ale může obsahovat i neplatné znaky, zkusíme si tedy ještě přidat kontrolu každého bajtu:

program Keygen;
uses
Windows,DjH;

var
    Serial :int64;
//sn musi byt int64, aby mel pro sebe 8bytu (integer ma 4, a nemel by ukonceny string hexnulou)
    PtrSn :pointer; //Pointer na Serial (push addr serial)
   
Caption:pchar; //Caption MsgBoxu
   
label start; //pozn. autora:
begin //JNGE cíl (je menší)
    Randomize; //JNLE cíl (je větší)
start:
    Caption := 'Keygen4CMe1-Programujte.com';
    serial := ((($1E19D44A) + Random($17777)) xor $4452415A);
    PtrSn := Addr(Serial);
asm
    push edi
    xor edi,edi

//########################################//
@az: 
    cmp byte ptr ds:[serial+edi], 'a' 
    jnge @@AZ 
@az2: 
    cmp byte ptr ds:[serial+edi], 'z' 
    jnge @dale2 

//########################################//
@@AZ: 
    cmp byte ptr ds:[serial+edi], 'A' 
    jnge @09 
    @@AZ2: 
    cmp byte ptr ds:[serial+edi], 'Z' 
    jnge @dale2 

//########################################//
@09: 
    cmp byte ptr ds:[serial+edi], '0' 
    jnge start 
@092: 
    cmp byte ptr ds:[serial+edi], '9' 
    jnge @dale2 

//########################################//
    pop edi 
    jmp start 

//########################################//
@dale2:
    inc edi
    cmp edi, 3
    jnz @az
    pop edi
end;

asm
    push 0
    push caption
    push PtrSn
    push 0
    call messagebox
  end;
end.


Jak vidíte, musíme začít kontrolovat od znaku s největší ASCII hodnotou, a postupně je zmenšovat. Největší ASCII hodnotu mají ‚a‘ – ‚z‘, potom je ‚A‘ – ‚Z‘ a nakonec ‚0‘ – ‚9‘. Pokud je v serialu nalezen byť jeden neplatný ASCII znak, vygeneruje se nové s/n a kontrola se provádí znovu, dokud neprojde v pohodě všemi kontrolami. Podobným způsobem bysme mohli udělat keygen i s oknem a tlačítkem „Generate“, ale myslím, že stačí že je v balíku, je to velmi obdobné a vypisovali bysme pořád dokola ten stejný kód. V balíku je i „Bruteforcer“. Není to sice přesný název, ale dejme tomu… V balíku jsou dva:
1. uloží do souboru VŠECHNY platná s/n (i s netisknutelnými znaky)
2. uloží do souboru jen ty, která mají znaky tisknutelné…

Nyní si uděláme keygen v MASM. V Delphi už jsme „nakousli“ tuto část vkládaným assemblerem. Jestli používáte WinAsm studio (v 12. balíku) vytvořte si nový project s dialogem. Na dialog si dejte jeden button(ID_BTN – id=100) a jeden editbox(ID_EDT – id = 102). Po kliku na ID_BTN bude tato operace:

; --------------------------------------------------
; Po kliku na OK
; --------------------------------------------------
call hash
invoke SetDlgItemText, hWin, ID_EDT , ADDR serial ;nastavi SNtext na SN


Kde hash, je tato funkce:


hash:

;randomize:
    ADD ESP, -8
    PUSH ESP
;/pPerformanceCount
    CALL QueryPerformanceCounter ;\QueryPerformanceCounter
    TEST EAX, EAX
    JE lbl1
    MOV EAX, DWORD PTR SS:[ESP]
    MOV DWORD PTR DS:[rndprom], EAX
    POP ECX
    POP EDX
    jmp rnd
lbl1:
    CALL GetTickCount
;[GetTickCount
    MOV DWORD PTR DS:[rndprom], EAX
    POP ECX
    POP EDX

rnd:
    mov eax, 17777h

;call random:
    XOR EBX, EBX
    IMUL EDX, DWORD PTR DS:[EBX+rndprom], 8088405h
    INC EDX
    MOV DWORD PTR DS:[EBX+rndprom], EDX
    MUL EDX
    MOV EAX, EDX

    add eax, 1E19D44Ah
    xor eax, 4452415Ah

    mov dword ptr ds:[serial], eax

    xor edi,edi


;//########################################//
@az: 
    cmp byte ptr ds:[serial+edi], 'a' 
    jnge @@AZ 
@az2: 
    cmp byte ptr ds:[serial+edi], 'z' 
    jnge @dale2 

;//########################################//
@@AZ: 
    cmp byte ptr ds:[serial+edi], 'A' 
    jnge @09 
@@AZ2: 
    cmp byte ptr ds:[serial+edi], 'Z' 
    jnge @dale2 

;//########################################//
@09: 
    cmp byte ptr ds:[serial+edi], '0' 
    jnge rnd 
@092: 
    cmp byte ptr ds:[serial+edi], '9' 
    jnge @dale2 

;//########################################//
    jmp rnd 
;//########################################//
@dale2:
    inc edi
    cmp edi, 3
    jnz @az
ret


Kompletní kód je samozřejmě v balíku :). Co se týče funkce Randomize a Random(x);. Tyto funkce jsem, jak jinak, zjistil z DeDe, stačí si dekompilovat unitu System.dcu. Pokud chcete mít IntToStr, StrToInt atd. v MASMu, není problém si je tam takto přidat, vždyť je to vlastně assembler, a ten prostě fungovat musí…všude (třeba ‚Randomize‘ z Delphi funguje („dumplá“) v MASM…).
PS: Tento keygen vytvořený v MASM má 3kB (3072b). UPX ho zkomprimovat už nedokáže, ale Upack ano, po zkomprimování Upackem, má program 1,46kB (1500b)!!!
Ještě můžeme do rozpoznávání uMsg dosadit tento řádek:
.elseif uMsg == WM_INITDIALOG ;API - OnCreate ;)
call hash
invoke SetDlgItemText, hWin, ID_EDT , ADDR serial
;hned po startu je v editboxu nahodny serial :)

Myslím, že není co dodat k Msg wm_initdialog.
Po spuštění Bruteru, je jedno, ať už toho, co filtruje printable chars nebo ne, všimněte si jedné věci. Správné sériové číslo je vlastně ve tvaru „xxHZ“, kde „xx“ jsou úplně libovolné tisknutelné znaky. Tedy například „00HZ“, „F8HZ“, „4ZHZ“, „ZHHZ“… Funguje i „xxIZ“, ale s čísly je to horší. Ale aspoň platí, že i v tomto případě lze za „x“ dosadit libovolné písmeno. Rázem se dostáváme asi na 1500 řešení (pomocí tisknutelných znaků, malá písmena se CMe automaticky převádějí na velká). Jinak asi na 20‘000 (!) s použitím všech znaků (tedy i netisknutelných).
Myslím si, že tento díl nebyl až tak nezajímavý, jak by se mohlo zprva zdát :)…


Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 1.67/36

1  2  3  4  5    
(známkování jako ve škole)