Iczelion’s tutorial N°24
Windows Hooks

Data

by "Death_Reaver"

 

01/06/2005

UIC's Home Page

Published by Quequero

…un giorno saremo tutti senza catene

Grazie!

Speriamo che non nevichi!

....

Home page (se presente):NADA

E-mail: [email protected]

Nick, UIN, canale IRC/EFnet frequentato

....

Difficoltà

( )NewBies (*)Intermedio (*)Avanzato ( )Master

 

 

Introduzione

Un bel giorno decisi di imparare a programmare in assembler. Girando sulla rete inceppai nei FAVOLOSI tutorial di Iczelion sulla programmazione a 32 bit in assembler, non quei pallosi programmi stile dos ma finalmente dialog, finestre ecc.

Pultoppo, andando avanti, notai che la traduzione in italiano arrivava fino al 23 su un totale di 35. Tra i non tradotti c’era anche qualcosa di veramente interessante per il reversing (tipo le DebugApi).

Poi mi sono detto: L’inglese lo conosco percui facciamo un favore alla nazione e traduciamo questi cavolo di tutorial. Questo fu l’inizio…

 

Tools usati

ALLEGATO (codice sorgente + eseguibile già compilato)

MASM32 v.8 sp1 (nella sezione tools)

RadAsm (IDE perfetto per programmare in asm)

 

Notizie sul programma

In questo tutorial impareremo ad utilizzare gli hook (letteralmente “ganci”) nelle nostre applicazioni.

 

Essay

 Teoria:

 I Windows Hooks possono essere considerati una delle caratteristiche più potenti di windows. Con essi, si può "agganciare" eventi che accadono in un nostro processo o in altri. Con l' "Hooking" dici a windows di una funzione, chiamata filter function (funzione di filtro) o "hook procedure", che verrà chiamata ogni volta che l'evento a cui siamo interessati accade.

Ci sono due tipi di Hook: LOCAL HOOK e REMOTE HOOK.

1)LOCAL HOOK agganciano un evento che avviene in un nostro processo

2)REMOTE HOOK agganciano un evento che avviene in altri processi. Ce ne sono due tipi:

 

Thread-Specific, i quali agganciano eventi che avvengono in uno specifico thread. In poche parole, li userai quando vuoi osservare un evento in uno specifico thread, in un processo specifico.

 

system-wide, che agganciano tutti gli eventi che avvengono in qualsiasi thread di qualsiasi processo nel sistema

 

Quando installi degli hooks, ricordati che pesano sulla performance del sistema. I System-Wide sono i più instabili. Quando gli eventi scelti passeranno per la nostra filter function, in nostro computer può rallentare di molto. Perciò se decidi di usare i System Hook, dovresti usarli con giudizio e sganciarli appena non ti servono più.

 

Inoltre, c'è una grande possibilità di crash quando entri in conflitto con altri processi e se ci sono errori nella filter function. In questo caso con esso possono terminare anche altri processi. RICORDA: IL POTERE VA USATO CON RESPONSABILITA'

 

Prima di usarli con efficienza, dobbiamo capire bene come funzionano gli hook. Quando crei un hook, windows crea una struttura di dati in memoria contenente informazioni dell'hook, e la aggiunge a una linked-list (lista collegata) dove sono presenti tutti gli hook. Il nuovo hook sarà aggiunto davanti agli altri. Quando l'evento scelto accade, se installi un LOCAL HOOK, sarà chiamata la filter-function del processo e così via. Ma, se c'è un REMOTE HOOK, il sistema deve sistemare il codice per l'hook nell' address space degli altri processi. E il sistema lo può fare solo se la funzione (filter-function) risiede in una DLL, perciò, se vuoi usare un REMOTE HOOK, la tua hook procedure deve stare in una DLL. Ci sono solo due eccezioni: JOURNAL RECORD e JOURNAL PLAYBACK HOOKS. La hook procedure di questi due hooks deve risiedere nel thread che li installa. I motivi sono che tutti e due gli hook trattano con intercettazioni di basso livello degli eventi dell'input dell'hardware. Gli eventi di input devono essere registrati/riavviati nell'ordine in cui appaiono. Se il codice è in una DLL, gli eventi di input potrebbero espandersi in altri thread ed è impossibile conoscerne l'ordine. La soluzione sarebbe di mettere la procedura di hook di questi due in un singolo thread, ovvero il thread che li installa.

Ci sono 14 tipi di hooks:

 

WH_CALLWNDPROC, chiamato quando è chiamato un SendMessage

