Zoom Icon

Creare Keygen Originali

From UIC Archive

Skinning Delle Finestre

Contents


Creare Keygen Originali
Author: Kry0rath
Email: [email protected]
Website:
Date: 01/01/2010 (dd/mm/yyyy)
Level: Luck and skills are required
Language: Italian Flag Italian.gif
Comments:



Introduction

In questo tutorial, andremo a creare una finestra avente forma e sfondo da noi deciso (cioè il cosiddetto "skinning" della finestra)

Prima di tutto creeremo una generifa finestra in Win32, poi ci staccheremo un attimo dalla programmazione dedicandoci alla grafica :P ed infine metteremo tutto insieme, aggiungendo anche qualche pulsantino per rendere la nostra finestra simile a quelle dei crackme/keygen delle varie crew in circolazione :D



Tools

Notepad++ o un qualcunque altro editor di testo

Ci servirà per scrivere il codice :P

FASM

L'assembler che uso e che consiglio. Naturalmente potete usarne altri, ma a quel punto la traduzione delle varie direttive spetta a voi.

Un programma per disegnare

QUi la scelta è ampia, dal paint di windows a Photoshop e derivati. Io uso di solito la suite di CorelDraw, ma come ho detto la scelta è soggettiva, ne va bene qualunque possa salvare in bitmap puro (.BMP)

Creatore Regioni

Un resource compiler

Ovvero il programmino che da resource script (.RC) ci dà la versione compilata e pronta al linking (.RES).

Potete scegliere quello che vi aggrada di più, se non sapete quale prendere, usate questo: GoRC

Guida API

Conoscienza dell'assembly (e del FASM magari)

Conoscienza della programmazione Win32


ALLEGATO



Essay


PARTE [1] -> Creazione della finestra generica


Bene Iniziamo:

Allora, apriamo il nostro editor di testo e iniziamo col creare una generica finestra in win32 (Nel sito ci sono tutorial a riguardo, altrimenti potete vedere anche il sito di Iczelion)

Quindi: Format PE GUI 4.0 entry start

Con questo, indicheremo al linker interno del fasm il formato di file in output (Win32) e che l'EntryPoiny del programma sarà all'etichetta start include "C:\FASM\INCLUDE\WIN32A.INC"

Includiamo il file win32a.inc che contiene alcune macro utili per velocizzare la scrittura del codice e per evitare di scriversi i descrittori dell'IT a mano (cosa che il fasm permette di fare ;) ) section "import" import data readable

library kernel32,"kernel32.dll",\ user32,"user32.dll",\ gdi32,"gdi32.dll"

include "C:\FASM\INCLUDE\API\kernel32.inc" include "C:\FASM\INCLUDE\API\user32.inc" include "C:\FASM\INCLUDE\API\gdi32.inc"

Ecco a voi la prima sezione che scriveremo: la cosiddetta sezione .idata (che per comodità ho chiamato "import"), alla quale ho attivato il flag di lettura

Per informazioni su l'uso di library e import vi rimando al sito del FASM.

Scriviamo ora una sezione per i dati: section "dativari" data readable writeable

Classname db "SkinClass",0

wc WNDCLASSEX sizeof.WNDCLASSEX,\ CS_BYTEALIGNWINDOW + CS_BYTEALIGNCLIENT,\ WndProc,0,0,\ 0,\ 0,0,\ 0,\ 0,Classname,0 msg MSG

hInst dd 0 hwnd dd 0 himg dd 0

Come vedete, la sezione si chiama dativari, contiene dati generici e è leggibile e scrivibile.

Naturalmente c'è la struttura WNDCLASSEX inizializzata con i membri di cui abbiamo già il valore, una struttura MSG per la gestione dei messaggi e un pò di dword per handle vari.

Ora cominciamo a esaminare il codice della prima parte: section "codice" code readable executable start: push 0 call [GetModuleHandle]

mov dword [hInst],eax mov dword [wc.hInstance],eax

push IDC_CROSS push 0 call [LoadCursor] mov dword [wc.hCursor],eax

push IDI_APPLICATION push 0 call [LoadIcon] mov dword [wc.hIcon],eax mov dword [wc.hIconSm],eax

mov dword [wc.hbrBackground],COLOR_WINDOW

push wc call [RegisterClassEx] or eax,eax jz endofall

Dunque, con questo primo frammento, creiamo la sezione per il codice (chiamata appunto "codice") con permessi per la lettura ed esecuzione.

Nel codice vero e proprio, chiamiamo GetModuleHandle per ottenere l'instance handle del nostro programma e depositiamo tale valore sia nella variabile hInst che nella struttura WNDCLASSEX

