Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

ProtectedProcess, czyli słów kilka o ochronie procesu

Począwszy od Visty Microsoft wprowadził do systemu mechanizm 'Protected Processes', który w założeniach miał chronić niektóre procesy przed innymi wścibskimi procesami. Rozwiązanie to znalazło zastosowanie w DRM oraz WER... i właściwie nigdzie więcej. O tym, dlaczego PP to nie jest dobry pomysł pisał swego czasu Alex Ionescu, który udostępnił (niedostępne już) do pobrania narzędzie D-Pin Purr.

Prosty przykład

Zanim przejdziemy dalej, zobaczmy o czym mowa. Rozpocznijmy od uruchomienia Windows Media Playera i otwarcia jakiegoś pliku muzycznego (nie musi być chroniony). W tym momencie na liście procesów powinien pojawić się dodatkowo proces audiodg.exe, który został załadowany przez svchost.exe w kontekście usługi lokalnej. Przeglądając Process Explorerem niektóre właściwości tego procesu możemy zobaczyć kilka ciekawych róźnic w stosunku do innych procesów. I o ile zakładka 'Image' dostarcza nam jeszcze pewnych informacji

Rys 1. Audiodg - ogólne właściwości

to już w ramach zakładki 'Security' dostajemy lakoniczny komunikat 'Error: Process is Protected'

Rys 2. Audiodg - zakładka security

podobnie jest zresztą w zakładce 'Strings'->Memory, czyli przy próbie odczytania zawartości pamięci procesu.

Rys 3. Audiodg - zakładka memory

Gdy próbujemy podejrzeć stos któregokolwiek z wątków, otrzymamy

Rys 4. Audiodg - próba podejrzenia stosu wywołań dla jednego z wątków

a w przypadku próby zrzutu dumpa procesu, w taskmgr dostaniemy

Rys 5. Próba zrzutu pamięci dla audiodg (task manager)

co nie będzie wiele różne od tego, co nam zaserwuje procexp:

Rys 6. To samo w przypadku Process Explorera

Po tym prostym przykładzie możemy przejść dalej, czyli spróbować opisać sam mechanizm chronionych procesów.

Chronione procesy - oficjalna dokumentacja

W oficjalnej dokumentacji Microsoft dosyć ogólnie opisuje sam mechanizm, ograniczając się na dobrą sprawę do stwierdzenia, że z takim procesem niewiele da się zrobić oraz tego, że właściwie jest to mechanizm zarezerwowany dla komponentów systemowych, albowiem chroniony proces musi być specjalnie podpisany, co ogranicza takie procesy do Microsoftowych.
W dokumencie możemy m.in. przeczytać:

"Constraints on protected processes. A typical process cannot perform operations such as the following on a protected process:
- Inject a thread into a protected process
- Access the virtual memory of a protected process
- Debug an active protected process
- Duplicate a handle from a protected process
- Change the quota or working set of a protected process"

Dodatkowo, na stronach MSDN, w dokumencie opisującym bezpieczeństwo procesu oraz prawa dostępu (Process Security and Access Rights) w sekcji dotyczącej chronionych procesów możemy znaleźć:

"Protected Processes 
Windows Vista introduces protected processes to enhance support for Digital Rights Management. The system restricts access to protected processes and the threads of protected processes.

The following standard access rights are not allowed from a process to a protected process:
 DELETE READ_CONTROL
 WRITE_DAC
 WRITE_OWNER
The following specific access rights are not allowed from a process to a protected process:
 PROCESS_ALL_ACCESS
 PROCESS_CREATE_PROCESS
 PROCESS_CREATE_THREAD
 PROCESS_DUP_HANDLE
 PROCESS_QUERY_INFORMATION
 PROCESS_SET_INFORMATION
 PROCESS_SET_QUOTA
 PROCESS_VM_OPERATION
 PROCESS_VM_READ
 PROCESS_VM_WRITE
The PROCESS_QUERY_LIMITED_INFORMATION right was introduced to provide access to a subset of the information available through PROCESS_QUERY_INFORMATION."

Proces podlega ochronie już w momencie jego tworzenia. Decyduje o tym odpowiednia flaga, którą można ustawić podczas wywoływania jednej z rodziny funkcji CreateProcess*, dla przykładu w przypadku CreateProcess:

BOOL WINAPI CreateProcess(
  __in_opt     LPCTSTR lpApplicationName,
  __inout_opt  LPTSTR lpCommandLine,
  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in         BOOL bInheritHandles,
  __in         DWORD dwCreationFlags,
  __in_opt     LPVOID lpEnvironment,
  __in_opt     LPCTSTR lpCurrentDirectory,
  __in         LPSTARTUPINFO lpStartupInfo,
  __out        LPPROCESS_INFORMATION lpProcessInformation
);

