Ответ 1
Часть 1 из 3
Если вы серьезно относитесь к обратному проектированию - забудьте о тренерах и чит-двигателях.
Хороший обратный инженер должен сначала узнать ОС, основные функции API, общую структуру программы (что такое цикл запуска, структуры окон, процедуры обработки событий), формат файла (PE). Классика Петцольда "Программирование Windows" может помочь (www.amazon.com/exec/obidos/ISBN=157231995X), а также онлайн-MSDN.
Сначала вы должны подумать о том, где можно вызвать процедуру инициализации минного поля. Я подумал о следующем:
- Когда вы запускаете игру
- Когда вы нажимаете счастливое лицо
- Когда вы нажмете "Game- > New" или нажмите F2
- При изменении уровня сложности
Я решил проверить команду ускорителя F2.
Чтобы найти код обработки ускорителя, вы должны найти процедуру обработки сообщений окна (WndProc). Его можно проследить по вызовам CreateWindowEx и RegisterClass.
Считать:
- CreateWindowEx http://msdn.microsoft.com/en-us/library/ms632680%28VS.85%29.aspx
- RegisterClass http://msdn.microsoft.com/en-us/library/ms633586%28VS.85%29.aspx
- Петцольд Глава 3 "Windows и сообщения"
Откройте окно 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
Это простой способ узнать значения идентификатора сообщения.
Чтобы понять обработку акселератора, выполните следующие действия:
- Использование ускорителей клавиатуры
- Хакер ресурсов (http://angusj.com/resourcehacker/)
Это довольно много текста для одного ответа. Если вам интересно, я могу написать еще пару сообщений. Длинное короткое минное поле, хранящееся в виде массива байтов [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 ................................
Хмм, похоже, мне нужно другое сообщение, чтобы закрыть тему