WH_CALLWNDPROCRET, chiamato quando un SendMessage ritorna

WH_GETMESSAGE, chiamato quando è chiamato un GetMessage o un PeekMessage

WH_KEYBOARD, chiamato quando GetMessage o PeekMessage restituiscono WM_KEYUP o  WM_KEYDOWN alla coda di messaggi

WH_MOUSE, quando GetMessage o PeekMessage danno un qualsiasi messaggio del mouse

WH_HARDARE, quando GetMessage o PeekMessage danno un altro messaggio hardware che non sia della tastiera o del mouse

WH_MSGFILTER, chiamato quando in una dialogbox, un menù o una scroll-bar stanno processando un messaggio. Questo hook è locale. E' specifico per gli oggetti che hanno un message-loop interno

WH_SYSMSGFILTER, come sopra, solo che è system-wide

WH_JOURNALRECORD, chiamato quando windows restituisce un messaggio dalla coda degli hardware input

WH_JOURNALPLAYBACK, chiamato quando un evento è richiesto dalla coda di sistema degli hardware input

WH_SHELL, chiamato quando succede qualcosa di interessante riguardo la shell come quando la task-bar ha bisogno di ridisegnare i suoi pulsanti.

WH_CBT usato specialmente per i computer-based training

WH_FOREGROUNDIDLE, usato internamente a windows. Poca utilità per applicazioni classiche

WH_DEBUG, usato per debugare la hooking procedure.

 

Adesso che conosciamo un di teoria, possiamo osservare come si installano/disinstallano gli hooks.

Per installare un hook, si usa SetWindowsHookEx:

                                                                                    

SetWindowsHookEx PROTO HookType:DWORD, pHookProc:DWORD, hInstance:DWORD, ThreadID:DWORD

 

 

Se la chiamata ha successo, eax conterrà l'handle dell' hook. Altrimnti eax sarà NULL. Devi salvare l'handle per "sganciare" l'hook più tardi.

 

Puoi sganciare un hook chiamando UnhookWindowsHookEx, che prende solo un parametro, l'handle dell'hook che vuoi sganciare. Se la chiamata riesce, eax sarà !=0 altrimenti sarà NULL. Adesso che sai come agganciare/sganciare gli hook, possiamo esaminare la hook procedure. La hook procedure verrà chiamata ogni volta che si presenterà l'evento con coi è stata associata. Per esempio, se installi un WH_MOUSE, quando si presenta un evento da mouse, la hook procedure verrà chiamata. Indipendentemente dal tipo di hook, la hook procedure ha sempre la seguente forma:

 

<nome> proto nCode:DWORD, wParam:DWORD, lParam:DWORD

 

 

Il significato di nCode, lParam, wParam dipende dal tipo di hook installato. Anche il valore di ritorno varia, per esempio:

 

WH_CALLWNDPROC

-nCode può essere solo HC_ACTION, che ci dice che c'è un messaggio mandato a una finestra

-wParam contiene il messaggio che è stato mandato

-lParam punta a una struttura CWPSTRUCT

-valore di ritorno non è usato, è zero

WH_MOUSE

-nCode può essere HC_ACTION o HC_NOREMOVE

-wParam contiene il messaggio del mouse

-lParam punta a una struttura MOUSEHOOKSTRUCT

-valore di ritorno zero se il messaggio deve essere processato, 1 se il messaggio sarà scartato

 

Per avere ulteriori informazioni sul significato dei parametri e dei valori di ritorno, cercare nella vostra guida API.

 

Ricorda che gli hook sono legati a una linked-list, dove, l'hook più recente è in testa. Quando arriva l'evento, windows chiamerà il primo hook della catena. La responsabilità di chiamare l'hook seguente è della tua hook procedure. Puoi scegliere di non chiamare l'hook seguente, ma sarebbe meglio conoscere quello che stai facendo. La maggior parte delle volte è bene fare pratica chiamando la hook-procedure seguente, in modo che gli altri hook possano avere il proprio turno. Per chiamare l'hook successivo si usa CallNexHookEx che ha il seguente prototipo:

 

CallNextHookEx proto hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD

 

 

