Pod pojmem SSDT (System Service Descriptor/Dispatch Table) si většina z lidí znalých jádra Windows představí datové struktury, které zajišťují správné fungování mechanismu systémových volání. Jejich modifikací lze monitorovat a ovlivňovat nejen chování aplikací.
Protože mě obsah těchto tabulek odjakživa zajímal a různé bezpečnostní aplikace jej nezobrazovaly příliš podrobně, rozhodl jsem se napsat utilitu SSDTInfo, která najde a zobrazí všechny dostupné informace.
Před samotným představením této malé aplikace se ještě pár odstavci zmíním o tabulkách systémových voláních jako takových. Je pravda, že jsem o nich psal již v článcích SSDT – System Service Descriptor Table a Malý trik se SSDT, aneb jak Rootkit Unhooker opět slavně zvítězil, ale tam podávané informace nejsou úplně přesné, zvláště v díle druhém. Pokusím se je tedy uvést na pravou míru. V druhém díle například tvrdím, že stínová tabulka systémových volání je obsažena v modulu win32k.sys. To není pravda, nachází se v hlavním modulu jádra (ntoskrnl.exe či ntkrnlpa.exe), avšak její tabulka adres a tabulka argumentů leží v paměti win32k.sys.
V systému existují dvě tabulky systémových volání známé pod názvy KeServiceDescriptorTable a KeServiceDescriptorTableShadow. První z nich zajišťuje systémová volání týkající se vlastního jádra (práce se soubory, procesy, vlákny, paměťově mapovanými soubory, synchronizační primitiva). "Stínová" tabulka je navíc schopná obsloužit i volání související s grafickým uživatelským rozhraním (okna, kreslení).
Obě tabulky obsahují několik struktur – podtabulek –, jejichž definici vidíte pod tímto odstavcem. Slovo "několik" zastupuje na Windows 2000 a Windows XP číslovku čtyři, na vyšších verzích systému jak normální, tak stínová tabulka obsahují dvě podtabulky.
typedef struct
{
PVOID *AddressTable;
PULONG CounterTable;
ULONG NumberOfServices;
PBYTE ArgumentTable
}
Při přechodu do režimu jádra v rámci systémového volání vlákno dostane z uživatelského režimu pouze následující informace:
Tyto informace jádro dokáže přetavit na adresu rutiny (systémové služby), kterou chce aplikace vykonat a počet parametrů, které tato rutina potřebuje. Pro zjištění první informace stačí použít horní část registru EAX jako index do tabulky systémových volání a jeho dolní část jako index do pole AddressTable. Počet parametrů se zjistí obdobně – dolní část EAX se použije jako index do ArgumentTable, místo do pole adres.
Jakmile je známá adresa systémové služby a počet parametrů, které tato rutina akceptuje, překopíruje se příslušný počet bytů z uživatelského režimu (adresa je v registru EDX) a dojde k jejímu zavolání. Následně se vlákno vrátí opět do uživatelského režimu.
Podtabulka obsahuje ještě dvě položky. NumberOfServices udává počet položek v polích AddressTable, ArgumentTable a CounterTable (pokud je toto pole přítomno). Struktura CounterTable, pokud je přítomna (tedy, není-li její adresa rovna NULL), obsahuje statistické informace o počtech volání každé systémové služby.
Z využití informací v registrech EAX a EDX není patrné, zda vlákno k vyhledávání adresy služby a počtu parametrů použije normální či stínovou tabulku systémových volání. Pravda je taková, že se použije ta tabulka, jejíž adresu obsahuje položka ServiceTable struktury ETHREAD reprezentující dané vlákno. Ta na počátku nese adresu KeServiceDescriptorTable, ale s prvním voláním funkce grafického uživatelského rozhraní (která se v normální tabulce systémového volání nenachází) dojde k jejímu přepsání na adresu stínové tabulky. K dalším změnám pak již během života vlákna nedochází.
SSDTInfo dokáže zobrazit obecné informace o tabulkách systémových volání, mezi které patří obsah jejich podtabulek a vlastnosti jednotlivých systémových služeb z toho plynoucí. Pomocí menu Tabulka lze určit, jakou z obou struktur má program prozkoumat.
Pomocí položky Tabulka | Zkontrolovat se spustí kontrola konzistence. Program zobrazí všechny informace z oblasti tabulek systémových volání, které mu připadají podezřelé. Zde je nutné uvést, že aktuální verze aplikace nedokáže zjistit pravé adresy KeServiceDescriptorTable a KeServiceDescriptorTable, ale zobrazí ty informace, které bude systém s největší pravděpodobností používat, když nějaké obyčejné vlákno provede systémové volání.
Doplňkové služby spočívají v možnosti uložit nasbírané informace do textových souborů (položka Soubor | Uložit) a nastavit jazyk. Zatím je podporována čeština a angličtina, ale podporu dalšího jazyka lze snadno doplnit, stačí se držet následujícího návodu:
SSDTInfo podporuje 32bitové verze operačních systémů Windows 2000, Windows XP, Windows Server 2003, Windows Vista, Windows 7 a Windows Server 2008.
Na 64bitových Windows se tabulky systémových volání liší polem AddressTable, které místo adres systémových služeb obsahuje jejich offsety vzhledem k jeho začátku. Dolní čtyři bity offsetu navíc mohou být využity k uchování informace o počtu parametrů, protože začátky rutin jsou zarovnány na 16 bajtů. Díky této optimalizaci není třeba při každém systémovém volání sahat do tabulky argumentů (ArgumentTable), což vede k určitému zrychlení.
Větším problémem je nalezení adres tabulek systémových volání, protože na této platformě ani jedna z nich není exportována a struktury ETHREAD postrádají položku ServiceTable. Ačkoliv způsob, jak potřebné informace získat, znám, zatím jsem nenašel čas na jeho implementaci.
Binárky aplikace si můžete stáhnout níže. Součástí je i ovladač ssdtinfo.sys, z čehož vyplývá, že program pro svůj běh vyžaduje administrátorská práva. Na Windows podporujících Kontrolu uživatelských účtů (User Account Control) by si o něm měl sám pomocí známého dialogu požádat.
Zatím si můžete stáhnout pouze binárky, ale uvolnění zdrojových kódů je též plánováno.