Quindi, Riempiamo gli altri membri di WNDCLASSEX con LoadIcon, LoadCursor e sistemando temporaneamente (visto che successivamente lo cambieremo) il valore COLOR_WINDOW al membro hbrBackground

Riempita così la struttura WNDCLASSEX, la passiamo a RegisterClassEx controllando poi che sia tutto ok (risultato diverso da 0)

PS. Ricordatevi che il FASM, quando incontra il nome di un dato senza parentesi quadre o altre forme esplicite, intende l'indirizzo di quella variabile

Proseguiamo col codice: push 0 push dword [hInst] push 0 push 0 push 250 push 250 push 300 push 300 push WS_VISIBLE or WS_SYSMENU or WS_CAPTION or WS_BORDER push Classname push Classname push 0 call [CreateWindowEx]

or eax,eax jz endofall

mov dword [hwnd],eax

msgloop: push 0 push 0 push 0 push msg call [GetMessage]

or eax,eax jz endofall

push msg call [TranslateMessage] push msg call [DispatchMessage] jmp msgloop

endofall: push 0 call [ExitProcess] nop

Avendo registrato la classe, adesso possiamo creare la finestra, e lo facciamo con CreateWindowEx e memorizzando l'handle dentro la variabile hwnd

Notate che come stile di finestra, per ora, abbiamo importato WS_VISIBLE or WS_SYSMENU or WS_CAPTION or WS_BORDER. Anche questo successivamente andrà cambiato

Dopo la creazione della finestra e la verifica di successo (or eax,eax è uno dei mille metodi per verificare se eax==0) scriviamo il generico ciclo di gestione di messaggi. (Se siete estranei a ciò, vi rimando ad altri tutorial :P)

Ora è tutto pronto per la WndProc. Eccola qui di seguito: WndProc: label .hwnd at ebp+8 label .msg at ebp+0Ch label .wParam at ebp+10h label .lParam at ebp+14h

enter 0,0

mov eax,dword [.msg]

cmp eax,WM_DESTROY jnz @f push 0 call [PostQuitMessage] jmp .end @@: push dword [.lParam] push dword [.wParam] push dword [.msg] push dword [.hwnd] call [DefWindowProc] leave ret 10h

.end: xor eax,eax leave ret 10h

A parte la dichiarazione delle label che è un mio tipico modo di fare (potete anche usare proc....endp per dichiarare funzioni e parametri), qui gestiamo il solo messaggio WM_DESTROY.

A questo punto la prima parte è finita. Assemblate il tutto, eseguite e avrete una piccola finestra semplicissima.


PARTE [2] -> Grafica!

Accantonate temporaneamente l'editor e prendete il vostro programma di grafica.

Quello che dobbiamo fare è creare un immagine bitmap delle dimenzioni della nostra finestra. La cosa importante è che L'immagine deve avere come sfondo un colore che differisca il più possibile dall'immagine stessa. Cioè se volessimo fare qualcosa sul verde-nero, consideriamo l'ipotesi di mettere come sfondo un colore quale il rosso o il magenta come sfondo.

In ogni caso, se volete un consiglio, per evitare di modificare l'immagine e ricompilare 500 volte, lo sfondo consiglio di farlo di colori come il bianco o il nero, cosicchè i bordi dell'imamgine, se sfumati, non presenteranno inesteticità evidenti....vi invito comunque a fare prove e vedere il colore più adatto per ogni situazione

Altra cosa che come detto, dobbiamo decidere, è la dimenzione. Io in questo tutorial utilizzerò le dimenzioni 600x600, ma potete scegliere qualunque dimenzione, l'importante è che utilizziate la stessa sia per la grandezza della finestra in CreateWindowEx sia per quanto riguarda l'immagine.

QUindi, ecco di seguito quello che ho fatto io, le dimenzioni sono come ho detto, 600 pixel per 600 pixel

Skin k0h.jpg

Come vedere, lo sfondo è nero, mentre i colori usati nell'immagine spaziano dal bianco al blu.

Assicuratevi di aver salvato in bitmap, quidni prendete il Region Creator, caricate l'immagine e, scrivete nei campi Red, Green e Blue i valori RGB del colore usato come sfondo (in decimale). (Se non sapete dove prenderli, buttate questo tutorial e andate a funghi :D ...oppure studiatevi il vostro programma di grafica )

Se tutto vi è filato liscio a questo punto avremo il file .rgn (al quale farò riferimento col nome region).


Parte [3] -> File delle Risorse

