Minesweeper Consultant & Solitaire Expert

Opisana ponizej sztuczke pokazywalem ostatnio w ramach demo podczas sesji na spotkaniu WiT i na prosbe uczestniczek opisuje ja jeszcze raz i powoli.

Na poczatek, nalezy zaopatrzyc sie w Debugging Tools for Windows i gre Minesweeper z Windows XP. System, na którym przeprowadzamy doswiadczenie nie ma znaczenia. Chodzi o to, zeby w uruchomionym procesie winmine.exe odpowiedzialnym za gre Minesweeper, tak zmodyfikowac kod, aby funkcja wyswietlajaca plansze byla przekonana, ze ma wyswietlic wszystkie miny. W efekcie robi to, a gra staje sie szybka i przyjemna, choc nieco nudnawa.

Aby osiagnac zamierzony cel, nalezy kolejno:

  1. Uruchomic program winmine.exe. Posluzylem sie angielska wersja 5.1.2600.0 i ostrzegam, ze w innych moze byc nieco inaczej.

  2. Uruchomic debugger. Sugeruje uzycie WinDBG, choc twardzieli nie powinien przerazac równiez CDB lub NTSD. Wszystkie trzy programy pochodza z Debugging Tools i choc praktycznie nie róznia sie funkcjonalnoscia w przypadku debugowania winmine.exe, to WinDBG ma najbardziej przyjazny interfejs. Poniewaz mój program winmine.exe jest programem 32 bitowym, powinnismy uzyc narzedzi w wersji x86. Nalezy pamietac, ze zalezy to od programu, w który ingerujemy a nie od systemu, na którym wszystko instalujemy i uruchamiamy.

  3. Jezeli dziala i proces i debuger – mozna sie do procesu przypiac: nalezy nacisnac F6 i wybrac, który proces mamy na mysli. Nalezy pamietac, ze bez praw administratora lista procesów bedzie mocno tajemnicza, jednak winmine.exe sie na niej znajdzie i bedziemy mogli sie podlaczyc.
    image 

    Warto zwrócic uwage, ze proces winmine.exe ulegnie zatrzymaniu. Teraz rzadzimy nim my! Opcja noninvasive moze sie przydac, jezeli  pózniej bedziemy chcieli zamknac debugger, pozostawiajac dzialajacy proces.

  4. Kolejnym krokiem jest sprawdzenie gdzie w pamieci znajduje sie kod wykonywalny programu. Kazdy proces w systemie Windows ma swoja strukture zwana PEB czyli Process Environment Block. Struktura ta jest dokladnie udokumentowana na przyklad w MSDN, a w debuggerze mozna ja wyswietlic poleceniem !peb Wsród wielu ciekawych informacji, dla naszych potrzeb najwazniejsze jest pole zaczynajace sie od offsetu 8 czyli ImageBaseAddress. Jego wartosc wskazuje na adres pod którym zaczyna sie kod wykonywalny programu.
     image

  5. Interesuje nas liczba 14047 czyli szesnastkowo 36FA Przemilcze (z kilku róznych powodów) metode pozyskania tej liczby, jednak wazna jest dla tego, ze pod tym adresem znajduje sie prosta instrukcja OR sprawdzajaca czy juz pora na wyswietlenie min. Naciskajac Alt+7 mozna wyswietlic kod wykonywalny programu.  Nas interesuje kod pod adresem 010036fa (szesnastkowo), który opisac mozna jako (wskazywany polu ImageBaseAddress w strukturze PEB)+14047. Adres ten nalezy wpisac w pole offset.
    image

  6. Zamiast wyliczac nowa wartosc zmiennej przy pomocy OR, wpiszemy tam gotowa wartosc równa 138, czyli kazemy programowi wykonac operacje MOV BYTE PTR [EAX], 8Ah. W tym celu potrzebujemy ta instrukcje przelozyc na bajty (C6 00 8A) które wpiszemy pod zadany adres. W debuggerze, robi sie to poleceniem eb (enter bytes). W efekcie, instrukcja, która nalezy wprowadzic ma postac: eb poi(@$peb+8)+36FA C6 00 8A

  7. Po wydaniu polecenia, w oknie "disassembly" powinien pojawic sie stosowny kod opisany powyzej. Jezeli tak jest – mozna nakazac procesowi dalsza prace poleceniem G jak GO!

  8. Minesweeper powinien zaczac prace, obslugujac najpierw hurtem wszystkie komunikaty systemowe, które dostal, gdy byl zatrzymany.

  9. Gdy kazemy aplikacji namalowac nowa plansze – podmieniona przez nas funkcja wyswietli wszystkie miny.

image

Milej zabawy!

Warto przy tym pamietac, ze od Windows 2000, programisci maja mozliwosc oznaczania (przy pomocy funkcji VirtualProtect) fragmentów swojego kodu jako niemodyfikowalny. Gdyby twórcy naszego Minesweepera tak zrobili – cala zabawa zakonczylaby sie niepowodzeniem. Nie zadbano o to jednak (istnieje wiele mozliwych powodów), dzieki czemu proste demo konczy sie calkiem interesujacym efektem.

Autor: Grzegorz Tworek [MVP]