RICORDATE: la hook procedure deve risiedere in una DLL che sarà mappata negli altri processi. Quando windows mappa la DLL nei processi, non mapperà la sezione dati. In poche parole, tutti i processi si condividono una singola copia di codice (hook procedure) ma hanno ognuno la propria DLL nella sezione dati. Puo essere una brutta sorpresa per gli incauti. Potresti pensare che quando metti un valore in una variabile di una DLL, quel valore sarà condiviso tra tutti i processi che la importano nel loro process-space. Ma non è vero. Nelle situazioni normali, questo comportamento è desiderabile in quanto dà l'illusione che ogni processo abbia la propria DLL. Ma non quando ci sono di mezzo gli hook. Noi vogliamo che la DLL sia UGUALE per tutti i processi, inclusi i dati. SOLUZIONE: bisogna "marcare" la sezione come "condivisa". Puoi farlo specificando gli attributi di sezione della fase di link. Per il masm si :

 

/SECTION:<section name>, S

 

Il nome dei dati inizializzati è .data e quelli dei dati non-inizializzati è .bss. Per esempio, se vuoi creare una DLL che contenga una hook procedure e vuoi che la sezione di dati non-inizializzati sia condivisa, devi linkare con la seguente riga:

 

link /section:.bss,S  /DLL  /SUBSYSTEM:WINDOWS ..........

"S" ci dice che la sezione è condivisa

ESEMPIO

Ci sono due moduli: quello principale si occupa della GUI e la DLL installa/disistalla gli hooks

;--------------------------------------------- Programma principale--------------------------------------

.386

.model flat,stdcall                               (se volete risparmiarvi tutto questo, usate il mio personale include file allegato Death_Reaver.inc)

option casemap:none

 

include \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

 

include mousehook.inc

includelib mousehook.lib

 

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

 

wsprintfA proto C :DWORD,:DWORD,:VARARG

wsprintf TEXTEQU <wsprintfA>

 

.const

IDD_MAINDLG                   equ 101

IDC_CLASSNAME              equ 1000

IDC_HANDLE                     equ 1001

IDC_WNDPROC                 equ 1002

IDC_HOOK                         equ 1004

IDC_EXIT                           equ 1005

 

WM_MOUSEHOOK             equ WM_USER+6

 

DlgFunc PROTO :DWORD,:DWORD,:DWORD,:DWORD

 

.data

HookFlag dd FALSE

HookText db "&Hook",0

UnhookText db "&Unhook",0

template db "%lx",0

 

.data?

hInstance dd ?

hHook dd ?

 

.code

start:

    invoke GetModuleHandle,NULL

    mov hInstance,eax

    invoke DialogBoxParam,hInstance,IDD_MAINDLG,NULL,addr DlgFunc,NULL

    invoke ExitProcess,NULL

 

DlgFunc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

 

    LOCAL hLib:DWORD

    LOCAL buffer[128]:byte

    LOCAL buffer1[128]:byte

    LOCAL rect:RECT

    .if uMsg==WM_CLOSE

        .if HookFlag==TRUE

            invoke UninstallHook

        .endif

        invoke EndDialog,hDlg,NULL

    .elseif uMsg==WM_INITDIALOG

        invoke GetWindowRect,hDlg,addr rect

        invoke SetWindowPos, hDlg, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW

    .elseif uMsg==WM_MOUSEHOOK

        invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128

        invoke wsprintf,addr buffer,addr template,wParam

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer

        .endif

        invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128

        invoke GetClassName,wParam,addr buffer,128

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer

        .endif

        invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128

        invoke GetClassLong,wParam,GCL_WNDPROC

        invoke wsprintf,addr buffer,addr template,eax

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer

        .endif

    .elseif uMsg==WM_COMMAND

        .if lParam!=0

            mov eax,wParam

            mov edx,eax

            shr edx,16

            .if dx==BN_CLICKED

                .if ax==IDC_EXIT

                    invoke SendMessage,hDlg,WM_CLOSE,0,0

                .else

                    .if HookFlag==FALSE

                        invoke InstallHook,hDlg

                        .if eax!=NULL

                            mov HookFlag,TRUE

                            invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText

                        .endif

                    .else

                        invoke UninstallHook

                        invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText

                        mov HookFlag,FALSE

                        invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL

                        invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL

                        invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL

                    .endif

                .endif

            .endif

        .endif

    .else

        mov eax,FALSE

        ret

    .endif

    mov eax,TRUE

    ret

 

DlgFunc endp

end start

 

;----------------------------------------------------- Codice della DLL--------------------------------------

 

.386

.model flat,stdcall

option casemap:none

 

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib

 

.const

WM_MOUSEHOOK equ WM_USER+6

 

.data

hInstance dd 0

 

.data?

hHook dd ?

hWnd dd ?

 

.code

DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD

 

    .if reason==DLL_PROCESS_ATTACH

        push hInst

        pop hInstance

    .endif

    mov  eax,TRUE

    ret

 

