Vývojářský blog Jakuba Čermáka

Tisk článku Tisk článku

Hrátky s WinAPI: “buď já nebo BSOD” aneb kritické procesy systému

[Zpět na blog]

Datum: 28. 6. 2009 20:14       Autor: Jakub Čermák       Zobrazeno: 2897x

Kategorie: C#, Aplikace, Život, vesmír a vůbec


Dneska jsem během náhodného procházení internetu narazil (z mého pohledu) zajímavou věc – jak udělat to, co umí např. proces CSRSS, tj. že když ho někdo nebo něco killne nebo umře přirozenou programovou smrtí, tak s sebou vezme i celý systém – Windows hodí BSOD (KeBugCheckEx) s tím, že mu (volně řečeno) umřel kritický proces a bez něj už nemá smysl dál existovat :)

Windows XP Professional-2009-06-28-16-22-57

Kód Bluescreenu se liší podle toho jestli hlídaný program skončil v pořádku (vrátil 0), pak je to CRITICAL_PROCESS_DIED (0xEF), nebo jestli skončil s chybou, pak se zjeví BSOD CRIITICAL_OBJECT_TERMINATION       (0xF4).

Jak se tedy takováhle věc nastavuje? V podstatě jsou 2 cesty, kdy první používá interně tu druhou. V obou dvou případech je třeba, aby proces měl seDebugPrivilege (v .NETu to lze zařídit pomocí fcí Process.EnterDebugMode a Process.LeaveDebugMode) a nejspíš jsou potřeba i admin práva (bez nich mi to nefungovalo). Nejjednodušší je asi použít nedokumentovanou API funkci RtlSetProcessIsCritical, které se (mj.) předá BOOL vyjadřující, jestli tento proces je pro systém kritický nebo není. Zásadní nevýhoda je, že se toto nedá použít pro nastavování jiných procesů. A protože jsem člověk zvědavý, tak jsem se podíval do referenčních zdrojáků NTOSKRNL (část Windowsího kernelu) a implementaci té funkce tam ke své spokojenosti našel – je to víceméně jen obálka nad dvojicí (zase nedokumentovaných) funkcí NtSetInformationProcess a NtQueryInformationProcess, sloužících pro nastavování či čtení nejrůznějších parametrů procesů.

Implementace

Nejdřív definice těch 3 funkcí :

 [DllImport("ntdll.dll", SetLastError = true)]
extern static unsafe UInt32 NtSetInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, void* ProcessInformation, uint ProcessInformationLength);

[
DllImport("ntdll.dll", SetLastError = true)]
extern static unsafe UInt32 NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, void* ProcessInformation, uint ProcessInformationLength, uint* ReturnLength);

[
DllImport("ntdll.dll")]
extern static unsafe void RtlSetProcessIsCritical(bool NewValue, bool* OldValue,bool CheckFlag);

ProcessInformationClass je enum vyjadřující, co vlastně chceme zjistit nebo nastavit za informaci, na internetu lze nalézt definici, my potřebujeme ProcessBreakOnTermination, což je číselně 29, ProcessInformation je pak daná informace. Pomocí toho pak už kód je jednoduchý:

 unsafe void SetCritical(Process proc, bool enable)
{
    
Process.EnterDebugMode();
    
uint ienable = enable ? 1u : 0u;
    
try
    {
        
UInt32 status = NtSetInformationProcess(proc.Handle, ProcessBreakOnTermination, &ienable, sizeof(uint));
        
if (status < 0)    MessageBox.Show("Error " + status);
     }
    
catch (Win32Exception e)
     {       
MessageBox.Show("Error " + e.Message);    }
    
Process.LeaveDebugMode();
}

unsafe bool GetCritical(Process proc)
{
    
uint ienable = 0;
    
Process.EnterDebugMode();
    
try
    {
        
UInt32 status = NtQueryInformationProcess(proc.Handle, ProcessBreakOnTermination, &ienable, sizeof(uint), (uint*)IntPtr.Zero.ToPointer());
        
if (status < 0)    MessageBox.Show("Error " + status);               
     }
    
catch (Win32Exception e)
     {       
MessageBox.Show("Error " + e.Message);    }
    
Process.LeaveDebugMode();
    
return ienable != 0;
}

Užitečnost

je v tomto případě celkem diskutabilní :) Napadá mě použítí do nějakých ochranných systémů a případně na hraní, kdy takto odděláte ochranu důležitým systémovým procesům a sledujete, co se stane po killu. Nejspíše by se to také dalo zneužít na nějaký pěkný kanadský žertík. Mě osobně se na tom líbí to, že ony systémové procesy nejsou “něco víc” než ty moje a liší se jen voláním jedné API funkce. Případné nápady na využití můžete psát do diskuze pod článkem.

Zdrojový kód aplikace si můžete stáhnout na http://dl.jcermak.cz/clanky/CriticalSysProcessExample.zip


> Na začátek

 

Hodnocení:

Hlasů: 5
Zvolte své hodnocení

Jakub Čermák

Jakub pochází z Pardubic, kde vystudoval osmileté gymnázium, a v současné době pobývá v Praze, kde studuje 3. ročník bakalářského oboru informatika na Matematicko-fyzikální fakultě UK. Poslední dobou se věnuje spíše programování v C++ a v C#, nejlépe paralelizované věcí na desítkách procesorů:) .Taky občas píše články nebo dělá přednášky, přičemž za svou činnost získal "ocenění" Microsoft Student Partner. Ve volném čase spí, pobývá v hospodě, kouká na anime s hrnkem dobrého čaje nebo si s něčím hraje.


RSS Feed RSS Feed

Diskuse

1 

...

Datum: 29.6.2009 10:12
Autor: Tomáš Jecha
Hodnocení autora: 697
Příspěvků: 1285
Instantní BSOD. Hezké...

V zásadě je ale dobře, že není možné, aby běžel systém bez důležitých procesů. Ještě pamatuji Windows 95, kde prostě bylo možné mazat za běhu složku Windows. V průběhu mazání se funkce systému začali zužovat (mizení ikon, chyby ve vykreslování, nejdříve špatná, pak žádná nabídka Start atp.) a nakonec vše spadlo. To mělo do bezpečnosti hodne daleko.
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...

Re: ...

Datum: 2.5.2010 13:44
Autor: Šprici
Hodnocení autora: 11
Příspěvků: 83
Dá sa niečo takéto spraviť aj vo Visual Basic .NET ?? začínam sa učiť C# , ale hodil by sa mi takýto kód aj pre VB.NET a online konvertorom moc neverím vo winAPI :)
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...
1 
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.