Ebbene si, dobbiamo inserire nell'eseguibile sia il file bitmap che la region, e per farlo ci serviremo di un classico resource script (.rc)

Volendo potremo prendere qualche editor specifico per il lavoro che faremo tra poco, ma per 2 righe contante non vedo vantaggi :D

Dunque, create un nuovo file, dategli l'estenzione .rc e apritelo col vostro editor e scriviamo le seguenti righe: (sostituite i nomi dei file bitmap e region con i vostri)

401 BITMAP "skin.bmp" REGION RGN "skin.rgn"

Se conoscete un minimo di script RC, come dovreste, potete modificarvelo a piacimento

Salvate il tutto e passatelo al resource compiler e otterrete così il file di risorse compilato e pronto all'uso. (.res)


Parte [4] -> Cambiamo Sfondo

Ed è arrivato il momento di far prendere forma al nostro progetto: cominciamo col sostituire allo sfondo della finestra, il file bitmap che abbiamo inserito nelle risorse

Riaprite il file .asm e aggiungiamo a fine file una sezione per le risorse

section "res" resource from "rsrc.res" data readable

Questa riga dice al FASM di utilizzare il file rsrc.res per le risorse. (Cambiate il nome del file col vostro se diverso)

Ora per sicurezza potete assemblare e verificare con ResHack o CFF se le risorse che abbiamo aggiunto ci sono effettivamente.

Prima di continuare, ecco praticamente quello che faremo:

Per impostare come sfondo la nostra bitmap, per prima cosa dichiariamo una nuova variabile per l'handle della bitmap: hbmp dd 0

Dopodichè, carichiamo la bitmap in memoria con LoadBitmap:

push 401 ; lo stesso ID usato nel file rc push dword [hInst] call [LoadBitmap] mov dword [hbmp],eax

Così facendo avremo in eax l'handle della bitmap.

Adesso dobbiamo far vedere la bitmap al programma come fosse il brush da usare per disegnare lo sfondo della finestra. A questo scopo usiamo CreatePatternBrush: push eax call [CreatePatternBrush]

Come risultato, in eax avremo l'handle del nuovo brush.

Quello che ci rimane da fare è quindi inserire l'handle ottenuto dentro il membro hbrBackground della struttura WNDCLASSEX, al posto di COLOR_WINDOW.

Ricapitolando, risaliamo nel codice scritto fino a questo punto: push IDI_APPLICATION push 0 call [LoadIcon] mov dword [wc.hIcon],eax mov dword [wc.hIconSm],eax

mov dword [wc.hbrBackground],COLOR_WINDOW

push wc call [RegisterClassEx] or eax,eax jz endofall

Applicando quello che ho detto sopra, diventerà: push IDI_APPLICATION push 0 call [LoadIcon] mov dword [wc.hIcon],eax mov dword [wc.hIconSm],eax

;------------da qui

push 401 push dword [hInst] call [LoadBitmap]

mov dword [hbmp],eax

push eax call [CreatePatternBrush]

mov dword [wc.hbrBackground],eax

;-------------a qui

push wc call [RegisterClassEx] or eax,eax jz endofall

Altra cosa da aggiungere è la distruzione della bitmap quando chiudiamo il programma. La cosa più normale da fare risulta chiamare DeleteObject' in risposta a WM_DESTROY, poco prima della chiamata a PostQuitMessage. Il codice quindi prenderà questo aspetto: cmp eax,WM_DESTROY jnz @f push dword [hbmp] call [DeleteObject]

push 0 call [PostQuitMessage] jmp .end

Salvate, compilare e avrete la vostra finestra che come sfondo ha la vostra bitmap :D


Parte [5] -> Skinniamo!

Ora il succo del discorso: lo skinning vero e proprio.

Quello che faremo è scrivere è scrivere una funzione chiamata SkinWindow che caricherà la region, contenuta nelle risorse, in memoria e l'adatterà e applicherà alla finestra.

Per iniziare, aggiungiamo le seguenti variabili: restype db "RGN",0 resname db "REGION",0

hrgn dd 0

La prima non è altro che il tipo di risorsa (vedere il file rc), la seconda è il nome che abbiamo dato alla region (ancora, vedere il file rc), mentre la terza è una varibabile (globale) che useremo per memorizzare l'handle della regione una volta che sarà pronta all'uso.

Poi, andiamo alla chiamata di CreateWindowEx e cambiamo lo stile in WM_POPUP, ovvero: push 0 push dword [hInst] push 0 push 0 push 600 push 600 push 0 push 0 push WS_VISIBLE or WS_POPUP ;cioè una finestra visibile e senza bordature varie push Classname push Classname push 0 call [CreateWindowEx]