chodzi o parametr dwCreationFlags, a dokładnie o ustawienie wartości:

"CREATE_PROTECTED_PROCESS 0x00040000
The process is to be run as a protected process. The system restricts access to protected processes and the threads of protected processes. For more information on how processes can interact with protected processes, see Process Security and Access Rights.
 
To activate a protected process, the binary must have a special signature. This signature is provided by Microsoft but not currently available for non-Microsoft binaries. There are currently four protected processes: media foundation, audio engine, Windows error reporting, and system. Components that load into these binaries must also be signed. Multimedia companies can leverage the first two protected processes. For more information, see Overview of the Protected Media Path."

Wow, wygląda na to, że oto istnieje mechanizm, który daje możliwość zabezpieczenia dowolnego procesu przed niepowołanym dostępem, i to już w momencie jego tworzenia! Szkoda tylko, że mechanizm jest ograniczony wyłącznie do kilku rozwiązań Microsoftu...

Na tym kończy się oficjalna dokumentacja Microsoftu i po zapoznaniu się z nią właściwie nie wiemy nic o tym, jak ten mechanizm został zrealizowany.

Zajrzyjmy do środka

Nasze poszukiwania rozpocznijmy od sprawdzenia, czy w eksportach dla ntoskrnl.exe znajdziemy coś ciekawego:

>dumpbin /exports c:\Windows\System32\ntoskrnl.exe | findstr Protected
       1270  4F5 00048228 PsIsProtectedProcess = PsIsProtectedProcess

Wygląda zachęcająco. Odpalamy zatem PEBrowse z ustawionymi publicznymi symbolami i sprawdzamy w sekcji debug co też kryje się w funkcji PsIsProtectedProcess.

Rys 7. Podgląd kodu funkcji PsIsProtectedProcess w PEBrowse

0x0000000140048228: 8B813C040000   MOV     EAX,DWORD PTR [RCX+0x0000043C]
0x000000014004822E: C1E80B         SHR     EAX,0x0B
0x0000000140048231: 83E001         AND     EAX,0x01
0x0000000140048234: C3             RET    

Mamy zatem funkcję przyjmującą 1 parametr (rejestr rcx, o konwencjach wywołania w ramach x86-64 można poczytać np. na stronach Intela) i sądząc po nazwie możemy przypuszczać, że jest nim adres struktury _EPROCESS opisującej sprawdzany proces. Zobaczmy więc, co się skrywa interesującego w tej strukturze, a właściwie 0x43c bajtów od jej początku...

Struktura _EPROCESS

Jak już wielokrotnie na tym blogu pisałem, warto zaprzyjaźnić się ze strukturą _EPROCESS , gdyż system korzysta z niej bardzo intensywnie (vide choćby posty o żetonie procesu, czy ukrywaniu procesu).
Tym razem skorzystamy z narzędzia Symbol Type Viewer, z którego pomocą rozszyfrujemy strukturę opisującą pole Flags2 tejże struktury i zobaczymy, czy znajdziemy tam coś ciekawego.

Rys 8. Symbol Type Viewer - podgląd struktury _EPROCESS

W interesującym nas miejscu, tj. 0x43C bajty od początku struktury _EPROCESS znajdujemy pole Flags2 i na jego 11 (0xb) bicie znajduje się interesująco brzmiąco pole ProtectedProcess o rozmiarze 1 bita.

/*0x43C*/ ULONG32  Flags2;        
struct                               // 20 elements, 0x4 bytes (sizeof)   
{               
ULONG32  JobNotReallyActive : 1;           // 0 BitPosition         
ULONG32  AccountingFolded : 1;             // 1 BitPosition         
ULONG32  NewProcessReported : 1;           // 2 BitPosition         
ULONG32  ExitProcessReported : 1;          // 3 BitPosition         
ULONG32  ReportCommitChanges : 1;          // 4 BitPosition         
ULONG32  LastReportMemory : 1;             // 5 BitPosition         
ULONG32  ReportPhysicalPageChanges : 1;    // 6 BitPosition         
ULONG32  HandleTableRundown : 1;           // 7 BitPosition         
ULONG32  NeedsHandleRundown : 1;           // 8 BitPosition         
ULONG32  RefTraceEnabled : 1;              // 9 BitPosition         
ULONG32  NumaAware : 1;                    // 10 BitPosition        
ULONG32  ProtectedProcess : 1;             // 11 BitPosition        
ULONG32  DefaultPagePriority : 3;          // 12 BitPosition        
ULONG32  PrimaryTokenFrozen : 1;           // 15 BitPosition        
ULONG32  ProcessVerifierTarget : 1;        // 16 BitPosition        
ULONG32  StackRandomizationDisabled : 1;   // 17 BitPosition        
ULONG32  AffinityPermanent : 1;            // 18 BitPosition        
ULONG32  AffinityUpdateEnable : 1;         // 19 BitPosition        
ULONG32  PropagateNode : 1;                // 20 BitPosition        
ULONG32  ExplicitAffinity : 1;             // 21 BitPosition        
};

