La protezione delle versioni Trial
dei sistemi Windows NT


9/4/2000

by "Alga"

 

 

UIC's Home Page

Published by Quequero

Il primo che accese il fuoco non è da ritenere responsabile di tutti gli incendi

Jean Rostand
Le alghe all'avvicinarsi dell'estate salgono in superficie, si avvicinano alla costa e si attaccano copiose sotto i nostri nudi piedini, attirando l'attenzione di svariati tipi di pesci erbivori, nonchè lo stupore di varie famiglie di celenterati che, veloci nella loro cecità, guidati solo da qualche organo di senso, vengono a saggiare questi nuovi cibi estivi, destando in noi lo sgomento più totale e la rabbia più nera...Ma un'alga in particolare, del diametro di un centimetro, rosso scuro, liscia come una foglia di insalata e che porta vagamente la forma di una manina, si appresta ad uscire veloce dalle acque marine per poter raggiungere il più rapidamente possibile un luogo umido (perchè si sa, le alghe non hanno ghiandole sudoripare) ed impossessarsi di una copia di WinTonno 2000 da poter crackare...Finito il suo compito, la piccola alga, prima ancora di rientrare nelle familiari acque marine, si appresta a far conoscere al mondo dei mammiferi il funzionamento di una protezione che potremmo definire "originale"...Poi, tranquilla, quasi sull'orlo della disidratazione, si posa gentile sulle onde, per tornare nelle profondità marine....E risalire, forse, un giorno...Non si sa quando...Perchè è noto, le alghe NON hanno un cervello!
Beh, però un pò antipatico lo è...

Giovanna D'Arco
UIC's form   UIC's form

Difficoltà

( )NewBies ( )Intermedio ( )Avanzato ( )Master (X)Non ne ho idea

 

Questo tutorial concerne l'implementazione della protezione a tempo delle versioni trial dei sistemi operativi Windows NT. I riferimenti più dettagliati, ed i frammenti di disassemblato mostrati si riferiscono in particolar modo a Windows 2000 RC2, ma i concetti esposti sono, almeno fino a questo momento, applicabili a tutte le trial version di tutte le versioni di Windows NT.


La protezione delle versioni Trial
dei sistemi Windows NT


Written by Alga

Introduzione

Com'è noto, le alghe sono organismi vegetali, e tra i più semplici; tassonomicamente si pongono tra i protozoi e le piante superiori, ma molto più simili ai primi (dai quali si differenziano per la capacità di fotosintesi) che non alle seconde.
Quindi, sono un'organismo estremamente elementare; non aspettatevi troppo da me!

Un lavoro come quello descritto nel testo avrebbe dovuto venire eseguito avvalendosi di i386kd e due macchine collegate tramite null-modem; ciò avrebbe consentito di scoprire anche ciò che invece è rimasto inspiegato.
Ma le alghe sono pigre...si lasciano cullare dalle onde senza muovere un dito (soprattutto perchè - non so se avete mai osservato un'alga da vicino - non hanno dita; non vi dico i problemi con la tastiera...), e così quanto descritto nel testo è stato realizzato su una sola macchina, e con "gli attrezzi" descritti nella sezione "Tools".

L'esecuzione delle operazioni descritte prevede però l'uso di macchina con boot multiplo di due o più sistemi operativi con file systems compatibili.

NON ESEGUITE ALCUNA OPERAZIONE SU UNA MACCHINA SULLA QUALE SIA INSTALLATO SOLO W2000, O SULLA QUALE SIANO PRESENTI SISTEMI OPERATIVI CON FILE SYSTEMS INCOMPATIBILI, PRIMA DI AVER ULTIMATO LA LETTURA DEL TUTORIAL ED AVERE ESEGUITO LE OPERAZIONI E PRESO LE PRECAUZIONI ELENCATE NELLA SEZIONE "DISCLAIMER".

In caso contrario potreste ritrovarvi con un sistema assolutamente non più riavviabile a meno che:
1) il volume principale non sia FAT16, o abbiate un convertitore su dischetto (come quello di System Internals) abilitato in scrittura
2) non abbiate provveduto a fare delle copie di ciò che vi serve
3) non sappiate REALMENTE dove mettere le mani


AVVERTITI!

Tools usati

In generale vi occorrono

- un debugger
- un disassemblatore
- un editor esadecimale
- qualcosa che vi consenta il calcolo del checksum
- un monitor accessi al registro di sistema
- il programma "Istrial" di System Internals
- un convertitore di base/calcolatrice vi renderà, come al solito, la vita meno dura

La scelta del primo è, dovendo lavorare su una sola macchina, praticamente obbligata: SoftICE.

Per quanto riguarda il secondo, in teoria potreste scegliere tra IDA (qualunque versione), MFVDasm di Jean-Louise Seigne, e Borg2.
Quest'ultimo, mentre ha funzionato (sebbene con una lentezza esasperante) su un sistema W95, si è bloccato su NT4.

MFVDasm disassembla correttamente, ma non tiene in benchè minima considerazione la possibilità che alcuni valori esadecimali all'interno di un'eseguibile non siano istruzioni (e così, niente stringhe), sebbene lo abbia visto menzionato in qualche articolo come disassemblatore consigliato per Win32.

IDA disassembla correttamente tutto (come era d'altra parte logico aspettarsi); potete usare qualunque versione (anche la freeware), ma raccomando caldamente una di quelle che gestiscono il formato Unicode per le stringhe (semplifica il lavoro). Anche la versione demo, comunque, funzionerà.

Riguardo al calcolo di checksum, potete trovare un programma di EliCZ nella sezione Tools di questo sito.

Istrial e RegMon li trovate in System Internals, com'è noto, mentre per il convertitore c'è BaseCalc; ce n'era anche uno scritto da me, che gestiva anche shift e rotazioni, ma Quequero dice che non serve a niente...Eddai, non mi trattà male solo perchè c'ho la memoria labile :))))....Cmq considero PHOG un ottimo programma davvero...NdQuequero

URL o FTP del programma

Windows 2000 Release Candidate 2 Edizione Italiana è stato pubblicato sul CD ROM allegato al numero 106 (Gennaio 2000) di PC Professionale.
Windows NT Workstation 4.0 trial 120 giorni è stato pubblicato sul CD ROM allegato al numero 134 (Gennaio 1997) di PC Magazine.
Versioni trial da 120 giorni di Windows 2000 possono venire richieste (a pagamento) a Microsoft Italia

Notizie sul programma 

Volete davvero che vi spieghi a cosa serva un sistema operativo, e cosa si intenda per limite di tempo di una versione di prova?

Essay

Qualcuno di voi è interessato a Windows 2000? Probabilmente sì, se state leggendo questo tutorial. Oppure siete interessati solamente alla protezione?

PERCHE' LA RAM AUMENTA DI PREZZO?
Inizialmente, quando NT 5 divenne ufficialmente Windows 2000, io non ero interessata né all'uno, né all'altro aspetto; il mio interesse cominciò a destarsi quando si verificarono gli improvvisi, inaspettati ed inspiegabili (come sanno anche i sassi, il terremoto a Taiwan non ha mai avuto nulla a che vedere con ciò) incrementi di prezzo della RAM.
Poichè lo zio Bill controlla una buona percentuale delle fabbriche di chip, pensai che il tutto potesse essere scaturito dalla mente di mamma Microsoft.

Perchè, infatti, qualcuno avrebbe dovuto desiderare Windows 2000? Le recensioni "precoci" che era possibile leggere su alcune riviste (PcPlus in testa) dicevano, in pratica: fa schifo, NT4 + il Service Pack di turno è molto meglio.

Mi venne allora il sospetto che in realtà W2000 richiedesse meno risorse del suo predecessore, e questo dovrebbe divenire un buon motivo per acquistarlo; domandai un pò in giro, ed i soliti bene informati (leggi persona cha ha un amico/a che a sua volta ha un amico/a che conosce benissimo qualcuno che ha avuto una versione pre-pre-alfa in esclusiva direttamente dalla moglie di Guglielmo Cancelli) sostenevano che sì, sembrava avesse bisogno di una minore quantità di RAM.

Da qui nacque la curiosità di verificare se fosse vero.

Così sparsi la voce presso i bene informati riguardo ad una richiesta di una copia di una qualunque versione (anche pre-pre-pre-alfa) del sistema operativo, ma non ottenni un bel nulla.

