CreateToolhelp32Snapshot – nieudokumentowane zachowanie


Podczas pracy nad narzędziem do wizualizacji pamięci obcego procesu, natrafiłem na pewne nieudokumentowane zachowanie funkcji CreateToolhelp32Snapshot w WinApi. Zgodnie z dokumentacją funkcja ta wykonuje „zapis” stanu analizowanego procesu. Co dokładnie zostanie zapamiętane, zależy od wartości pierwszego argumentu.

Opis działania CreateToolhelp32Snapshot

Możemy zapisać stan procesu w następujących obszarach:

  • Sterty, jakie proces posiada (Heaps).
  • Moduły, jakie zostały załadowane do pamięci procesu z rozróżnieniem na te 32-bitowe oraz 64-bitowe.
  • Wątki, jakie proces wykonuje.
  • Procesy – sytuacja, gdy chcemy enumerować wszystkie procesy w systemie.

Dokumentacja rozróżnia moduły 32- i 64-bitowe, ponadto jest określone wyraźnie, że jeśli proces analizowany jest 64 bitowy, a proces analizujący 32 wówczas nie otrzymamy informacji o modułach 64 bitowych.

Ważne jest, że nie ma czegoś takiego jak 64-bitowa sterta – dokumentacja przewiduje tylko jeden parametr, aby „zamrozić” stan wszystkich stert w procesie TH32CS_SNAPHEAPLIST.
Nie znalazłem również ani słowa o jakichkolwiek ograniczeniach, gdy to analizowany proces jest x86, a analizujący x64.

Zachowanie CreateToolhelp32Snapshot zależnie od sposobu kompilacji

Program badany

Poniżej przedstawiam prostą aplikację, jaka posłuży nam za obiekt badawczy.

Aplikacje kompilujemy Visual Studio 2015 przy pomocy poniższej komendy.

Otrzymamy 32 bitową binarkę, która potrzebuje WOW64 do pracy na maszynach 64 bitowych – Nic specjalnego.

WinApi problem CreateToolhelp32Snapshot

Aplikacja analizująca

Załóżmy, że chcemy się dowiedzieć, jak nasz program badany wykorzystuje stertę. Chcemy poznać lokalizacje stert oraz ich ilość, a następnie ewentualnie przejść wszystkie alokacje, do tego celu możemy wykorzystać funkcje WinApi: Heap32ListFirst, Heap32ListNext, Heap32First, Heap32Next.  Poniżej prosa aplikacja wyświetlająca ID (adres) wszystkich stert w obcej aplikacji.

Okazuje się ze wyniki, jakie uzyskamy, zależą od tego, jak skompilujemy naszą aplikacje diagnostyczną. Badana aplikacja pozostaje bez zmian, nawet jej nie restartuje, podczas gdy zależnie od trybu kompilacji otrzymujemy zupełnie różne informacje o stertach.

Sterty po kompilacji x86

PID is [ 7024 ]
HEAP ID: 0x1450000

Sterty po kompilacji x64

PID is [ 7024 ]
HEAP ID: 0x1380000
HEAP ID: 0xdc0000

Wyniki są różne, „prawdziwa” sterta to ta zwracana w trybie 32-bitowym, te w trybie 64-bitowym prawdopodobnie są wykorzystywane przez WOW64. W dokumentacji do żadnej z wykorzystywanych funkcji nie znalazłem ani słowa o takim zachowaniu.

Rozwiązanie

Nie udało mi się zmusić aplikacji 64-bitowej do uzyskania informacji o wszystkich stertach programu 32-bitowego, musiałem więc iść okrężną drogą. Gdy chcę poznać lokalizację sterty procesu 32-bitowego, odpalam osobny 32-bitowy proces pochodny,  który zbiera dane, a następnie komunikuje się z procesem macierzystym przy pomocy jednego z dostępnych mechanizmów IPC.

Dodaj komentarz

Twój adres email nie zostanie opublikowany.