читы на сапера windows 10
Взламываем игру-головоломку «Сапер»
Intro
Холодным зимним вечером, начитавшись статей об исследовании различного ПО и насмотревшись различного рода видео про взломы игр и прочее, у меня вдруг тоже возникло желание повозиться под дебагерром с чем-нибудь интересным. Крякингом я занимаюсь сравнительно давно, поэтому практический опыт имеется. Поначалу я, как и многие, просто искал различные CrackME в сети и взламывал их с целью обучения, затем перешел на взломы платных приложений(поиск/подбор ключей) и написание различного рода KeyGen`ов. В данный момент «набиваю руку» и пытаюсь оттачивать мастерство взлома.
Ну да ладно, это лирическое отступление от сути. Теперь определимся с некоторыми деталями.
В данной статье главным объектом внимания для нас будет компьютерная игра «Сапер».
Исследование и последующая отладка приложения происходят под Windows 7 x64 (реализация игры «Сапер» отличается в различных версиях OS Windows).
В качестве дизассемблера будем использовать встроенный дебаггер CheatEngine. Мне он нравится своей простотой и изящностью, некоторые вещи в нем делаются гораздо легче, чем, например, в OllyDBG.
Окей, c деталями разобрались, приступим же к делу!
Наверняка, почти каждый, кто использует Windows, когда-либо имел дело с игрой «Сапер». В «семерке» игра выглядит так:
Это стандартное поле( в данном случае 16×16 клеток ). Мы будем ломать игру на среднем уровне сложности, т.е на уровне «Любитель». В общем-то для уровней сложности «Новичок» и «Профессионал» эта статья также будет актуальна, ничего кроме времени, количества мин и размеров поля не изменится.
Итак, открываем наш CheatEngine( в дальнейшем будет использоваться сокращение CE ) и аттачимся к процессу игры:
Ок, присоединились. Поиск нужных нам значений будет основываться на поиске открытых в текущий момент клетках. Поэтому, ищем нужное нам значение текущего количества открытых клеточек. В CE это делается достаточно просто:
1) Вводим в поле «Value» первоначальное количество открытых клеток, т.е ноль, нажимаем на «First Scan»
2) Переходим в игру и кликаем на случайной клетке, после переходим в CE и в поле «Scan Type» выбираем «Increased Value»(значение увеличилось), жмем «Next Scan»
Делаем похожие действия, пока не найдем то самое, заветное значение:
Мы отыскали адрес, в котором хранится другой адрес, который, в свою очередь, хранит статическое значение.
Добавляем значение в «AddressList». Теперь если немного поиграть в игру, можно будет заметить, что значение меняется.
Теперь ищем asm-инструкцию, которая как-то взаимодействует с данным значением( меняет, читает ):
Открываем игру и еще немного играем, затем видим такую картину:
Ага, очень интересно 🙂 Особенный интерес представляют 1 и 3 инструкции, так как они во-первых пишут в память, а во вторых они схожи и в общем счете выполняются целых 3 раза! Вот мы и переходим в дебаггер, выделив 1 или 3 инструкцию и нажав на кнопку «Show Disassembler».
Так, так, так, все становится интереснее и интереснее! Особый интерес представляет вот эта цепочка с заверщающим сравнением( cmp ):
Если повесим «бряк» на сравнение «cmp edx,eax», то при возврате в игру и попытке кликнуть на клетку, бряк сработает. При чем, как при клике на клетку с миной, так и при клике на обычную клетку. А что это значит? А значит это то, что где-то здесь происходит «распознавание» того, что находится под в закрытой клетке: пустота, мина или цифра. Пробуем изменить это значение на какое-либо бессмысленно сравнение, например, на такое:
Здесь, как некоторые поняли, главная задача — активация процессорного флага «Z», которая происходит в случае, если оба операнда инструкции CMP эквивалентны.
Возвращаемся в игру и кликаем по какой-либо закрытой клетке. В итоге:
Хах, прикольно! Оказывается, это была проверка » на выигрывание игры «, которая происходит при каждом клике по клетке поля, что в общем-то логично. Уже неплохо, но мы ведь хотим именно играть, минуя все мины, а не тупо выигрывать игру при открытии первой же клетки поля, верно? Так что, продолжаем наше исследование.
Во втором этапе взлома мы постараемся выяснить, что является «переломным моментом» при распознавании «нутра» клетки, на которую пришелся клик. Ок, снова идем в CE и проделываем те же операции, что и в первом этапе, разве что дебажить код не требуется. Видим уже знакомую последовательность инструкций:
Попытаемся отыскать границы функции( блока инструкций ), в которой мы находимся в данный момент( где находится инструкция ):
Ага, и что же мы видим:
Нас визуально перекинуло в начало текущей функции. Это нам пока что еще ни о чем важном не говорит, но если поразмыслить, обдумать, все что имеем, то можем прийти к выводу, что данная функция может быть как-либо связана с графикой игры, например. К такому выводу можно прийти, исходя из 1 этапа, где мы отыскали проверку игры «на выигрывание», что, скорее всего, сказывается на отрисовке поля. Ладно, проверим эту теорию. Спускаемся от начала функции немного вниз, где вскоре обнаружим весьма интересную инструкцию:
Это первое сравнение в данной функции… Хм, попробуем поставить бряк на инструкцию, затем переходим в игру:
Мы не можем перейти в игру. Почему? Да потому что наша теория подтвердилась! Эта функция и правда связана с графикой игры. При каждой активации окна и прочем взаимодействии с игровым интерфейсом вызывается эта функция, а в ней установлен BreakPoint на сравнении => активировать окно и «Сапёрить» мы не сможем, пока не снимем бряк. Снимаем его. Есть вероятность, что данное сравнение играет ключевую роль в последующем поведении всей функции. Попробуем изменить данное сравнение на бессмысленно сравнение, чтобы флаг процессора «Z» активировался, как это было сделано в первом этапе:
Размер новой инструкции( 2 байта ) в 2 раза меньше, чем тот, что был изначально( 4 байта ), следовательно, добавились инструкции «nop» в 1 байт, чтобы «Занопалось» оставшееся пространство в 2 байта. Переходим в игру и пытаемся играть. Тыкаем по клеткам, натыкаемся на мину, и… ничего не произошло! Хм, не удивительно. Ладно, попробуем не включать, а выключать флаг процессора «Z». Для этого надо заменить сравнение на такое, чтобы два сравниваемых элемента никогда не были равными. Для этого восстанавливаем изначальную инструкцию:
cmp dword ptr [rax+38],01
Теперь возвращаемся в игру и начинаем «саперить». При клике на некоторые области, они отрисовываются с некоторым запозданием, или их «нутро» отрисовывается лишь со второго раза. Оно и верно, ведь мы нагло влезли в графическую функцию и беспощадно отдебажили её :). Зато при клике на «опасные области» с минами ничего не происходит вообще!
Результат:
Профит 🙂 Мы хакнули игру «Сапер» из стандартного комплекта игр от Microsoft.
В следующей статье я расскажу о том, как можно использовать переполнение буфера для взлома игры, о других не менее интересных фичах.
Сапер Cheats
Игра одиночная, так что ничьи нервы не пострадают от того, что вы почитерите, в отличии от онлайновых игр.
UPD: как подсказывает CheMax, есть еще несколько похожих способов:
Во время игры нажмите на игровом поле две кнопки мыши одновременно,
и кнопку [Esc] на клавиатуре. Время остановится.
Чтобы оно пошло, сверните и разверните окно Сапера.
Существует программа для разгадывания логических загадок сапера, происходит чтение из оперативной памяти, в результате чего все мины становятся явными. К сожалению, на моей системе это не сработало, т.к. я в данный момент использую Windows XP, программа работает только до windows ME включительно.
Также для решения сапера есть программа [ http://empire-of-games.ru/gl__url/depositfiles.com/files/fdmtl2udj]Saper Helper[/url] (сайт автора погиб в глубине времени, код=идентификатору xD).
Программа была создана, чтобы использовать её в игре «Сапер на деньги», но ведь ничто не помешает нам использовать ее в наших благородных целях.
Главное помните всего 2 вещи:
Если все время читерить, играть разучишься! Все это очень серьезно.
Бот для сапера с изюминкой
Наверное у многих такое бывает: на работе нечего делать, или нужно подумать перед выполнением очередной задачи, да или попросту нет ничего вкусненького к чаю, тогда рука автоматически тянется к мышке и начинает играть в сапера. И вот в порыве очередного приступа саперомании меня посетила мысль о том, что я уже не думаю, как раньше, где расположены мины, а просто на автомате по выработанному алгоритму тычу по полю, ломая мышку. А раз я действую по алгоритму, без особых творческих усилий, то можно написать бота, который будет играть вместо меня, наверняка внимательнее и быстрее.
Таким образом, вместо того чтобы самому играть в сапера в свободное время, я решил обучить игре бота — написать программу на С#, которая будет выполнять следующее:
1) по картинке окна с игрой заполнять матрицу размеров 16*30(размеры поля сапера в профессиональном режиме) числами в соответствии с диспозицией на экране;
2) прогонять эту матрицу через алгоритм, выполняющий шаблонные действия;
3) в ходе алгоритма тыкать по полю мышкой, расставляя флаги и открывая поле, и возвращаться к первому пункту.
4) поскольку за счет третьего пункта мышь занята, то для остановки программы необходимо настроить перехват нажатых клавиш в операционной системе(т.к. активным постоянно является окно сапера, а не наша программа).
5)Осилив четыре предыдущих пункта, я решил добавить изюминку — сделать программу хоть немного более
полезной/юзабельной — сделать из нее заставку, т.е. автоматически запускать игру в сапера при бездействии клавиатуры и мыши по истечении времени, указанного пользователем(по желанию пользователя, разумеется).
Программа писалась и тестировалась для классического сапера, который был в версиях Windows до XP включительно. Далее я решил перенести ее также и на MineSweeper — сапер из Windows7, об этом в конце статьи.
Итак, пойдем по порядку.
1) В первом пункте мы создаем глаза нашего бота. Получить картинку с игрой нам поможет следующий код:
Распознать изображение и заполнить матрицу нам поможет оболочка известной библиотеки OpenCV для C# EmguCV, она очень проста в подключении и
использовании. Распознавание в приложении происходит следующим образом: из большого изображения с окном игры, полученного на предыдущем этапе, по очереди вырезаются маленькие изображения — ячейки и сравниваются с заранее заготовленными эталонами. Для более эффективного сравнения делаем изображения черно-белыми: если интенсивность серого в конкретном пикселе меньше THRESHOLD, то он окрашивается в белый, иначе в черный, далее идет попиксельное сравнение.
2) Теперь наш бот может видеть, надо научить его думать; алгоритм игры — мозг нашего бота, он состоит из нескольких частей.
Для удобства использования нашей таблицы с числами в алгоритмах прохождения игры создадим класс SaperCell, в котором помимо типа ячейки и координат зададим еще несколько свойств:
Первая часть алгоритма — самая простая, в ней мы пробегаем по всем открытым клеткам(по цифрам от 1 до 8) и проверяем, равно ли количество неоткрытых соседей данной клетки количеству мин, которых она должна касаться(типу данной клетки). Если это так, то мы знаем, что мины расположены во всех соседних неоткрытых ячейках. После этой части алгоритма обработаются все следующие ситуации:
Вторая часть алгоритма отлавливает все типичные ситуации, которые выработались у меня за время, когда не было ничего вкусненького к чаю. Таких шаблонов несколько:
1) Тройка 1, 2, 1 — в этом случае мины стоят напротив единиц.
2) Четверка 1, 2, 2, 1 — в этом случае мины стоят напротив двоек.
3) Замкнутая тройка 1, 1, 1 (это значит, что по диагонали от крайних единиц нет неоткрытых клеток, т.е. напротив тройки ровно три неоткрытых клетки) — в этом случае мина напротив центральной единицы.
4) Замкнутая четверка 1, 1, 1, 1 — мины напротив крайних единиц.
Третья часть алгоритма (если это так можно назвать): пробегаем по всем клеткам, которые уже касаются нужного количества мин, и тыкаем одновременно левой и правой кнопками мыши.
Четвертая часть алгоритма — умный клик, если предыдущие алгоритмы больше не дают результата(не раскрывают ничего нового), то идет поиск клеток, где точно нет мин: если множество неоткрытых соседей клетки А является подмножеством неоткрытых соседей клетки В, и клетка В не должна касаться большего числа мин, чем клетка А, то можно смело открывать всех неоткрытых соседей клетки В, не являющихся соседями клетки А.
Далее, аналогичным образом, идет поиск клеток, где точно есть мина.
3) Теперь наш бот знает, где точно есть мины и где их точно нет, а ничего поделать не может, как говорится нет ручек — нет конфеток. Приделаем нашему боту руки: вот код, позволяющий совершать левый клик мышью в нужной клетке окна сапера:
Теперь в ходе алгоритма, чтобы кликнуть по ячейке с координатами (x,y) достаточно написать:
Здесь mouse — это класс, содержащий все виды кликов, позволяющий проще манипулировать мышью в ходе игры.
4) После предыдущих пунктов наш бот просто неудержим — готов играть в сапера до посинения, занимая мышку. Поэтому нужно приделать ему уши, чтоб он слышал, когда останавливаться. Поскольку мышь занята, то для остановки программы придется использовать… клавиатуру, что же еще. Но и с этим есть проблема, так как активным постоянно является окно сапера, то придется отлавливать все нажатые клавиши в операционной системе. Поискав в интернетах, я набрел вот на это готовое решение. Остается создать два отдельных потока — в одном будет трудиться наш бот, во втором перехватчик нажатых клавиш, а также механизм их взаимодействия.
В функции KeyboardHook при нажатии клавиши:
В функции SaperGame:
Поток saper при игре постоянно проверяет, переменную isPaused, если она равна true(значит была нажата клавиша), то поток тормозит и ждет отмашки от ивент вайт хэндлера, а он ее дает только при повторном нажатии клавиши.
5) Теперь наш бот не только хорошо играет, но и стал очень послушным. После всяких оптимизаций (рекорд бота 5 секунд) я уже не знал, что бы еще с ним сделать, а хотелось добавить какую-то изюминку, уж очень меня это увлекло.
Теперь скажу немного об обучении бота играть в Minesweeper из Windows7. Когда программа работала как часы под Windows XP, но я думал, что всего пару штришков — и все заработает под Windows7. Но не тут то было, хотя, по сути, переделать нужно было только процесс распознавания, но это потребовало времени почти столько же, сколько написание всего предыдущего кода. Дело в том, что однотипные ячейки в сапере из Windows7 очень сильно отличаются в разных частях поля. Поэтому для каждого типа ячейки пришлось заготовить сразу несколько эталонов, но и это не избавило от ошибок в распознавании, так как установить один и тот же THRESHOLD для такого количества картинок не удавалось. Поэтому пришлось для каждой ячейки на ходу высчитывать THRESHOLD, как среднюю интенсивность серого всей картинки, за счет этого время распозвнавания увеличилось в два раза. Ну ладно, главное надежно, но и после этого периодически проскакивали косяки, причем при пошаговой отладке их не было. Все дело оказалось в плавном обновлении самого окна сапера в Windows7, пришлось делать искусственные паузы перед каждым снимком экрана. Кажется все просто, но пока я дошел до этого, я проклял, что взялся за допиливание проги под MineSweeper-а, что начал изобретать этот хромающий велосипед с распознаванием. Но, благо, после небольшой оптимизации прога начала раскладывать сапера за приемлимое время и почти не сбиваться.
Исходный код программы доступен на github.
Таким вот образом у меня получилось написать довольно-таки интересное приложение, попрактиковать свои навыки программирования и изучить что-то новое. Всем, кто прочитал — спасибо, а кто скачал и попробывал бота в действии — огромная благодарность!
Технолгичный взлом Сапера
Загружаем Сапера в W32Dasm:
видим, что ID этого пункта меню равен [ID=01FEh]. В поиске вбиваем это значение, ищем. Находим это:
именно тут и происходит выбор нашего пункта, идем по этому адресу. А тут:
Хорошо, идем в эту процедуру. Она начинается так:
По этим адресам лежат число клеток по X и Y, они (эти адреса) нам понадобятся!. Шагая по этой подпрограмме можно найти адрес с которого начинается рэндомно заполняющаяся карта. у меня он равен: 01005360h. Ну и начиная с этого адреса идут клетки поля, если в них находиться значение 8F, значит тут мина, иначе стоит FF, а начало и конец строки определяются как 10h, причем строчки находятся друг от друга на интервале 20h.
Этого нам достаточно для написания программы. На форме находится sg: TStringGrid.
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids;
type
TPole = record
x: Byte;
y: Byte;
End;
type
TForm1 = class(TForm)
Button1: TButton;
sg: TStringGrid;
procedure Button1Click(Sender: TObject);
private
SapMap: Tpole;
public
end;
procedure TForm1.Button1Click(Sender: TObject);
Var
hWn: HWND;
PID, hProc, dwReaded: DWord;
buf: Byte;
i, r: Dword;
StartAddr: Dword;
begin
hWn := HWND(FindWindow(nil, PChar(‘Сапер’)));
If IsWindow(hWn) Then
Begin
GetWindowThreadProcessId(hWn, PID);
hProc := OpenProcess(PROCESS_VM_READ, False, PID);
Try
If (hProc <> 0) Then
Begin
ReadProcessMemory(hProc, ptr($10056AC), @buf, 1, dwReaded);
SapMap.x := buf;
ReadProcessMemory(hProc, ptr($10056A8), @buf, 1, dwReaded);
SapMap.y := buf;
End;
Finally
CloseHandle(hProc);
End;
End;
end;
Как играть в Сапёр: забава, ставшая легендой
Мало кто сейчас помнит старые добрые времена, когда компьютеры только-только становились персональными, а о современных 3-мерных стрелялках никто и не мечтал. Тогда единственным способом отдохнуть за ПК для многочисленной армии офисных работников были встроенные в Windows несложные игры. Пасьянсы обычно предпочитали барышни, а легендарного минёра – мужчины. Игра давно завоевала статус культовой, но в наши дни уже не пользуется большой популярностью, а зря. Она не требует никаких ресурсов, запускается на очень старых компьютерах и с лёгкостью может скрасить короткие минуты отдыха. Потому разобраться в том, как играть в Minesweeper, будет полезно и познавательно.
Видео о гуру игры «Сапёр»
Перед вами откроется пустое игровое поле с синими квадратиками
Цифры в квадратиках означают количество мин, которые находятся вокруг конкретного поля
На данном рисунке, отмеченные поля гарантированно содержат мину
Поля, которые точно содержат мину, отмечаем флажочком
Далее нужно отметить флажками те клеточки, в которых мин гарантировано нет
Точно определиться с минами в белом квадрате сразу же не получится, а вот красные и зеленые участки анализу поддаются
Таким образом, вы сможете «обезопасить» весь квадрат, если не станете никуда торопиться и внимательно анализировать игровую ситуацию. Удачи!
Впрочем, при определённом стечении обстоятельств игра может оказаться очень «непослушной», когда, несмотря на все усилия, вы будете раз за разом проигрывать. В таком случае придётся либо сдаться, либо «уговорить» минёра быть более терпимым. Что для этого нужно сделать?