NE AVEVO LE TASCHE PIENE DI WINDOWS 2000!
Così, quando, qualche mese dopo, PC Professionale pubblicò il CD con la versione detta "RC2" di W 2000, gli amici che sapevano della mia curiosità si affrettarono (la permanenza in edicola di quel numero di PC Professionale non superò la mezza giornata) ad acquistarne una copia anche per me. Oltre quella che avevo acquistato io, naturalmente.
Per non creare disparità le accettai tutte, ringraziando.
Quando tornai a casa avevo le tasche ben riempite da 4 CD di Windows 2000 RC2.

ALGA MEDIANICA
Sono in grado di leggere nel pensiero. In questo momento state pensando: e di tutto questo a noi che ce frega?
Nulla, ovviamente. Ma realmente non sono in grado di raccontare alcunchè senza condire il tutto con una miriade di particolari stupidi, irrilevanti e non attinenti.
Le alghe, si sa, non hanno cervello.

PEGGIO DEL MILLENNIUM BUG...
Arrivata a casa, mi affrettai a leggere la documentazione acclusa al CD, nella quale veniva dichiarato che il sistema operativo avrebbe cessato di funzionare dopo 444 giorni; cioè, il sistema sarebbe rimasto avviabile, ma non avrebbe funzionato per più di un'ora.
Ero esterrefatta! Molto peggio del Millennium Bug! Come era possibile che una casa seria come Microsoft mettesse in giro un prodotto con un simile difetto? Non erano stati in grado di produrne uno in grado di funzionare correttamente per più tempo?
In effetti bisogna dire che qualche tempo dopo Microsoft ha immesso sul mercato una versione (denominata, chissà perchè, "FINAL") in grado di funzionare per più tempo (in teoria, indefinitamente), ma...costa un sacco di soldi!
Ritengo che ciò sia in relazione alle risorse che hanno dovuto impegnare (ed ai conseguenti oneri che hanno dovuto sostenere) per eliminare il tremendo bug; l'avessero chiesto a me, l'avrei fatto gratis...

