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

Я пытаюсь узнать об обратном проектировании, используя Minesweeper в качестве примера приложения. Я нашел эту статью статью MSDN о простой команде WinDbg, которая показывает все мины, но она старая, не объясняется в деталях и на самом деле не является 't, что я ищу.

У меня дизассемблер IDA Pro и отладчик WinDbg и я загрузил winmine.exe в оба из них. Может ли кто-нибудь дать некоторые практические советы для любой из этих программ с точки зрения поиска местоположения структуры данных, которая представляет минные поля?

В WinDbg я могу установить точки останова, но мне трудно представить, в какой момент установить точку останова и в каком месте памяти. Точно так же, когда я просматриваю статический код в IDA Pro, я не уверен, где даже начать находить функцию или структуру данных, которая представляет поле мины.

Есть ли какие-либо обратные инженеры в Stackoverflow, которые могут указывать на меня в правильном направлении?

Ответ 1

Часть 1 из 3


Если вы серьезно относитесь к обратному проектированию - забудьте о тренерах и чит-двигателях.

Хороший обратный инженер должен сначала узнать ОС, основные функции API, общую структуру программы (что такое цикл запуска, структуры окон, процедуры обработки событий), формат файла (PE). Классика Петцольда "Программирование Windows" может помочь (www.amazon.com/exec/obidos/ISBN=157231995X), а также онлайн-MSDN.

Сначала вы должны подумать о том, где можно вызвать процедуру инициализации минного поля. Я подумал о следующем:

  • Когда вы запускаете игру
  • Когда вы нажимаете счастливое лицо
  • Когда вы нажмете "Game- > New" или нажмите F2
  • При изменении уровня сложности

Я решил проверить команду ускорителя F2.

Чтобы найти код обработки ускорителя, вы должны найти процедуру обработки сообщений окна (WndProc). Его можно проследить по вызовам CreateWindowEx и RegisterClass.

Считать:

Откройте окно IDA, Import, найдите "CreateWindow *", перейдите к нему и используйте команду "Перейти xref to operand (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 - mine.

Часть 2 из 3


Хорошо, продолжайте с кнопкой F2.

В соответствии с Использование ускорителей клавиатуры, когда нажата кнопка F2 Функция wndProc

... получает WM_COMMAND или WM_SYSCOMMAND сообщение. Слово низкого порядка Параметр wParam содержит идентификатор ускорителя.

Хорошо, мы уже нашли, где WM_COMMAND обрабатывается, но как определить соответствующее значение параметра wParam? Здесь Resource hacker входит в игру. Подайте его двоичным, и он показывает вам все. Как таблица ускорителей для меня.

alt text 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

Это приводит к фрагменту кода, который вызывает некоторый proc и выходит из 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'; в break '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 ячейки (хотя UI позволяет максимально использовать поле 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  ................................

Хмм, похоже, мне нужно другое сообщение, чтобы закрыть тему

Ответ 2

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

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

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

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

Ответ 3

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

http://www.codeproject.com/KB/trace/minememoryreader.aspx

Изменить

И эта статья, хотя и не о тральщице напрямую, дает вам пошаговое руководство по охоте через память с помощью WinDbg:

http://www.codingthewheel.com/archives/extracting-hidden-text-with-windbg

Изменить 2

Опять же, речь идет не о тральщице, но он определенно дал мне некоторую пищу для размышлений для моей отладки памяти, здесь есть множество учебников:

http://memoryhacking.com/forums/index.php

Также загрузите CheatEngine (упомянутый Nick D.) и пройдите через учебник, в котором он входит.

Ответ 4

"В WinDbg я могу установить контрольные точки, но мне трудно представить себе какой момент установить точку останова и на какое место памяти. Аналогичным образом, когда Я просматриваю статический код в IDA Pro, я не уверен, где даже начать находить функции или структуры данных, которые представляет собой месторождение мин."

Точно!

Ну, вы можете искать такие подпрограммы, как random(), которые будут вызываться во время построения таблицы шахт. Эта книга очень помогла мне, когда я экспериментировал с обратной инженерией.:)

В общем, хорошими местами для установки точек останова являются вызовы в ящики сообщений, вызовы для воспроизведения звука, таймеры и другие подпрограммы Win32 API.

Кстати, я сейчас просматриваю тральщик с OllyDbg.

Обновление: nemo напомнило мне отличный инструмент, Cheat Двигатель Эрика "Темный байт" Хейнен.

Cheat Engine (CE) - отличный инструмент для просмотра и изменения пространства памяти других процессов. Помимо этого базового объекта, CE имеет более специальные функции, такие как просмотр дизассемблированной памяти процесса и ввод кода в другие процессы. (реальная ценность этого проекта заключается в том, что вы можете загрузить исходный код -Delphi- и посмотреть, как эти механизмы были реализованы. Я сделал это много лет назад: o)

Ответ 5

Довольно хорошую статью по этой теме можно найти на Uninformed. Он охватывает реверсирование Minesweeper (как введение в обратную разработку приложений Win32) в довольно большой детализации и вокруг довольно большой ресурс.

Ответ 6

Этот сайт может быть более полезным:

http://www.subversity.net/reversing/hacking-minesweeper

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

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

В ответ на Bounty

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

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

alt text

Введите

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

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

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

alt text

WinDBG немного привыкает, но он так же хорош, как и любой другой отладчик.

Ответ 7

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

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

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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