Rootkiti u korisničkom načinu rada - "Naivna" metoda sakrivanja datoteka i procesa

Za početak ćemo se postaviti u ulogu napadača koji nema previše iskustva u izradi zloćudnih programa i ne poznaje detaljno operacijski sustav i njegov programski model.

Pri otkrivanju zloćudnih programa i neželjenih podataka na svome računalu, običan korisnik se pouzdaje prije svega u antivirusni program i ostale programe koji otkrivaju zloćudne aktivnosti. Mnogi korisnici međutim nisu svjesni činjenice da se antivirusni programi oslanjaju na antivirusne definicije i potpise, tj. datoteke koje (laički rečeno) sadržavaju mali odsječak kôda (ili sažetak odsječka koda) zloćudnog programa. Ako za neki virus ili drugi zloćudni program nije prisutna odgovarajuća definicija, tada antivirusni program takav kôd neće moći otkriti. Autori zloćudnih programa smišljaju različite tehnike izbjegavanja antivirusnih programa i nažalost, u tome vrlo često i uspijevaju, pogotovo ako nije zaražen veliki broj računala, tj. ako zloćudni kôd nije previše raširen. Neke aktivnosti, koje bi se itekako mogle okarakterizirati kao zloćudne i neželjene, prolaze sasvim nezapaženo od strane antivirusnih i drugih programa za zaštitu, a to će biti demonstrirano u nastavku. Osim tih alata koji predstavljaju nužnu zaštitu, korisnikov osnovni uvid u stanje sustava daje ugrađeni alat Windows Task Manager. Također, korištenjem Windows Explorer-a korisnik može uočiti neke datoteke i direktorije koje nije sam stvorio (niti su dio nekog poznatog programa koje je korisnik instalirao) i to može pobuditi sumnju korisnika da se na njegovom računalu nalazi zloćudni program.

Naš prvi korak u ulozi napadača je sakriti proces u listi procesa i odgovarajuće direktorije/datoteke od pogleda korisnika, točnije, sakriti proces u ispisu Task Managera i sakriti direktorij u Exploreru. Iako kao naivni napadač nemamo puno znanja o operacijskim sustavima i ne poznajemo interne strukture sustava, postavljajući si za cilj skrivanje procesa i direktorija i uz malo znanja možemo postići relativno mnogo.

Promatrajući Task Manager aplikaciju, lako je uočiti da se radi o običnom prozoru u kojem se ispisuju aktivni procesi na sustavu zajedno s nekim drugim interesantnim informacijama. Zanima nas kako se točno ti procesi ispisuju, tj. možemo li nekako iz te liste obrisati naš (zloćudni) proces?

Iako je teorijska pozadina prozora u operacijskom sustavu Windows daleko izvan opsega ovog teksta, važno je napomenuti da su prozori u osnovi objekti koji međusobno komuniciraju porukama. Ovisno o primljenim porukama, svaki prozor može promijeniti svoje dimenzije, svoj oblik, vidljivost, može iscrtati željene podatke, obrisati neke podatke, može se zatvoriti i slično. Svaki prozor također može imati jedan ili više prozora djece koji imaju isti identifikator procesa kao i glavni prozor, no najčešće se izvode u zasebnim dretvama. Svaki prozor identificiran je svojim imenom i/ili svojom klasom. Klasa prozora djeteta naravno može biti potpuno drukčija od klase glavnog prozora. Također, kao i za sve ostale objekte operacijskog sustava Windows, postoji vrlo bogat skup dokumentiranih funkcija za rad s prozorima.

Znajući neke osnovne teorijske aspekte prozora, možemo iskoristiti alat Spy++ (dio alata koji dolaze uz Visual Studio 2005) ili nešto sofisticiraniji alat Winspector [4aR. Freeman, Winspector software, studeni 2006.] kako bismo vidjeli strukturu prozora Task Manager, da li postoje prozori djeca, koje poruke Task Manager razmjenjuje s ostalim prozorima i slične važne informacije.