PUO' UN'ALGA ESSERE DEMORALIZZATA?
Bene, al lavoro, aiutiamo Microsoft a migliorare i suoi programmi.
La prima cosa che feci fu quella di andare a curiosare tra le stringhe di NTDLL.DLL. Perchè proprio NTDLL.DLL? Perchè non avevo intenzione, per il momento di installare nulla, e NTDLL.DLL era addirittura già decompresso (pigrissima Alga!).
Tra le stringhe era possibile leggere: "Avviso valutazione di Windows""Il periodo di valutazione di questa installazione di Windows è terminato..". Fortissima Alga!, pensai. Senza neanche installare...già trovato!
Caricando NTDLL.DLL in un editor esadecimale era possibile ricavare l'offset della stringa; dando un'occhiata all'header era possibile verificare che essa si trovasse effettivamente all'interno della sezione .rsrc.
A questo punto disassemblai e cercai i riferimenti all'interno del disassemblato. Niente. Beh, dopo tutto W32Dasm è carino, ma non è adatto per questo genere di lavoretti.
Disassemblai con IDA. Niente. Diedi un'occhiata alla sezione .rsrc con un decompilatore di risorse. Nessun riferimento.
Risultato: Alga demoralizzata (non più fortissima :( )

L'AGO NEL PAGLIAIO
Così, il sistema operativo, dopo la data di scadenza, avrebbe funzionato per un'ora. Ma quanti millisecondi sono contenuti in un'ora? Tremilioniseicentomila. E come si dice tremilioniseicentomila in esadecimale? 36EE80. OK, decomprimiamo WINLOGON.EXE e cerchiamo 36EE80 nel disassemblato.
Arrivai ad un segmento di codice che veniva invocato da un salto condizionale dopo una chiamata a ZWQuerySystemTime e che diceva più o meno :"Fai partire un thread in background e ponilo in Suspend per 36EE80 millisecondi..".
Ci siamo!, pensai. Installai W2000 dual boot, installai SICE 4.01 in modalità boot (con ICEPACK, driver di tastiera nuovo, etc. - una pena), misi un break point all'inizio del segmento di codice in fase di boot, e nulla successe. Durante il riavvio del sistema, reimpostai la data nel BIOS a due anni più tardi, inserii di nuovo il breakpont e finalmente...non successe nulla lo stesso! Aspettai un'ora e comparve: "Avviso valutazione di Windows: il periodo..." etc. etc.
Aspettai un'altra ora. Il sistema si bloccò mostrando un Bug Check; niente logoff e shutdown comandati dal sistema, solo il blocco totale.

OK, daccapo. Feci ripartire il tutto, brkpoint su ShowWindow, e dopo un'ora ecco la console di SICE. Con un pò di stack si risale a quello che ha originato la finestra di messaggio: NTOSKRL.EXE. Evidente. Ma da dove partiva il tutto? Lo stack non forniva alcuna informazione.

Una buona idea poteva essere quella di cercare 36EE80 in altri files. Quali? La protezione in teoria poteva essere ubicata ovunque; in un servizio, in un file qualunque utilizzato da un servizio…si sarebbe potuta eseguire una ricerca in automatico con un programma Grep…Ok, facciamolo.
Dopo aver letto sulla finestra di dialogo del programma "searching 5160 files for 36EE80…" pensai 'no, grazie, comunque troppo oneroso'.

Ma Microsoft desidera o no che questa protezione venga disattivata, e tutto il mondo usi W2000, che l'abbia regolarmente acquistato o no? Oppure non ne ha più bisogno (tanto tutto il mondo lo userà comunque), e vuole soltanto venderlo? Nel primo caso trovare la protezione (o le informazioni relative) sarebbe facile, nel secondo la protezione sarebbe difficilissima da disattivare.
Bé, comunque ditelo, e non fate perdere tempo inutile ad un'onesta cracker che ha un sacco di altre cose da fare...

DEDICATO A COLORO CHE CI CHIAMANO 'PIRATI'
Tanto la risoluzione di un enigma è appassionante (quando la natura dell'enigma è chiara e definita), quanto è noiosa la ricerca delle informazioni.
Al diavolo Microsoft e i suoi giochetti! Non mi interessava affatto avere una versione "full" di W2000 RC2; sapevo benissimo che subito dopo la presentazione ufficiale del prodotto, mi sarebbe stata fornita, in maniera assolutamente gratuita, una versione "final" originale, con licenza regolare, ed in Inglese, prima che qui cominciassero a circolare le copie pirata della versione italiana.
Così mi disinteressai del problema, e giorno 18 febbraio pomeriggio la fantasmagorica etichetta olografica del CD originale occhieggiava dal tavolo da lavoro. Ricambiai lo sguardo, ed in quel momento decisi che...mai una copia regolare di questo sistema operativo sarebbe stata installata su una macchina utilizzata da me, a qualunque titolo, se prima essa non avesse ospitato, anche per un solo giorno, la versione italiana "RC2 full cracked". Ho detto!

MARK RUSSINOVICH E BRYCE COGSWELL SONO CORRETTI, O CI PRENDONO SOLO IN GIRO?
La ricerca delle informazioni ricominciava. La sera stessa notavo che sul sito di System Internals era presente, tra gli altri, un programma denominato "Istrial". Cosa fa Istrial? Verifica se una versione di NT (qualunque versione) sia full o sia un trial, e nel secondo caso visualizza la data di scadenza.
Allora System Internals sa! E, cosa più importante, anche io saprò!
Le funzioni importate da Istrial sono essenzialmente le ADVAPI32 che riguardano il registro di sistema; quindi qualcosa è scritto lì, ed il programma lo legge. Basta allora utilizzare il RegMon che la stessa System Internals ci mette gentilmente a disposizione...
Una cosa che avevo notato, ma sulla quale non mi ero soffermata più di tanto, era un leggero ritardo nella risposta di Istrial all'avvio. Dopo aver chiesto a RegMon di salvare il log degli accessi al registro di Istrial ed avere avviato quest'ultimo, un'occhiata alle dimensioni del fle di log generato (2Megs all'incirca) chiarificò istantaneamente le ragioni della "torpidità" nella risposta all'avvio di Istrial: Istrial legge tutto il registro, per intero, prima di pronunciarsi su versione e data di scadenza del sistema operativo.
Ma che bisogno ha di leggere tutto il registro? Mascherare quale fosse la chiave realmente interessante, supposi.
Allora Russinovich e Cogswell sarebbero estremamente corretti? E ritorniamo all'ago nel pagliaio, dunque?
Disassemblando Istrial, il segmento di codice nel quale viene stabilito se il sistema operativo sia o meno una versione trial è di individuazione praticamente immediata: la locazione di memoria 407A20 (un flag), viene controllata: se il flag è resettato, la versione è full, se è settato, una data viene calcolata a partire dal contenuto delle locazioni 407BE0 e seguenti.

.text:00401356             add     esp, 0Ch
.text:00401359             xor     eax, eax
.text:0040135B             mov     al, byte_0_407A20  QUESTA QUI
.text:00401360             test    eax, eax
.text:00401362             jz      loc_0_40142F
.text:00401368             mov     ecx, dword_0_407BE4
.text:0040136E             mov     [ebp+var_8C], ecx
.text:00401374             mov     edx, dword_0_407BE0
.text:0040137A             mov     [ebp+var_90], edx
.text:00401380             mov     eax, dword_0_407BE8
.text:00401385             xor     ecx, ecx
.text:00401387             push    0
.text:00401389             push    3Ch
.text:0040138B             push    ecx
.text:0040138C             push    eax
.text:0040138D             call    __allmul
.text:00401392             push    0
.text:00401394             push    989680h
.text:00401399             push    edx
.text:0040139A             push    eax
.text:0040139B             call    __allmul
.text:004013A0             add     eax, [ebp+var_90]
.text:004013A6             adc     edx, [ebp+var_8C]
.text:004013AC             mov     [ebp+var_98], eax
.text:004013B2             mov     [ebp+var_94], edx
.text:004013B8             lea     edx, [ebp+var_88]
.text:004013BE             push    edx
.text:004013BF             lea     eax, [ebp+var_98]
.text:004013C5             push    eax
.text:004013C6             call    ds:FileTimeToLocalFileTime
.text:004013CC             lea     ecx, [ebp+var_A8]
.text:004013D2             push    ecx
.text:004013D3             lea     edx, [ebp+var_88]
.text:004013D9             push    edx
.text:004013DA             call    ds:FileTimeToSystemTime
.text:004013E0             push    40h
.text:004013E2             lea     eax, [ebp+var_80]
.text:004013E5             push    eax
.text:004013E6             push    0
.text:004013E8             lea     ecx, [ebp+var_A8]
.text:004013EE             push    ecx
.text:004013EF             push    0
.text:004013F1             push    400h
.text:004013F6             call    ds:GetDateFormatA
.text:004013FC             push    40h
.text:004013FE             lea     edx, [ebp+var_40]
.text:00401401             push    edx
.text:00401402             push    0
.text:00401404             lea     eax, [ebp+var_A8]
.text:0040140A             push    eax
.text:0040140B             push    0
.text:0040140D             push    400h
.text:00401412             call    ds:GetTimeFormatA
.text:00401418             lea     ecx, [ebp+var_40]
.text:0040141B             push    ecx
.text:0040141C             lea     edx, [ebp+var_80]
.text:0040141F             push    edx
.text:00401420             push    offset aThisTrialVersi ; "This trial version of NT will expire on"...
.text:00401425             call    sub_0_401754
.text:0040142A             add     esp, 0Ch
.text:0040142D             jmp     short loc_0_40143C
.text:0040142F loc_0_40142F:                   ; CODE XREF: sub_0_40121F+143j
.text:0040142F             push    offset aThisIsTheFullV ; "This is the full version of NT.\n\n"
.text:00401434             call    sub_0_401754
.text:00401439             add     esp, 4
.text:0040143C loc_0_40143C:                   ; CODE XREF: sub_0_40121F+20Ej
.text:0040143C             xor     eax, eax
.text:0040143E loc_0_40143E:                   ; CODE XREF: sub_0_40121F+4Dj
.text:0040143E             mov     esp, ebp
.text:00401440             pop     ebp
.text:00401441             retn
 


Il setting viene stabilito in base al valore di una sottochiave letta dal programma:
.text:00401105              call    ds:RegEnumValueA
.text:0040110B             mov     [ebp+var_428], eax
.text:00401111 loc_0_401111:                   ; CODE XREF: sub_0_401000+C3j
.text:00401111             push    offset aQsjpsjuzrvbouv ; "qsjpsjuzrvbouvnnbusjy"
.text:00401116             lea     ecx, [ebp+var_424]
.text:0040111C             push    ecx
.text:0040111D             call    004053E0
.text:00401122             add     esp, 8
.text:00401125             test    eax, eax
.text:00401127             jnz     short loc_0_401161
.text:00401129             mov     edx, [ebp+var_20]
.text:0040112C             mov     [ebp+var_4], edx
.text:0040112F             mov     eax, [ebp+var_4] QUI
.text:00401132             cmp     dword ptr [eax+4], 0
.text:00401136             jz      short loc_0_40114B
.text:00401138             mov     byte_0_407A20, 1
.text:0040113F             mov     ecx, [ebp+var_4]
.text:00401142             mov     edx, [ecx+4]
.text:00401145             mov     dword_0_407BE8, edx
.text:0040114B loc_0_40114B:                   ; CODE XREF: sub_0_401000+136j
.text:0040114B             mov     eax, [ebp+var_4]
 

ma il nome della sottochiave è crittato, come si vede, e viene decrittato in 4053E0.
Dobbiamo reversare l'algoritmo di decrittazione allora? In realtà non ce ne importa un fico secco dell'algoritmo di decrittazione: carichiamo il programma in SICE, inseriamo un breakpoint in 40112F, facciamo partire il programma ed al break di SICE verifichiamo il valore della locazione.
Indi, con Notepad o un altro editor a scelta, cerchiamo le occorrenze di tale valore nel log di RegMon. Ne troviamo una sola. E' stato troppo facile. Per quale parte del corpo (il cui nome comincia per "C") ci prendono Mark Russinovich e Bryce Cogswell?...Alguzza, sarebbe un problema anzichè no, se riuscissero a prenderti per quella parte del corpo....Ti chiami Alga, mica Platinette :))) NdQuequero

IL PERIODO DI TRIAL
La chiave è HKLM/SYSTEM/CurrentControl/Control/Session Manager/Executive/PriorityQuantumMatrix, che ha un valore binario composto in pratica da tre campi a 32bit; se il campo centrale è posto a zero, la versione è full, se non lo è, il campo centrale indica la scadenza.
Verifichiamo sul mio sistema NT4: il campo è zero.
Scriviamo qualcosa nel campo: Istrial sostiene che il mio sistema è una trial version.
Sulla mia installazione di Windows 2000 RC2 il campo centrale è 80 C1 09 00, ovverossia 9C180, e cioè 639360 in decimale, che diviso 1440 (il numero di minuti contenuti in un giorno) fa per l'appunto 444: il campo centrale è la durata in secondi (pignola Microsoft!) del periodo di trial.
Proviamo adesso ad azzerare il campo in W2000 RC2: non succede niente. Ma proprio niente, nel senso che il valore del campo resta invariato. Qualcosa presta attenzione alle eventuali variazioni della voce nel registro, e ripristina prontamente il valore originale. La faccenda comincia finalmente a farsi interessante.

Per identificare il nostro avversario, diciamo a RegMon di moniritozzare (originale sto termine...moniritozzare NdQue) soltanto gli accessi in scrittura alla chiave che ci interessa, e riproviamo a variare il campo. OK, RegMon rileva che qualcuno ha riscritto il valore della chiave, e questo qualcuno è System.
System vuol dire NTDLL.DLL oppure NTOSKRNL.EXE. Le funzioni del sistema operativo sono rigorosamente "undocumented"
(almeno per i comuni mortali), e se esse vengono chiamate nell'ambito di API per svolgere solo una parte dei compiti delle funzioni, capire come e cosa facciano può essere difficile; ma molte di esse hanno nomi evocativi, ed un comportamento dello stack straordinariamente simile ad alcune API di sistema (vedi ad esempio NtQuerySystemTime), e quindi si può avere un'idea riguardo al loro comportamento.

In NTOSKRNL.EXE sono presenti tre funzioni dal nome "interessante": ZwSetValueKey, ZwNotifyChangeKey e ZwFlushKey. Per le prime due di esse, un maggior numero di parametri viene passato nello stack, ma possiamo supporre che, in linea di massima, esse agiscano come le "corrispondenti" funzioni di ADVAPI32. Inoltre, mentre le occorrenze della prima sono numerose, ZwNotifyChangeKey compare solo due volte. Ponendo un breakpoint su quest'ultima, e tentando di cambiare il valore del campo centrale della sottochiave, SICE blocca l'esecuzione in questo punto:
PAGE:004BB4C8         push    ebp
PAGE:004BB4C9         mov     ebp, esp
PAGE:004BB4CB         sub     esp, 2Ch
PAGE:004BB4CE         push    ebx
PAGE:004BB4CF         xor     ebx, ebx
PAGE:004BB4D1         push    dword_0_472AD0
PAGE:004BB4D7         mov     [ebp+var_1], bl
PAGE:004BB4DA         call    ZwClose
PAGE:004BB4DF         lea     eax, [ebp+var_C]
PAGE:004BB4E2         push    offset off_0_4BB400
PAGE:004BB4E7         push    eax
PAGE:004BB4E8         call    RtlInitUnicodeString
PAGE:004BB4ED         lea     eax, [ebp+var_C]
PAGE:004BB4F0         mov     [ebp+var_2C], 18h
PAGE:004BB4F7         mov     [ebp+var_24], eax
PAGE:004BB4FA         lea     eax, [ebp+var_2C]
PAGE:004BB4FD         push    eax
PAGE:004BB4FE         push    2001Fh
PAGE:004BB503         push    offset dword_0_472AD0
PAGE:004BB508         mov     [ebp+var_28], ebx
PAGE:004BB50B         mov     [ebp+var_20], 40h
PAGE:004BB512         mov     [ebp+var_1C], ebx
PAGE:004BB515         mov     [ebp+var_18], ebx
PAGE:004BB518         call    ZwOpenKey
PAGE:004BB51D         cmp     eax, ebx
PAGE:004BB51F         jl      short loc_0_4BB59A
PAGE:004BB521         cmp     byte_0_472B74, bl
PAGE:004BB527         jnz     short loc_0_4BB59A
PAGE:004BB529         cmp     byte_0_473AE9, bl
PAGE:004BB52F         jnz     short loc_0_4BB56C
PAGE:004BB531         lea     eax, [ebp+var_14]
PAGE:004BB534         push    offset a188     ; "PriorityQuantumMatrix"
PAGE:004BB539         push    eax
PAGE:004BB53A         call    RtlInitUnicodeString
PAGE:004BB53F         call    sub_0_4600A5 equivalente di LockResource
PAGE:004BB544         push    0Ch
PAGE:004BB546         push    offset dword_0_473AF8 ; key value
PAGE:004BB54B         push    3
PAGE:004BB54D         lea     eax, [ebp+var_14]
PAGE:004BB550         push    ebx
PAGE:004BB551         push    eax
PAGE:004BB552         push    dword_0_472AD0
PAGE:004BB558         mov     [ebp+var_1], 1
PAGE:004BB55C         call    ZwSetValueKey
PAGE:004BB561         push    dword_0_472AD0
PAGE:004BB567         call    ZwFlushKey
PAGE:004BB56C
PAGE:004BB56C loc_0_4BB56C:           ; CODE XREF: sub_0_4BB4C8+67_j
PAGE:004BB56C         push    1
PAGE:004BB56E         push    4
PAGE:004BB570         push    offset unk_0_472B80
PAGE:004BB575         push    ebx
PAGE:004BB576         push    0Fh
PAGE:004BB578         push    offset unk_0_472C00
PAGE:004BB57D         push    1
PAGE:004BB57F         push    offset dword_0_472BD0
PAGE:004BB584         push    ebx
PAGE:004BB585         push    dword_0_472AD0
PAGE:004BB58B         call    ZwNotifyChangeKey QUI 
PAGE:004BB590         cmp     [ebp+var_1], bl
PAGE:004BB593         jz      short loc_0_4BB59A
PAGE:004BB595         call    sub_0_48DE28 equivalente di UnLockResource 
PAGE:004BB59A
PAGE:004BB59A loc_0_4BB59A:           ; CODE XREF: sub_0_4BB4C8+57_j
PAGE:004BB59A               ; sub_0_4BB4C8+5F_j ...
PAGE:004BB59A         pop     ebx
PAGE:004BB59B         leave
PAGE:004BB59C         retn    4
PAGE:004BB59C sub_0_4BB4C8    endp
  
La routine è chiamata da una call in 418874, che è all'interno di una procedura eseguita periodicamente; se una modificazione del valore della sottochiave viene rilevato, il valore originario, inserito in 473AF8 in fase di caricamento del sistema operativo, viene utilizzato per ripristinare il valore originario.

La ricerca delle altre occorrenze di 473AF8 (o, più semplicemente, l'analisi della cross reference table se stiamo usando IDA) non consente di rilevare da dove venga letto il valore della sottochiave che verrà copiato.

L'evento che scrive il valore nella locazione 473AF8 avviene all'avvio di NTOSKRNL.EXE, e quindi prima del caricamento di SICE; quest'ultimo non può intercettarlo.

L'aspetto più noioso del reversing di NTOSKRNL.EXE eseguito con SoftICE e su una sola macchina è appunto questo: gran parte delle attività relative alla protezione vengono eseguite durante la sequenza di startup, quindi SICE non può intercettarle, ed una volta avviato NTOSKRNL tutte le modificazioni fatte sul file o sulla sua immagine in memoria non avranno evidemente alcuna influenza su ciò che è già accaduto. Windows non può ricaricare NTOSKRNL perchè Windows E' NTOSKRNL!
Ciò comporta il fatto di doversi servire in prevalenza del "dead listing" (senza documentazione sulle funzioni :( ), e di dover riavviare ogni volta che si voglia provare l'effetto di una modifica (azione, come vedremo, che può risolversi in "spiacevoli" eventi)

Dalle informazioni fin qui raccolte però, tre dati fondamentali possono venire estrapolati:

1) Il valore binario della sottochiave in esame è composto da tre campi a 32 bit, ed il campo che ci riguarda è il secondo (da ISTRIAL, REGMON e REGEDIT)
2) In 473AF8 inizia l'intero valore della sottochiave, ovvero vi si trovano tutti e tre i campi (da SICE)
3) Il valore del secondo campo si troverà allora evidentemente in 473AFC, e questa locazione è referenziata separatamente (si vede nel disassemblato):
.data:00473AF8 dword_0_473AF8  dd 0          ; DATA XREF: sub_0_4BB0FC+77_o  I campo
.data:00473AF8                 ; sub_0_4BB4C8+7E_o ...
.data:00473AFC*dword_0_473AFC  dd 0          ; DATA XREF: sub_0_4BA6F5+B9_r  II campo
.data:00473AFC*                ; sub_0_4BA6F5+EF_r ...
.data:00473B00 dword_0_473B00  dd 0          ; DATA XREF: sub_0_541342+2A_r  III campo
.data:00473B04           db    0 ;
.data:00473B05           db    0 ;
.data:00473B06           db    0 ;
.data:00473B07           db    0 ;
 

