P-Programowanie

Edycja pamięci procesów

Ostatania modyfikacja: 28 września 2017, kategoria: C++

Windows udostępnia nam funkcje pozwalające odczytywać i zapisywać pamięć innych procesów. Służą do tego ReadProcessMemory i WriteProcessMemory. Przed odczytaniem pamięci procesu musimy uzyskać jego uchwyt (HANDLE) i posiadać odpowiednie prawa dostępu. Najlepszym darmowym programem do operacji na pamięci procesu jest CheatEngine oraz TSearch. Naszą aplikacją testową będzie Saper, ponieważ tę grę każdy posiada.

Znajdywanie adresów

Jest to artykuł skierowany raczej do początkujących, pominę sprawę ASLR oraz wskaźników. Zajmiemy się adresami statycznymi.

Każdy bajt aplikacji jest zapisany w pamięci procesu i posiada swój unikalny adres. Aby odczytać np. czas z gry saper musimy wiedzieć pod jakim adresem się znajduje. Otwieramy grę Saper a następnie program CheatEngine. Wybieramy z listy proces o nazwie „winmine.exe”. Teraz możemy przeprowadzać dowolne operacje na pamięci Sapera. Standardowo ilość min w grze Saper to 10 – a więc musimy znaleźć tą wartość. W polu ‚Value’ wpisujemy wartość 10, Scan type należy ustawić na „Exact Value”, Value type proponuję ustawić na 4Bytes – więcej nie będzie potrzebne. Skanujemy proces w poszukiwaniu wpisanej wartości, klikając na przycisk First Scan. Prawdopodobnie adresów pojawi się dość dużo, dlatego przełączamy się na okienko sapera i zmniejszamy ilość min (klikamy prawym na dowolne pole). Ilość min została zmniejszona z 10 na 9. Powtarzamy czynność wyszukania wartości, wpisując w pole ‚Value’ liczbę 9 (aktualna ilość min) i klikając w przycisk Next Scan. Czynność powtarzamy aż na liście nie zostanie tylko jeden adres (pamiętaj aby za każdym razem klikać Next Scan). Gdy mamy już tylko jeden adres, jest to z pewnością adres min w grze. Wartość możemy dowolnie modyfikować poprzez dwukrotne kliknięcie i wpisanie nowej wartości min. W celu znalezienia adresu odpowiedzialnego za czas, robimy dokładnie to samo jak wyżej. Skanujemy proces aż zostanie tylko jeden adres.

Znaleziony przeze mnie adres wskazujący na ilość min w Saperze to 1005194, Twój adres może się różnić jeżeli posiadasz inną wersję gry.

Odczytywanie wartości z pamięci

Znaleźliśmy interesujące nas adresy pamięci. Deklarujemy je w kodzie programu, należy pamiętać że są one w formacie heksadecymalnym, więc aby zadeklarować je w C++ należy dodać przedrostek 0x, w VisualBasic &H a w delphi $.

Szukamy okna o tytule „Saper” za pomocą funkcji FindWindow, zwraca ona hwnd okna. Jeżeli nie znajdzie okna (tzn aplikacja jest zamknięta) zwraca 0. Za pomocą funkcji GetWindowThreadProcessId pobieramy uchwyt (HANDLE) aplikacji, tutaj wymagany jest wcześniej odczytany hwnd. Następnie za pomocą OpenProcess otwieramy proces Sapera, określając prawa dostępu. Prawa dostępu można znaleźć w MSDN więc nie będę ich kopiował. Nas interesuje jedynie PROCESS_VM_READ, co pozwoli na odczyt.

Uwaga! Bądź precyzyjny używając flag dostępu w funkcji OpenProcess. Jeżeli chcesz odczytywać wartości użyj PROCESS_VM_READ, jeżeli zapisywać PROCESS_VM_WRITE | PROCESS_VM_OPERATION. Nigdy nie używaj PROCESS_ALL_ACCESS, jeżeli nie jest to wymagane! Flaga ta nadaje wszystkie uprawnienia i nie działa na wszystkich systemach bez praw do debugowania (to już funkcja SeDebugPrivilege). Konsekwencją tego będzie np. brak możliwości odczytywania pamięci na koncie ograniczonym w Windows Vista/7.