DllEntry Endp

 

MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD

 

    invoke CallNextHookEx,hHook,nCode,wParam,lParam

    mov edx,lParam

    assume edx:PTR MOUSEHOOKSTRUCT

    invoke WindowFromPoint,[edx].pt.x,[edx].pt.y

    invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0

    assume edx:nothing

    xor eax,eax

    ret

 

MouseProc endp

 

InstallHook proc hwnd:DWORD

 

    push hwnd

    pop hWnd

    invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL

    mov hHook,eax

    ret

 

InstallHook endp

 

UninstallHook proc

 

    invoke UnhookWindowsHookEx,hHook

    ret

 

UninstallHook endp

 

End DllEntry

 

;---------------------------------------------- MakeFile per la DLL----------------------------------------------

 

NAME=mousehook

$(NAME).dll: $(NAME).obj

        Link /SECTION:.bss,S  /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm\lib $(NAME).obj

$(NAME).obj: $(NAME).asm

        ml /c /coff /Cp $(NAME).asm

 

Analisi:

L'esempio mostrerà una dialog-box con tre edit-control che andranno riempiti con il nome della classe, l'handle della finestra e l'indirizzo della windows-procedure associata alla finestra su cui è posato il cursore del mouse. Ci sono due pulsanti: "Hook" e "Exit". Quando si preme il pulsante "Hook" il programma aggancia l'input del mouse e il testo del pulsante cambia in "UnHook" (sgancia). Quando si muove il cursore sopra una finestra, le informazioni sulla finestra saranno mostrate sulla finestra principale del nostro programma. Quando si preme il pulsante "UnHook", il programma rimuove l'hook. Il programma principale usa una dialog-box come sua finestra. inoltre si definisce un messaggio personalizzato, WM_MOUSEHOOK che sarà usato come tramite tra il programma e la hook-DLL. Quando il programma riceve tale messaggio, wParam contiene l'handle della finestra dove è il cursore. Naturalmente usare wParam è stata una decisione arbitraria. Ho deciso di mettere l'handle in wParam per semplicità. Puoi scegliere il tuo metodo di comunicazione tra il programma e la hook-DLL a piacere.

 

.if HookFlag==FALSE

              invoke InstallHook,hDlg

              .if eax!=NULL

                  mov HookFlag,TRUE

                  invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText

              .endif

 

 

 

 

 

 

 

Il programma definisce un flag,HookFlag, per monitorare lo stato dell'hook. E' FALSE se l'hook non è installato e è TRUE se l'hook è installato. Quando un utente preme il pulsante "Hook" il programma controlla se l'hook è già stato installato. Se non lo è, chiama la funzione InstallHook della DLL per installarlo. Nota che passiamo l'handle della dialogbox principale come parametro della funzione cosichè la hook-DLL possa inviare i WM_MOUSEMOVE alla giusta finestra, cioè la nostra.

Quando il programma è caricato, anche la hook-DLL è caricata. Le DLL sono caricate in memoria immediatamente dopo il programma principale. La funzione di entry-point della DLL è chiamata prima della prima istruzione del programma principale. Perciò quando il programma esegue la DLL, essa è già inizializzata. Noi abbiamo messo il seguente codice nella funzione di entry della hook-DLL:

 

   .if reason==DLL_PROCESS_ATTACH

        push hInst

        pop hInstance

    .endif

 

 

 

 

 

Il codice salva la sua l'instance handle in una variabile globale chiamata hInstance per usarla nella funzione InstallHook. Finchè la funzione di entry della DLL è chiamata prima delle altre funzioni, hInstance è sempre valida. Abbiamo messo hInstance nella sezione .data? in modo che sia utilizzabile da tutti i processi. Quando il cursore del mouse punta su una finestra, la hook-DLL è mappata nel processo. Immagina che ci sia già una DLL che occupa l'indirizzo di mappatura della hook-DLL, in questo caso la hook-DLL potrebbe essere rimappata in un altro indirizzo. Il valore di hInstance sarà aggiornato con il nuovo indirizzo. Quando l'utente preme il pulsante UnHook e successivamente Hook, SetWindowsHookEx sarà chiamato di nuovo. Però questa volta userà il nuovo indirizzo come instance handle che sarà sbagliato poiché nell'esempio l'indirizzo di mappatura della hook-DLL non è stato cambiato. L'hook diventerà un hook locale dove puoi agganciare solo gli eventi del mouse della tua finestra. Situazione poco desiderabile.

 