La cross reference table di IDA fornisce sette riferimenti per 473AFC:
4BA7AE
4BA7E4
4BB10D
540DB1
541355
54135B
54138C



di essi, il primo ed il secondo, ed il quinto ed il sesto si trovano nell'ambito della stessa subroutine; questo segmento di codice è l'inizio della sub che contiene il quinto ed il sesto riferimento:
INIT:00541342         push    ebp
INIT:00541343         mov     ebp, esp
INIT:00541345         sub     esp, 20h
INIT:00541348         push    ebx
INIT:00541349         xor     ebx, ebx        ; EBX è zero 
INIT:0054134B         cmp     byte_0_473AE9, bl ; questo flag è zero? 
INIT:00541351         push    esi
INIT:00541352         push    edi
INIT:00541353         jz      short loc_0_54135B ; si, salta  
INIT:00541355         mov     dword_0_473AFC, ebx ; no, azzera campo centrale 
INIT:0054135B
INIT:0054135B loc_0_54135B:           ; CODE XREF: sub_0_541342+11_j
INIT:0054135B         cmp     dword_0_473AFC, ebx ;campo centrale è zero?  

etc.
Come si può vedere, viene eseguito il check del "flag" alla locazione 473AE9; se è diverso da zero il valore di EBX (posto a zero in 514349) viene copiato in 473AFC.
Quindi "qualcosa" potrebbe indicare a W2000 RC2 di trasformarsi in versione "full"? E' probabile, ma non è possibile usare SICE, poichè l'evento sembrerebbe accadere prima del caricamento del debugger.
La cross reference table relativa a 473AE9 ci mostra che il flag viene resettato in 5408D3, e settato in 5409A8.
Patchamo NTOSKRNL in modo da forzare il flusso del programma sulla locazione 5409A8: non succede niente. Il segmento di codice non è mai stato eseguito? Il flag è stato settato, ma un evento non previsto lo ha resettato? Con questa metodica non lo sapremo mai.