Kolejnym krokiem jest użycie naszej właściwej funkcji ReadProcessMemory. Jej najważniejsze argumenty to uchwyt otwartego procesu, adres bazowy, bufor do którego zapisujemy wartość i wielkość bufora. Funkcja jest typu BOOL tzn zwraca true lub false w razie niepowodzenia.

Wynik działania programu:

Aktualna ilość min: 7
Aktualna wartość czasu: 12

Zapisywanie wartości do pamięci

Wszystko odbywa się tak jak w przypadku odczytywania. Używamy funkcji WriteProcessMemory. Określamy adres oraz wartość jaką chcemy zapisać. Zwróć uwagę na flagi OpenProcess, w przeciwieństwie do ReadProcessMemory tutaj wymagana jest jeszcze PROCESS_VM_OPERATION.

Podsumowanie

Poznanie działania funkcji służących do operacji na pamięci danego procesu, jest absolutną podstawą. Do bardziej zaawansowanych działań potrzebny Ci będzie debbuger oraz znajomość Assemblera. Nie musisz umieć programować w asmie, ja też nie umiem. Wystarczy znać podstawowe rozkazy, wiedzieć czym jest stos, rejestry oraz przerwania.

Użytkownik Gość napisał:

06 stycznia 2013


Witam,dla mnie osobiście świetny Art, poprosił bym o więcej tak zrozumiałych i czytelnych.Pozdrawiam

Użytkownik mario napisał:

19 kwietnia 2013


Witam, swietny art ale moje pytanie jest dlaczego kompilator dev c++ pokazuje błąd: GetWindowThreadProcessId undeclared ???

Użytkownik Karol napisał:

19 kwietnia 2013


Prawdopodobnie nie dołączyłeś pliku „windows.h”. Dev C++ nie jest już od dawna uaktualniany. Wszyscy bardzo nie zalecają tego kompilatora. Polecam Ci Code::Blocks, przesiadka będzie dla Ciebie korzystna.

Użytkownik Mariusz napisał:

15 września 2013


Ja mam taki, że program cały czas pokazuje wartość min i czasu 0. Jak czas wynosi np. 7, to uruchamiam program i dalej 0 i 0. Byłbym wdzięczny za pomoc

Użytkownik Alek napisał:

15 września 2013


Czy odczytywanie pamięci procesów jest ingerencją w dany proces (program). Mam na myśli, czy program jest w stanie wykryć, że inny program odczytuje z niego jakąś wartość?

Użytkownik Karol napisał:

15 września 2013


@Mariusz
Powodów może być setki. Najprawdopodobniej masz złe adresy pamięci. Artykuł napisałem wzorując się na Saperze z Windows XP. Na innych Windowsach są inne wersje sapera i wszystkie adresy się zmieniają.

@Alek
Jest to ingerencja w proces i można to wykryć, jednak rzadko twórcom zależy na wykrywaniu OpenProcess lub ReadProcessMemory. Przeważnie dla zabezpieczenia aplikacji, wykrywane są wszelkie działania modyfikacji pamięci czyli WriteProcessMemory.

Użytkownik Tomek napisał:

22 grudnia 2013


Artykuł świetny. Był bym wdzięczny za artykuł o tym jak znajdować adresy dynamiczne.

Użytkownik Marko napisał:

05 lutego 2014


To dojebałeś z tym Dev C++ jak łysy o kant dupy.

Użytkownik nort napisał:

25 października 2015


Tutaj często przy szukaniu liczb w CheatEngine przydaje się język python np. przy szukaniu liczby 5 wpisujemy w pythonie ord(‚5’) wypisze nam liczbę 53 wpisujemy to w cheatengine i szukamy itd. potem podmieniamy na inną liczbę tak samo posępujemy z literami

Użytkownik Zeroche napisał:

13 lutego 2016


Prosil bym o poprawienienie Tego kodu : „HWND hSaper = FindWindow(„Saper”,NULL);” okna na HWND hSaper = FindWindow(NULL,”Saper”); poniewarz powoduje to bledy w kompilatorach Visual C++ PS:sorra za orto

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0