Intro
Холодным зимним вечером, начитавшись статей об исследовании различного ПО и насмотревшись различного рода видео про взломы игр и прочее, у меня вдруг тоже возникло желание повозиться под дебагерром с чем-нибудь интересным. Крякингом я занимаюсь сравнительно давно, поэтому практический опыт имеется. Поначалу я, как и многие, просто искал различные CrackME в сети и взламывал их с целью обучения, затем перешел на взломы платных приложений(поиск/подбор ключей) и написание различного рода KeyGen`ов. В данный момент «набиваю руку» и пытаюсь оттачивать мастерство взлома.
Ну да ладно, это лирическое отступление от сути. Теперь определимся с некоторыми деталями.
В данной статье главным объектом внимания для нас будет компьютерная игра «Сапер».
Исследование и последующая отладка приложения происходят под Windows 7 x64 (реализация игры «Сапер» отличается в различных версиях OS Windows).
В качестве дизассемблера будем использовать встроенный дебаггер CheatEngine. Мне он нравится своей простотой и изящностью, некоторые вещи в нем делаются гораздо легче, чем, например, в OllyDBG.
Окей, c деталями разобрались, приступим же к делу!
Наверняка, почти каждый, кто использует Windows, когда-либо имел дело с игрой «Сапер». В «семерке» игра выглядит так:
![](https://habrastorage.org/storage2/2b3/e15/9cc/2b3e159cc405f214c4e098077fad6b31.png)
Это стандартное поле( в данном случае 16x16 клеток ). Мы будем ломать игру на среднем уровне сложности, т.е на уровне «Любитель». В общем-то для уровней сложности «Новичок» и «Профессионал» эта статья также будет актуальна, ничего кроме времени, количества мин и размеров поля не изменится.
1 этап
Итак, открываем наш CheatEngine( в дальнейшем будет использоваться сокращение CE ) и аттачимся к процессу игры:
![](https://habrastorage.org/storage2/332/0d7/53e/3320d753e3d29a8c7dcd8f0dab1c2d58.png)
Ок, присоединились. Поиск нужных нам значений будет основываться на поиске открытых в текущий момент клетках. Поэтому, ищем нужное нам значение текущего количества открытых клеточек. В CE это делается достаточно просто:
1) Вводим в поле «Value» первоначальное количество открытых клеток, т.е ноль, нажимаем на «First Scan»
2) Переходим в игру и кликаем на случайной клетке, после переходим в CE и в поле «Scan Type» выбираем «Increased Value»(значение увеличилось), жмем «Next Scan»
Делаем похожие действия, пока не найдем то самое, заветное значение:
![](https://habrastorage.org/storage2/934/ae3/4fa/934ae34fa3cfc544e5351081874cd72f.png)
Мы отыскали адрес, в котором хранится другой адрес, который, в свою очередь, хранит статическое значение.
Добавляем значение в «AddressList». Теперь если немного поиграть в игру, можно будет заметить, что значение меняется.
Теперь ищем asm-инструкцию, которая как-то взаимодействует с данным значением( меняет, читает ):
![](https://habrastorage.org/storage2/453/f82/7a5/453f827a507f49709adfb66b21725392.png)
Открываем игру и еще немного играем, затем видим такую картину:
![](https://habrastorage.org/storage2/834/a70/7fa/834a707fa608d54aaf7ff3bca7716650.png)
Ага, очень интересно :) Особенный интерес представляют 1 и 3 инструкции, так как они во-первых пишут в память, а во вторых они схожи и в общем счете выполняются целых 3 раза! Вот мы и переходим в дебаггер, выделив 1 или 3 инструкцию и нажав на кнопку «Show Disassembler».
Так, так, так, все становится интереснее и интереснее! Особый интерес представляет вот эта цепочка с заверщающим сравнением( cmp ):
![](https://habrastorage.org/storage2/859/afc/ff9/859afcff9d357aea2449ea0f3b84b180.png)
Если повесим «бряк» на сравнение «cmp edx,eax», то при возврате в игру и попытке кликнуть на клетку, бряк сработает. При чем, как при клике на клетку с миной, так и при клике на обычную клетку. А что это значит? А значит это то, что где-то здесь происходит «распознавание» того, что находится под в закрытой клетке: пустота, мина или цифра. Пробуем изменить это значение на какое-либо бессмысленно сравнение, например, на такое:
![](https://habrastorage.org/storage2/d72/3ed/074/d723ed074180524126c5d3e07f3ff80b.png)
Здесь, как некоторые поняли, главная задача — активация процессорного флага «Z», которая происходит в случае, если оба операнда инструкции CMP эквивалентны.
Возвращаемся в игру и кликаем по какой-либо закрытой клетке. В итоге:
![](https://habrastorage.org/storage2/746/b97/fa9/746b97fa971c46aa13e0ba3ff41ce77d.png)
Хах, прикольно! Оказывается, это была проверка " на выигрывание игры ", которая происходит при каждом клике по клетке поля, что в общем-то логично. Уже неплохо, но мы ведь хотим именно играть, минуя все мины, а не тупо выигрывать игру при открытии первой же клетки поля, верно? Так что, продолжаем наше исследование.
2 этап
Во втором этапе взлома мы постараемся выяснить, что является «переломным моментом» при распознавании «нутра» клетки, на которую пришелся клик. Ок, снова идем в CE и проделываем те же операции, что и в первом этапе, разве что дебажить код не требуется. Видим уже знакомую последовательность инструкций:
![](https://habrastorage.org/storage2/859/afc/ff9/859afcff9d357aea2449ea0f3b84b180.png)
Попытаемся отыскать границы функции( блока инструкций ), в которой мы находимся в данный момент( где находится инструкция ):
![](https://habrastorage.org/storage2/826/76c/4b0/82676c4b023b33f1352813a4f30f2e78.png)
Ага, и что же мы видим:
![](https://habrastorage.org/storage2/ed1/964/0b0/ed19640b0cafb43d9f54fdac55d0795f.png)
Нас визуально перекинуло в начало текущей функции. Это нам пока что еще ни о чем важном не говорит, но если поразмыслить, обдумать, все что имеем, то можем прийти к выводу, что данная функция может быть как-либо связана с графикой игры, например. К такому выводу можно прийти, исходя из 1 этапа, где мы отыскали проверку игры «на выигрывание», что, скорее всего, сказывается на отрисовке поля. Ладно, проверим эту теорию. Спускаемся от начала функции немного вниз, где вскоре обнаружим весьма интересную инструкцию:
![](https://habrastorage.org/storage2/02a/928/c32/02a928c32fc1e2624c35895bc30892bb.png)
Это первое сравнение в данной функции… Хм, попробуем поставить бряк на инструкцию, затем переходим в игру:
![](https://habrastorage.org/storage2/211/bcc/658/211bcc658337170f8bcda467b7675dcc.png)
Мы не можем перейти в игру. Почему? Да потому что наша теория подтвердилась! Эта функция и правда связана с графикой игры. При каждой активации окна и прочем взаимодействии с игровым интерфейсом вызывается эта функция, а в ней установлен BreakPoint на сравнении => активировать окно и «Сапёрить» мы не сможем, пока не снимем бряк. Снимаем его. Есть вероятность, что данное сравнение играет ключевую роль в последующем поведении всей функции. Попробуем изменить данное сравнение на бессмысленно сравнение, чтобы флаг процессора «Z» активировался, как это было сделано в первом этапе:
![](https://habrastorage.org/storage2/429/a6e/3f0/429a6e3f0bd52b740bf02134d203ec60.png)
Размер новой инструкции( 2 байта ) в 2 раза меньше, чем тот, что был изначально( 4 байта ), следовательно, добавились инструкции «nop» в 1 байт, чтобы «Занопалось» оставшееся пространство в 2 байта. Переходим в игру и пытаемся играть. Тыкаем по клеткам, натыкаемся на мину, и… ничего не произошло! Хм, не удивительно. Ладно, попробуем не включать, а выключать флаг процессора «Z». Для этого надо заменить сравнение на такое, чтобы два сравниваемых элемента никогда не были равными. Для этого восстанавливаем изначальную инструкцию:
cmp dword ptr [rax+38],01
и изменяем сравнение содержимого указателя, например, на сравнение с отрицательным числом( с -1 ):
![](https://habrastorage.org/storage2/a02/a73/669/a02a7366959c12cbe0e4a0a86c9a55da.png)
Теперь возвращаемся в игру и начинаем «саперить». При клике на некоторые области, они отрисовываются с некоторым запозданием, или их «нутро» отрисовывается лишь со второго раза. Оно и верно, ведь мы нагло влезли в графическую функцию и беспощадно отдебажили её :). Зато при клике на «опасные области» с минами ничего не происходит вообще!
Результат:
![](https://habrastorage.org/storage2/6a0/698/2fa/6a06982fa40ac43f6efc8c940e79da57.png)
Профит :) Мы хакнули игру «Сапер» из стандартного комплекта игр от Microsoft.
В следующей статье я расскажу о том, как можно использовать переполнение буфера для взлома игры, о других не менее интересных фичах.