Se forzassimo l'inserimento di un 1 in 540D83? Il sistema operativo si blocca in fase di caricamento, mostrando un Bug Check 0x1E KMODE_EXCEPTION_NOT_HANDLED. Beh, meglio lasciar perdere questa soluzione, se non si può eseguire il debugging su un'altra macchina, e passare a soluzioni alternative.

VIOLAZIONE DELLA LICENZA!
Una soluzione sicuramente meno elegante è quella di annullare il salto in 541353. Cosa succede in questo caso? Il sistema si blocca sempre in fase di caricamento mostrando un Bug Check software: LICENSE_VIOLATION.
Ci siamo, allora! La subroutine in 541342 è stata eseguita, ma esiste qualche altro controllo che ha rilevato un'incongruenza e generato il Bug Check. Questo è il listato completo della subroutine:
INIT:00541342         push    ebp
INIT:00541343         mov     ebp, esp
INIT:00541345         sub     esp, 20h
INIT:00541348         push    ebx
INIT:00541349         xor     ebx, ebx        ; EBX è zero
INIT:0054134B         cmp     byte_0_473AE9, bl ; questo flag è zero?
INIT:00541351         push    esi
INIT:00541352         push    edi
INIT:00541353         jz      short loc_0_54135B ; si, salta 
INIT:00541355         mov     dword_0_473AFC, ebx ; no, azzera campo centrale
INIT:0054135B
INIT:0054135B loc_0_54135B:           ; CODE XREF: sub_0_541342+11_j
INIT:0054135B         cmp     dword_0_473AFC, ebx ; campo centrale è zero?
INIT:00541361         jz      loc_0_54144A    ; si, salta controllo SystemTime e
                                                ZwNotifyChangeKey  
INIT:00541367         mov     eax, dword_0_473AF8
INIT:0054136C         mov     ecx, dword_0_473B00
INIT:00541372         cmp     eax, ebx
INIT:00541374         jnz     loc_0_5414AC
INIT:0054137A         cmp     ecx, ebx
INIT:0054137C         jnz     loc_0_5414AC
INIT:00541382         push    offset dword_0_472BE8
INIT:00541387         call    KeQuerySystemTime
INIT:0054138C
INIT:0054138C loc_0_54138C:           ; CODE XREF: sub_0_541342+165_j
INIT:0054138C               ; sub_0_541342+175_j
INIT:0054138C         mov     eax, dword_0_473AFC
INIT:00541391         push    ebx
INIT:00541392         imul    eax, 3Ch
INIT:00541395         cdq
INIT:00541396         push    989680h
INIT:0054139B         push    edx
INIT:0054139C         push    eax
INIT:0054139D         call    _allmul
INIT:005413A2         add     eax, dword_0_472BE8
INIT:005413A8         mov     ecx, 0FFDF02C8h
INIT:005413AD         push    offset aRegistryMach_4 ; "\\Registry\\Machine\\System\\CurrentControl"...
INIT:005413B2         adc     edx, dword_0_472BEC
INIT:005413B8         mov     dword_0_472B78, eax
INIT:005413BD         mov     dword_0_472B7C, edx
INIT:005413C3         mov     [ecx], eax
INIT:005413C5         mov     eax, dword_0_472B7C
INIT:005413CA         mov     [ecx+4], eax
INIT:005413CD         lea     eax, [ebp+var_8]
INIT:005413D0         push    eax
INIT:005413D1         mov     byte_0_472B74, bl
INIT:005413D7         mov     dword_0_472BD8, offset sub_0_4BB4C8
INIT:005413E1         mov     dword_0_472BDC, ebx
INIT:005413E7         mov     dword_0_472BD0, ebx
INIT:005413ED         call    RtlInitUnicodeString
INIT:005413F2         lea     eax, [ebp+var_8]
INIT:005413F5         mov     [ebp+var_20], 18h
INIT:005413FC         mov     [ebp+var_18], eax
INIT:005413FF         lea     eax, [ebp+var_20]
INIT:00541402         push    eax
INIT:00541403         push    2001Fh
INIT:00541408         push    offset dword_0_472AD0
INIT:0054140D         mov     [ebp+var_1C], ebx
INIT:00541410         mov     [ebp+var_14], 40h
INIT:00541417         mov     [ebp+var_10], ebx
INIT:0054141A         mov     [ebp+var_C], ebx
INIT:0054141D         call    ZwOpenKey
INIT:00541422         cmp     eax, ebx
INIT:00541424         jl      short loc_0_54144A
INIT:00541426         push    1
INIT:00541428         push    4
INIT:0054142A         push    offset unk_0_472B80
INIT:0054142F         push    ebx
INIT:00541430         push    0Fh
INIT:00541432         push    offset unk_0_472C00
INIT:00541437         push    1
INIT:00541439         push    offset dword_0_472BD0
INIT:0054143E         push    ebx
INIT:0054143F         push    dword_0_472AD0
INIT:00541445         call    ZwNotifyChangeKey
INIT:0054144A
INIT:0054144A loc_0_54144A:           ; CODE XREF: sub_0_541342+1F_j
INIT:0054144A               ; sub_0_541342+E2_j
INIT:0054144A         push    ebx
INIT:0054144B         mov     edi, offset unk_0_472A40
INIT:00541450         push    offset loc_0_418628
INIT:00541455         push    edi
INIT:00541456         call    KeInitializeDpc
INIT:0054145B         mov     esi, offset unk_0_472BA0
INIT:00541460         mov     dword_0_472B28, offset sub_0_4BA6F5
INIT:0054146A         push    esi
INIT:0054146B         mov     dword_0_472B2C, ebx
INIT:00541471         mov     dword_0_472B20, ebx
INIT:00541477         call    KeInitializeTimer
INIT:0054147C         push    0FFFFFFF7h
INIT:0054147E         mov     eax, 9E3B9800h
INIT:00541483         pop     ecx
INIT:00541484         mov     dword_0_472B08, eax
INIT:00541489         push    edi
INIT:0054148A         push    ecx
INIT:0054148B         push    eax
INIT:0054148C         push    esi
INIT:0054148D         mov     dword_0_472B0C, ecx
INIT:00541493         call    KeSetTimer
INIT:00541498         push    offset unk_0_46A6C0
INIT:0054149D         call    ExInitializeResourceLite
INIT:005414A2         pop     edi
INIT:005414A3         pop     esi
INIT:005414A4         pop     ebx
INIT:005414A5         leave
INIT:005414A6         retn

 
Tutto appare molto semplice: sembrerebbe che venga eseguito il controllo su una locazione di memoria (che abbiamo etichettato come "flag") per resettare, eventualmente, il campo centrale del valore della chiave del registro; se esso risulta diverso da zero viene calcolato il tempo di utilizzo, altrimenti si salta alla fine della routine. Bene, allora deve esistere un altro check (se il sistema si blocca), e questo check deve tenere conto del fatto che abbiamo azzerato la locazione che ci interessa. Cercando tra le altre occorrenze di 473AFC troviamo facilmente il controllo:

INIT:00540D9E loc_0_540D9E:           ; CODE XREF: sub_0_5408BF+4B1_j
INIT:00540D9E               ; sub_0_5408BF+4D2_j ...
INIT:00540D9E         mov     eax, dword_0_473B08
INIT:00540DA3         mov     edx, dword ptr unk_0_473B0C
INIT:00540DA9         push    0Dh
INIT:00540DAB         pop     ecx
INIT:00540DAC         call    _allshr       ; scorrimento a destra di EAX di 13 bit
INIT:00540DB1         mov     ecx, dword_0_473AFC ;campo centrale in ECX
INIT:00540DB7         mov     [ebp+var_6C], edx ; salva 
INIT:00540DBA         mov     edx, eax        ; memorizza in EDX
INIT:00540DBC         and     edx, 0FFFFFFFh  ; maschera il primo byte
INIT:00540DC2         cmp     edx, ecx        ; confronta con il risultato precedente
INIT:00540DC4         jz      short loc_0_540DDC ; continua se uguali 
INIT:00540DC6         push    ecx
INIT:00540DC7         mov     ecx, dword ptr unk_0_473B0C
INIT:00540DCD         and     ecx, esi
INIT:00540DCF         shl     ecx, 3
INIT:00540DD2         push    ecx
INIT:00540DD3         push    eax
INIT:00540DD4         push    1
INIT:00540DD6         push    edi
INIT:00540DD7         call    KeBugCheckEx    ; FATAL SYSTEM ERROR! 
INIT:00540DDC
INIT:00540DDC loc_0_540DDC:           ; CODE XREF: sub_0_5408BF+505_j
INIT:00540DDC         mov     esi, 2079654Bh
INIT:00540DE1
INIT:00540DE1 loc_0_540DE1:           ; CODE XREF: sub_0_5408BF+41E_j
INIT:00540DE1         push    1
INIT:00540DE3         push    4
INIT:00540DE5         push    offset unk_0_472C78
INIT:00540DEA         push    ebx
INIT:00540DEB         push    5
INIT:00540DED         push    offset unk_0_472CA0
INIT:00540DF2         push    1
INIT:00540DF4         push    offset dword_0_472CC0
INIT:00540DF9         push    ebx
INIT:00540DFA         push    dword_0_472CB0
INIT:00540E00         call    sub_0_49C13C
INIT:00540E05         cmp     eax, ebx
INIT:00540E07         jge     loc_0_540ECB
INIT:00540E0D         cmp     byte_0_473AE9, bl
INIT:00540E13         jnz     loc_0_540A61
INIT:00540E19         cmp     byte_0_472CD0, bl
INIT:00540E1F         jnz     loc_0_540A61
INIT:00540E25         push    ebx
INIT:00540E26         push    ebx
INIT:00540E27         push    eax
INIT:00540E28         push    8
INIT:00540E2A         jmp     loc_0_540A5B


In 473B0C è presente una "copia" del valore, shiftata a sinistra di 13 bit. Forziamo il salto in 540DC4, copiamo la nuova versione di NTOSKRNL e riavviamo. Il sistema parte regolarmente. Al logon ci accorgiamo che la scritta "Copia di valutazione" sul desktop è scomparsa; quindi la 473AFC, rimasta a zero, sembra controllare tutto. Se cerchiamo di variare il campo centrale del valore binario della sottochiave HKLM/SYSTEM/CurrentControl/Control/Session Manager/Executive/PriorityQuantumMatrix, il valore rimane quello che impostiamo. Poniamolo a zero; Istrial ci dirà che la nostra è una versione full. OK, sembra fatto!

SI, MA DOV'E' UBICATA LA PROTEZIONE A TEMPO?
Qui:
PAGE:004BA795 loc_0_4BA795:           ; CODE XREF: sub_0_4BA6F5+3D_j
PAGE:004BA795               ; sub_0_4BA6F5+41_j ...
PAGE:004BA795         cmp     byte_0_4706B8, bl
PAGE:004BA79B         jz      short loc_0_4BA7AE
PAGE:004BA79D         call    sub_0_48A5C6
PAGE:004BA7A2         push    ebx
PAGE:004BA7A3         push    ebx
PAGE:004BA7A4         call    sub_0_47A8CE
PAGE:004BA7A9         call    sub_0_48A5DF
PAGE:004BA7AE
PAGE:004BA7AE loc_0_4BA7AE:           ; CODE XREF: sub_0_4BA6F5+A6_j
PAGE:004BA7AE         cmp     dword_0_473AFC, ebx ;verifica valore campo
PAGE:004BA7B4         jz      short loc_0_4BA801 ; salta se è zero
PAGE:004BA7B6         lea     eax, [ebp+var_C]
PAGE:004BA7B9         push    eax
PAGE:004BA7BA         call    KeQuerySystemTime ; verifica il tempo se è una trial version
PAGE:004BA7BF         mov     eax, [ebp+var_8]
PAGE:004BA7C2         cmp     eax, dword_0_472B7C ; rimane tempo?
PAGE:004BA7C8         jl      short loc_0_4BA801 ; si, continua
PAGE:004BA7CA         jg      short loc_0_4BA7D7 ; no, procedura di attivazione
PAGE:004BA7CC         mov     eax, [ebp+var_C] ; è uguale, verifica l'ora
PAGE:004BA7CF         cmp     eax, dword_0_472B78 ; minore?
PAGE:004BA7D5         jb      short loc_0_4BA801 ; sì, vai avanti 
PAGE:004BA7D7
PAGE:004BA7D7 loc_0_4BA7D7:           ; CODE XREF: sub_0_4BA6F5+D5_j
PAGE:004BA7D7         cmp     byte_0_472C08, bl ; flag avviso già visualizzato?  
PAGE:004BA7DD         jz      loc_0_4BA88B    ; no, parti 
PAGE:004BA7E3         push    ebx       ; si, shutdown
PAGE:004BA7E4         push    dword_0_473AFC
PAGE:004BA7EA         push    dword_0_472BEC
PAGE:004BA7F0         push    dword_0_472BE8
PAGE:004BA7F6         push    98h
PAGE:004BA7FB         push    ebx
PAGE:004BA7FC         call    PoShutdownBugCheck
PAGE:004BA801
PAGE:004BA801 loc_0_4BA801:           ; CODE XREF: sub_0_4BA6F5+BF_j
PAGE:004BA801               ; sub_0_4BA6F5+D3_j ...
PAGE:004BA801         mov     eax, 0FFFFFFFFh
PAGE:004BA806         mov     ecx, offset unk_0_472BE0
PAGE:004BA80B         xadd    [ecx], eax
PAGE:004BA80E         dec     eax
PAGE:004BA80F         cmp     eax, ebx
PAGE:004BA811         jnz     loc_0_4BA6FF
PAGE:004BA817         push    offset unk_0_472A40
PAGE:004BA81C         push    dword_0_472B0C
PAGE:004BA822         push    dword_0_472B08
PAGE:004BA828         push    offset unk_0_472BA0
PAGE:004BA82D         call    KeSetTimer
PAGE:004BA832         pop     esi
PAGE:004BA833         pop     ebx
PAGE:004BA834         leave
PAGE:004BA835         retn    4
PAGE:004BA838 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA838         jmp     loc_0_4BA772
PAGE:004BA83D ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA83D
PAGE:004BA83D loc_0_4BA83D:           ; CODE XREF: sub_0_4BA6F5+65_j
PAGE:004BA83D         shr     esi, 1
PAGE:004BA83F         cmp     esi, edx
PAGE:004BA841         jnz     short loc_0_4BA84B
PAGE:004BA843         test    al, 1
PAGE:004BA845         jz      loc_0_4BA772
PAGE:004BA84B
PAGE:004BA84B loc_0_4BA84B:           ; CODE XREF: sub_0_4BA6F5+6F_j
PAGE:004BA84B               ; sub_0_4BA6F5+77_j ...
PAGE:004BA84B         xor     ecx, ecx
PAGE:004BA84D         jmp     loc_0_4BA779
PAGE:004BA852 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA852
PAGE:004BA852 loc_0_4BA852:           ; CODE XREF: sub_0_4BA6F5+1C_j
PAGE:004BA852               ; sub_0_4BA6F5+28_j
PAGE:004BA852         mov     dword_0_472A60, ebx
PAGE:004BA858         mov     dword_0_472A64, ebx
PAGE:004BA85E         jmp     loc_0_4BA795
PAGE:004BA863 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA863
PAGE:004BA863 loc_0_4BA863:           ; CODE XREF: sub_0_4BA6F5+10_j
PAGE:004BA863         cmp     byte_0_473AE9, bl
PAGE:004BA869         jnz     loc_0_4BA795
PAGE:004BA86F         cmp     byte_0_472CD0, bl
PAGE:004BA875         jnz     loc_0_4BA795
PAGE:004BA87B         inc     dword_0_472AA0
PAGE:004BA881         jmp     loc_0_4BA795
PAGE:004BA886 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA886         jmp     loc_0_4BA801
PAGE:004BA88B ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA88B
PAGE:004BA88B loc_0_4BA88B:           ; CODE XREF: sub_0_4BA6F5+E8_j
PAGE:004BA88B         push    0C0000268h
PAGE:004BA890         push    offset sub_0_4BB3DA
PAGE:004BA895         push    ebx
PAGE:004BA896         push    ebx
PAGE:004BA897         push    ebx
PAGE:004BA898         lea     eax, [ebp+var_4]
PAGE:004BA89B         push    1F03FFh
PAGE:004BA8A0         push    eax
PAGE:004BA8A1         mov     byte_0_472C08, 1 ; partito! Da qui trascorrerà un'ora,
PAGE:004BA8A1                                  ; indi il flag risulterà settato
PAGE:004BA8A8         call    PsCreateSystemThread
PAGE:004BA8AD         cmp     eax, ebx
PAGE:004BA8AF         jl      loc_0_4BA801
PAGE:004BA8B5         push    [ebp+var_4]
PAGE:004BA8B8         call    ZwClose
PAGE:004BA8BD         jmp     loc_0_4BA801
PAGE:004BA8BD sub_0_4BA6F5    endp
PAGE:004BA8BD
PAGE:004BA8BD ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
PAGE:004BA8C2         db 0CCh