Na slici desno prikazan je ispis Spy++ alata za Task Manager.

Spy++ ispis

Na slici su zaokruženi zanimljivi prozori djeca unutar koji pripadaju Task Manager alatu. Prozor u kojem se ispisuju procesi ima ime Processes, a klasa mu je SysListView32. Ta klasa predstavlja sve one prozore koji imaju svoje podatke organizirane kao običnu listu koja se može sortirati i s kojom se mogu provoditi različite operacije, primjerice dodavati ili brisati elemente iz liste (funkcije i pripadne podatkovne strukture dobro su opisane u dokumentaciji).

Osim tog prozora, zanimljiv nam je i statusni prozor u kojem se ispisuje broj aktivnih procesa na sustavu. Taj prozor je klase statusbar32 i važan je zbog toga što ćemo taj broj morati umanjiti za 1 nakon pokretanja našeg zloćudnog procesa, kako bi prikrili njegovo djelovanje na sustavu.

Ono što naš program najprije mora pronaći jest prozor Windows Task Manager-a koji mora biti aktivan. To se postiže sljedećim odsječkom kôda u donjem ispisu (cjelokupni kôd može se preuzeti sa sljedećeg linka).

hTaskWindow = FindWindow(NULL, "Windows Task Manager"); if(hTaskWindow == NULL) { //prijavi grešku return -1; }

Nakon pronalaska glavnog prozora koji je identificiran hTaskWindow ručicom (engl. handle), moramo pronaći odgovarajuće prozore djecu koje smo identificirali pomoću Spy++ alata. To postižemo sljedećim kôdom:

EnumChildWindows(hTaskWindow, TraziProces, NULL); //TraziProces je Callback funkcija koja se poziva pri enumeraciji prozora djece BOOL CALLBACK TraziProces(HWND hChild, LPARAM lParam) { ... GetWindowText(hChild, imeDjeteta, 128); GetClassName(hChild, imeKlase, 128); //ako se prozor zove Processes i tip mu je SysListView, onda smo upravo na prozoru u kojem //je lista procesa if(!strcmp(imeDjeteta, "Processes") && !strcmp(imeKlase, "SysListView32")) { //budući da će se ovo vrtiti u petlji, moramo stvoriti zasebnu dretvu hHideProcThread = CreateThread(NULL, 0, SakrijProces, hChild, 0, NULL); } ...

Kada je nađen odgovarajući prozor koji sadržava listu procesa, stvaramo novu dretvu identificiranu ručicom hHideProcThread koja će proći kroz listu procesa SysListView32 i izbrisati onaj po našoj želji i pozivamo funkciju SakrijProces().

Kod ovakvog načina "brisanja procesa" iz liste javljaju se dva problema. Prvi i ključni problem je vremenske prirode. Lista procesa obnavlja se svake dvije sekunde ukoliko je brzina osvježavanja u opcijama Task Manager-a postavljena na normal, što je uglavnom slučaj. Proces koji se briše mora se dakle brisati u ovisnosti o brzini osvježavanja. Ako se briše nakon vremena manjeg od onog koje je određeno brzinom osvježavanja, željeni proces se uopće neće vidjeti u listi procesa i neće doći do njegovog brisanja, tj. lista će ostati netaknuta ili će se (ukoliko se brisanje obavlja po indeksu elementa liste, kao što je slučaj u našem kodu) obrisati neki proces koji je u listi blizu procesa koji se želio obrisati, što svakako nije željeno ponašanje. Ako se briše nakon većeg vremenskog intervala, tada će proces koji se briše jedno kratko vrijeme ipak biti vidljiv i to može pobuditi korisničku sumnju u postojanje neželjenog procesa. Ove vremenske operacije vrlo su osjetljive i pokazat će se da u općenitom slučaju problemi vezani uz njih nisu rješivi.

Drugi problem je programerske prirode i pojavljuje se zbog toga što je naš proces odvojen od procesa Task Manager-a. Prilikom komunikacije porukama, funkcije uglavnom vraćaju rezultate u međuspremnicima koji su lokalni za proces koji prima poruku i ne vide se u procesu koji šalje poruku. Zbog toga se u samom Task Manager procesu mora alocirati memorijski prostor preko kojega će se prenositi rezultati poruka. Zauzimanje memorije u adresnom prostoru drugog procesa moguće je jedino ako taj proces sam to dozvoli, a Task Manager proces dozvoljava pisanje i čitanje po svom adresnom prostoru (nije sasvim jasno zašto).

Funkcija koja obavlja samo "brisanje" procesa prikazana je u nastavku:

DWORD WINAPI SakrijProces(LPVOID lParam) { HWND hChild = (HWND) lParam; DWORD dPID = 0; LVITEM *listItem, item; TCHAR *procName; char buf[260]; //kako ne bi obrisali krivi proces, najprije se naš program mora pojaviti u //listi procesa, a tek onda nastavljamo s brisanjem Sleep(1200); //dohvati PID task manager procesa GetWindowThreadProcessId(hChild, &dPID); if(hTaskManagerProc == NULL) { //ako neka druga funkcija nije otvorila TaskManagerProces, onda ćemo ga mi otvoriti hTaskManagerProc = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dPID); if(hTaskManagerProc == NULL) { //nismo uspjeli otvoriti Task manager proces return false; } } //alociramo memoriju za element liste i za ime procesa u procesnom adresnom prostoru task //managera listItem = (LVITEM *) VirtualAllocEx(hTaskManagerProc, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE); procName = (TCHAR *) VirtualAllocEx(hTaskManagerProc, NULL, 260*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); item.cchTextMax = 260; //prolazit ćemo kroz cijelu listu pa nam je potreban broj procesa countProc = SendMessage(hChild, LVM_GETITEMCOUNT, 0, 0); while(true) { for(int i = 0; i < countProc; i++) { item.iSubItem = 0; item.pszText = procName; //zapiši strukturu preko koje ćemo dohvaćati podatke u adresni //prostor task managera WriteProcessMemory(hTaskManagerProc, listItem, &item, sizeof(LVITEM), NULL); //dohvati podatke o trenutnom elementu liste (elementu s indeksom i) SendMessage(hChild, LVM_GETITEMTEXT, (WPARAM) i,(LPARAM) listItem); //dohvati ime tog elementa (procesa) ReadProcessMemory(hTaskManagerProc, procName, buf, 260, NULL); //ako se radi o procesu kojeg zelimo sakriti if(!strcmp(buf, proces)) { //budući da element ostaje na toj poziciji, nećemo više //prolaziti kroz cijelu listu,već ćemo brisati isti element while(true) { /* najveći je problem u osvježavanju liste procesa, moramo spriječiti. To se ne može jednostavno spriječiti pa je zato najbolje da vršimo uzastopno pauziranje i pokretanje task managera, jer je to najbolja sinkronizacija sa stvarnim osvježavanjem koju možemo postići */ //signaliziraj da si obrisao proces i da funkcija //koja ažurira broj može smanjiti broj procesa za 1 SetEvent(hEvent); //neka task manager radi normalnom brzinom - //osvježava svake 2 sek SendMessage(hTaskWindow, WM_COMMAND, uNormalSpeed, 0); //odspavaj 2.1 sek Sleep(2100); //obriši element i SendMessage(hChild, LVM_DELETEITEM, (WPARAM) i, 0); //pauziraj task manager SendMessage(hTaskWindow, WM_COMMAND, uPauseUpdate, 0); } } } //ako nema doticnog procesa u listi, onda odspavaj 1 sek Sleep(1000); } //obriši zauzetu memoriju VirtualFreeEx(hTaskManagerProc, listItem, 0, MEM_RELEASE); VirtualFreeEx(hTaskManagerProc, procName, 0, MEM_RELEASE); return true;

Iako je kôd dobro komentiran, neke dijelove ipak treba detaljnije razmotriti. Prije svega valja naglasiti da se nikakvo brisanje stvarnih procesa ne događa, već se samo zapis procesa briše iz liste, sam proces naravno i dalje postoji. Prvo čekanje izvedeno Sleep() funkcijom potrebno je kako bi se najprije naš program pojavio u listi procesa i tek onda možemo započeti s pretragom i brisanjem. Kada tog čekanja ne bi bilo, postojala bi mogućnost da se brisanje željenog procesa obavi prije pojave našeg procesa (procesa u kojem se izvodi upravo navedeni kôd za brisanje). Ako proces koji se briše ima indeks i, u beskonačnoj petlji bi se čitavo vrijeme brisao proces s indeksom i. No nakon pojave našeg procesa u listi i u slučaju da se on u listi pojavio prije procesa koji se briše, proces koji se briše sada ima indeks i+1 i umjesto tog procesa u listi će se brisati neki drugi proces, što nije željeno ponašanje programa. Zato je izvedeno čekanje od 1.2 sekunde kako bi se našem procesu dala mogućnost da se pojavi u listi prije nego započne brisanje. Čak i uz ovo čekanje, u slučaju velikog opterećenja sustava, naš se proces neće pojaviti u listi u vremenu manjem od 1.2 sekunde i program neće raditi ispravno! No veće čekanje daje korisniku vremenski prozor unutar kojeg može vidjeti aktivnost "neželjenog" procesa, a to smo željeli spriječiti. Polako na vidjelo izlaze prvi nedostaci ovog pristupa.

U kôdu se dalje rezervira željeni memorijski prostor unutar Task Manager procesa i pretražuje se lista procesa u beskonačnoj petlji. Unutar beskonačne petlje prolazimo kroz cijelu listu procesa i ako traženi proces nije nađen, prolazimo od početka. Razlog tome je što se traženi proces u listi može pojaviti s nekim kašnjenjem ili tek kasnije tijekom rada Task Manager-a i moramo uzeti u obzir i takve situacije. U slučaju da smo našli proces koji želimo obrisati, tada više nećemo pretraživati kompletnu listu, već ćemo brisati samo element na toj poziciji, a to je upravo traženi proces. Zbog sinkronizacijskih problema najbolji mogući pristup je da se osvježavanje liste procesa zaustavi, zatim da se brzina osvježavanja postavi na normalnu, pozove funkcija Sleep() na dvije sekunde (jer je to vrijeme osvježavanja same liste) i zatim izbriše odgovarajući zapis te se cijeli postupak ponovi. Kako bismo mogli zaustavljati i ponovo pokretati osvježavanje, moramo dohvatiti odgovarajuće elemente u izborniku osnovnog prozora Task Manager procesa, što je prikazano dolje:

... HMENU hMenu = GetMenu(hTaskWindow); if(hMenu == NULL) { //nesto očito ne valja, ovo se zaista ne bi trebalo dogoditi return -1; } //0 je file, 1 je options, 2 je view, to nam treba za zaustavljanje HMENU hSubMenu = GetSubMenu(hMenu, 2); if(hSubMenu == NULL) { //kao i gore, ovo je nešto ozbiljno loše return -1; } //0 je refresh now, 1 je updateSpeed HMENU hUpdateSpeedMenu = GetSubMenu(hSubMenu, 1); if(hUpdateSpeedMenu == NULL) return -1; //doznaj koji je ID za pauzu i za normalnu brzinu uPauseUpdate = GetMenuItemID(hUpdateSpeedMenu, 3); uNormalSpeed = GetMenuItemID(hUpdateSpeedMenu, 1); ...

Nakon što smo obrisali proces, potrebno je još samo ažurirati broj procesa koji se ispisuje u statusnoj traci. Kao što je vidljivo na slici Spy++ programa, statusna traka je također običan prozor, pa se prilikom pretraživanja prozora djece glavnog prozora procesa Task Manager ispituje da li je pronađen takav prozor:

... if(!strcmp(imeKlase, "msctls_statusbar32")) { AzurirajBrojProcesa(hChild); } ...

Ključni dio funkcije AzurirajBrojProcesa() dan je u ispisu (ostatak je vrlo sličan funkciji SakrijProces()).

... WaitForSingleObject(hEvent, 7000); while(true) { //string u status baru ima oblik "Processes: <broj_procesa>", pa stvaramo takav string sprintf(buf, "Processes: %d", countProc-1); //zapiši to u alocirani buffer WriteProcessMemory(hTaskManagerProc, procNum, buf, 128, NULL); //i postavi tekst na taj koji smo stvorili SendMessage(hChild, SB_SETTEXT, 0, (LPARAM) procNum); //to ponavljaj svakih 50ms. Manja vrijednost bi uzela više procesora //(petlja bi se stalno vrtila i niti jedna druga dretva ne bi dobila //šansu da se izvede), a veća bi vrijednost bila vidljiva u task //manageru kao treperenje Sleep(50); }

Na početku funkcije čekamo na događaj (engl. event) API funkcijom WaitForSingleObject(). To je potrebno kako se broj procesa ne bi smanjio prije nego je stvoren proces u kojem se izvršava naš kôd (tada bi korisnik mogao vidjeti da je broj procesa za jedan manji od procesa koji su prisutni u listi, iako je u praksi to vrlo malo vjerojatno zbog najčešće velikog broja procesa u listi i zamornog ručnog brojanja procesa). U funkciji SakrijProces() dotični se događaj s ručicom hEvent postavlja u aktivno stanje nakon što se obriše željeni proces i može se započeti s ažuriranjem broja procesa. Ažuriranje broja svodi se na postavljanje naziva same statusne trake (koji ima oblik Processes: broj procesa) na željenu vrijednost. Ažuriranje moramo vršiti konstantno i relativno brzo jer bi se inače uočilo treperenje vrijednosti i to bi pobudilo sumnju korisnika. S druge strane, ne smijemo vršiti ažuriranje bez djelomičnog zaustavljanja dretvi (funkcijom Sleep()) jer bi zauzeće procesora i zauzimanje resursa bilo preveliko, pa je vrijeme neaktivnosti postavljeno na 50 ms. Program je nazvan Naive jer se radi o vrlo naivnom pristupu (razjašnjeno dalje u tekstu), a odabir procesa koji se skriva određuje se konfiguracijskom datotekom config.txt koja u prvom stupcu sadržava ime procesa koji se skriva, a u drugom stupcu nalazi se ime direktorija koji se želi sakriti.

Primjerice, ako se želi sakriti proces notepad.exe i direktorij Proba konfiguracijska datoteka ima izgled: notepad.exe Proba

Skrivanje direktorija se nasreću svodi na potpuno jednake korake kao i u slučaju skrivanja procesa jer se i datoteke prikazuju u prozoru klase SysListView32 (što se može ustanoviti korištenjem Spy++ programa kao i za slučaj procesa). Identično se postupa s datotekama jer razlika između tih objekata u samoj listi ne postoji: svi objekti su samo elementi liste. Za potrebe demonstracije skriva se samo jedan odabrani direktorij.

Funkcije za skrivanje direktorija su praktički identične kao i funkcije za skrivanje procesa i vrlo se lako mogu razumijeti analizom priloženog kôda. Potrebno je samo napomenuti da Windows Explorer može imati glavni prozor različitih klasa, ovisno o tome da li je pokrenut dvoklikom na My Computer ili je pokrenut kraticom WinKey + E. O tome se brine sljedeći kôd:

... //kada se explorer otvori s WinKey + E ili sa Explore funkcijom, onda on pripada klasi //ExploreWClass hExplorer = FindWindow("ExploreWClass", NULL); if(hExplorer == NULL) { //ako takav prozor nije otvoren, onda ćemo isprobati da li je otvoren explorer //preko My Computer, tada on ima CabinetWClass klasu hExplorer = FindWindow("CabinetWClass", NULL); if(hExplorer == NULL) { //ako ni on nije otvoren, onda zaista izlazimo return -1; } } ...

Neka je konfiguracijska datoteka upravo gore navedenog oblika. Najprije će biti prikazano stanje direktorija Naive u kojem se nalazi direktorij Proba prije pokretanja programa Naive, a zatim nakon pokretanja. Također, bit će naznačene i promjene u ispisu Task Manager procesa nakon pokretanja programa Naive uz aktivan proces notepad.exe koji se "briše" iz liste procesa. Prije pokretanja programa Naive.exe stanje je prikazano na slici lijevo, a stanje nakon pokretanja prikazano je na slici desno.

Ispis procesa i datoteka prije pokretanja programa Ispis procesa i datoteka nakon pokretanja programa

Na slikama su crvenim okvirima označeni ključni dijelovi. Na drugoj slici vidljiv je "nestanak" datoteke Proba – datoteka nije uistinu nestala, već je samo obrisana iz prikaza kao element liste. Također, iako je jasno vidljivo da je aplikacija Notepad pokrenuta, notepad.exe proces nije vidljiv u listi procesa jer je izbrisan od strane Naive programa (proces Naive.exe prisutan je u listi procesa). Također, broj procesa na sustavu ostao je jednak prije i poslije pokretanja Naive programa, kako se ne bi uočila razlika uzrokovana "izostankom" notepad.exe procesa.

Sudeći prema ovome, program dobro djeluje i skriva procese i direktorije od korisnika, čak bez obzira na privilegije koje korisnik ima!

Ipak, prava istina je da ovaj program (točnije, ova ideja i pristup sakrivanju od korisnika) ima znatno više nedostataka i ključnih manjkavosti nego prednosti.

Prednosti ovog pristupa su prije svega prenosivost na različite verzije Windows operacijskog sustava, neovisnost o privilegijama korisnika i "tiho" djelovanje. Budući da program ovisi prije svega o elementima sučelja, a sučelje ciljanih programa nije se mijenjalo od Windowsa NT 4.0 (1996. godina) pa sve do Windows Viste (2006. godina), Naive program uspješno obavlja svoj posao na svim operacijskim sustavima NT porodice. Druga velika prednost je potpuna neovisnost o privilegijama korisnika. Ako korisnik može pokrenuti navedene programe (u suprotnom skrivanje ne bi imalo smisla) i sam Naive program, Naive program će uspješno sakriti datoteke i procese. Treća i ne najmanje važna prednost je vrlo "tihi" rad, tj. djelovanje koje antivirusni programi i ostali alati specijalizirani za uočavanje zloćudnih aktivnosti mogu lako zanemariti ili uopće ne uočiti. Jedina aktivnost ovog programa koja se može detektirati je pisanje u adresni prostor drugog procesa i čitanje iz njega. Te aktivnosti su relativno uobičajene unutar samog operacijskog sustava Windows i vrlo je velika mogućnost da, čak i ako specijalizirani program dojavi sumnjivo ponašanje u sustavu (što je, osim za specijalizirani softver, vrlo malo vjerojatno), bude riječ o lažnoj uzbuni, tj. da korisnik zanemari upozorenje kada Naive zaista bude pristupao adresnom prostoru ciljnih procesa u namjeri da prevari korisnika.

Nedostaci ovog pristupa su toliko brojni da ga čine (gotovo) potpuno neupotrebljivim za stvarno djelovanje. Najveći problem je već spomenut, a vezan je uz sinkronizaciju. Prije svega, Naive program mora znati kada su prozori Task Manager-ai Windows Explorer-a aktivni. Onako kako su stvari dosad razmatrane, ne postoji druga mogućnost osim da program izvodi neku vrstu radnog čekanja i čitavo vrijeme u petlji ispituje da li su se pojavili odgovarajući procesi. To ispitivanje ne smije biti "preagresivno" jer bi u tom slučaju Naive.exe proces zauzeo veliki postotak resursa, već mora biti osigurano pravedno izvođenje svih dretvi na sustavu (to se u najjednostavnijem slučaju postiže pozivom funkcije Sleep()). Osim što je ovakav pristup iznimno nespretan, ostavlja mali vremenski prozorčić korisniku unutar kojeg on može uočiti aktivnost zloćudnog procesa (ako se dretva Naive.exe procesa probudila nakon što je korisnik već vidio stvarnu listu procesa, što je sasvim realna mogućnost). Također, osvježavanje liste procesa odvija se u diskretnim vremenskim intervalima, no usklađivanje brisanja ciljnog procesa s osvježavanjem na ovaj je način u općem slučaju nemoguće jer sama brzina brisanja ovisi o brzini izvođenja kôda Naive.exe procesa i o trenutnom opterećenju sustava, dostupnim resursima i drugim parametrima na koje se teško može izravno utjecati. Posljedica toga je vidljivo "treperenje" procesa koji se briše (njegovog pojavljivanja i ponovnog nestajanja). To treperenje može biti prisutno u velikoj ili vrlo maloj mjeri, no gotovo je uvijek uočljivo, barem do razine da se u korisniku pobudi sumnja u neobičnu aktivnost.

Jednak problem predstavlja i treperenje ukupnog broja procesa u statusnoj traci, no ono je manje izraženo jer se ažuriranje tog podatka može provoditi sa znatno većom frekvencijom. Ovom problemu može se doskočiti tako da se u potpunosti (iz programa Naive) zaustavi osvježavanje liste procesa. Problem time doista jest riješen, no korisniku to može biti znak neobične aktivnosti, pogotovo ako je sam postavio brzinu osvježavanja i ako se nakon ponovnog postavljanja od strane korisnika, osvježavanje ponovno zaustavi. Zbog toga takav pristup nije korišten u programu. Problemi treperenja nisu prisutni kod brisanja datoteka jer tamo nije prisutno automatsko osvježavanje. Međutim, korisnik u svakom trenutku može ručno osvježiti prozor korištenjem tipke F5. Rješenje te situacije je također uvođenje vremenskih brojača. Nakon što se prođe kroz kompletnu listu direktorija koji su trenutno prikazani na zaslonu i pronađe se onaj koji se treba obrisati, dretva koja obavlja brisanje postaje neaktivna na pola sekunde, a zatim ponovo prolazi kroz cijelu listu i traži odgovarajući direktorij (ako se on tipkom F5 slučajno ponovno pojavio). Manje ograničenje zauzima više procesorskog vremena, no i ovdje je prisutan problem s malim vremenom neaktivnosti unutar kojeg korisnik može uočiti sakrivani direktorij. Ako korisnik iz direktorija u kojem je vidljiv direktorij koji se skriva uđe u neki drugi direktorij i potom se vrati natrag (npr. ako se iz direktorija Naive koji je prikazan na slici korisnik pozicionira u direktorij Testing, a zatim se nazad vrati u direktorij Naive koji sadrži direktorij Proba koji se skriva), program neće raditi ispravno, tj. direktorij neće biti skriven. Razlog tome je što odgovarajući prozor dijete nestaje i zatim se ponovo stvara, pa ručica na prvotni prozor dijete više nije odgovarajuća, već ju treba obnoviti. Također, naknadnim otvaranjem novog Windows Explorer prozora i pozicioniranjem u direktorij koji sadržava direktorij koji se skriva, direktorij u tom prozoru neće biti sakriven jer program (u ovom obliku) djeluje samo na prvom pronađenom Explorer prozoru. Ako se Windows Explorer otvori kraticom WinKey + E, prozor će sadržavati i stablastu strukturu direktorija (koja se i u općem slučaju može uključiti u opcijama). Stablasta se struktura pojavljuje u svom prozoru koji je i potpuno druge klase (SysTreeView32) i ciljani direktorij ostaje neskriven u tom prozoru. Obnavljanje ručice, pretraživanje svih prozora i brisanje direktorija i u stablastoj strukturi je moguće provesti, no uvodi dodatnu kompleksnost u program jer je čitavo vrijeme potrebno osluškivati novostvorene prozore, obnavljati ručice, odnosno prolaziti kroz stablastu strukturu što podrazumijeva rekurziju. U priloženom demonstracijskom programu to nije učinjeno, u dorađenijem programu to je moguće provesti, no kompleksnost i zauzeće resursa zbog vremenske prirode osluškivanja na nove prozore bi poprilično poraslo, a zbog rekurzije bi se i prostorna složenost znatno povećala. Demonstracijski program nije potpun u smislu predviđanja svih mogućih događaja koji se u sustavu mogu pojaviti, ne vodi računa o greškama i ne rukuje ispravno s greškama i ne predstavlja optimalno rješenje problema. Međutim, iako su ovi nedostaci vidljivo vrlo ograničavajući, još nisu navedeni oni ključni, zbog kojih niti jedan program koji koristi ovakav pristup, ma koliko dorađen i pametno napisan bio, nije upotrebljiv u općem slučaju.

Osnovni je problem ovog pristupa što je površan i što je ovisan o aplikacijama. Površnost pristupa očituje se u tome što se ne mijenjaju nikakve stvarne strukture podataka, već se samo mijenja ispis, mijenja se izgled onoga što korisnik na svome zaslonu vidi. Izgled je moguće mijenjati samo u ovisnosti o aplikaciji koja te informacije prezentira (u ovom slučaju Task Manager/Windows Explorer) i od tuda ovisnost o pojedinim aplikacijama.

Na sreću običnog korisnika, ove aplikacije nisu jedine koje pružaju informacije o procesima, odnosno o direktorijima i datotekama na sustavu. Postoji bezbroj aplikacija takve vrste i nemoguće je da program s ovakvim pristupom istodobno i uspješno skriva željene informacije u svim potrebnim programima. Štoviše, postoji alat čiji je ispis na ovaj način nemoguće mijenjati, a najbolje od svega je da je ugrađen u sam operacijski sustav. Radi se o običnoj komandnoj liniji operacijskog sustava – cmd.

Uporabom takvih "dodatnih" alata djelovanje Naive programa u potpunosti je poništeno, što je prikazano na slici.

Ispis Process explorer alata i komandne linije

Za ispis aktivnih procesa korišten je alat Process Explorer [5aSysInternals (Mark Russinovich), Process Explorer] koji nudi mnoštvo opcija i otporniji je na "napade" od obične Task Manager aplikacije jer koristi vlastiti upravljački program za pribavljanje aktivnih procesa. U ispisu je vidljivo da Process Explorer vidi proces notepad.exe, dok ga Task Manager ne vidi jer je on sakriven Naive programom. Na slici je istaknuta i razlika u ukupnom broju procesa na sustavu. Iako se datoteka Proba ne vidi u Explorer prozoru, ona je jasno vidljiva u komandnoj liniji. Budući da se komandna linija/konzola u operacijskom sustavu Windows tretira kao specijalan prozor koji nema sve mogućnosti komunikacije porukama kao ostali prozori, program Naive je protiv obične komandne linije nemoćan. Komandna linija je zbog ovog svojstva (činjenice da se radi o posebnom prozoru, o dijelu tzv. klijent – poslužitelj podsustava, engl. CSRSSClient – Server Runtime Server Subsystem) izrazito korisna i obični bi ju korisnici trebali često koristiti kao pomoć pri otkrivanju zloćudnih aktivnosti na sustavu.

Program Naive pokazao se kao gotovo potpuni neuspjeh, no ipak je ukazao na vrlo važne aspekte sakrivanja objekata u operacijskom sustavu. Program za zaštitu od ovakvih aktivnosti u svakom slučaju mora imati listu procesa dobivenu iz potpuno povjerljivog izvora kojeg nije moguće lako izmijeniti. Na taj način bi se izbjegle ovakve (ali i znatno sofisticiranije) manipulacije. Nešto složenije je izvesti nadzor adresnog prostora nekog procesa i uočiti i dojaviti manipulaciju s tim prostorom od strane nekog drugog procesa, no potpuniji i bolji programi bi to svakako trebali imati u popisu funkcionalnosti.

Natrag na vrh