Ricordiamoci che avendo applicato lo stile WM_POPUP non avremo pulsanti di chiusura: dovremo chiudere la finestra con ALT+F4 !!

Ora, andiamo nel codice appena dopo la WndProc e cominciamo a scrivere:

SkinWindow:

label hres1 at ebp-4 label hres2 at ebp-8 label ressize at ebp-0Ch

enter 0Ch,0

push restype push resname push 0 call [FindResource] mov dword [hres1],eax

Iniziamo a commentare: prima di tutto, ci sistemiamo le label per 3 dword che ci serviranno come variabili locali.

l'istruzione enter ci eviterà di scrivere quello che normalmente andrebbe scritto come: push ebp mov ebp,esp sub esp, 0Ch

La prima chiamata a funzione che facciamo è FindResource, che ci permette a partire da un tipo di risorsa e un nome, di ottenere un identificatore per la risorsa cercata. (Lo 0 indica che la risorsa è nel modulo usato per creare il processo, cioè alla fine dei conti, il nostro file .exe)

Memorizziamo il valore che ci viene restituito nella variabile locale hres1

Poi, ;in eax c'è il risultato di FindResource push eax ;attenzione, questo è il secondo parametro di LoadResource!

push eax push 0 call [SizeofResource] mov dword [ressize],eax

push 0 call [LoadResource] mov dword [hres2],eax

push eax call [LockResource]

push eax push dword [ressize] push 0 call [ExtCreateRegion] mov dword [hrgn],eax

Chiamiamo in seguenza SizeofResource per ottenere la grandezza in bytes del file region, LoadResource per caricare tutto in memoria, LockResource per ottenere il puntatore alla region in memoria e ExtCreateRegion per adattare i dati della region ai nostri usi (Date uno sguardo alla guida API per maggiori informazioni)

Ecco il finale della funzione:

push 1  ;ridisegnare tutto? yes push eax  ;risultato di ExtCreateRegion push dword [hwnd] call [SetWindowRgn]

push dword [hres1] ;chiudiamo tutti gli handle rimasti aperti call [CloseHandle]

push dword [hres2] call [CloseHandle]

push dword [hrgn] call [CloseHandle]

leave ret

Tutto viene infine applicato con una chiamata a SetWindowRgn

Quello che ci rimane da fare per completare questo passo è di far fare al programma una chiamata a questa funzione. Una buona idea è quella di metterla appena dopo creata la finestra cioè:

or eax,eax jz endofall

mov dword [hwnd],eax

call SkinWindow ;->>>>>>>>>>> QUI !

msgloop: push 0 push 0 push 0 push msg call [GetMessage]

Ora salvate assemblate e godetevi il risultato....ma sappiate che ancora non è finita :P


PARTE [6] -> Muovimi!


...Non è finita perchè infatti abbiamo una finestra, ma non ha pulsanti di chiusura, ne possibilità di muoverla.

In questa parte ci occuperemo del movimento della finestra.

Il concetto che useremo sarà il seguente: faremo in modo che, ogni volta che "trascineremo" dentro la finestra, essa pensi che il puntatore del muose sia in realtà sulla caption della finestra (cioè sulla barra del titolo), cosicchè windows la muova a nostro piacimento :D

Per fare questo, dovremo tornare nella WndProc e far gestire 'WM_LBUTTONDOWN:

(per semplificare, eccovi tutta la WndProc)

WndProc: label .hwnd at ebp+8 label .msg at ebp+0Ch label .wParam at ebp+10h label .lParam at ebp+14h

enter 0,0

mov eax,dword [.msg]

cmp eax,WM_DESTROY jnz @f push dword [hbmp] call [DeleteObject]

push 0 call [PostQuitMessage] jmp .end @@: cmp eax,WM_LBUTTONDOWN jnz @f push dword [.lParam] push 2 push WM_NCLBUTTONDOWN push dword [.hwnd] call [SendMessage] jmp .end @@: push dword [.lParam] push dword [.wParam] push dword [.msg] push dword [.hwnd] call [DefWindowProc] leave ret 10h

Come potete vedere, appena ci arriva un messaggio di tipo WM_LBUTTONDOWN, noi ne rispediamo un altro con SendMessage, più precisamente, mandiamo un WM_NCLBUTTONDOWN (per esteso, Non Client Left Button Down). A questo messaggio mandiamo ome wParam il valore HTCAPTION (che è uguale a 2) e come lParam la struttura POINT che indica la posizione del mouse e che già abbiamo dentro lParam stesso.

Salvate, assemblare e provate a trascinare :D