Risulta chiaro il modo di operare di NTOSKRNL: solo se la solita 473ACF è diversa da zero (e quindi il sistema è una versione trial) verifica se il periodo di trial è scaduto. Se lo è, verifica un certo flag (472C08). Se esso è resettato, parte e lo setta, riverificando il tutto dopo un'ora. Se esso risulta già settato, un'ora è già trascorsa, quindi visualizza l'avviso, e dopo un'altra ora il sistema si inginocchierà miseramente mostrando un Bug Check.

Anche qui dunque 473AFC è la chiave di tutto, e questo sembrerebbe aprire delle interessanti possibilità.

LE INTERESSANTI POSSIBILITA'
Istrial è un'utility relativa a tutti i sistem NT. Di fatto sui sistemi NT 4 (Workstation e Server) esiste la sottochiave verificata da Istrial, mentre la stessa non è presente sui sistemi W 9x. Come accennavo all'inizio, io non mi ero mai occupata della protezione a tempo dei sistemi NT; mi sono chiesta allora: oltre alla presenza della sottochiave ed al significato del suo valore, cos'altro hanno in comune le trial NT4 con quelle W2000? Lo schema della protezione è lo stesso?

Sì, è identico. Su un vecchio CD-ROM (PC Magazine Gennaio '97) era presente una versione trial 120 giorni di NT 4 Workstation.
L'equivalente della routine in 4BA795 si trova in 80155686; il controllo relativo alla violazione della licenza che in W2000 inizia in 540D9E ha il suo corrispettivo in NT4 in 801BEF14, ed infine l'analogo della routine "principale" di W2000 (541342) è in 801BF05E.

Chiarifico, adesso, l'accenno fatto precedentemente alle "interessanti possibilità".
Consideriamo la routine che inizia in 4BA795. Forzando il solo salto condizionale in 4BA7C8 (oltre, naturalmente, quello in 540DC4, pena il blocco del sistema all'avvio per generazione del Bug Check LICENSE_VIOLATION), il campo centrale del valore di HKLM/SYSTEM/CurrentControl/Control/Session Manager/Executive/PriorityQuantumMatrix resterebbe non alterabile, così come immutato rimarebbe il valore corrispondente in 473AFC; ciò significa che il sistema verrebbe visto come trial da Istrial (e da qualunque altro programma), la dicitura "Copia di valutazione" rimarebbe ben visibile sul desktop e verosimilmente (ritengo che anche questo aspetto sia controllato da 473AFC - ma è solo un'ipotesi) non sarebbero applicabili i Service Packs.
La copia di W2000 sarebbe una versione trial a tutti gli effetti legali (e legalmente si sarebbe autorizzati ad usarla - la licenza è acclusa) ma...non si fermerebbe mai.

Stesso discorso vale per la versione trial 120 giorni di NT4 Workstation; qualunque ispezione legale troverebbe una trial version "legale", e si sarebbe ottenuta la licensa d'uso di un sistema operativo in maniera assolutamente gratuita. Sarebbe infatti veramente difficile verificare che la versione di NTOSKRNL.EXE attiva sulla macchina è diversa da quella presente sul CD di installazione...

Purtroppo però, come vedremo, ciò è attualmente vero solo in (minima) parte, mentre lo era totalmente ai tempi di NT 4.

I TEMPI STANNO CAMBIANDO
Come già accennato, la versione trial 120 giorni di NT4 workstation in mio possesso era inserita (gratuitamente, quindi) in un CD ROM accluso ad una rivista.
Anche la RC2 di W2000 era inserita gratuitamente in un CD ROM accluso ad una rivista, e sembrerebbe assolutamente funzionale; sono riuscita a rilevare solo un ridicolo bug in WordPad, ed un ben più grave blocco totale del sistema (stallo totale - bisogna resettare) durante il recupero da suspend mode degli hard disk, ma per il resto non sembrerebbero esistere altri problemi.
Il periodo di valutazione dura però ben 444 giorni (più di un anno, una valutazione veramente accurata!), e soprattutto il programma di installazione esegue di default l'aggiornamento del sistema.
Microsoft Italia fornisce a richiesta delle versioni trial 120 giorni, ma le vende, 50000 lire a copia.

Vi pregherei di notare questi tre fatti salienti:

1) Tre anni addietro le copie trial 120 giorni erano distribuite gratuitamente

2) RC2 è distribuita gratuitamente, ma se non si sta in guardia effettua l'aggiornamento del sistema; tutto procede magnificamente e poi, più di un anno dopo, quando il vostro sistema è pieno della roba vostra (di tutto quello che avete potuto inserire in un anno) il sistema si blocca e vi si chiede di acquistare la licenza. Non volete? Avevate una magnifica copia di Windows 95 perfettamente funzionante e con licenza e volete continuare ad utilizzarla? Benissimo, nessun problema! Baste seguire questi semplici passi, ancora più semplici, per l'utilizzatore medio, del Plug&Play:

a) convertitevi una partizione in FAT16
b) copiatevi tutta la roba che non volete perdere
c) riformattate il volume principale
d) reinstallate Windows 95 dall'inizio
e) reinstallate tutte le vostre applicazioni
f) rimettete a posto tutto ciò contenuto nel backup effettuato in b).

Ah, dimenticavo, naturalmente i passi a) e b) vanno eseguiti nelle due ore che ogni avvio di RC2 scaduta vi lascia...non sbagliate a calcolarvi il tempo...se andate fuori tempo Microsoft non vi esegue un logoff forzato, vi manda in crash il sistema...vi conviene farlo poco per volta riavviando ogni ora e mezza...tutto ciò se non avete letto questo tutorial, naturalmente! :)

3) Adesso le copie trial 120 giorni vengono vendute

Riparleremo di questi tre punti tra poco.

LA CERTIFICAZIONE VERISIGN DEI FILE DI SISTEMA
Adesso possiamo scrivere un patcher; solo due byte da patchare agli offset 140DC4 e 141354, più altri due in 128 e 129 per il checksum...fatto, funziona, patchato, riavviamo e...la scritta "copia di valutazione" è sempre lì, ed il registro di sistema non consente variazioni.

Se scriviamo una patch che disattivi solo il limite di tempo si verifica la stessa cosa. Le differenze non sarebbero visibili, ma un file compare con la copia originale di NTOSKRNL.EXE mostra che i file sono comunque uguali.
Se cerchiamo di sovrascrivere NTOSKRNL con una versione patchata il risultato non cambia.

