Hookowanie syscalli z win32k

czerwiec 28th, 2007

Hi,

O ile hookowanie syscalli zawartych w kernelu Windowsa z rodziny NT, czyli ntoskrnl, nie sprawia żadnych problemów, o tyle w przypadku syscalli odpowiedzialnych za GUI jest trochę więcej kombinowania. Ale po kolei.

Każdy thread pod WinNT ma określony zestaw syscalli (KSERVICE_TABLE_DESCRIPTOR[]) z którego może korzystać. Na dobrą sprawę mamy dwa takie zestawy:

  • KeServiceDescriptorTable - zawierający jedynie odniesienie do syscalli z ntoskrnl
  • KeServiceDescriptorTableShadow - zawierający odniesienie za równo do syscalli z ntoskrnl, jak i win32k

Domyślnie każdy utworzony thread ma przypisany (Thread->Tcb.ServiceTable) pierwszy zestaw, czyli KeServiceDescriptorTable. Symbol tego zestawu jest wyexportowany, więc zlokalizowanie zestawu oraz tablicy syscalli nie jest żadnym problemem.

W przypadku kiedy thread wywoła jakiś syscall >= 0×1000, np NtUserFindWindowEx (poprzez np funkcję FindWindow), uruchamiana jest procedura PsConvertToGuiThread() (base\ntos\ps\psquery.c) która między innymi podmienia zestaw syscalli na KeServiceDescriptorTableShadow.

I tutaj zaczynają się “schody”. Mianowicie KeServiceDescriptorTableShadow nie jest exportowany przez kernel, czyli w legalny sposób nie można się do tego dobrać. Ale OK, tak w zasadzie wystarczy tylko adres tablicy syscalli (_W32pServiceTable) w win32k, bo to pointery w tej tablicy podmieniamy.  Niestety, _W32pServiceTable również nie jest eksportowany.

Wyjść jest oczywiście kilka:

  • Sprawdzić w symbolach gdzie jest KeServiceDescriptorTableShadow lub _W32pServiceTable i użyć tego adresu (jako stałego). Niestety co patch na kernel/win32k trzeba ten adres ponownie sprawdzać.
  • Alexander Volynkin zaproponował przeszukanie wszystkich adresów występujących w funkcji KeAddSystemServiceTable, tak aby natrafić na adres który wskazuje na strukturę wypełnioną identycznymi danymi jak KeServiceDescriptorTable, ale jednak nie będącą pod tym samym adresem (pierwszy wpis w obu strukturach w końcu jest identyczny, bo opisuje tablicę syscalli z ntoskrnl). Jest to niezła metoda, chociaż trochę “hackish” (jak to mawia pewien mój pro znajomy ;>).
  •  Różni ludzie proponują aby poszukać identycznego wpisu jak pierwszy z KeServiceDescriptorTable gdzieś w okolicy (+- 256 bajtów) KeServiceDescriptorTable. Faktycznie KeServiceDescritorTableShadow jest umieszczany zazwyczaj przez kompilator w tych okolicach (w źródle kernela obie struktury są koło siebie), jednak to nie jest zbyt pewna metoda. Niemniej jednak póki co skuteczna.
  • Można przeszukać DriverEntry win32k na odwołania do KeAddSystemServiceTable, w końcu ta funkcja jako parametr przyjmuje adres tablicy syscalli (push offset _W32pServiceTable). Ta metoda nie brzmi jednak zbyt pewnie.
  • Można poczekać aż driver zostanie wywołany w kontekscie threadu z “pełnym” zestawem syscalli (np. użyć procedur powiadamiania o zniszczeniu wątku i poczekać aż się jakiś trafi, a one często się trafiają), po czym odczytać z Thread->Tcb.ServiceTable adres tabeli syscalli.
  • Można przeszukać listę threadów i zobaczyć które mają inną zestaw inny niż KeServiceDescriptorTable.
  • Ewentualnie można podmienić procedurę obsługującą SYSENTER i zobaczyć gdzie ona szuka/skacze. Ta metoda jednak nie jest najszczęśliwsza (nie spełnia zasady KISS ;>).
  • etc.

Metod jest dużo, wszystkie jednak zmuszają do uciekania się do pewnych sztuczek. Cóż, czasem ważne żeby po prostu działały.

To niestety nie koniec “schodów”. Okazuje się że w przypadku Windowsa XP (nie wiem jak z nowszymi) win32k nie zawsze jest widoczny w pamięci wirtualnej. Owszem, jest zawsze w pamięci fizycznej, ale jeśli dany thread nie jest ustawiony jako GUI, to win32k nie jest zamapowany do pamięci wirtualnej, nawet w przypadku gdy thread działa kernel mode. To wymaga znowu kombinowania. Metod znowu jest kilka:

  • Znaleźć win32k w pamięci fizycznej i zamapować go “ręcznie”. Szybkość nie jest mocną stroną tej metody.
  • Postarać się aby podmiana syscalli następowała w momencie gdy driver działa w kontekscie threadu GUI (patrz poprzednia metoda z PsSetCreateProcessNotifyRoutine tudzież PsSetCreateThreadNotifyRoutine, lub można też część działającą w user mode poprosić o “dotknięcie” drivera po uprzednim zainicjowaniu GUI).

Osobiście skorzystałem z tej drugiej metody. Nyom. Po rozwiązaniu takich dwóch problemów możemy się cieszyć sliczymi hookami w win32k.

Dodam jeszcze na koniec że należy uważać przy korzystaniu ze źródeł ReactOS do określania parametrów przyjmowanych przez dany syscall. Okazuje się iż mimo że ReactOS ma być w 100% kompatybilny z Windows’em, to nie wszystkie rzeczy są zachowane. Przykładem może być NtUserFindWindowEx który w przypadku ReactOS pobiera 16 bajtów parametrów (4 x 4 bajty), a  przypadku Windows XP 20 bajtów parametrów (5 x 4 bajty). Cóż ;>

Dobra, to tyle ;>
Zachęcam do komentowania tego oraz poprzednich postów ;>

G.C.

Leave a Reply

You must be logged in to post a comment.

              


cheap vps - list motywacyjny - tworzenie sklepów - apartament gdańsk - skoki spadochronowe - tanie wycieczki - Odszkodowanie z OC sprawcy - ogłoszenia matrymonialne inne - szkolenia dla osób bezrobotnyc