Как я могу найти структуру данных, которая представляет расположение шахты Minesweeper в памяти?

StackOverflow https://stackoverflow.com/questions/931257

Вопрос

Я пытаюсь узнать о реверс-инжиниринге, используя 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.

Читать:

Откройте 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

Это простой способ узнать значения идентификаторов сообщений.

Чтобы понять, как обращаться с акселератором, ознакомьтесь:

Это довольно много текста для одного ответа.Если вам интересно, я могу написать еще пару постов.Короче говоря, минное поле хранится в виде массива байтов [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 есть функция, которая позволяет вам именно это.

http://www.freeimagehosting.net/uploads/fcc1991162.png

Как только вы окажетесь в пространстве памяти, нужно будет делать снимки памяти, пока вы возитесь с доской.Выделите, что меняется, а что нет.Когда вы решите, что у вас есть представление о том, где находится структура данных в шестнадцатеричной памяти, попробуйте отредактировать ее, пока она находится в памяти, и посмотрите, изменится ли в результате плата.

Процесс, который вам нужен, мало чем отличается от создания "трейнера" для видеоигры.Обычно они основаны на поиске того, где в памяти хранятся такие ценности, как здоровье и боеприпасы, и изменении их "на лету".Возможно, вам удастся найти несколько хороших руководств по созданию игровых тренажеров.

Ознакомьтесь с этой статьей 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

Общий способ сделать это таков:

  1. Каким-то образом получить исходный код.
  2. Разберите и надейтесь, что оставшиеся символы помогут вам.
  3. Угадайте тип данных и попытайтесь манипулировать ими, а также используйте сканер памяти, чтобы ограничить возможности.

В ответ на щедрость

Что ж, при повторном прочтении кажется, что вам нужно руководство по использованию отладчика, подобного WinDbg, а не обычный вопрос о том, как выполнить обратный инжиниринг.Я уже показывал вам веб-сайт, на котором указаны значения, которые вам нужно найти, поэтому вопрос в том, как вы их ищете?

В этом примере я использую Блокнот, потому что у меня не установлен Minesweeper.Но идея та же самая.

alt text

Вы печатаете

s <options> <memory start> <memory end> <pattern>

Пресса"?- а потом "s", чтобы увидеть справку.

Как только вы найдете нужный шаблон памяти, вы можете нажать alt + 5, чтобы вызвать программу просмотра памяти для удобного отображения.

alt text

К WinDbg требуется некоторое привыкание, но он так же хорош, как и любой другой существующий отладчик.

Хорошим моментом для начала трассировки в отладчике было бы наведение курсора мыши вверх.Итак, найдите процедуру главного окна (я думаю, что такие инструменты, как spyxx, могут проверять свойства Windows, и адрес обработчика событий является одним из них).Взломайте его и найдите, где он обрабатывает события мыши - там будет переключатель, если вы сможете распознать его в ассемблере (посмотрите значение WM_XXX для мыши в windows.h).

Поставьте там точку останова и начинайте действовать.Где-то между моментом, когда вы отпустили кнопку мыши, и обновлением экрана victum получит доступ к структуре данных, которую вы ищете.

Будьте терпеливы, постарайтесь определить, что делается в данный момент времени, но не утруждайте себя слишком глубоким изучением кода, который, как вы подозреваете, неинтересен для вашей текущей цели.Чтобы исправить это, может потребоваться несколько запусков в отладчике.

Знание обычного рабочего процесса приложений win32 тоже помогает.

Мины, вероятно, будут храниться в каком-то двумерном массиве.Это означает, что это либо массив указателей, либо один массив логических значений в стиле C.

Всякий раз, когда форма получает событие наведения курсора мыши, делается ссылка на эту структуру данных.Индекс будет вычислен с использованием координаты мыши, вероятно, с использованием целочисленного деления.Это означает, что вам, вероятно, следует поискать cmp или аналогичная инструкция, где один из операндов вычисляется с использованием смещения и x, где x является результатом вычисления, включающего целочисленное деление.Тогда смещение будет указателем на начало структуры данных.

Вполне разумно предположить, что информация о минах размещена в памяти последовательно, по крайней мере, для строк (т. е.это 2D-массив, или массив из массивов).Таким образом, я бы попробовал открыть несколько соседних ячеек в одной строке, создавая дампы памяти процесса по ходу работы, а затем дифференцировать их и искать любые повторяющиеся изменения в одной и той же области памяти (т.Е.1 байт изменен на первом шаге, следующий байт изменен на точно такое же значение на следующем шаге и т.д.).

Также существует вероятность того, что это упакованный битовый массив (3 бита на шахту должно быть достаточно для записи всех возможных состояний - закрыто / открыто, шахта / без шахты, помечено / без флага), поэтому я бы тоже обратил на это внимание (шаблоны также были бы повторяемыми, хотя их было бы сложнее обнаружить).Но с этой структурой неудобно иметь дело, и я не думаю, что использование памяти было узким местом для Minesweeper, поэтому маловероятно, что подобные вещи будут использоваться.

Хотя это не совсем "инструмент обратного проектирования", а скорее игрушка, которую мог бы использовать даже такой идиот, как я, посмотрите Читерский Движок.Это несколько упрощает отслеживание того, какие части памяти были изменены, когда, и даже содержит положения для отслеживания измененных частей памяти с помощью указателей (хотя вам, вероятно, это не нужно).В комплект входит приятный интерактивный учебник.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top