Questo è ciò che mamma Microsoft chiama "Protezione file"; siccome mamma Microsoft ci vuole bene, e non vuole che il nostro sitema subisca danni se qualche cattivaccio decide di sovrascrivere i file del sistema operativo, installa in duplice copia e tiene sotto controllo, regolarmente gli accessi in scrittura a 3427(!) file, e se il cattivaccio di cui sopra ne sovrascrive uno il sistema operativo verifica innanzitutto che

1) la nuova versione sia dotata della firma digitale; se non lo è

2) preleva una copia del file dalla copia (compressa in %SystemRoot%\Driver Cache\i386\driver.cab) e

3a) sovrascrive l'attività del cattivaccio, oppure, se anche la copia nella cache dei file dovesse essere priva di firma digitale

3b) non sovrascrive nulla e segnala che nel sistema è presente un file (ed anche quale) privo della firma digitale.


Ma, pensava un'Alga qualunque, non sarebbe stato più sensato porre gli attributi dei file a sola lettura in fase di boot, considerando anche che file come NTOSKRNL non verranno più caricati da disco dopo l'avvio, anzichè rallentare il sitema per eseguire ciclicamente tutti questi controlli in background, ed occupare altri 52 Mega(!) per la copia dei file, nonchè altri 6 Mega per cataloghi e chiavi?

No,no,no...assolutamente no! Ormai i processori sono potenti, gli hard disk sono capienti, e la sicurezza è sicurezza!

Bene, allora se vogliamo patchare il kernel dobbiamo disattivare protezione file. In realtà la cosa non presenterebbe alcun problema; anche il nostro patcher può eseguire ciò, rinominando il file driver.cab (ad esempio drivers.cab). In questo caso la patch sarà applicabile e funzionerà perfettamente, ma...l'utility SIGVERIF.EXE segnalerà che la versione in uso di NTOSKRNL.EXE è priva di firma digitale.

Così se il nostro sistema dovesse venire sottoposto a qualche "controllo", sarebbe molto più facile verificare che i file di sistema sono stati alterati. Ed abbiamo anche identificato il cattivaccio che vuole sovrascrivere, e dal quale mamma Microsoft ci protegge benevolmente: il cattivaccio siamo noi stessi.

Tutto questo non esisteva per le trial di Windows NT 4, delle quali, se vogliamo possiamo ancora "usufruire" :)

SCAPPATOIA!
E se noi (monelli!) volessimo ugualmente mantenere una copia "pseudolegale" ma funzionante di RC2 (o di qualunqua altra trial, purchè legalmente posseduta)?

Bene, rinominiamo DRIVER.CAB, patchamo NTOSKRNL, ripristiniamo DRIVER.CAB e viviamo tranquilli; nell'ipotesi di un controllo o qualcos'altro basterà tentare di rinominare NTOSKRNL.EXE e Protezione File ripristinerà prontamente il file originale, munito di firma digitale. Attenzione però a non variare assolutamente il campo centrale del valore di HKLM/SYSTEM/CurrentControl/Control/Session Manager/Executive/PriorityQuantumMatrix! Diversamente, al riavvio successivo al ripristino il sistema si bloccherà visualizzando il Bug Check LICENSE_VIOLATION e, a meno che non abbiate preso le precauzioni di cui parlo alla fine, o non abbiate un sistema multiple boot, sarete costretti a reinstallare.

SI, MA QUANTO DURERA'?
Poco, ritengo. Fino al prossimo NT, comunque si chiamerà. Dopodichè, penso diverrà estremamente difficile e soprattutto "pericoloso" aggirare Protezione File.
Perchè la strada imboccata è a senso unico, ed ormai la diffusione del sistema comincia ad essere tale che esso verrà praticamente imposto.
Tra l'altro, diviene così possibile rispondere ad una delle domande poste all'inizio: Microsoft vuole o no che la protezione venga disattivata?

Ieri, voleva.
Oggi, forse.
Domani, non avrà più alcuna importanza.

Ah, e la RAM? Sembra che le cose stanno in maniera assolutamente opposta a come avevo immaginato.
Microsoft ha altre frecce al suo arco per "costringere" all'acquisto di W2000.
Questo sembra adottare una serie di accorgimenti che diano l'illusione di una maggiore rapidità nel logon (ma appare solo una diversa sequenza nell'esecuzioni di operazioni di Phase 4 - dopo la comparsa del desktop e di tutte le icone il sistema diviene non rispondente agli input di mouse e tastiera per una ventina di secondi almeno - bella trovata, no? - ma non ho approfondito più di tanto), ma dalle prove fatte necessita di più RAM per essere più veloce di un NT4 con Service Pack 6a (anche Protezione File avrà il suo ruolo in questo, probabilmente).
Note finali


QUANTO E' GIUSTO TUTTO CIO'?
Una simile domanda si presta ad una duplice interpretazione. La prima è: "Quanto è legale tutto ciò?", cioè quanto è legale spiegare come è fatta la protezione a tempo?
Beh, molto poco, anzi, quasi per niente.
Teoricamente, magistrati giusti ed equi potrebbero prendere in considerazione una serie di condizioni che di fatto rendono subdolo l'operato di Microsoft (specialmente nei confronti degli utenti inesperti) per quanto riguarda la durata spropositata del periodo di trial, e l'installazione di default come aggiornamento di una versione che è solo di valutazione (se è distribuita solo per valutarla, perchè mai dovrebbe sostituire un sistema operativo preesistente e funzionante senza limiti di tempo?) e ne denunciano chiaramente la malafede; ma l'esperienza (mia e di persone che mi sono vicine) mi ha insegnato che non esistono magistrati giusti ed equi (se qualche magistrato dovesse per caso leggere queste parole, anzichè utilizzare le sue energie mentali per indignarsi, le utilizzi per cercare di diventare giusto ed equo, per piacere). Quindi...

Ma se l'interpretazione è: "Quanto è morale tutto ciò?", beh, la risposta è nelle righe che precedono. E questo mi ha portato a scrivere quanto state per finire di leggere, passando spietatamente sopra gli interessi della povera Microsoft Italia.

Ma le alghe, si sa, non hanno cuore.

Disclaimer

In teoria, qui dovrei scrivere che il software va acquistato e non rubato, che ho scritto tutto ciò per invogliare l'utente ad acquistare il software, per consentire una migliore valutazione del prodotto in prova, etc.; ma sarò sincera: non credo a queste frasi.
L'ultima affermazione però sarebbe applicabile: ho scritto questo tutorial per consentire una migliore valutazione del prodotto in prova; una prova di 444 giorni, con sostituzione totale del sistema non ha senso, una prova indefinita, in queste condizioni, può averla.

Ma le verità vera è un'altra: ho scritto questo tutorial per mostrarvi a cosa andiamo, e soprattutto andremo, incontro.
Per quel poco che un'alga può fare.

Tenete presente, infine, che se volete provare le patch su un sistema dove è installato il solo W2000 RC2 (o qualsiasi altra trial, come abbiamo visto) dovreste:

1) Utilizzare FAT16 sull'unita in cui risiede la directory di sistema
2) Creare una copia di NTOSKRNL originale
3) Creare una copia di NTOSKRNL già patchata correttamente
4) Non dimenticare MAI di correggere il checksum sulle copie patchate (
Exception Code 0xC0000221: STATUS_IMAGE_CHECKSUM_MISMATCH ed il sistema è bloccato)

Infine, se è il registro di sistema ad essere danneggiato e non consentire l'avvio, vi ricordo che le copie dei file di registro che il sistema crea all'atto dell'installazione si trovano in
%SystemRoot%\repair, mentre il file che genera l'attuale HKEY_LOCAL_MACHINE (e cioè System) è in %SystemRoot%\System32\config; sostituendo il file da DOS è possibile recuperare un'installazione, sebbene qualcosa vada persa.
Tutto ciò semprechè non siate disposti a reinstallare a cuor leggero; se utilizzate il CD ROM di PC Professionale, poichè è avviabile, se il BIOS della vostra macchina ve lo consente...

In ogni caso, io non potrò essere ritenuta responsabile di qualunque danno provochiate al vostro sistema seguendo quanto esposto in questo tutorial.

Buon divertimento!

UIC's page of reverse engineering, scegli dove andare:

Home   Anonimato   Assembly    CrackMe   ContactMe   Forum   Iscrizione      
       Lezioni    Links   Linux   NewBies   News   Playstation        
  Tools   Tutorial   Search   UIC Faq

UIC