Parte [7] -> E chiudiamola!

Certo, chiudere la finestra con ALT+F4 non è che sia proprio eccezionale come cosa...per questo aggiungeremo un piccolo pulsantino che ci permetterà di chiudere tutto

Dobbiamo prima aggiungere 3 variabili:

btnclass db "Button",0 btntitle db "[X]",0 hXbtn dd 0

La prima è la il nome della classe standard per i pulsanti, la seconda è il testo che metteremo nel pulsante (originale eh?) e la terza è dove andremo a depositare l'handle del pulsante

Per comodità, aggiungiamo una nuova funzione, che chiamerò CreaControlli, nella quale creeremo tutti i controlli di cui abbiamo bisogno (per ora è solo un pulsante ma lascio a voi la fantasia :P)

La funzione non contiene altro che chiamate a CreateWindowEx, eccovela: CreaControlli: push 0 push dword [hInst] push 1 ; essendo un controllo, al posto di hmenù va messo l'ID che vogliamo per il controllo push dword [hwnd] ;qui va l'handle del parent, cioè la finestra principale in questo caso push 18 ;altezza push 22 ;larghezza push 10 ;coordinata y push 500 ;coordinata x push WS_VISIBLE or BS_FLAT or WS_CHILD ;attenzione! deve avere lo stile WS_CHILD!! push btntitle ;testo push btnclass ;classe push 0 call [CreateWindowEx] mov dword [hXbtn],eax ;memorizziamo dentro la variabile hXbtn ret

Dopo creato, il pulsante va fatto funzionare (comunque prima di ciò, vi invito a assemblare e eseguire per vedere se il pulsante viene creato). Per far ciò è inutile dire che aggiungeremo la gestione del messaggio WM_COMMAND nella WndProc:

(la rimetto tutta di nuovo) WndProc: label .hwnd at ebp+8 label .msg at ebp+0Ch label .wParam at ebp+10h label .lParam at ebp+14h

enter 0,0

mov eax,dword [.msg]

cmp eax,WM_DESTROY jnz @f push dword [hbmp] call [DeleteObject]

push 0 call [PostQuitMessage] jmp .end @@: cmp eax,WM_LBUTTONDOWN jnz @f push dword [.lParam] push 2 push WM_NCLBUTTONDOWN push dword [.hwnd] call [SendMessage] jmp .end @@: cmp eax, WM_COMMAND jnz @f mov eax,dword [.lParam] cmp eax,dword [hXbtn] jnz .end

push 0 push 0 push WM_DESTROY push dword [.hwnd] call [SendMessage]

jmp .end @@: push dword [.lParam] push dword [.wParam] push dword [.msg] push dword [.hwnd] call [DefWindowProc] leave ret 10h

.end: xor eax,eax leave ret 10h

Appena riceviamo il WM_COMMAND, verifichiamo che l'handle del controllo (che ci arriva da lParam) sia quello del nostro pulsante. Se è il nostro pulsantino, mandiamo con SendMessage un bel WM_DESTROY alla finestra :D

Attenzione: se volete fare le cose bene, verificate anche che la word alta di wParam sia uguale a BN_CLICKED prima di chiamare SendMessage

Salvate, assemblate e godetevi la vostra finestra....per ora :P


Parte [8] -> Alla moda!

Ebbene si, la trasparenza delle finestre è alla moda...o così dicono :P

Mettiamola anche noi nella nostra finesta, è semplicissimo.

Per prima cosa, cambiate gli Exstyle della finestra (primo parametro) in WS_EX_LAYERED, poi chiamiamo SetLayeredWindowAttributes per impostare la trasparenza: push 0 push dword [hInst] push 0 push 0 push 600 push 600 push 0 push 0 push WS_VISIBLE or WS_POPUP push Classname push Classname push WS_EX_LAYERED call [CreateWindowEx]

or eax,eax jz endofall

mov dword [hwnd],eax

push LWA_ALPHA ; ci basiamo sul canale alpha (da 0 a 255) push 7Fh ; indovinate qual'è la metà di 255 ;P push 0  ; il nero come base va sempre benissimo push eax ; handle della finestra call [SetLayeredWindowAttributes]

Fatto, salvate, compilate et voilà!

Ora potete anche cambiare il valore 7Fh in qualcos'altro per regolare la trasparenza, o magari aggiungere una scrollbar o un paio di pulsanti per farla cambiare a runtime!



Note Finali

Ringrazio tutta la UIC, e in particolare tutte le brave persone che mi faranno notare, o che correggeranno, errori grammaticali e sbiforchiate vari :D


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.