Как я могу найти структуру данных, которая представляет расположение шахты Minesweeper в памяти?
-
06-09-2019 - |
Вопрос
Я пытаюсь узнать о реверс-инжиниринге, используя Minesweeper в качестве примера приложения.Я нашел это Статья в MSDN с помощью простой команды WinDbg, которая показывает все мины, но она старая, не объяснена ни в каких деталях и на самом деле не является тем, что я ищу.
У меня есть Дизассемблер IDA Pro и тот Отладчик WinDbg и я загрузил winmine.exe в них обоих.Может ли кто-нибудь дать несколько практических советов для любой из этих программ с точки зрения определения местоположения структуры данных, представляющей минное поле?
В WinDbg я могу установить точки останова, но мне трудно представить, в какой момент устанавливать точку останова и в какой ячейке памяти.Аналогично, когда я просматриваю статический код в IDA Pro, я даже не уверен, с чего начать поиск функции или структуры данных, которая представляет минное поле.
Есть ли какие-нибудь реверсивные инженеры в Stackoverflow, которые могут указать мне правильное направление?
Решение
Часть 1 из 3
Если вы серьезно относитесь к реверс-инжинирингу - забудьте о трейнерах и читерских движках.
Хороший реверс-инженер должен сначала ознакомиться с операционной системой, основными функциями API, общей структурой программы (что такое цикл выполнения, структуры Windows, процедуры обработки событий), форматом файла (PE).Классика в Петцольд "программирование для Windows" может помочь (www.amazon.com/exec/obidos/ISBN=157231995X), а также на интернет-сайте MSDN.
Сначала вам следует подумать о том, где можно вызвать процедуру инициализации минного поля.Я подумал о том, чтобы последовать за:
- Когда вы запускаете игру
- Когда вы нажимаете на счастливое лицо
- Когда вы нажимаете Game-> New или нажимаете F2
- Когда вы меняете уровень сложности
Я решил проверить команду F2 accelerator.
Чтобы найти код обработки ускорителя, вам нужно найти процедуру обработки сообщений window (WndProc).Это можно отследить с помощью вызовов CreateWindowEx и RegisterClass.
Читать:
- Создать Windowex http://msdn.microsoft.com/en-us/library/ms632680%28VS.85%29.aspx
- Регистрационный класс http://msdn.microsoft.com/en-us/library/ms633586%28VS.85%29.aspx
- Глава 3 Петцольда "Окна и сообщения"
Откройте IDA, окно импорта, найдите "CreateWindow *", перейдите к нему и используйте команду "Перейти по внешней ссылке к операнду (X)", чтобы увидеть, где он вызывается.Должен быть только один звонок.
Теперь посмотрите выше на функцию RegisterClass и ее параметр WndClass.lpfnWndProc.В моем случае я уже назвал функцию mainWndProc .
.text:0100225D mov [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264 mov [ebp+WndClass.cbClsExtra], edi
.text:01002267 mov [ebp+WndClass.cbWndExtra], edi
.text:0100226A mov [ebp+WndClass.hInstance], ecx
.text:0100226D mov [ebp+WndClass.hIcon], eax
.text:01002292 call ds:RegisterClassW
Нажмите Enter в названии функции (используйте 'N', чтобы переименовать его во что-то лучшее).
Теперь взгляните на
.text:01001BCF mov edx, [ebp+Msg]
Это идентификатор сообщения, который при нажатии кнопки F2 должен содержать значение WM_COMMAND.Вы должны найти, где он сравнивается с 111h.Это можно сделать либо путем отслеживания edx в IDA, либо с помощью установка условной точки останова в WinDbg и нажимаем клавишу F2 в игре.
Любой способ приводит к чему-то вроде
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
Щелкните правой кнопкой мыши на 111h и используйте "Символьную константу" -> "Использовать стандартную символьную константу", введите WM_ и Enter.Теперь у вас должно быть
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
Это простой способ узнать значения идентификаторов сообщений.
Чтобы понять, как обращаться с акселератором, ознакомьтесь:
- Использование клавиатурных ускорителей
- Хакер ресурсов (http://angusj.com/resourcehacker/)
Это довольно много текста для одного ответа.Если вам интересно, я могу написать еще пару постов.Короче говоря, минное поле хранится в виде массива байтов [24x36], 0x0F показывает, что байт не используется (поле меньшего размера), 0x10 - пустое поле, 0x80 - мое.
Часть 2 из 3
Хорошо, давайте продолжим с кнопкой F2.
Согласно Использование клавиатурных ускорителей при нажатии кнопки F2 функция WndProc
...получает WM_COMMAND или WM_SYSCOMMAND Сообщение.Младшее слово параметра wParam содержит идентификатор ускорителя.
Хорошо, мы уже нашли, где обрабатывается WM_COMMAND, но как определить соответствующее значение параметра wParam?Это то место, где Хакер ресурсов вступает в игру.Используйте двоичный файл, и он покажет вам все.Для меня это как таблица ускорителей.
альтернативный текст http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
Вы можете видеть здесь, что кнопка F2 соответствует значению 510 в wParam.
Теперь давайте вернемся к коду, который обрабатывает WM_COMMAND.Он сравнивает wParam с различными константами.
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 210h
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 1FEh
.text:01001DD8 jz loc_1001EC8
Используйте контекстное меню или сочетание клавиш "H" для отображения десятичных значений, и вы сможете увидеть наш переход
.text:01001DBC HandleWM_COMMAND: ; CODE XREF: mainWndProc+197j
.text:01001DBC movzx eax, word ptr [ebp+wParam]
.text:01001DC0 mov ecx, 528
.text:01001DC5 cmp eax, ecx
.text:01001DC7 jg loc_1001EDC
.text:01001DC7
.text:01001DCD jz loc_1001ED2
.text:01001DCD
.text:01001DD3 cmp eax, 510
.text:01001DD8 jz loc_1001EC8 ; here is our jump
Это приводит к фрагменту кода, который вызывает некоторый процесс и завершает работу с WndProc.
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
Это та функция, которая запускает новую игру?Узнайте это в последней части!Оставайтесь с нами.
Часть 3 из 3
Давайте взглянем на первую часть этой функции
.text:0100367A sub_100367A proc near ; CODE XREF: sub_100140C+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, dword_10056AC
.text:0100367F mov ecx, uValue
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, dword_1005334
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, dword_1005338
.text:0100369E jnz short loc_10036A4
Имеются два значения (dword_10056AC, uValue), считываемые в регистры eax и ecx и сравниваемые с другими двумя значениями (dword_1005164, dword_1005338).
Взгляните на фактические значения, используя WinDbg ('bp 01003696';на перерыве 'p eax;p ecx') - для меня они казались размерами минного поля.Игра с пользовательским размером минного поля показала, что первая пара - это новые размеры, а вторая - текущие.Давайте установим новые имена.
.text:0100367A startNewGame proc near ; CODE XREF: handleButtonPress+CAp
.text:0100367A ; sub_1001B49+33j ...
.text:0100367A mov eax, newMineFieldWidth
.text:0100367F mov ecx, newMineFieldHeight
.text:01003685 push ebx
.text:01003686 push esi
.text:01003687 push edi
.text:01003688 xor edi, edi
.text:0100368A cmp eax, currentMineFieldWidth
.text:01003690 mov dword_1005164, edi
.text:01003696 jnz short loc_10036A4
.text:01003696
.text:01003698 cmp ecx, currentMineFieldHeight
.text:0100369E jnz short loc_10036A4
Чуть позже новые значения перезаписывают текущие, и вызывается подпрограмма
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
И когда я увидел это
.text:01002ED5 sub_1002ED5 proc near ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5 ; sub_100367A+38p
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA: ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
Я был полностью уверен, что нашел массив минных полей.Причина цикла, который вводит массив длиной 360 байт (dword_1005340 ) с 0xF.
Почему 360h = 864?Ниже есть несколько подсказок, что строка занимает 32 байта, а 864 можно разделить на 32, поэтому массив может содержать 27 * 32 ячейки (хотя пользовательский интерфейс допускает максимальное поле 24 * 30, вокруг массива есть один байт отступа для границ).
Следующий код генерирует верхнюю и нижнюю границы минного поля (0x10 байт).Я надеюсь, вы можете увидеть повторение цикла в этом беспорядке ;) Мне пришлось использовать бумагу и ручку
.text:01002EE4 mov ecx, currentMineFieldWidth
.text:01002EEA mov edx, currentMineFieldHeight
.text:01002EF0 lea eax, [ecx+2]
.text:01002EF3 test eax, eax
.text:01002EF5 push esi
.text:01002EF6 jz short loc_1002F11 ;
.text:01002EF6
.text:01002EF8 mov esi, edx
.text:01002EFA shl esi, 5
.text:01002EFD lea esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03
.text:01002F03 loc_1002F03: ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h ; top border
.text:01002F0B mov byte ptr [esi+eax], 10h ; bottom border
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11: ; CODE XREF: sub_1002ED5+21j
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
А остальная часть подпрограммы рисует левую и правую границы
.text:01002F18 mov eax, esi
.text:01002F1A shl eax, 5
.text:01002F1D lea edx, MineField?[eax]
.text:01002F23 lea eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A: ; CODE XREF: sub_1002ED5+62j
.text:01002F2A sub edx, 20h
.text:01002F2D sub eax, 20h
.text:01002F30 dec esi
.text:01002F31 mov byte ptr [edx], 10h
.text:01002F34 mov byte ptr [eax], 10h
.text:01002F37 jnz short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39: ; CODE XREF: sub_1002ED5+41j
.text:01002F39 pop esi
.text:01002F3A retn
Разумное использование команд WinDbg может обеспечить вам классный дамп минного поля (пользовательский размер 9x9).Посмотрите на границы!
0:000> db /c 20 01005340 L360
01005340 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005360 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005380 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053a0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053c0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010053e0 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005400 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005420 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005440 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005460 10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
01005480 10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054a0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054c0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
010054e0 0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ................................
Хм, похоже, мне понадобится еще один пост, чтобы закрыть тему
Другие советы
Похоже, что вы пытаетесь разобрать исходный код, но что вам нужно сделать, это посмотреть на объем памяти запущенной программы.Шестнадцатеричный редактор HxD есть функция, которая позволяет вам именно это.
Как только вы окажетесь в пространстве памяти, нужно будет делать снимки памяти, пока вы возитесь с доской.Выделите, что меняется, а что нет.Когда вы решите, что у вас есть представление о том, где находится структура данных в шестнадцатеричной памяти, попробуйте отредактировать ее, пока она находится в памяти, и посмотрите, изменится ли в результате плата.
Процесс, который вам нужен, мало чем отличается от создания "трейнера" для видеоигры.Обычно они основаны на поиске того, где в памяти хранятся такие ценности, как здоровье и боеприпасы, и изменении их "на лету".Возможно, вам удастся найти несколько хороших руководств по созданию игровых тренажеров.
Ознакомьтесь с этой статьей code project, она немного более подробная, чем запись в блоге, о которой вы упомянули.
http://www.codeproject.com/KB/trace/minememoryreader.aspx
Редактировать
И эта статья, хотя и не о minesweeper напрямую, дает вам хорошее пошаговое руководство по поиску в памяти с помощью WinDbg:
http://www.codingthewheel.com/archives/extracting-hidden-text-with-windbg
Правка 2
Опять же, это не о minesweeper, но это определенно дало мне пищу для размышлений по отладке моей памяти, здесь есть множество руководств:
http://memoryhacking.com/forums/index.php
Кроме того, скачайте Мошеннический двигатель (упоминается Ником Д.) и поработайте с руководством, которое прилагается к нему.
"В WinDbg я могу устанавливать точки останова, но мне трудно представить, в какой момент устанавливать точку останова и в какой ячейке памяти.Аналогично, когда я просматриваю статический код в IDA Pro, я даже не уверен, с чего начать поиск функции или структуры данных, которые представляют минное поле. "
Вот именно!
Ну, вы можете поискать такие подпрограммы, как random(), которые будут вызываться во время построения таблицы mines.Это книга это очень помогло мне, когда я экспериментировал с обратным инжинирингом.:)
В общем, хорошими местами для установки точек останова являются вызовы окон сообщений, вызовы для воспроизведения звука, таймеры и другие подпрограммы win32 API.
Кстати, прямо сейчас я сканирую minesweeper с помощью OllyDbg.
Обновить: немо напомнил мне отличный инструмент, Читерский Движок автор: Эрик "Темный байт" Хейнен.
Cheat Engine (CE) - отличный инструмент для просмотра и изменения пространства памяти других процессов.Помимо этого Базовые модели кроме того, CE обладает более специальными функциями, такими как просмотр дизассемблированной памяти процесса и внедрение кода в другие процессы.
(тот самый реальный ценность этого проекта в том, что вы можете загрузить исходный код - Delphi - и посмотреть, как были реализованы эти механизмы - я сделал это много лет назад : o)
Довольно хорошую статью на эту тему можно найти по адресу Неосведомленный.В нем довольно подробно описывается reversing Minesweeper (как введение в реверс-инжиниринг приложений Win32), и все это основано на довольно большом ресурсе.
Этот веб-сайт мог бы быть более полезным:
http://www.subversity.net/reversing/hacking-minesweeper
Общий способ сделать это таков:
- Каким-то образом получить исходный код.
- Разберите и надейтесь, что оставшиеся символы помогут вам.
- Угадайте тип данных и попытайтесь манипулировать ими, а также используйте сканер памяти, чтобы ограничить возможности.
В ответ на щедрость
Что ж, при повторном прочтении кажется, что вам нужно руководство по использованию отладчика, подобного WinDbg, а не обычный вопрос о том, как выполнить обратный инжиниринг.Я уже показывал вам веб-сайт, на котором указаны значения, которые вам нужно найти, поэтому вопрос в том, как вы их ищете?
В этом примере я использую Блокнот, потому что у меня не установлен Minesweeper.Но идея та же самая.
Вы печатаете
s <options> <memory start> <memory end> <pattern>
Пресса"?- а потом "s", чтобы увидеть справку.
Как только вы найдете нужный шаблон памяти, вы можете нажать alt + 5, чтобы вызвать программу просмотра памяти для удобного отображения.
К WinDbg требуется некоторое привыкание, но он так же хорош, как и любой другой существующий отладчик.
Хорошим моментом для начала трассировки в отладчике было бы наведение курсора мыши вверх.Итак, найдите процедуру главного окна (я думаю, что такие инструменты, как spyxx, могут проверять свойства Windows, и адрес обработчика событий является одним из них).Взломайте его и найдите, где он обрабатывает события мыши - там будет переключатель, если вы сможете распознать его в ассемблере (посмотрите значение WM_XXX для мыши в windows.h).
Поставьте там точку останова и начинайте действовать.Где-то между моментом, когда вы отпустили кнопку мыши, и обновлением экрана victum получит доступ к структуре данных, которую вы ищете.
Будьте терпеливы, постарайтесь определить, что делается в данный момент времени, но не утруждайте себя слишком глубоким изучением кода, который, как вы подозреваете, неинтересен для вашей текущей цели.Чтобы исправить это, может потребоваться несколько запусков в отладчике.
Знание обычного рабочего процесса приложений win32 тоже помогает.
Мины, вероятно, будут храниться в каком-то двумерном массиве.Это означает, что это либо массив указателей, либо один массив логических значений в стиле C.
Всякий раз, когда форма получает событие наведения курсора мыши, делается ссылка на эту структуру данных.Индекс будет вычислен с использованием координаты мыши, вероятно, с использованием целочисленного деления.Это означает, что вам, вероятно, следует поискать cmp
или аналогичная инструкция, где один из операндов вычисляется с использованием смещения и x
, где x
является результатом вычисления, включающего целочисленное деление.Тогда смещение будет указателем на начало структуры данных.
Вполне разумно предположить, что информация о минах размещена в памяти последовательно, по крайней мере, для строк (т. е.это 2D-массив, или массив из массивов).Таким образом, я бы попробовал открыть несколько соседних ячеек в одной строке, создавая дампы памяти процесса по ходу работы, а затем дифференцировать их и искать любые повторяющиеся изменения в одной и той же области памяти (т.Е.1 байт изменен на первом шаге, следующий байт изменен на точно такое же значение на следующем шаге и т.д.).
Также существует вероятность того, что это упакованный битовый массив (3 бита на шахту должно быть достаточно для записи всех возможных состояний - закрыто / открыто, шахта / без шахты, помечено / без флага), поэтому я бы тоже обратил на это внимание (шаблоны также были бы повторяемыми, хотя их было бы сложнее обнаружить).Но с этой структурой неудобно иметь дело, и я не думаю, что использование памяти было узким местом для Minesweeper, поэтому маловероятно, что подобные вещи будут использоваться.
Хотя это не совсем "инструмент обратного проектирования", а скорее игрушка, которую мог бы использовать даже такой идиот, как я, посмотрите Читерский Движок.Это несколько упрощает отслеживание того, какие части памяти были изменены, когда, и даже содержит положения для отслеживания измененных частей памяти с помощью указателей (хотя вам, вероятно, это не нужно).В комплект входит приятный интерактивный учебник.