Wygląda więc na to, że funkcja PsIsProtectedProcess sprawdza stan pola ProtectedProcess i zależnie od jego wartości zwraca true (protected == 1), lub false (==0). Sprawdźmy zatem, czy zmiana tego pola wystarczy, aby proces był chroniony!

Ręczna modyfikacja

Najwyższy czas wrócić do zagadki z poprzedniego mojego wpisu. Postępujemy zatem zgodnie z instrukcją tam przedstawioną i zobaczmy, co się stanie.
Niech naszym testowym procesem będzie notatnik, dla którego zakładka 'Security' procexpa na początku wygląda zupełnie normalnie.

Rys 9. Zakładka security notatnika w wersji startowej

Przejdźmy jednak do debuggera i spróbujmy podejrzeć zawartość naszego pola. Zaczynamy od znalezienia procesu i ustawienia go jako domyślnego, dzięki czemu będziemy mogli skorzystać z pseudorejestrów.

3: kd> !process 0n3048 0
Searching for Process with Cid == be8
Cid handle table at fffff8a0012d8000 with 611 entries in use
PROCESS fffffa80031f5b30
    SessionId: 1  Cid: 0be8    Peb: 7fffffdf000  ParentCid: 07f0
    DirBase: 062aa000  ObjectTable: fffff8a001beea20  HandleCount:  56.
    Image: notepad.exe
3: kd> .process fffffa80031f5b30
Implicit process is now fffffa80`031f5b30
WARNING: .cache forcedecodeuser is not enabled

W następnym kroku sprawdźmy aktualny stan interesującego nas pola. Tu krótkie wyjaśnienie: korzystamy z pseudorejestru $proc, dzięki któremu mamy dostęp do adresu bloku EPROCESS. Reszta, to prosta arytmetyka bitowa.

3: kd> ?? ((@$proc->Flags2 & (1<<0xb)) >> 0xb)
unsigned int 0

A więc jest tak, jakbyśmy się tego spodziewali. Spróbujmy zatem zmienić tę wartość i zobaczymy, co się będzie dalej działo.

3: kd> ?? (@$proc->Flags2 |= (1<<0xb))
unsigned long 0xd800
3: kd> ?? ((@$proc->Flags2 & (1<<0xb)) >> 0xb)
unsigned int
1
3: kd> g

Sprawdzamy teraz dostęp do procesu z poziomu procexpa

Rys 10. Notatnik pod ochroną systemu!

i okazuje się, że proces jest chroniony!
Aby odwrócić tę sytuację, ustawiamy ponownie wartość pola ProtectedProcess na 0:

0: kd> .process fffffa80031f5b30
Implicit process is now fffffa80`031f5b30
WARNING: .cache forcedecodeuser is not enabled
0: kd>
?? (@$proc->Flags2 &= ~(1<<0xb))
unsigned long 0xd000
0: kd>
?? ((@$proc->Flags2 & (1<<0xb)) >> 0xb)
unsigned int 0

i nasz notatnik znowuż jest bez ochrony.

Na tym kończymy dzisiejszą zabawę z chronionymi procesami i rozwiązywanie zagadki internalsowej z poprzedniego wpisu. Temat jednak nie jest jeszcze wyczerpany i na pewno do niego powrócę. Pytanie tylko, czy już w następnym wpisie, czy może najpierw napiszę kilka słów o dosyć zagadkowej funkcji RtlCreateProcessReflection z ntdll... macie jakieś sugestie?

Opublikowane 22 stycznia 2012 05:50 przez mgrzeg

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

stycznia 22, 2012 08:16
 

Paweł said:

Jeśli chodzi o mnie to ja chętnie poczytam o klonowaniu.

stycznia 23, 2012 11:36
 

ucel said:

A da sie tak zrobic w druga strone? Sciagnac flage z audiodg.exe przykladowo?

stycznia 24, 2012 10:28
 

mgrzeg said:

@ucel: Niedobry Ty! :) Tu piszą o ACTA, a Ty chcesz audiodg odbezpieczać! ;)

Ale tak, oczywiście, ustawiając ProtectedProcess na 0 całkowicie odbezpieczasz dowolny proces.

stycznia 24, 2012 12:02
 

Polski TechNet Blog said:

Service Manager jest jednym z moich ulubionych mechanizmów w systemie. Wiem, że to może dziwnie brzmieć

lutego 11, 2014 19:58
 

Niezabijalne procesy | Polski TechNet Blog said:

kwietnia 29, 2016 14:43
 

Niezabijalne procesy | Polski TechNet Blog said:

kwietnia 29, 2016 14:43

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems