Hlavné menuPrihlásenieHľadať |
Píšeme rootkity v r0
pondelok, 18.08.2008 17:30
V tomto článku si projdeme absolutně základní principy a fungování rootkitů v kernel mode - podíváme se na to, co je od rootkitů očekáváno a jak těchto očekávání dosáhnout. Rovněž si základní rootkit napíšeme a zaimplementujeme do něj nekteré krycí techniky a bypassneme tak například IceSword, či Eset SysInspector. UPOZORNĚNÍ: NÁSLEDUJÍCÍ DOKUMENT JE URČEN POUZE PRO STUDIJNÍ ÚČELY. ZA JAKÉKOLIV ZNEUŽITÍ TOHOTO DOKUMENTU A JEHO SOUČÁSTÍ, VČETNĚ ZDROJOVÝCH KÓDU NENESE AUTOR ŽÁDNOU ZODPOVĚDNOST. ČLÁNEK NESMÍ BÝT KOPÍROVÁN BEZ POVOLENÍ AUTORA. WARNING: FOLLOWING DOCUMENT IS INTENDED FOR STUDY PURPOSES ONLY. AUTHOR HAS NO RESPONSIBILITY FOR ANY ABUSE OF THIS DOCUMENT OR ITS PARTS INCLUDING SOURCE CODE. IT IS NOT ALLOWED TO COPY THIS DOCUMENT WITHOUT AUTHORS PERSMISSION. if you do not agree, please close your eyes and try to close your browser ;) Píšeme rootkity v r0Rootkit - důvody použitíDůvody existence rootkitů jsou snad všem zřejmé, ale jelikož je cílem tohoto článku vysvětlit a ozřejmit, jak rootkity pracují a jak je psát, není na škodu si připomenout, co vlastně mají dělat. Co má tedy rootkit za úkol? Úkolem rootkitu je skrýt činnost a projevy "škodlivého kódu". Důvod? Co největší a hlavně nejdelší nevědomost uživatele ohledně faktu, že je jeho systém napaden a zneužíván proti němu samotnému. V tomto díle si řekneme, jak skrýt pouze základní projevy a to, běžící proces a hodnotu v registru. Hákování - pojem, praxe a tvrdá realita pro ring3 rootkityV hákování spočívá celé provedení rootkitů, ať už v r3 nebo v r0. Psaní rootkitů v ring3 má několik nevýhod - jedná se zcela o neeficientní a neefektivní implementaci hákování pro potřebu skrytí kompromitujících dat viru. Situace je ilustrována na následujícím diagramu: Jak si můžete všimnout, všechny procesy musí být zaháknuty r3 rootkitem, aby měl nějaký valný efekt - každý z procesů totiž představuje potenciální prohlížeč souborů, procesů, registrů, atp., který by mohl zobrazit právě ony kompromitující údaje ohledně přitomnosti viru - což je pochopitelně naprosto nepřípustné (vlastně jak pro koho, že? :)). Jaké strasti tedy použití ring3 rootkitů přináší? 1) proces viru nemusí mít dostatečná privilegia na to, aby pracoval se všemi procesy (debug privs, atp.) Když se nad tím zamyslíme, příjdeme na to, že implementovat ring3 rootkit je spíše nebezpečné, zbytečné a příliš pracné na to, jaký minimální efekt může mít. Co s tím? Na tuto otázku je velice jednoduchá odpověď, prostě se přesuneme níže. Přesuneme se do jádra systému a tam teprve začne opravdová zábava. Proč právě do jádra? Právě tam míří volání všech esenciálních funkcí systému, aby si například "popovídali" s ovladači disku, když chce nějaký program načíst soubor, nebo načíst data systému, když chce nějaký program načíst informace o běžícím procesu, atd. Jak vlastně vypadá takové čtení souboru? Program (explorer.exe) -> ReadFile (kernel32.dll) -> ZwReadFile (ntdll.dll) -> SYSENTER / Int 2Eh -> | (a jsme v ring0) (>SSDT>) NtReadFile (ntoskrnl.exe) -> drajvry, drajvry, drajvry... S ring3 rootkitem zahákeme maximálně ZwReadFile, dál už se nedostaneme, avšak s driverem ano - s ním si můžeme zaháknout SYSTENTER / Int 2Eh, SSDT, inline hákama samotné funkce a klidně i samotné drivery. Jelikož všechna volání zmíněných esenciálních usermode funkcí volají jejich ekvivalent v jádru, je potřeba zaháknout jen ten. Což znamená, namísto hákování ZwReadFile ve všech procesech zahákneme jedinou funkci v jádru. Viz obrázek: Ring0 aka KernelModeÚvod do pekelNejprve bych chtěl trochu upřesnit oč jde. Zábava to sice bude, ale sranda rozhodně ne. Jakákoliv chyba, ať už sebemenší dříve nebo později způsobí BSOD, restart, prohledávání kódu, kompilaci, nahrání a vytvoření další služby - prostě koloběh "života", který u vývoje usermode aplikací tak častý není. Abychom vůbec mohli začít, je nutné si projít seriály o psaní driverů, které napsal kolega Vrtulex, včetně článků SSDT - System Service Descriptor Table a článku o triku se SSDT, který rovněž využijeme pro skrytí před IceSwordem zde: Malý trik se SSDT, aneb jak RootkitUnhooker opět slavně zvítězil. Hlavní je obsah článků pochopit, pokud jste články četli a přesto vám unikají některé věci, tak se můžete pokusit pochopit vše z mého příkladu. Pro úplnost ještě dodávám, že uvedený příklad je napsaný v MASMu s použitím KmdKit od Four-F a WinAsm studia. flOwPokud tuto hru neznáte, rozhodně ji zkuste, až budete mít pocit, že musíte vzít monitor a hodit jej z okna, tato hra Vám svou relaxační podstatou velice pomůže. Píšeme r0 rootkit (konečně)Hákujeme SSDTCo SSDT je, už asi víte z článku od kolegy Vrtuleho, proto můžeme část věnovanou SSDT prospat. Dobře, dobře, tak si projdeme ty nejzákladnější věci, které budeme potřebovat. SSDT je struktura (panebože, struktura!), vypadá následovně: struct SSDT_ENTRY
{
PULONG DispatchBase;
PULONG CounterBase;
ULONG DispatchCount;
PCHAR ParamTable;
}Pointer na tuto strukturu je exportován z ntoskrnl pod jménem KeServiceDescriptorTable. Hodnota DispatchBase je pointer na pole ukazatelů na důležité funkce - tzv. DispatchTable. Hodnota DispatchCount je počet pointerů držených v DispatchTable. Když je volána Zw funkce, je načtena z DispatchTable adresa Nt ekvivalentu: Program (explorer.exe) -> ReadFile (kernel32.dll) -> ZwReadFile (ntdll.dll) -> SYSENTER / Int 2Eh -> | SSDT->DispatchTable (NtReadFile) -> NtReadFile (ntoskrnl.exe) ... Pokud tedy adresu v DispatchTable zaměníme za pointer na naši funkci, bude volána právě naše funkce. Takže naším jediným cílem je zaměnit adresu API za adresu naší funkce. Je tu ovšem několik háčků. První háček je, že paměť ve které SSDT je, je read-only. Musíme přenastavit EnableWrite bit v Cr0 registru na 1. Pak už můžeme zapisovat do SSDT, jak se nám zachce. Otázka ale zní: kam? Pořadí pointerů na funkce v DispatchTable není zdokumentováno. Jsme tak donuceni zdokumentovat si tabulku sami, nebo použít zase nějaký trik, který nám pomůže. V příkladu jsem použil trik stavějící na předpokladu a znalosti, jak fungují Zw API: ZwReadFile 7C90E27C - b8 b7 00 00 00 - mov eax,000000b7 7C90E281 - ba 00 03 fe 7f - mov edx,7ffe0300 7C90E286 - ff 12 - call dword ptr [edx] 7C90E288 - c2 24 00 - ret 0024 V EAX je uložen index adresy v DispatchTable (tedy to, co aktuálně potřebujeme), EDX ukazuje na rutinu se SYSENTER, případně Int 2e. Jelikož je ntdll.dll přítomna i v kernelu, můžeme si načíst adresu Zw API a dword obsahující index Nt API si z první instrukce MOV vytáhnout. Index stačí shiftnout o dva bity doleva, přičíst k DispatchBase a máme pointer na adresu dané Nt funkce v DispatchTable. Nyní stačí jen bezpečně vyměnit pointry na funkce. Píšeme handleryJelikož jsme se dostali přesně mezi usermode aplikace a jádro systému, máme nad celým usermodem ohromnou moc. Můžeme upravit vše, co se nám jen zlíbí. Veškerá volání funkcí, které jsou pro nás nějakým způsobem důležité jdou přes nás - náš hák a náš hook handler... parametry, vstupy i výstupy, to vše máme nyní pod kontrolou. Je samozřejmé, že nebudeme upravovat nebo ignorovat veškerá volání těchto funkcí. Většinu z nich pustíme jádru ke zpracování a nerušeně je necháme, aby si dělaly co potřebují - musíme se chovat tiše. Kontrolovat vstupy, výstupy a volat originální funkce mají za úkol tzv. handlery - naše hákovácí funkce, na které jsme přesměrovali adresy v DispatchTable. Zjednodušeně bychom si mohli představit hák a jeho handlování následovně. Předpokládejme funkci ZískejSeznamProcesů (byref Seznam). Aplikace zavolá funkci ZískejSeznamProcesů, ta si nějakým způsobem tyto informace zjistí, zapíše je do seznamu a ten vrátí aplikaci. Nyní předpokládejme, že jsme funkci ZískejSeznamProcesů vyměnili za Hook_ZískejSeznamProcesů, který vypadá následovně: Hook_ZískejSeznamProcesů (byref Seznam) Call ZískejSeznamProcesů Projdi Seznam Je v Seznam "virus.exe" ? Ano: Smazat "virus.exe" ze seznamu Vrátit Seznam Konec Nejjednodušší a snad všem známý koncept háku, který budeme implementovat v našem prvním rootkitu. V případě, že je v seznamu nalezen náš proces, je ze seznamu vyňat a aplikace se tak o žádném "virus" procesu nedozví. Prosté - jen doprogramováváme některé systémové funkce, nic víc. My budeme skrývat proces a hodnotu v registru. Na to potřebujeme dva háky - NtQuerySystemInformation a NtEnumerateValueKey. Pokud ještě nejste zcela zžiti s Nt API, nebo neznáte principy fungování high level API, tak doporučuji stáhnout nějaký dasm a projít si knihovny jako kernel32, advapi32, kde velmi rychle zjistíte všechny návaznosti na Nt funkce. Skrýváme procesProtože jsme zatím v začátcích, není nic jednoduššího, než skrýt proces tak, že zahákneme NtQuerySystemInformation v případě, kdy je tato funkce volána s classou 5, tedy požadavek o výpis aktuálně běžících procesů, včetně nějakých těch detailů. Zmizíme tak nadobro z Task Manageru, Hijackthis, Process Exploreru atp. Abychom tohle dokázali, musíme vědět, jak vypadají výstupní data a jak je tedy správně filtrovat. U mnoha Nt API se můžeme setkat s "deltováním", v některých případech, jako například právě v tomto je velmi pohodlné. Jindy je zase velice otravné a bude nám zbytečně komplikovat naši práci. V čem tedy deltování spočívá? Představme si bloky dat, uložené za sebou. Každý z nich je jinak dlouhý. Delta je rozdíl mezi začátkem následujícího a aktuálního bloku (tedy nic jiného, než délka aktuálního bloku) - po přičtení k ukazateli na aktuální blok tedy dostáváme ukazatel na blok další. V případě, že je blok poslední je delta rovna nule. NtQuerySystemInformation s classou 5 nám vrátí seznam procesů s jejich detaily právě ve struktuře na bázi deltování. My potřebujeme znát pouze některé členy této struktury: Struct SYSTEM_PROCESS_INFORMATION offset name type 0: DELTA: DWORD 44h: PID: DWORD EndS To je vše, co potřebujeme vědět. Už vidíte kód? ;) Jasně, je to přesně tak, jak si myslíte - prostě budeme skákat po deltách a testovat, zda-li je dword na 68. bytu roven PIDu našeho chráněného procesu. V případě, že ano, přepíšeme deltu předchozího záznamu tak, aby ukazovala na záznam před námi (delty přičteme), případně ji vynulujeme (pokud je záznam poslední). Aplikace, která obdrží takovýto seznam bude skákat právě po deltách a načítat si detaily procesů - ovšem bez toho našeho. Jednoduché, efektivní, ale přesto velice dobře odhalitelné. Jak to? 1) jen jsme přepsali deltu, v seznamu jsou pořád naše údaje - ty ale můžeme smazat Jak tedy vypadá takový handler? Upozorňuji, že obsahuje jednu chybu, jedná se však o předpoklad, který snad bude vždy splněn. Kdo na to příjde? :) Pro úplnost ještě dodávám význam funkce Hook_ToModify, která pouze vyhodnotí požadované podmínky, pro umožnění prohledávání / úpravy výstupu. Hook_NtQuerySystemInformation proc InfoType:DWORD, lpBuffer:DWORD, dwBufferSize:DWORD, pReqSize:DWORD
local dwRetVal: DWORD push pReqSize ;:: MODIFY RETURNED DATA ::::::::::::::::::::::::::::::::::::::::::::::::: .WHILE dword ptr[EDI] mov eax, dwRetVal Jakmile je výsledek volání funkce NtQuerySystemInformation prohnán přes handler uvedený výše, aplikace, které procházejí seznam pomocí delt nic neuvidí. Skrýváme hodnotu registruJak určitě dobře víte, enum hodnot v klíči se přes high-level API provádí pomocí advapi32, konkrétně RegEnumValue. Když prozkoumáme cally v RegEnumValueW, narazíme na volání funkce NtEnumerateValueKey - na tu se zaměříme. Tato funkce je dokumentována v DDK, ovšem nastává otázka, na kterou classu se zaměřit - nejlépe na všechny. My se pro začátek a z demonstračních účelů podíváme pouze na classu KeyValueFullInformation = 1, která je použitá pro enum hodnot například v Hijackthis, atp. Vše co potřebujeme o struktuře této classy vědět: Struct KEY_VALUE_FULL_INFORMATION offset name type 10h: NameLen DWORD 14h: Name[] WCHAR EndS Tato struktura v sobě drží informace pouze o jedné hodnotě v klíči. Pro výpis všech hodnot v klíči je tedy nutné volat NtEnumerateValueKey tolikrát, kolik je v klíči hodnot, popřípadě do té doby, než tato funkce nevrátí STATUS_NO_MORE_ENTRIES. To pro nás znamená z prvního pohledu ohromnou výhodu, z druhého, že to taková výhoda není a z pohledu třetího zjistíme, že kvalitní řešení tohoto problému spotřebuje mnohem více myšlení, než jsme prvně mysleli a to hlavně kvůli multithreadingu. O těchto problémech si můžete přečíst v kolegově článku Vývoj ovladačů jádra 3. díl - synchronizace. Nejjednodušší řešení je využít správného chování aplikací, které testují návratovou hodnotu funkce na úspěch, většina programů ani nepípne, když dojde k chybě, prostě pokračují další hodnotou - co lepšího si přát? Hook_NtEnumerateValueKey proc hKeyHandle:DWORD, dwIndex:DWORD, dwKeyValInfoClass:DWORD, lpBuffer:DWORD, dwLen:DWORD, dwOutResLen:DWORD
local dwRetVal: DWORD push dwOutResLen invoke Hook_ToModify, eax, lpBuffer, dwKeyValInfoClass, 1 invoke RtlCompareMemory, addr C_SU_STARTUPVAL, eax, sizeof C_SU_STARTUPVAL-2 mov dwRetVal, STATUS_INVALID_PARAMETER mov eax, dwRetVal Tento handler funguje velice jednoduše, nejprve otestuje, zda-li jméno hodnoty, která je vrácena NtEnumerateValueKey má stejnou délku, jako jméno hodnoty, kterou chceme schovat, v pozitivím případě porovnáme oba řetězce, řetězec který chceme skrýt je definován identifikátorem C_SU_STARTUPVAL. V případě, že jsou stejné můžeme hodnotu vynulovat a vrátíme STATUS_INVALID_PARAMETER. V této chvíli bychom neměli být vidět ve většině programů - výsledek je absolutně základní rootkit napsaný těmi nejzákladnějšími možnostmi. Ovšem nám zůstává několik otázek. Abychom mohli skrýt proces, musíme znát jeho PID. Otázkou je, jak co nejjednodušeji driveru říct, který PID má skrýt - tedy, jak s driverem (rootkitem) co nejjednodušeji komunikovat. Komunikace s rootkitemNejjednodušší ukázka chování dropperu je taková, kdy se po jeho spuštění vyextrahuje driver (např. z resource), je načten do jádra a po ovladači se chce, aby tento dropper skryl - ten pak povětšinou začne s různou nekalou činností. Otázkou je, jak dropper driveru řekne, jaký má PID? Mohl by PID zapsat přímo do souboru driveru, nebo použít některý z konvenčních způsobů, jako je dorozumívání pomocí trubek, registrů, souborů, devicio, atp. Tyto konvenční způsoby mají jednu velkou nevýhodu - nemám je rád. Osobně dám přednost přímému volání funkce, než použít prostředníka. Jak ale volat funkci driveru z aplice běžící v usermode? Jednoduše. Zahákneme nějakou moc nepoužívanou Nt API a (s)prostě ji využijeme - handler bude při speciálních vstupních datech fungovat jako komunikační rozhraní. Pro tento účel jsem zvolil funkci NtFlushInstructionCache. Obsahuje tři parametry. Vůbec nás nemusí zajímat, co funkce dělá, nebo jaké parametry má. Tři parametry jsou pro tento účel naprosto perfektní, v prvním pošleme magickou hodnotu - například "RKIT" (&H524B4954), v druhém parametru pošleme identifikátor funkce, ve třetím její parametr: Communicate_Hook_NtFlushInstructionCache proc \
ddA:DWORD, ddB:DWORD, ddC:DWORD
.IF ddA == "RKIT" ; codename "RKIT"
.IF ddB == "PID:" ; PID command
mov eax, ddC
mov G_HIDE_PID, eax ; save PID to hide
.ENDIF
mov eax, 0
.ELSE
push ddC ; original call
push DDB
push ddA
Call g_tHook_NtFIC.PtrToOriginal
.ENDIF
Ret
Comunicate_Hook_NtFlushInstructionCache EndPJednoduché a efektivní. Nyní můžeme bez problémů automaticky skrýt libovolný proces podle potřeby aplikace v usermode. AntirootkityProblémy...Všichni je známe, teď už i přesně víme, proti čemu jsou určené. Otázkou nyní je, jak přesně nás antirootkity ohrožují a jak detekují, že je v sýstemu rootkit. Doufám, že si uvědomujete tu jednoduchost hákování SSDT - proto je ve většině antirootkitů tato tabulka vypsána celá, včetně položky "Zaháknuto Ano / Ne", což je první větší problém. Antirootkity rády testují procesy, zda-li se některý z nich neskrývá a protože my pomocí rootkitu, který hákuje SSDT proces skrýváme, máme další problém. Je zde však jedno velké "ale". Podobně, jako různé r3 programy, např. náš oblíbený Hijackthis, obsahují i antirootkity chyby, nedodělky, špatné předpoklady, nebo zcela nepochopitelné hlouposti. Ovšem si také musíme uvědomit, že vývoj r0 rootkitů není tak "průhledný", jako psaní virů v usermode. IceSword- vývoj tohoto antirootkitu byl již ukončen relativně dávno a obsahuje tedy určitá, řekněme negativa, která některé funkce v IceSwordu velice degradují. IceSword je však stále používán a proto bychom si mohli povědět o dvou tricích, které na něj fungují. Skrývání změn v SSDT má pro nás velkou výhodu, antirootkity uživatele neupozorní na to, že je SSDT změněna, tudíž se uživatel nedozví o zaháknutých funkcích a náš rootkit zůstane bez povšimnutí. IceSword a mnoho jiných antirootkitů jsou náchylné právě k oklamání pomocí tohoto triku, který je navíc velice snadné implementovat. Jedná se o trik o kterém jsem mluvil v úvodu - tedy byste měli znát teorii, kterou nyní převedeme do praxe. Raději ještě celou teorii shrnu do podstatných informací. SSDT jsou dvě - SSDT a SSDTS. Na SSDT ukazuje KeServiceDescriptor, ta ukazuje na DispatchTable, kterou statečně hákujeme; SSDT je používána z prvu všemi vlákny. Vlákna, která prošla GUI API se "přepnou" a začnou používat SSDTS. SSDTS má tu ohromnou výhodu, že používá tu samou DispatchTable, jako SSDT: Co se stane, když SDDTS bude ukazovat na jinou DispatchTable? Nic. Bude to všechno fungovat stále normálně dál. Co se stane, když zahákneme právě funkce v SSDTS? Antirootkit si načte KeServiceDescriptor, podívá se na SSDT, na DispatchTable a zjistí, že je vše v pořádku. Ale vlákna, která už prošla nějakými grafickými funkcemi používají SSDTS, která je zaháknutá! Prostě a jednoduše, antirootkitům podstrčíme originální nezaháknutou SSDT a pro systém - vlákna použijeme háknutou DispatchTable. Prosté, jednoduché a efektivní. Jak taková implementace může vypadat: HideSSDTTrick proc uses esi edi lpSSDT:DWORD, lpNewSSDT:DWORD
local dwDTSize: DWORD mov esi, lpSSDT invoke ExAllocatePool, NonPagedPool, eax Tato funkce má dva stavy. První, kdy se nejprve kopíruje originální SSDT - neupravená, kteoru předhodíme antirootkitům. A stav druhý, po té, co jsou všechny funkce zaháknuty, je zaměněn ukazatel SSDT DispatchTable na originální neupravenou. Skromná funkce na ovládnutí celé SSDT může vypadat třeba následovně: HookSSDT proc uses esi edi dwHook:DWORD
invoke GetSSDT, 0 mov esi, eax invoke HideSSDTTrick, esi, 0 push esi Parametr dwHook specifikuje, zda-li se má daná funkce zaháknout, nebo naopak odháknout. GetSSDT vrátí pointer na SSDT, tu nakopírujeme, zahákneme funkce a vyměníme pointery SSDT DispatchTable na čistou DisaptchTable. SSDTS stále ukazuje na tu původní zaháknutou, takže je vše tak, jak by pro nás mělo být. Ring3 cirkus Eset SysInspectorJen ze zajímavosti pro techniky Esetu (greetz) a samozřejmě i pro Vás ostatní - malá ukázka, že i tento slibně vypadající program s antirootkit jádrem má několik vážných slabin, podobného rázu jako výše zmíněný Ring3 cirkus s IceSwordem. Z mírně nepochopitelných důvodů je pro získávání cesty ke spustitelnému souboru procesu použita funkce GetModuleFileNameEx, čímž seznam procesů řadí na stejnou informační hodnotu, jako Hijackthis. To ale není to nejzajímavější. To nejzajímavější nastává až tehdy, kdy je v systému přítomen rootkit a skrývá proces. Proces skrytý pomocí SSDT háku a jeho vyřazení pomocí deltování odhalí! Ovšem, pokud má proces v PEBu jako cestu uvedenou nějaký z MS souborů, je tato skutečnost ignorována - proces zmizel (screenshot). Ale abych nebyl příliš negativistický, SI si to vynahrazuje jinak (zatím přesně nevíme jakým způsobem přesně, ale v článku věnovaném testování antirootkitů si to určitě řekneme a obejdeme to), dokáže odhalit skrytý záznam v registru a tehdy jsme nahraní. ZávěrKaždý z antirootkitů obsahuje nějaké ty chyby, například DarkSpy (nevím, jak je to s aktuální verzí) také bojuje s problémy ring3 cirkusu u běžících procesů, starší verze GMERu také, ale každý z nich je lepší v něčem jiném a převyšuje tak ostatní. Který z antirootkitů bychom Vám tedy doporučili? Především RootkitUnhooker, GMER a RootRepeal a jakmile bude připraven i detektor skrytých souborů FileDetector kolegy Vrtuleho, tak i ten ;). DownloadStahovat kompletní zdrojový kód v MASMu můžete zde: Dotazy směřujte prosím sem do komentářů, popřípadě do fóra. |
Fórum | IRCOdkazy |
Ahoj, je nejaka moznost ako
Ahoj, je nejaka moznost ako nieco s r0 skusat v Delphi?
Delphi
Ahoj!
Když to vezmeme kolem a kolem, určitě by se Delphi nějakým způsobem dalo donutit vytvořit driver. Zatím jeden z možných postupů je, ručně nalinkovat obj vytvořené Delphi některým jiným linkerem. S kolegou Vrtulem jsme se o tom již bavili a snad v budoucnu zbyde trochu času zrealitovat nějaký kompletní template pro Delphi.
Ring 0 a Delphi
Kdysi (myslím, že na stránkách hackerdefenderu) existoval projekt s názvem DelphiDDK, který se tímhle zabýval a dosáhli docela zajímavého pokroku. Ale používat ho nebylo snadné (kompilovalo se přes příkazovou řádku).
Jinak i v Delphi lze samozřejmě docílit, aby byl kód vykonáván v Ring 0, ať už pomocí callgate či přepsáním určité fyzické paměti (a určitě existují i jiné způsoby).
Hook_NtQuerySystemInfor
Upozorňuji, že obsahuje jednu chybu, jedná se však o předpoklad, který snad bude vždy splněn.
Tou chybou je myslený implicitný prepodklad preskočenia, resp. nekontrolovanie PID prvého systémového procesu?
Ano,
presne tak