InstallHook proc hwnd:DWORD

    push hwnd

    pop hWnd

    invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL

    mov hHook,eax

    ret

InstallHook endp

 

 

 

 

 

 

 

 

La funzione InstallHook è molto semplice. Salva l'handle della finestra, passato come suo parametro, in una variabile globale chiamata hWnd per uso futuro. Quindi chiama SetWindowsHookEx per installare un mouse-hook. Il valore di ritorno di SetWindowsHookEx viene messo in un altra variabile globale chiamata hHook per poterla poi usare con UnhookWindowsHookEx. Dopo che SetWindowsHookEx è chiamata, il mouse-hook è funzionante. Quando si verificherà un evento da  mouse nel sistema, è chiamata MouseProc (la tua procedura di hook).

 

MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD

    invoke CallNextHookEx,hHook,nCode,wParam,lParam

    mov edx,lParam

    assume edx:PTR MOUSEHOOKSTRUCT

    invoke WindowFromPoint,[edx].pt.x,[edx].pt.y

    invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0

    assume edx:nothing

    xor eax,eax

    ret

MouseProc endp

 

 

 

 

 

 

 

 

 

 

 

La prima cosa che fa è chiamare CallNextHookEx per dare agli altri hook la possibilità di processare l'evento del mouse. Dopodichè chiama la funzione WindowFromPoint per prendere l'handle della finestra che è a specifiche coordinate. Notare che usiamo una struttura POINT nella struttura MOUSEHOOKSTRUCT (puntata da lParam) come coordinate attuali del mouse. Poi, mandiamo l'handle al programma principale con PostMessage con il messaggio WM_MOUSEHOOK. Una cosa da ricordare: Non dovresti usare SendMessage dentro la hook-procedure, essa infatti può causare il blocco del messaggio. PostMessage è raccomandato. La struttura

MOUSEHOOKSTRUCT è definita sotto:

 

MOUSEHOOKSTRUCT STRUCT DWORD

  pt            POINT <>

  hwnd          DWORD      ?

  wHitTestCode  DWORD      ?

  dwExtraInfo   DWORD      ?

MOUSEHOOKSTRUCT ENDS

 

 

 

 

 

 

 

 

Quando la finestra principale riceve WM_MOUSEHOOK, usa l'handle in wParam per prendere informazioni dalla finestra.

.elseif uMsg==WM_MOUSEHOOK

        invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128

        invoke wsprintf,addr buffer,addr template,wParam

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer

        .endif

        invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128

        invoke GetClassName,wParam,addr buffer,128

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer

        .endif

        invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128

        invoke GetClassLong,wParam,GCL_WNDPROC

        invoke wsprintf,addr buffer,addr template,eax

        invoke lstrcmpi,addr buffer,addr buffer1

        .if eax!=0

            invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer

        .endif

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Pen non commettere errori, controlliamo che il testo che è nelle editbox sia uguale a quello da immettere. Se è uguale, passiamo avanti.

Prendiamo il nome della classe chiamando GetClassName, l'indirizzo della windows-procedure chiamando GetClassLong con GCL_WNDPROC e quindi le formattiamo e le mettiamo nei propri edit controls.

    invoke UninstallHook

     invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText

     mov HookFlag,FALSE

     invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL

     invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL

     invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL

 

 

 

 

 

 

 

Quando l'utente preme il tasto "UnHook", il programma chiama la funzione UninstallHook dalla hook-DLL. UninstallHook chiama solo UnHookWindowsHookEx. Dopodichè cambia il testo del pulsante di nuovo in "Hook", HookFlag in FALSE e pulisce il contenuto delle edit-controls

Lo switch del linker nel makefile:

 

Link /SECTION:.bss,S  /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS

 

Specifica la sezione .bss come sezione condivisa per fare in modo che tutti i processi condividano la stessa sezione non-inizializzata della hook-DLL. Senza questo switch, la tua hook-DLL non funzionerebbe.

DEATH_REAVER

Note finali

Prima di tutto ringrazio Iczelion. Senza di lui non avreste letto questo tutorial (l’avete fatto vero?)

Poi ringrazio Quequero, Zero_G e tutti gli appassionati della programmazione in Win32asm

Disclaimer

Vorrei ricordare che il software va comprato e  non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo che ogni sviluppatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Reversiamo al solo scopo informativo e per migliorare la nostra conoscenza del linguaggio Assembly.

PS Se qualcuno continua a dire che il VB o il Java ecc ecc ecc sono meglio dell’assembler sappia che lo sta facendo a suo rischio e pericolo