Zagłębmy się w system (x86)

Dzisiejszy mini-artykuł ma pokazać, jak działają takie funkcje API jak WriteProcessMemory, ReadProcessMemory, OpenProcess, VirtualProtect itd.

Wiedza którą się tutaj podzielę, z pewnością się komuś przyda w wielu przypadkach.

Zacznijmy więc...
System operacyjny jest również programem komputerowym, więc tak należy go traktować.Jak każdy program, system również może wywoływać swoje eksportowane funkcje (czyli API), zarówno na poziomie użytkownika, jak i jądra.

Więc przejdźmy do tego, jak działa np. funkcja OpenProcess
Przyda nam się, mój ulubiony Cheat Engine, w którym zobaczymy kod maszynowy (Assembler x86) tejże funkcji.

  1. Otwórzmy w Cheat Engine dowolny proces np. explorer.exe.
  2. Przejdźmy do zakładki Memory View, w menu kontekstowym wybierzmy 'Go to address' i wpiszmy OpenProcess
  3. Cheat Engine przeniesie nas do adresu procedury OpenProcess w kernel32.dll

Tak będzie wyglądać widok pamięci po wykonaniu opisanych kroków:

Jak widzimy, funkcja OpenProcess nic konkretnego nie robi, wywołuje tylko kolejną funkcję (patrz zaznaczone na czerwono) ZwOpenProcess z biblioteki.ntdll.

Przejdźmy zatem pod adres funkcji ZwOpenProcess. Ujrzymy oto taki kod:

Teraz widzimy, że ZwOpenProcess wywołuje kolejną funkcję.
Tym razem nie jest tak łatwo, ponieważ nie widzimy jaka funkcja jest wywoływana.

Jednakże analizując kod możemy dojść do tego, jaka to funkcja.
mov edx, 7ffe0300 - mówi nam, że na rejestr edx trafia liczba 0x7ffe0300
call dword ptr [edx] - wywołuje funkcję, której adres jest zapisany pod adresem z edx. Wykonuje się funkcja, której adres jest zapisany pod adresem 7ffe0300.

Więc docieknijmy, co to za funkcja.
Odczytajmy zatem, co znajduje się pod adresem 7ffe0300 (4 bajty - hex).
U mnie jest to wartość 0x7C90E510 (zależne od wersji systemu).
Przejdźmy zatem, analogicznie jak do funkcji OpenProcess, tyle że wpisując zamiast 'OpenProcess', taki oto adres 7C90E510.

I.. trafiliśmy do celu - funkcja która jest pod tym adresem to KiFastSystemCall.
Wywołuje ona instrukcję sysenter, nakazującą procesorowi przejście w tryb Kernel Mode (tryb jądra). Teraz system rozpozna po wcześniejszym rejestrze eax z funkcji ZwOpenProcess, jaką funkcję ma wybrać z tabeli SSDT w jądrze i ją wywołać. W moim przypadku będzie to funkcja o numerze 0x7a.

Sytuacja w Cheat Engine jest taka:

Po wywołaniu funkcji NtOpenProcess w jądrze systemu zostanie wywołana funkcja ObReferenceObjectByPointer, która zwróci nam uchwyt do procesu (uchwyt zostanie skojarzony z procesem w wewnętrznej tablicy systemowej z procesami) i w taki oto sposób będzie do tego procesu dostęp.

Wszystkie inne funkcje operujące na uchwycie np. ReadProcessMemory w jądrze systemu będą musiały użyć ObReferenceObjectByHandle, by otrzymać adres struktury PEPROCESS i następnie podczepić się do procesu i skopiować dane z danego procesu A do bufora w jądrze a następnie już do docelowego bufora w procesie B.

Tak to generalnie działa.

Komentarze

Prześlij komentarz