Corso UIC Newbies 06 Omikron
From UIC
Corso UIC Newbies 06 Omikron
Contents |
| Infos | |
|---|---|
| Author: | Omikron |
| Email: | |
| Website: | Home page |
| Date: | 15-21/09/2000 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | |
Tools
- Softice oppure OllyDbg v1.10
- Regmon
- Regedit (Lo trovate nella cartella Windows)
Link e Riferimenti
Questo è il Corso UIC Newbies n°06 disponibile alla pagina Corsi UIC Newbies
Introduzione
Questa volta smanetteremo un pò con il registry di di Wintoast
Notizie sul Programma
Crackme a 4 livelli molto semplice basato sulla creazione di chiavi e valori nel registry di Wintoast
Essay
Come detto in precedenza questo crackme è basato su 4 livelli. Una volta risolto un livello verrà abilitato il successivo. Let's start from the top! (oggi mi sento anglofono!)
PREPARAZIONE
Prima di iniziare diamo un'occhiata alle istruzioni : "E' vietato patchare" (altrimenti che gusto c' è...), "Bisogna trovare le chiavi giuste nel registry" (ci può servire RegMon...), "i primi due livelli possono essere risolti anche senza softice" (...infatti.). Let's go on with the first level!
LIVELLO 1: Semplice chiave
Dunque, avviamo RegMon e settiamolo inserendo nel campo Process Include(s) il nome del crackme, cioè Sesto (in questo modo il RegMon ci mostrerà soltanto gli accessi al registro da parte del programma che ci interessa). Una volta fatto ciò, clicchiamo sul pulsante controlla la chiave e stiamo a vedere che succede... Ooops una messagebox ci dice che non ci siamo!. Ma noi vogliamo starci, quindi diamo un' occhiata a RegMon e vediamo che cosa ha registrato...
| Sesto | OpenKey | HKCU\AndreaGeddon | NOT FOUND |
|---|---|---|---|
| Sesto | QueryValueEx | HKCU\0xC18A3120\C:\Windows\Media\Chord.wav | NOT FOUND |
| Sesto | CloseKey | 0x63FBCC | BADKEY |
AHAHAHAHAH! Fregato!
Il programma ha tentato di aprire nel ramo HKCU (HKEY_CURRENT_USER) la chiave AndreaGeddon ma non l'ha trovata. Non disperiamo e aggiungiamola noi manualmente. Per far questo ci serve il regedit che si trova nella cartella di Windows.Per avviarlo cliccate su Start ---> Esegui , scrivete regedit e premete Invio. Ora possiamo immettere la nostra benedetta chiave. Per fare ciò, clicchiamo col tasto destro del mouse sul ramo HKEY_CURRENT_USER, selezioniamo Nuovo ---> Chiave e rinominiamola AndreaGeddon. Clicchiamo per la seconda volta sul pulsante controlla la chiave... GOOD WORK!, il primo livello è completato! Let's go on with the second one!
LIVELLO 2: Un accorgimento in più
Per il secondo livello useremo lo stesso procedimento usato per il primo. Questa volta , però, il programma cercherà la sottochiave HKCU\AndreaGeddon\1. Quindi non ci resta che aggiungerla. Dopo averla aggiunta clicchiamo sul pulsante controlla la chiave II ma una messagebox ci dice che c'è ancora qualcosa che non va! mmm... Ridiamo un' occhiata al RegMon. Ecco cosa abbiamo:
| Sesto | OpenKey | HKCU\AndreaGeddon\1 | SUCCESS |
|---|---|---|---|
| Sesto | OpenKey | HKCU\AndreaGeddon\1\2 | NOT FOUND |
Dunque, la chiave che abbiamo immesso era giusta, solo che ora ne cerca un' altra. Aggiungiamola con il solito procedimento... Fatto?... Ok!, clicchiamo di nuovo sul pulsante del secondo livello... e porca miseria, che vuole ancora !?!?!. Diamo uno sguardo al RegMon...
| Sesto | OpenKey | HKCU\AndreaGeddon\1 | SUCCESS |
|---|---|---|---|
| Sesto | OpenKey | HKCU\AndreaGeddon\1\2 | SUCCESS |
| Sesto | OpenKey | HKCU\AndreaGeddon\1\2\4 | NOT FOUND |
Cavolo!, cerca ancora una chiave, speriamo che sia l' ultima!!!. Lo scopriremo solo aggiungendola... Clicchiamo per l'ennesima sul pulsante di verifica...... COOL! ce l' abbiamo fatta. Let's go on with the third level!
LIVELLO 3: Chiave e codice
Mmmmm..... Qui le cose dovrebbero complicarsi, ma noi non disperiamo e proviamo ad usare lo stesso procedimento usato per gli altri due livelli. Avviamo il RegMon e clicchiamo sul pulsante del terzo livello... Dunque:
| Sesto | OpenKey | HKCU\AndreaGeddon\WhatIsTheMatrix | NOT FOUND |
|---|
Ok! Questa volta ha bisogno della chiave "WhatIsTheMatrix", e noi colmeremo i suoi bisogni...
Riclicchiamo sul pulsante...
| Sesto | OpenKey | HKCU\AndreaGeddon\WhatIsTheMatrix | SUCCESS |
|---|---|---|---|
| Sesto | QueryValueEx | HKCU\AndreaGeddon\WhatIsTheMatrix\WelcomeToTheRealWorld | NOT FOUND |
Mmmmm.... questa volta, state accorti, non ci chiede una chiave ma un valore (QueryValueEx). Per immetterlo, clicchiamo sul ramo WhatIsTheMatrix ---> Nuovo e, invece di selezionare chiave, selezioniamo Stringa. Per sapere il perché, dobbiamo dare un' occhiatina al nostra guida sulle API (spero che la possediate) e cercare RegQueryValueEx. La sua sintassi è:
LONG RegQueryValueEx(
HKEY hKey, // handle of key to query
LPTSTR lpValueName, // address of name of value to query
LPDWORD lpReserved, // reserved
LPDWORD lpType, // address of buffer for value type
LPBYTE lpData, // address of data buffer
LPDWORD lpcbData // address of data buffer size
);
Quello che a noi interessa è il quarto parametro. In esso viene immagazzinato il tipo di valore che viene richiesto scegliendolo tra uno dei seguenti:
| REG_BINARY | = 3 |
|---|---|
| REG_DWORD | = 4 |
| REG_DWORD_LITTLE_ENDIAN | = 4 |
| REG_DWORD_BIG_ENDIAN | = 5 |
| REG_EXPAND_SZ | = 2 |
| REG_LINK | = 6 |
| REG_MULTI_SZ | = 7 |
| REG_NONE | = 0 |
| REG_RESOURCE_LIST | = 8 |
| REG_SZ | = 1 |
Per sapere quale tipo di valore ci serve, però, il RegMon non basta e ci occorre SOFTICE. Per questo motivo, se non lo avete ancora avviato fatelo...ZzZzZzZ Fatto? Ok! Andiamo avanti. Settiamo un bel bpx RegQueryValueExA e clicchiamo sul pulsante del CrackMe... Una volta che il Sice ha poppato, premiamo F12 in modo tale da uscire dal modulo advapi32. Una volta usciti ci dovremmo ritrovare in questa parte di codice:
0040177F lea ecx, dword ptr [esp+10]
00401783 push ecx
00401784 push ebx
00401785 push 00000000 // pusha il tipo di valore
00401787 push 00000000
Possible StringData Ref from Data Obj ->"WelcomeToTheRealWorld"
00401789 push 00404444 // pusha il nome del valore
0040178E push edx
Reference To: ADVAPI32.RegQueryValueExA, Ord:0136h
0040178F Call dword ptr [00405294] // chiama la nostra funzione
00401795 test eax, eax
00401797 je 004017AE
00401799 push 00000010
Ecco! Come possiamo vedere, all' indirizzo 401785 viene pushato 00 (REG_NONE), questo sta a significare che possiamo immettere qualunque tipo di valore. Per questo abbiamo scelto il valore Stringa che risulta più comodo.
Una volta inserita la chiave con il regedit, però, il terzo livello non è ancora superato. Questo sta a significare che il valore non deve restare vuoto (WelcomeToTheRealWorld è solo il nome del valore non il suo contenuto!). Proviamo ad inserire, doppiocliccando sul valore WelcomeToTheRealWorld, una parola nel campo Valore. Riabilitiamo il breakpoint su RegQueryValueEx e clicchiamo sull' ormai consumato pulsante. Dopo che il Sice ha poppato premiamo F12 e ci ritroveremo qui:
00401797 je 004017AE // se la risposta è si salta, altrimenti nisba!
00401799 push 00000010
Possible StringData Ref from Data Obj ->"Mi spiace non sei l'eletto"
0040179B push 00404428
Possible StringData Ref from Data Obj ->"Posso solo indicarti la soglia"
004017A0 push 004043D4
004017A5 mov ecx, esi
Reference To: MFC42.Ordinal:1080, Ord:1080h
004017A7 Call 00401C2E
004017AC jmp 0040180B
Referenced by a (U)nconditional or (C)onditional Jump at Address:
00401797(C)
004017AE push edi siamo saltati qui
004017AF xor edi, edi azzeriamo edi per usarlo come contatore
Referenced by a (U)nconditional or (C)onditional Jump at Address:
004017E5(C)
004017B1 mov al, byte ptr [edi+ebx] muove uno ad uno in al i byte del
valore immesso da noi
004017B4 mov cl, byte ptr [esp+edi+18] muove uno ad uno in cl i byte letti
da una determinata locazione
004017B8 cmp al, cl // e li confronta
004017BA jne 004017E9 // se non sono uguali salta al messaggio di errore
004017BC cmp edi, 00000007 altrimenti controlla se il contatore è arrivato
a sette
004017BF jne 004017E1 // in caso contrario continua il confronto
004017C1 push 00000030
Possible StringData Ref from Data Obj ->"System Failure"
004017C30 push 004043C4
Possible StringData Ref from Data Obj ->"Sei l'eletto!"
004017C8 push 00404378
004017CD mov ecx, esi
A questo punto non ci resta che dare un'occhiata alla locazione da cui vengono presi i byte confrontati con quelli del valore immesso da noi. Per far questo scriviamo in Sice "d esp+18" e premiamo invio... Ed ecco, sotto i nostri occhi, materializzarsi la scritta "Trinityy", che sia ciò di cui abbiamo bisogno? Inseriamola con il regedit e... B O O M ! Level 3 complete!
LIVELLO 4: Chiave + codice + Algo
Finalmente siamo giunti al quarto ed ultimo livello. Dal titolo si può capire che questa volta avremo a che fare con un algoritmo che genererà il nostro valore e che probabilmente il nostro valore non sarà fisso. Non adagiamoci e vediamo cosa ci loggerà il RegMon dopo aver cliccato sul pulsante del quarto livello...
| Sesto | OpenKey | HKCU\AndreaGeddon\Sergej\Rachmaninov | NOT FOUND |
|---|
Cerca di aprire la chiave HKCU\AndreaGeddon\Sergej\Rachmaninov che noi prontamente andremo ad immettere. Riclicchiamo...
| Sesto | QueryValueEx | HKCU\AndreaGeddon\Sergej\Rachmaninov\QualBuonVento | NOT FOUND |
|---|
Settiamo un bpx RegQueryValueExA per sapere, come in precedenza, che tipo di valore occorre immettere...
00401887 lea ecx, dword ptr [esp+10]
0040188B push edi
0040188C push ecx
0040188D push esi
0040188E push 00000000 // ecco il push che ci interessa
00401890 push 00000000
Possible StringData Ref from Data Obj ->"QualBuonVento"
00401892 push 0040461C
00401897 push edx
Reference To: ADVAPI32.RegQueryValueExA, Ord:0136h
00401898 Call dword ptr [00405294]
Anche questa volta viene pushato il valore 00, quindi il nostro valore può essere di qualsiasi tipo. Sempre per comodità, creeremo un valore Stringa. Ora non ci resta che trovare quale/i valore/i potrà contenere il nostro QualBuonVento affinché il CrackMe li prenda per buoni. Come fare? Semplice, riabilitiamo il bpx su RegQueryValueExA e, dopo aver cliccato sul solito pulsante, premiamo F12 e facciamo un pò di stepping (F10).
00401898 Call dword ptr [00405294] // La nostra call
0040189E test eax, eax // è andata a buon fine ?
004018A0 je 004018B3 // si? Allora salta all'algoritmo
004018A2 push 00000010
Possible StringData Ref from Data Obj ->"E' l'ora del te?"
004018A4 push 00404608
Possible StringData Ref from Data Obj ->"Decisamente il quadro non "
004018A9 push 004045D4
004018AE jmp 00401966
Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018A0(C)
004018B3 mov edi, esimuove esi in edi dove esi = puntatore al valore
immesso da noi
004018B5 or ecx, FFFFFFFF ]
004018B8 xor eax, eax ]
004018BA xor edx, edx ]
004018BC repnz ]
004018BD scasb ] questa parte di codice verifica se la lungezza
del valore da noi immesso è diversa da 0 (in pratica
004018BE not ecx ]controlla se abbiamo immesso un valore)
altrimenti salta direttamente al messaggio di errore
004018C0 dec ecx ]
004018C1 je 004018DC ]
Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018DA(C)
004018C3 mov al, byte ptr [edx+esi] muove in al ogni byte di esi usando
edx come contatore
004018C6 mov edi, esi
004018C8 add al, dl // aggiunge ad al il contatore che parte da 0
004018CA or ecx, FFFFFFFF // prepara ecx in modo tale da riusarlo come contatore
004018CD mov byte ptr [edx+esi], al // muove in (esi + contatore) al
004018D0 xor eax, eax // azzera eax
004018D2 inc edx // incrementa il contatore
004018D3 repnz
004018D4 scasb
004018D5 not ecx
004018D7 dec ecx
004018D8 cmp edx, ecx // il contatore è inferiore alla lunghezza della stringa ?
004018DA jb 004018C3 // se la risposta è si fai ripartire il ciclo
Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018C1(C)
004018DC mov edi, esi una volta finito il ciclo muove in edi il puntatore
alla nuova stringa
004018DE or ecx, FFFFFFFF ]
004018E1 xor eax, eax ]
004018E3 xor edx, edx ]
004018E5 repnz ]
004018E6 scasb ] // e ne ricontrolla la lungezza
004018E7 not ecx ]
004018E9 dec ecx ]
004018EA je 00401902 ]
Referenced by a (U)nconditional or (C)onditional Jump at Address:
00401900(C)
004018EC mov al, byte ptr [edx+esi]muove in al , uno per volta, i byte
puntati da esi usando sempre edx come
contatore
004018EF mov edi, esi
004018F1 add bl, al // e li somma in bl
004018F3 or ecx, FFFFFFFF ]
004018F6 xor eax, eax ]
004018F8 inc edx ]
004018F9 repnz ]
004018FA scasb ] // la solita solfa
004018FB not ecx ]
004018FD dec ecx ]
004018FE cmp edx, ecx ]
00401900 jb 004018EC ]
Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018EA(C)
00401902 cmp bl, D1confronta se la somma di tutti i byte puntati da esi
immagazzinata in bl dà come risultato D1 in hex (209 in dec)
00401905 jne 0040195A se non è cosi salta al messaggio di errore,
altrimenti...
00401907 push 00000030
Possible StringData Ref from Data Obj ->"Good work Mr. Cracker"
00401909 push 004045BC
Possible StringData Ref from Data Obj ->"Elemntare Watson"
0040190E push 00404570
00401913 mov ecx, ebp
Ricapitolando:
Il nostro valore sarà esatto quando : (1° carattere + 0) + ( 2° carattere + 1) + (3° carattere + 2).... = D1h. Chiaro? A questo punto vi starete chiedendo come calcolarci il nostro valore. Innanzitutto, si potrebbe immettere direttamente come valore un carattere che corrisponda in hex a D1. Io però ho preferito splittare il D1h (ricordando l'incremento del contatore) in (64h + 0) + (68h + 1) che in decimale sarebbe (100 + 0) + (108 + 1) e corrisponde alla stringa dl. Ora non ci resta che verificare i nostri calcoli: inseriamo "dl" come valore e clicchiamo per l' ultima volta sul 4° pulsante e..... finalmente ce l'abbiamo fatta, ci vediamo al prossimo CrackMe!
BONUS : Creiamo un "RisolviCrackMe" in W32asm
Bene, bene, anche se non era richiesto ho pensato di creare un programmino che risolva il crackme al posto nostro per smanettare un pò con il W32asm e con le API di WinTozzo. Se siete interessati continuate a leggere altrimenti saltate alla note finali., ("cmp eax, interessamento - jne notefinali" giusto per restare in tema...) ma ricordate: Sapere è Potere!
Ecco il listato:
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include res.inc
include w32.inc
- DEFINIZIONI ESTERNE non presenti in W32.inc
Extrn RegCloseKey:PROC
extrn RegSetValueExA:PROC
extrn RegDeleteKeyA:PROC
HKEY_CURRENT_USER equ 80000001h
.DATA
- MESSAGGI
Testo1 db "I dati sono stati inseriti correttamente nel registro",0
captionerr db "Errore!",0
testoerr db "Impossibile inserire o eliminare i dati del CrackMe nel registro",0
caption2 db "Azzeramento riuscito!",0
testo2 db "Dati del CrackMe rimossi dal registro",0
- CHIAVI
chiave2 db "AndreaGeddon\1\2\4",0
chiave3 db "AndreaGeddon\WhatIsTheMatrix",0
chiave4 db "AndreaGeddon\Sergej\Rachmaninov",0
- VALORI
VALUEValore1 db "Trinityy",0
NOMEValore2 db "QualBuonVento",0
VALUEValore2 db "dl",0
_hWnd dd ?
hkey dd 0
done dd 0
_msg MSG ?
main:
call GetModuleHandle, NULL // Trova l'Handle del programma
mov _hinst, eax // lo immagazzina
xor eax, eax // libera eax
mov ax, IDD_DIALOG1 // carica l'handle del dialog in eax
push 0 // valore di inizializzazione (non ci interessa qiundi = 0)
push offset DlgProc // Puntatore alla procedura che si preoccupa di gestire i messaggi per il Dialog
push 0 // Non ci serve in quanto non abbiamo una finestra principale
push eax // Il Dialog che vogliamo caricare
push _hinst // L'hInst
call DialogBoxParamA // Crea il Dialog
call ExitProcess // Esce dal programma
- Il DlgProc, intercetta i messaggi per la Dialog Box
DlgProc proc STDCALL, __hwnd:DWORD, wmsg:DWORD, _wparam:DWORD, _lparam:DWORD
USES ebx, edi, esi
xor eax,eax // Azzera eax
mov ax, word ptr [wmsg] // mette il messaggio in ax
.IF ax==WM_DESTROY // se il messaggio è WM_DESTROY
jmp _wmdestroy // distruggi la finestra
.ELSEIF ax==WM_CLOSE // fai lo stesso se il messaggio è WM_CLOSE
jmp _wmdestroy
.ELSEIF ax==WM_COMMAND // se il messaggio è WM_COMMAND
jmp _wmcommand // verificane l'entità
.ENDIF
xor eax,eax
ret // Esci dal loop dei messaggi, con valore di ritorno = 0
_wmdestroy:
push 0 // valore di ritorno = 0
push __hWnd // handle della Dialog Box
call EndDialog // chiudi la finestra
call ExitProcess // Esci dal processo
mov done, 1
ret
_wmcommand:
cmp _wparam, IDC_BUTTON2 // se il pulsante premuto è il secondo
jne Risolv
call Azzera, __hwnd // chiama la routine "Azzera"
Risolv:
cmp _wparam, IDC_BUTTON1 // se il pulsante premuto è il primo
jne ripeti
call Risolvi, __hwnd // chiama la routine "Risolvi"
ripeti:
ret
DlgProc ENDP
push offset hkey puntatore al buffer che riceverà l'handle della
chiave creata
push offset chiave2 // indirizzo della chiave da creare
push HKEY_CURRENT_USER // il ramo principale da aprire
call regcreatekeya // chiama la funzione
test eax, eax se il valore di ritorno non è zero (la call non
ha avuto successo)
jne errore // salta al messaggio di errore
push hkey // pusha il buffer che contiene l'handle della chiave creata
call regclosekey // chiudila.
push offset hkey // stesso discorso di prima
push offset chiave3
push HKEY_CURRENT_USER
call regcreatekeya
test eax, eax
jne errore
push 08h // immagazzina la lunghezza in byte del valore da settare
push offset VALUEValore1 // indirizzo del valore da settare
push 01 // tipo di valore da settare
push 00 // riservato (deve essere = 0)
push offset NOMEValore1 // nome del valore
push hkey // handle della chiave creata
call regsetvalueexa // setta il valore
test eax, eax // se qualcosa è andato storto
jne errore // mostra il messaggio d'errore
push hkey
call regclosekey
push offset hkey // il procedimento si ripete per l'altra chiave
push offset chiave4
push HKEY_CURRENT_USER
call regcreatekeya
test eax, eax
jne errore
push 02h
push offset VALUEValore2
push 01
push 00
push offset NOMEValore2
push hkey
call regsetvalueexa
test eax, eax
jne errore
push hkey
call regclosekey
push MB_ICONINFORMATION // stile della MessageBox
push offset caption1 // caption
push offset testo1 // testo
push 0 // non c'è finestra principale quindi il valore = 0
call MessageBoxA // mostra il messaggio di operazione riuscita
ret
risolvi endp
push offset chiave1 // indirizzo della chiave da eliminare
push HKEY_CURRENT_USER
call regdeletekeya // eliminiamola
test eax, eax
jne errore
push MB_ICONINFORMATION
push offset caption2
push offset testo2
push 0
call MessageBoxA // eliminazione riuscita
ret
errore:
push MB_ICONSTOP
push offset captionerr
push offset testoerr
push 0
call MessageBoxA
ret
azzera endp
end main
Per quanto riguarda la compilazione del listato, fate affidamento al file Zip allegato al tute in cui troverete tutto ciò che vi serve più un' altra versione del programmino con qualche feature in più (nulla di fondamentale, però...).
Note Finali
Anche il mio secondo tutorial è terminato, sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!sigh!... ;-( Non disperate, mi rifarò vivo al più presto! Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!Alè!... :-) Scherzi a parte, fatemi sapere le vostre impressioni tanto la mia e-mail dovreste conoscerla, altrimenti provate a vedere sotto il commento di Quequero, quella strana scritta in blu vi indicherà la retta via....
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 malevoli 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.