seminarski rad: procesna zaštitna...
TRANSCRIPT
Sveučilište u Zagrebu Fakultet elektrotehnike i računarstva
Martin Grmek
Seminarski rad: Procesna zaštitna stijena
Zagreb, rujan 2005.
Procesna zaštitna stijena
II
Sadržaj
1. Uvod ............................................................................................................................................1
2. Detekcija pokretanja aplikacije (procesa)..................................................................................2
2.1. Uporaba dinamičke biblioteke........................................................................................................2 2.1.1. Uporaba Registry-a ....................................................................................................................................3 2.1.2. Uporaba sveobuhvatnih sistemskih Windows zakački ..............................................................................3
2.2. Uporabom API funkcije PsSetCreateProcessNotifyRoutine().....................................................5 2.2.1. Kako radi komunikacija između jezgrenog upravljačkog program i nadzorne aplikacije .........................5 2.2.2. NT jezgreni upravljački program...............................................................................................................5 2.2.3. Problem zaustavljanja procesa ...................................................................................................................6
2.3. Modifikacijom tablice SSDT...........................................................................................................7 2.3.1. Modifikacija SSDT tablice u praksi...........................................................................................................8
3. Praktični rad .............................................................................................................................10
3.1. Manipulacija procesima ................................................................................................................10
3.2. Detekcija novog procesa s provjerom sigurnosne politike .........................................................11 3.2.1. Detekcija novog procesa ..........................................................................................................................12 3.2.2. Sustav sigurnosne politike .......................................................................................................................14
4. Upute za korištenje ...................................................................................................................16
4.1. Instalacija .......................................................................................................................................19
5. Zaključak ..................................................................................................................................20
6. Literatura ..................................................................................................................................21
I
Procesna zaštitna stijena
1
1. Uvod
Ideja je napraviti zaštitu koja bi štitila operacijski sustav od pokretanja neželjenih aplikacija kao što su crvi, trojanski konji i druge aplikacije sa skrivenim destruktivnim svojstvima (sadržajem). Zaštita bi radila na principu kao i zaštitne stijene za mrežu. Definirala bi se sigurnosna politika koja bi definirala ponašanje aplikacija, odnosno procesa. Drugim riječima, prilikom pokretanja aplikacije za koju nije definirana sigurnosna politika (kao i kod zaštitne stijene za mrežu) korisniku bi se dalo na izbor, što želi učiniti s trenutno pokrenutom aplikacijom:
• dopustiti da se pokrene • zabraniti da se pokrene.
Svaka odluka, po želji korisnika, pamtila bi se i spremala u sustav sigurnosne politike. Ovakav način zaštite sustava pouzdaniji je od bilo kojeg antivirusnog programa. Npr. ako je
virus novi, i nema ga u bazi virusa, anti-virusni program nije ga u mogućnosti prepoznati sve dok proizvođač antivirusnog programa ne izda proširenje baze virusa. Do tog trenutka može proći i više dana, a do tada već može biti kobno za operacijski sustav. Možda je za „običnog“ korisnika ovakav sustav zaštite prekompliciran, ali postoji rješenje da administrator računala snimi već definiranu sigurnosnu politiku i time olakša korištenje za „običnog“ korisnika.
Procesna zaštitna stijena
2
2. Detekcija pokretanja aplikacije (procesa)
Postoji više metoda detekcije pokretanja aplikacije odnosno procesa. Spomenuti ću neke od metoda koje ću u daljnjem tekstu detaljnije objasniti:
1. Uporaba dinamičke biblioteke (DLL) 2. Uporabom API funkcije PsSetCreateProcessNotifyRoutine() 3. Modifikacijom tablice SSDT (System Service Dispatch Table)
2.1. Uporaba dinamičke biblioteke Stvara se dinamička biblioteka datoteka koja u DllMain funkciji detektira poruke
DLL_PROCESS_ATTACH. Kada neka aplikacija otvara dinamičku biblioteku, tada se u DllMain funkciji, unutar dinamičke biblioteke, signalizira poruka DLL_PROCESS_ATTACH. Ideja je da se svaki proces „prisili“ na učitavanje naše dinamičke biblioteke prilikom pokretanja, koja bi onda detektirala pokretanja procesa. Ostaje problem kako učitati dinamičku biblioteku u svaki proces, tj. kako „prisiliti“ svaki proces da prilikom pokretanja učita našu dinamičku biblioteku. To je moguće uporabom:
1. registry-a 2. sveobuhvatnih sistemskih Windows zakački
Nakon što detektiramo poruku DLL_PROCESS_ATTACH, pozivom API funkcije
GetCurrentProcessId() možemo dobiti oznaku procesa. Preko oznake procesa korištenjem ostalih API funkcija možemo doći do imena datoteke procesa i drugih stvari koje su nam potrebne za provjeru procesa u sustavu sigurnosne politike. Slijedi primjer DllMain funkcije:
Slika 2.1: Primjer DllMain funkcije
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if( ul_reason_for_call == DLL_PROCESS_ATTACH ) { // dohvati ime procesa u kojem je u čitan DLL char lib_name[MAX_PATH]; ::GetModuleFileName(hModule, lib_name, MAX_PATH); DWORD pID = ::GetCurrentProcessId(); // Javi aplikaciji da je proces kreiran ... } return TRUE; }
Procesna zaštitna stijena
3
2.1.1. Uporaba Registry-a
Da bi novi proces, koji koristi dinamičku biblioteku USER32.DLL, učitao unaprijed pripremljenu dinamička biblioteku, možemo jednostavno ubaciti naziv naše dinamičke biblioteke u sljedeći registry ključ:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Cu rrentVersion\Windows\AppInit_DLLs
Vrijednost ovog ključa sadrži naziv jedne dinamičke biblioteke ili grupe dinamičkih biblioteka
odvojenih ili zarezom ili razmakom. Prema MSDN dokumentaciji [1], sve dinamičke biblioteke navedene kao vrijednost tog ključa, učitavaju se od svake Windows aplikacije pokrenute u trenutnoj sjednici. Zanimljivo je da je stvarno učitavanje navedenih dinamičkih biblioteka dio inicijalizacijskog postupka USER32.DLL datoteke. USER32 u svojoj DllMain funkciji čita vrijednost navedenog registry ključa i poziva funkciju LoadLibrary() za svaku od navedenih datoteku.
Međutim ovaj trik se primjenjuje samo na aplikacije koje koriste USER32.DLL. Drugo ograničenje je da je ovaj mehanizam podržan samo u Windows-ima NT, 2k i XP. Premda je ovo bezopasan način učitavanja dinamičke biblioteke u procese Windows-a postoji nekolicina nedostataka:
• U želji da aktiviramo odnosno deaktiviramo proces učitavanja dinamičke biblioteke,
moramo ponovno pokrenuti operacijski sustav. • Dinamička biblioteka koju želimo učitati će se jedino u procese koje koriste USER32.DLL
datoteku, stoga nećemo dobiti informaciju o pokretanju konzolnih aplikacija, budući da one obično ne koriste USER32.DLL datoteku.
• Nemamo nikakvu kontrolu nad učitavanjem dinamičke biblioteke u procese. To znači da se dinamička biblioteka učitava u svaku GUI aplikaciju, bez obzira željeli mi to ili ne. Time se pojavljuje redundantni dodatak, koji može poprilično narast ukoliko je trenutno aktivan velik broj aplikacija.
• Problem zaustavljanja procesa, nešto kasnije više o ovom problemu (poglavlje 2.2.3.).
2.1.2. Uporaba sveobuhvatnih sistemskih Windows zak ački
Jako popularan način učitavanja dinamičke biblioteke u ciljani proces bazira se na Windows zakačkama (Windows Hooks). Kako je pokazano u MSDN-u zakačka je zamka u sustavu baratanja porukama.
Aplikacija može instalirati filtar funkciju koja će pratiti promet poruka u sustavu i pojedinom procesu prije nego one stignu na cilj.
Zakačka se uobičajeno implementira u dinamičkoj biblioteci kako bi se udovoljili osnovni
zahtjevi za sveobuhvatne sistemske zakačke (system-wide hooks). Osnovni koncept ove vrste zakački je da se procedure povratnog poziva zakačke izvrši u adresnom prostoru svakog zakačenog procesa u sustavu. Da bi instalirali zakačku koristimo API funkciju SetWindowsHookEx() s odgovarajućim parametrima. Jednom kada aplikacija instalira sveobuhvatnu sistemsku zakačku, operacijski sustav raspoređuje dinamičku biblioteku u adresni prostor svakog procesa.
Zbog toga će globalne varijable u dinamičkoj biblioteci biti u svakom procesu posebno i ne
mogu se dijeliti između procesa koji su učitani unutar zakačene dinamičke biblioteke. Sve varijable koje sadrže dijeljene podatke moraju biti postavljeni unutar shared data sekcije. Sljedeći dijagram pokazuje primjer registriranja zakačke od strane Hook Server procesa i učitavanje u adresni prostor aplikacija Apllication One i Application Two. (dijagram i dio teksta preuzeto iz [2]).
Procesna zaštitna stijena
4
Slika 2.2: Način rada sveobuhvatne sistemske zakačke Sveobuhvatna sistemska zakačka registrirana je samo jednom nakon pokretanja API funkcije
SetWindowsHookEx() . Ako nije došlo do pogreške, funkcija vraća hvataljku na zakačku. Vraćena vrijednost potreban je na kraju naše proizvoljne funkcije zakačke, kada se poziva API funkcija CallNextHookEx() . Nakon uspješnog poziva API funkcije SetWindowsHookEx() , operacijski sustav automatski učitava (ali ne nužno i odmah) dinamičku biblioteku u sve procese koji udovoljavaju zahtjevima konkretnog filtara zakačke.
Slika 2.3: Proizvoljne funkcije zakačke
Ne postoji drugi način da se rastereti jednom zakačena dinamička biblioteka (učitana je u adresni
prostor ciljnog procesa) nego da proces koji je registrirao zakačku pozove API funkciju UnhookWindowsHookEx() ili da se aplikacija koja je bila zakačena ugasi.
Evo nekih prednosti ovog pristupa:
• Ovaj mehanizam podržan je od Windows-a NT/2K/XP i familije Windows 9x, a vjerojatno će biti i podržan i u budućim verzijama Windows-a.
• Za razliku od registry metode, ovaj mehanizam omogućuje učitavanje i rasterećivanje dinamičke biblioteke po potrebi.
Iako je ovakav način učitavanja dinamičke biblioteke zgodan, prate ga neki nedostaci:
• Windows zakačke mogu značajno degradirati performanse cijelog sustava, zato što povećavaju količinu procesiranja koji sustav mora obaviti za svaku poruku.
LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam) { if ( (nCode==HCBT_ACTIVATE) || (nCode==HCBT_SYSCOM MAND) || (nCode==HCBT_QS) || (nCode==HCBT_CREATEWND) ) { //pokrenut je novi proces, izvrši obradu i javi a plikaciji } // Sve poruke moramo proslijediti dalje sa CallNex tHookEx. return ::CallNextHookEx(sg_hGetMsgHook, nCode, wPa ram, lParam); }
Procesna zaštitna stijena
5
• Vrlo je teško uklanjati pogreške kod ovog mehanizam • Ova vrsta zakački utječe na procesiranje cijelog sustava i u nekim slučajevima (greške -
bug) mora se resetirati sustav kako bi se ispravila greška. • Ova metoda neće raditi sa sistemskim servisima (system services). • Problem zaustavljanja procesa, nešto kasnije više o ovom problemu (poglavlje 2.2.3.).
2.2. Uporabom API funkcije PsSetCreateProcessNotifyRoutine() Windows NT/2K/XP pružaju API funkcije, poznate kao „Process Structure Routines“ [3]
eksportirane od strane NTOSKRNL.DLL. Jedna od tih funkcija je PsSetCreateProcessNotifyRoutine() i ona nudi mogućnost registriranja sveobuhvatne sistemske funkcije povratnog poziva, koji operacijski sustav poziva svaki puta kada ne pokreće novi proces ili se postojeći uništava. Korištenjem spomenute funkcije lako se implementira metoda praćenja stvaranja i uništavanja procesa jednostavnim NT jezgrenim upravljačkim programom, koji će nadzornoj aplikaciji javljati stanja procesa. Uloga upravljačkog programa je detekcija izvođenja procesa i obavješćivanje nadzorne aplikacije o tim događajima.
Prednosti ove metode su:
• Dinamički je moguće učitati i rasteretit jezgreni upravljački program. • Omogućeno je registriranje i odjava funkcije povratnog poziva.
Nedostatak ove metode je isti onaj kao i kod metode detekcije uporabom dinamičke biblioteke, a
to je problem zaustavljanja procesa.
2.2.1. Kako radi komunikacija izme đu jezgrenog upravlja čkog program i nadzorne aplikacije
Jezgreni upravljački program tada kreira imenovani događaj koji se koristi za signalizaciju nadzorne aplikacije u trenutku kada je došlo do događaja (npr. proces je pokrenuo ili završio). Nadzorna aplikacija otvara isti događaj i kreira osluškujući dretvu koja čeka na događaj.
Nadzorna aplikacija pošalje zahtjev upravljačkom programu za početak nadgledanja. Upravljački
program pozove funkciju PsSetCreateProcessNotifyRoutine() s odgovarajuća dva parametra. Prvi specificira adresu funkcije povratnog poziva, odgovorne za primanje obavijesti o kreiranju ili uništavanju procesa od operacijskog sustava. Na temelju obavijesti iz funkcije povratnog poziva, upravljački program signalizira događaj kako bi se obavijestila nadzorna aplikacija da se nešto desilo. Nadzorna aplikacija tada dobiva podatak, o konkretnom događaju, iz upravljačkog programa i sprema ga u specijalni red za čekanje za daljnju obradu.
Ukoliko nema više potrebe za nadzorom, nadzorna aplikacija šalje zahtjev upravljačkom programu za prestanak nadzora. Upravljački program tada deaktivira nadzorni mehanizam.
2.2.2. NT jezgreni upravlja čki program
Ulazna točka DriverEntry() izvodi jedino inicijalizaciju upravljačkog programa. I/O menadžer poziva ovu funkciju kada je upravljački program učitan. Pošto PsSetCreateProcessNotifyRoutine() dopušta registraciju i odjavu funkcije povratnog poziva, implementirat ćemo proces registracije i odjave u otpremnoj rutini upravljačkog programa (driver's dispatch routine). To će nam omogućiti dinamičko pokretanje i zaustavljanje procesa za nadziranje koristeći IOCTL signale (kontrolni kod IOCTL_PROCESSFIREWALL_ACTIVATE_MONITORING). Jednom kad je funkcija povratnog poziva registrirana, svaki puta kada se proces pokrene ili uništi, operacijski sustav pozvat će funkciju povratnog poziva. Ova funkcija punit će spremnik koji će se čitati iz nadzorne aplikacije. Sljedeće što se dešava je da upravljački program signalizira imenovani događaj
Procesna zaštitna stijena
6
čime će nadzorna aplikacija, koja čeka taj događaj, biti obaviještena da ima dostupnih podataka za dohvatiti.
2.2.3. Problem zaustavljanja procesa
Zasad nijedna od familije Windows operacijskih sustava nema dokumentiranu API funkciju za zaustavljanja proces, kao što postoji funkcija SuspendThread() za zaustavljanje dretvi.
Proces bi se trebao zaustaviti prilikom svog pokretanja. To bi nam omogućilo da proces provjerimo u sustavu sigurnosne politike, prije nego što on počine djelovati. Nakon što se utvrdi prema sustavu sigurnosne politike, proces se može nastaviti ili uništiti.
Problem smo riješili na sljedeći način: Prolazeći kroz listu dretvi koje pripadaju određenom
procesu, svaku dretvu zaustavljamo funkcijom SuspendThread() . Nažalost postoje neki problemi:
• Pozivanjem funkcije SuspendThread() za dretvu koja posjeduje sinkronizacijski objekt, muteks ili kritični odsječak, može dovesti do potpunog zastoja ukoliko neka dretva pokušava održati sinkronizaciju sa dretvom koja je zaustavljena.
• Nisu svi programi predviđeni da budu zaustavljeni, pogotovo oni više dretveni. Tako da neki programi se mogu ponašati neprirodno nakon ponovnog pokretanja.
• Može se dogoditi da nakon dohvaćanja liste dretvi procesa, proces kreira novu dretvu koja nije u listi, i koja onda neće biti zaustavljena.
Dohvaćanje liste dretvi željenog procesa moguće je korištenjem CreateToolhelp32Snapshot()
funkcije. Evo kôda funkcije PauseProcess() :
Slika 2.4: Funkcija PauseProcess , za zaustavljanje procesa
BOOL PauseProcess(DWORD dwOwnerPID) { HANDLE hThreadSnap = NULL; BOOL bRet = FALSE; THREADENTRY32 te32 = {0}; // Napravimo snimak svih dretvi u sustavu hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAP THREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) return (F ALSE); // Pripremimo strukturu za prihva ćanje informacija o dretvi. te32.dwSize = sizeof(THREADENTRY32); // Slijedi nastavak ...
Procesna zaštitna stijena
7
Slika 2.5: Nastavak funkcija PauseProcess , za zaustavljanje procesa
Analogno PauseProcess() funkciji definiramo i ResumeProcess() funkciju, jedino umjesto
SuspendThread() koristimo funkciju ResumeThread() .
2.3. Modifikacijom tablice SSDT Po mojem mišljenju, modifikacija SSDT (System Service Dispatch Table) tablice jedna od
najboljih, ali i najsloženijih metoda za detekciju pokretanja procesa. Temelji se na modifikaciji ponašanja sustava, stavljanjem zakačke na izvorne API funkcije jezgre (Kernel Native API), odnosno samo na funkciju ZwCreateProcess() .
Ova tehnika implementira se modifikacijom zapisa unutar jezgrene sistemsko servisne otpremne tablice (System Service Dispatch Table). Ovakve modifikacije osiguravaju da zakačena funkcija biva pozvana prije originalne temeljne API funkcije (Native API). Zakačena funkcija najčešće na kraju poziva originalnu temeljnu API funkciju i mijenja izlazne rezultate prije vraćanja rezultata u pozivajući program. Ova tehnika nam pored detekcije pokretanja procesa omoguće i sakrivanje datoteka i procesa, sprečavanje uništavanje procesa i dr.
Prednost uporabe ove metode:
• Kao glavnu prednost ove metode mogao bi istaknuti da se procesi detektiraju u realnom vremenu i ne može se dogoditi da obavijest o kreiranju procesa kasni.
• Ovdje se ne javlja problem zaustavljanja procesa, jer se proces provjerava u sustavu sigurnosne politike i prije nego što biva kreiran. Time se ujedno i štede sredstva koje bi proces zauzeo prilikom svog kreiranja.
Nedostaci:
• Nažalost ovu metodu koriste i neki zlonamjerni programi (kernel rootkits) pa se može dogoditi da neki antivirusni programi ili neki drugi programi za zaštitu detektiraju naš program kao zlonamjerni program.
... // Prolazimo kroz snimak, i tražimo dretve koje pr ipadaju traženom procesu // Ukoliko dretva pripada, suspendirajmo ju if (Thread32First(hThreadSnap, &te32)) { do { if (te32.th32OwnerProcessID == dwOwnerPID) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESU ME, FALSE, te32.th32ThreadID); SuspendThread(hThread); CloseHandle(hThread); } } while (Thread32Next(hThreadSnap, &te32)); bRet = TRUE; } else bRet = FALSE; CloseHandle (hThreadSnap); return (bRet); }
Procesna zaštitna stijena
8
Da je ova metoda vrlo kvalitetna i učinkovita pokazuje da se ona koristi u nekim vrlo kvalitetnim programima za zaštitu od upada kao što su Kerio Personal Firewall 4, DiamondCD Process Guard 2 i Sebek 2.1.5.
2.3.1. Modifikacija SSDT tablice u praksi
Pokazat ćemo način zakačivana funkcije ZwWriteFile() . U Windows-ima, aplikacije za
zapisivanje podataka u datoteke koriste API funkciju WriteFile() eksportiranu od strane KERNEL32.DLL. U KERNEL32.DLL implementacija funkcije WriteFile() poziva temeljnu API funkciju ZwWriteFile() eksportiranu od strane NTDLL.DLL . Posao obavljen od strane ZwWriteFile() obavlja se u jezgrenom prostoru, tj. u prostoru jezgre operacijskog sustava. Zato implementacija ZwWriteFile() u NTDLL.DLL sadrži samo minimalni kôd koji se prenosi u prostor jezgre operacijskog sustava korištenjem prekida 0x2E .
Slika 2.6: Rastavljanje (disassembly) funkcije ZwWriteFile()
Čarobni broj 0xED u prvoj liniji je servisni broj (Service Number) za funkciju ZwWriteFile() u
Windows-ima 2k. Koristi se kao indeks u jezgrinoj servisno otpremnoj tablici (SSDT) za pronalaženje adrese funkcije koja sadrži stvarni kôd za zapisivanje podataka u datoteku. Adresa SSDT-a može se pronaći unutar servisne opisne tablice (Service Descriptor Table – SDT).
Referenciranje na SDT moguće je KeServiceDescriptorTable simbolom, koji je eksportiran od strane NTOSKRNL.EXE.
Slika 2.7: Struktura KeServiceDescriptorTable simbola
Prvi član strukture, SDT.ServiceDescriptor[0].KiServiceTable , sadrži pokazivač na SSDT
sistemskih funkcija implementiranih od NTOSKRNL.EXE. Kako je bilo spomenuto ranije, SSDT sadrži polje funkcijskih pokazivača koji pokazuju na temeljne API pozive. Broj ServiceLimit sadrži broj funkcijskih pokazivača u polju.
Vrijednost tipa DWORD KiServiceTable[0xED] je funkcijski pokazivač na NtWriteFile()
funkciju, koja sadrži stvarni kôd za zapisivanje u datoteku. Dakle, da bi promijenili ponašanje API funkcije WriteFile() , jednostavno trebamo napisati zamjensku funkciju, učitat je u prostor jezgre operacijskog sustava kao upravljački program, i izmijeniti KiServiceTable[0xED] da pokazuje na zamjensku funkciju. Zamjenska funkcija treba zadržati kopiju originalnog funkcijskog pokazivača
1- MOV EAX, 0ED 2- LEA EDX, DWORD PTR SS:[ESP+4] 3- INT 2E 4- RETN 24
typedef struct ServiceDescriptorTable { SDE ServiceDescriptor[4]; } SDT; typedef struct ServiceDescriptorEntry { PDWORD KiServiceTable; PDWORD CounterTableBase; DWORD ServiceLimit; PBYTE ArgumentTable; } SDE;
Procesna zaštitna stijena
9
(originalnu vrijednost KiServiceTable[0xED] ), tako da se originalna funkcija može pozvati te da se obavi namjeravani zadatak.
Pored modifikacije SSDT-a iz prostora jezgre operacijskog sustava pomoću jezgrenog
upravljačkog programa, SSDT moguće je promijeniti i iz korisničkog prostora (user-space) prostora, korištenjem metode direktnog zapisa u memoriju jezgre operacijskog sustava korištenjem \device\physicalmemorij . Više o ovoj metodi možete pronaći u dokumentu Defeating Kernel Native API Hookers by Direct Service Dispach Table Restoration [5].
Procesna zaštitna stijena
10
3. Prakti čni rad
Za razliku od jezgrenog upravljačkog programa koji je napisan u C-u, nadzorna aplikacija je napisana u Delphi-u. Aplikacija je više dretvena i sastavljena od tri dijela:
• manipulacije procesima • detekcija novog procesa s provjerom sigurnosne politike • manipulacija pravilima sigurnosne politike.
Slika 3.1: Dijagram toka poruke od upravljačkog programa do nadzorne aplikacije Način kako aplikacija radi je sljedeći: Aplikacija čeka na imenovani događaj koji signalizira
operacijski sustav. Kada je događaj signaliziran, aplikacija zaustavlja novonastali proces, njegove informacije ubacuje u listu za čekanje, te signalizira da u redu za čekanje ima elemenata. Sada se za svaki proces u listi za čekanje provjerava u sustavu sigurnosne politike. Ukoliko je definirano pravilo, s procesom se postupa prema pravilu, a ukoliko nije definirano pravilo, stanje se prijavljuje korisniku koji onda odlučuje kako postupiti.
3.1. Manipulacija procesima Aplikacija prikazuje popis svih trenutno aktivnih procesa sa sljedećim informacijama:
• ikona procesa • ime datoteke procesa (Image Name) • jedinstveni broj procesa (PID) • količina memorije koju proces koristi (Mem Usage) • prikaz Description polja iz verzije datoteke procesa (Description) • prikaz File version polja iz verzije datoteke procesa (Version) • puna putanja do datoteke procesa (File Path) • argumenti procesa (Command Line)
Za dobivanje popisa aktivnih procesa, upotrijebljena je nedokumentirana NTDLL funkcija
NtQuerySystemInfomation . Ova funkcija ima mnogo mogućnosti, među ostalima, dohvaća listu svih aktivnih procesa. Funkcija vraća pokazivač na polje tipa SYSTEM_PROCESS_INFORMATION.
Procesna zaštitna stijena
11
Za razliku od Task Managera, aplikacija omogućuje ubijanje i više procesa odjednom. Pošto aplikacija prilikom pokretanja postavlja SeDebugPrivilege ovlasti, nemože se dogoditi da se neki proces ne može ubiti ili da mu se ne može pristupiti.
Slika 3.2: Kôda funkcije za postavljanje SeDebugPrivilege
3.2. Detekcija novog procesa s provjerom sigurnosne politike Kao što je već ranije spomenuto na početku 3. poglavlja, aplikacija čeka na imenovani događaj
koji signalizira operacijski sustav. Kada je događaj signaliziran, aplikacija zaustavlja novonastali proces, njegove informacije ubacuje u listu za čekanje, te signalizira da u redu za čekanje ima elemenata. Sada se za svaki proces u listi za čekanje provjerava u sustavu sigurnosne politike. Ukoliko
function NTSetPrivilege(sPrivilege: string = 'SeDeb ugPrivilege'; bEnabled: Boolean= true): Boolean; var hToken: THandle; TokenPriv: TOKEN_PRIVILEGES; PrevTokenPriv: TOKEN_PRIVILEGES; ReturnLength: Cardinal; begin Result := True; // Only for Windows NT/2000/XP and later. if not (Win32Platform = VER_PLATFORM_WIN32_NT) th en Exit; Result := False; // obtain the processes token if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then begin try // Get the locally unique identifier (LUID) . if LookupPrivilegeValue(nil, PChar(sPrivilege ), TokenPriv.Privileges[0].Luid) then begin TokenPriv.PrivilegeCount := 1; // one privi lege to set case bEnabled of True: TokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; False: TokenPriv.Privileges[0].Attributes := 0; end; ReturnLength := 0; // replaces a var parame ter PrevTokenPriv := TokenPriv; // enable or disable the privilege AdjustTokenPrivileges(hToken, False, TokenP riv, SizeOf(PrevTokenPriv), PrevTokenPriv, Ret urnLength); end; finally CloseHandle(hToken); end; end; // test the return value of AdjustTokenPrivileges . Result := GetLastError = ERROR_SUCCESS; if not Result then raise Exception.Create(SysErrorMessage(GetLastE rror)); end;
Procesna zaštitna stijena
12
je definirano pravilo, s procesom se postupa prema pravilu, a ukoliko nije definirano pravilo, stanje se prijavljuje korisniku koji onda odlučuje kako postupiti.
3.2.1. Detekcija novog procesa
Detekcija procesa sastavljena je od tri klase: • TProcessNotification • TQueuedContainer • TProcessMonitor
Slika 3.3: Dijagram toka obrade poruke o nastanku novog procesa
TProcessNotification je dretva koja čeka događaj kreiran od strane upravljačkog programa. Čim je proces bio kreiran ili uništen, upravljački program signalizira objekt događaja i dretva TProcessNotification klase se probudi. Tada aplikacija prima podatke od upravljačkog programa. Nadalje se podaci dodaju u spremnik reda za čekanje (TQueuedContainer ) korištenjem metode Append() .
TQueuedContainer je dretveno siguran upravljački mehanizam reda za čekanje. Evo načina
kako javna metoda Append() za dodavanje novih elemenata u red radi:
1. Pauzira proces 2. Zaključa pristup do objekta 3. Doda podatke 4. Signalizira fElementAvailableEvent objekt događaja 5. Otključa objekt
Procesna zaštitna stijena
13
Slika 3.4: Funkcija Append , za dodavanje elemenata u red Budući da je dizajnirana da obavještava kada je dostupan element u redu čekanja, ona sadrži
dretvu, koja čeka sve dok element ne postane dostupan u lokalnom spremniku. Evo i pseudo kôda:
1. Čeka se na objekt događaja fElementAvailableEvent 2. Zaključa pristup do objekta 3. Izdvoji se podatak stavke 4. Otključa se objekt 5. Procesiraju se podaci koji su dohvaćeni iz reda čekanja
Slika 3.5: Metoda za obradu novih elemenata u redu čekanja
function TQueuedContainer.Append(Item: PProcessInfo ): Boolean; begin // Pause all created processes if Item^.bCreate then SuspendProcess(Item^.hProce ssID); //Wait to get fMonitor Result := WAIT_OBJECT_0 = WaitForSingleObject(fMo nitor, INFINITE); if Result then begin try // Add it to the queue fContainer.Push(Item); // Notify the waiting thread that there is av ailable // element in the queue for processing SetEvent(fElementAvailableEvent); finally ReleaseMutex(fMonitor); end; end; end;
procedure TQueuedContainer.DoOnProcessCreatedTermin ated; var RemoveFromQueue: Boolean; ret: DWord; begin RemoveFromQueue := True; while RemoveFromQueue do begin fxItem := nil; ret := WaitForSingleObject(fMonitor, INFINITE); if ret = WAIT_OBJECT_0 then begin RemoveFromQueue := fContainer.Count > 0; if RemoveFromQueue then // Is there anything in the queue fxItem := fContainer.Pop // Get the element from the queue else ResetEvent(fElementAvailableEvent); end; ReleaseMutex(fMonitor); // Process it only there is an element that ha s been picked up if RemoveFromQueue then begin Synchronize(xAssigned); //Generated event syn chronize with VCL end else Break; end; end;
Procesna zaštitna stijena
14
Klasa TProcessMonitor predstavlja okosnicu sustava za detekciju novog procesa. Ona sadrži prethodne dvije klase, koje koristi za signaliziranje događaja OnProcess , te dvije javne metode za pokretanje i zaustavljanje sustava za detekciju novog procesa.
Slika 3.6: Deklaracija klase TProcessMonitor
Metode za pokretanje i zaustavljanje sustava za detekciju novog procesa, šalju podatak upravljačkom programu o vrsti akcije koja se poduzima.
Slika 3.7: Metoda za zaustavljanje nadzornog mehanizma
3.2.2. Sustav sigurnosne politike
Sustav sigurnosne politike trebao bi provjeravati autentičnost svakog pokrenutog procesa. Moglo bi se definirati više načina detekcije autentičnosti, recimo:
1. Jednostavna – koja bi provjerava veličinu, vrijeme kreiranje, vrijeme modificiranja
izvršne datoteke procesa 2. Detaljna – koja bi pored jednostavne provjere izračunala hash izvršne datoteke procesa
pomoću md5.
TProcessMonitor = class private ... public ... function StartMonitoring: Boolean; function StopMonitoring: Boolean; property OnProcess: TProcessMonitorEvent read f ProcessE write fProcessE; end;
function TProcessMonitor.StopMonitoring: Boolean; var cmd: TDriverCommand; dwBytesReturned: DWord; begin Result := not fStarted; if Result then Exit; if fDriverHandle = 0 then begin fDriverHandle := CreateFile(PAnsiChar('\\.\'+fD riverName), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_REA D or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, // Perform synchronous I/O 0); // No template Result := not (INVALID_HANDLE_VALUE = fDriverHa ndle); if not Result then Exit; end; cmd.bActivate := False; // Activate/Deactivate the process Result := DeviceIoControl(fDriverHandle, IOCTL_PROCESSFIREWALL_ACTIVATE_MONITORING, @cmd, sizeof(cmd), nil, 0, dwBytesReturned, nil); fStarted := not Result; end;
Procesna zaštitna stijena
15
Pored provjere autentičnosti, sustav sigurnosne politike za svaki proces bi pogledao da li je za taj proces definirano pravilo ponašanja. Ukoliko je definirano pravilo ponašanja, s procesom bi se postupilo prema pravilu, u suprotnom, korisniku bi se ponudila mogućnost odabira.
U početku ovakav sustav bio bi „naporan“ za korisnika. S vremenom, za često pokretane aplikacije definirala bi se pravila ponašanja, te bi se aplikacije izvršavale bez obavješćivanja korisnika.
Da se cijeli sustav ne bi previše usporio, implementiran je jednostavan način detekcije
autentičnosti. Klasa TSecurityPolicy podatke o pravilima ponašanja pohranjuje u dvostruko povezanu listu.
Element liste je tipa TParentNode :
Slika 3.8: Struktura TParentNode
Struktura NodeInfo sadrži dva pokazivača, na sljedeći i na prethodni element, dok su u
FileInfo zapisani podaci potrebni za detekciju autentičnosti. Ukoliko je postavljen parametar AllowChildProcess , tada se roditelju dozvoljava pokretanje procesa, s time da se još onda provjeravaju pravila za dijete. Ako je postavljen parametar AllowAllProcess , tada roditelj može pokrenuti bilo koji proces bez daljnje kontrole. Za svako dijete u listu se dodaje element tipa TChildNode :
Slika 3.9: Struktura TChildNode Postavljanjem parametra Allow , dopušta se pokretanje dijete procesa. Ukoliko dođe do
pokretanja izmijenjene datoteke procesa (promijenjene veličine, vremena kreiranje ili vremena modificiranja izvršne datoteke procesa) aplikacija će obavijestiti korisnika o tome, ako nije postavljen AllowModified parametar, i ako korisnik prihvati pokretanje procesa, tada će se osvježiti podaci potrebni za detekciju autentičnosti procesa.
Za svaki roditelj proces u listu se dodaje po jedan zapis o njegovom ponašanju. Svaki roditelj
ima pokazivač na dvostruko povezanu listu svoje djece. Ovakva organizacija ubrzava pretraživanje liste, zato što se prvo u jednoj manjoj listi traži roditelj, a zatim se u listi djece pronađenog roditelja traži dijete proces.
TParentNode = record NodeInfo: TSecurityNode; FileInfo: TSecurityFileInfo; ChildrenHead, ChildrenTail: PChildNode; AllowChildProcess, AllowAllProcess: Boolean; end;
TChildNode = record NodeInfo: TSecurityNode; FileInfo: TSecurityFileInfo; Allow, AllowModified: Boolean; end;
Procesna zaštitna stijena
16
PParentNode
Glava
PParentNode PParentNode
PChildNode
PChildNode
PChildNode
PChildNode
PChildNode
PChildNode
PParentNode
Slika 4: Organizacije liste procesa u sustavu sigurnosne politike Sva pravila moguće je snimiti u željenu datoteku. Snimanje se obavlja prilikom zatvaranja
aplikacije, dok se učitavanje obavlja prilikom pokretanja aplikacije.
4. Upute za korištenje
Program se nakon instalacije automatski pokreće i prikazuje se u SysTray-u.
Slika 4.1: Izgled aplikacije u SysTray-u Pritiskom desne tipke miša na ikonu otvara se izbornik, koji omogućuje otvaranje aplikacije (Show) ili izlaz iz aplikacije (Exit):
Procesna zaštitna stijena
17
Slika 4.2: Izbornik iz SysTray-a
Otvaranje aplikacije moguće je dvostrukim pritiskom lijeve tipke miša na ikonu aplikacije.
Slika 4.3: Glavni prozor aplikacije; prikaz aktivni procesa u sustavu
Pritiskom desne tipke miša na neki od obilježenih procesa otvara se izbornik koji omogućuje ubijanje procesa ili više njih odjednom. Ubijanje procesa moguće je i pritiskom tipke Del.
U izborniku Options moguće je podesiti brzinu osvježavanja liste aktivnih procesa. Postoje četiri mogućnosti:
• High, svakih 0.5 sekundi, • Normal, svake 1 sekunde, • Low, svakih 5 sekundi i • Pause, zaustavljeno osvježivanje liste procesa.
Procesna zaštitna stijena
18
Slika 4.4: Izbornik brzine osvježivanja liste aktivnih procesa Da bi se vidjelo stanje sigurnosne politike, odabire se opcija Security Policy.
Slika 4.5: Glavni prozor aplikacije; prikaz pravila iz sustava sigurnosne politike Ovdje su prikazana sva pravila iz sustava sigurnosne politike. Ukoliko pravilo nema postavljeno
polje Parent File Name, to znači da je to pravilo od roditelja. Poslije roditelja, dolaze i pravila za djecu tog roditelja. Pravila je moguće brisati odabirom opcije Delete iz izbornika koji se prikaže prilikom pritiskanja desne tipke miša na obilježeno pravilo. Brisanjem pravila roditelja, brišu se i sva pravila djece kojima je obrisan roditelj. Sva pravila se snimaju prilikom gašenja aplikacije, te se prilikom pokretanja aplikacije učitavaju.
Ako se želi izaći iz aplikacija, tada se mora odabrati opcija Exit iz izbornika File ili iz izbornika
koji se prikaže prilikom pritiskanja desne tipke miša na ikonu u SysTray-u.
Procesna zaštitna stijena
19
Kada se pokrene novi proces za kojeg nije definirano pravilo ponašanja u sustavu sigurnosne politike, korisniku se prikaže prozor sa mogućnošću odabira ponašanja.
Slika 4.6: Prozor s mogućnostima korisnika nakon pokretanja aplikacije za koju nije definirano pravilo u sustavu sigurnosne politike
Ako se odabere opcija Create a rule for this event and don't ask me again definirat će se pravilo
da se proces smije odnosno ne smije pokrenuti ako se pritisne gumb Permit odnosno Deny. Opcija Don't save the rule ima značenje da se, ukoliko se definira, pravilo ponašanja ne usnimi u datoteku sa svim pravilima ponašanja na izlasku iz aplikacije.
Obilježavanje opcije Create a rule for parent application, roditelj proces (u ovom slučaju Windows Explorer) moći će ili neće moći pokretati procese, ako pritisnemo gumb Permit odnosno Deny.
4.1. Instalacija Instalacijske program vodit će vas kroz korake instalacije programa. Da bi se program mogao
instalirati, korisnik mora imati mogućnost upisivanja u registry i mogućnost instalacije upravljačkog programa. Najjednostavnije rješenje je da korisnik ima administratorske ovlasti prilikom pokretanja instalacije programa.
Instalacija će zapisati putanju do izvršne datoteke pod nazivom ProcessFilewall u ključ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curre ntVersion\Run . Time će se omogućiti pokretanje aplikacije svaki puta prilikom pokretanja Windows-a. Nakon zapisivanja u registry, instalacija će kopirati datoteku ProcObsrv.sys u <Windows>\System32 direktorij, nakon čega će registrirati upravljački program za automatsko pokretanje prilikom pokretanja Windows-a.
Procesna zaštitna stijena
20
5. Zaklju čak
Detekcija pokretanja procesa modifikacijom SSDT tablice (System Service Dispatch Table) vrlo je komplicirana. Implementirana je nešto lakša, ali ne i jednostavna metoda detekcije pokretanja procesa uporabom API funkcije PsSetCreateProcessNotifyRoutine() .
Naizgled aplikacija radi dobro. Međutim javilo se nekoliko problema. Nadzorna aplikacija obavijesti korisnika o novom procesu, ali se proces „provuče“ pored funkcije za zaustavljanje procesa PauseProcess() .
Budući da su danas pisci nepoželjnih programa vrlo obrazovani, i moguće je da je virus napisan kao sistemski servis (system service), nažalost, ovaj program neće uspjeti detektirati njegovo pokretanje.
Implementacijom metode koja koristi modifikaciju SSDT tablice omogućilo bi se proširenje za
nadgledanje registry-a i drugih dijelova sustava, u svrhu zaštite sustava od neželjenih programa. Ubacivanjem mogućnosti nadzorne aplikacije u Task Manager, dodatno bi se približio program korisnicima.
Procesna zaštitna stijena
21
6. Literatura
[1] MSDN Knowledge base Q197571
[2] API hooking revealed by Ivo Ivanov, dostupno na: http://www.codeproject.com/system/hooksys.asp
[3] Windows DDK Documentation, Process Structure Routines, dostupno na: http://msdn.microsoft.com/library/default.asp?url=/ library/en-us/kmarch/hh/kmarch/k108_2qwi.asp
[4] Detecting Windows NT/2K process execution by Ivo Ivanov, dostupno na: http://www.codeproject.com/threads/procmon.asp
[5] Defeating Kernel Native API Hookers by Direct Service Dispach Table Restoration, dostuno na: http://www.security.org.sg/code/SIG2_DefeatingNativ eAPIHookers.pdf