group-telegram.com/cxx95/96
Last Update:
#story
Как сделать программу для читов в играх
«Я буду устанавливать сейчас все игры»
- Сашко «Компьютерный Монстр»
Когда-то давно я познакомился с программой ArtMoney. Эта программа шла на диске к журналу "Лучшие Компьютерные Игры". Она была очень простой, и я быстро смог настроить бесконечную валюту в игре Spore.
В ArtMoney нужно было указывать процесс игры, затем ввести значение игровой валюты. Программа проверяла всю память и запоминала адреса, где было это значение.
Потом надо было вернуться в игру, что-нибудь сделать, чтобы значение валюты изменилось, и указать новое значение в ArtMoney.
Адреса фильтровались (оставлялись только равные новому значению), и процесс повторялся, пока не останется единственный адрес, в котором можно поменять значение на нужное.
Я решил поисследовать, как работают такие программы. Так как я не пишу под Windows, то исследую аналог для Linux, особой разницы не должно быть
В этой программе также можно искать нужный адрес с переменной. Можно искать не только конкретное значение, но еще промежуток значений, а также "значение по адресу больше/меньше/равно/не равно чем было в прошлый раз" и так далее.
Такое бывает нужно, если например в игре есть "полоска здоровья" без числового значения, про которое известно, что оно становится больше/меньше чем в предыдущий раз.
Проверяется, что scanmem
был запущен из-под суперюзера (sudo scanmem
), без этого нельзя "следить" за другим процессом (если он не является процессом-"ребенком").
Проверка происходит через getuid() == 0
- uid суперюзера равен 0.
У процесса игры надо увидеть его виртуальное адресное пространство. Это память, которую игра использует и где надо будет фильтровать адреса. Увидеть регионы непрерывно занимаемой памяти может любой (в смысле не только суперюзер), прочитав файл /proc/<pid>/maps
:
cat /proc/<pid>/maps # вывод в терминалВывод примерно такой:
559b8c5d1000-559b8c5f2000 rw-p 00000000 00:00 0 [heap](подробнее об этих файлах можно прочитать тут)
7faa72001000-7faa72023000 rw-p 00000000 00:00 0
7faa72023000-7faa72055000 r--p 00000000 08:30 3023 /usr/lib/locale/C.UTF-8/LC_CTYPE
7faa726e0000-7faa726e1000 rw-p 0002d000 08:30 11854 /usr/lib/x86_64-linux-gnu/ld-2.31.so
7faa726e1000-7faa726e2000 rw-p 00000000 00:00 0
7ffeb2f53000-7ffeb2f74000 rw-p 00000000 00:00 0 [stack]
scanmem
просто открывает этот файл (через fopen) и парсит каждую строку. Оставляются только регионы с возможностью записи (флаг w
). Обычно этого флага нет у загруженных секций .text
(исполняемый код бинарника) и .rodata
(константные данные).Те, кто не программируют активно под Linux, могут удивиться двум специфичным вещам:
wpa_supplicant
(для поиска WiFi).scanmem
ждет, пока юзер введет текущее значение из игры. После ввода значения вызывается ptrace для слежки за другим процессом (target
- process id процесса игры), из-за этого процесс игры остановится (кинет сигнал SIGSTOP
):ptrace(PTRACE_ATTACH, target, NULL, NULL)Затем можно читать память процесса. Делать это можно двумя способами.
В первом способе (как бы вы думали?) снова открывается файл, на этот раз
/proc/<pid>/mem
.Во втором способе можно читать память через ptrace:
ptrace(PTRACE_PEEKDATA, target, cur_address, NULL)
Посмотрим на первый способ. В первый раз в этом файла читается вся память из занимаемых регионов, через pread. Из чужой памяти загружается 1 мегабайт (брать больше смысла нет), запоминаются все адреса с нужным значением, затем читается следующие 1 мегабайт, и так далее, пока не прошерстят всю память.ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