Программист, реверс-инженер
18,4
рейтинг
13 февраля 2009 в 00:15

Разработка → Расширение функциональности готовых программ

В мире ПО существует огромное количество программ, забытых своими разработчиками. Хорошо, когда уже есть хорошая альтернатива. А если ее нет? В программе может катастрофически не хватать каких-то мелочей, некоторые досадные ошибки могут годами доставлять массу неудобств пользователям, а на новых версиях ОС программа и вовсе может отказаться работать. Далеко не всегда имеются исходные коды, чтобы привести программу в порядок. Если программа простая — не составит труда за короткий срок создать альтернативу. Но если программа большая и сложная, что же делать в таком случае? Не всегда рационально тратить время и деньги на разработку полного аналога, ведь расширить в разумных рамках функциональность и исправить большинство ошибок можно уже в готовом исполняемом файле.
В этой статье будут продемонстрированы методики модификации исполняемых файлов на примере расширения функциональности легендарной игры Age of Empires II (стратегия реального времени).

Итак, что же мы имеем:
  • игра вышла в 1999 году и имеет статус abandonware — то есть она более не выставляется на продажу производителем и не приносит прибыли
  • последнее обновление выпущено в 2000 году, доработка не производится
  • игра является хорошим примером сложного ПО, полный аналог которого практически невозможно создать заново
  • имеются досадные ошибки, которые не были исправлены разработчиками
Пожалуй, можно попробовать что-то изменить, не глядя на запрет в лицензионном соглашении. Вы так не думаете? :)

Отказ от ответственности


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

Сведения о «пациенте»


Исследуемая игра написана на движке Genie, разработкой которого с 1997 до 2000 года занималась компания Ensemble Studios. За это время на данном движке было выпущено 4 игры из серии Age of Empires. Далее Genie был лицензирован компании LucasArts, которая в 2001-2002 годах выпустила еще 2 игры на этом движке, но уже из серии Star Wars. К этому времени движок уже сильно устарел, поскольку работал в режиме 256 цветов, что очень скромно по сравнению с играми даже 2000 года. Именно поэтому доработка движка была остановлена, новых игр на его основе не выпускалось.
Игровой движок Genie загружает всю игровую графику, музыку, а главное — списки юнитов и их характеристики — из внешних файлов. То есть все игры на базе этого движка по большей части имеют очень похожие исполняемые файлы, и практически все модификации для одной игры без особых проблем портируются на другие.

Чего мы хотим добиться?


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

2. Добавить поддержку оконного режима
Age of Empires поддерживает 3 фиксированных разрешения: 800×600, 1024×768 и 1280×1024. С такими разрешениями картинка на широкоформатных мониторах выглядит растянутой, что доставляет дискомфорт. Добавить поддержку новых разрешений в игру можно, но так как в игре для каждого разрешения используются своя графика интерфейса, оставим это на потом, и ограничимся пока что добавлением оконного режима работы в игру.

3. Добавить поддержку конфигурационных файлов
Для включения каких-то системных игровых опций, их приходится передавать через командную строку при каждом запуске программы. Можно поместить все параметры в ярлык, но после перемещения игры в другой каталог ярлык перестанет работать. Выход из ситуации — добавление поддержки конфигурационных файлов.

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

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

Что нам для этого понадобится?


IDA Pro — интерактивный дизассемблер и отладчик, широко используется для реверс-инжиниринга. Умеет строить понятные даже новичкам блок-схемы. Вся его сила проявляется в интерактивном взаимодействии с пользователем. После автоматического анализа пользователь может давать функциям и переменным осмысленные имена, комментировать код и т.д. Достаточно небольших познаниях в области ассемблера для того, чтобы начать заниматься исследованием программ прямо сейчас!

Flat Assembler — свободно распространяемый многопроходной ассемблер. FASM обладает небольшими размерами и очень высокой скоростью компиляции, имеет богатый и ёмкий макро-синтаксис, позволяющий автоматизировать множество рутинных задач. Одна из полезных возможностей — генерация чистого машинного кода без заголовков и т.д. Все это пригодится нам для генерации ассемблерных вставок.

Hexplorer — бесплатный HEX-редактор. Имеет простой дизассемблер x86, что позволяет удобнее ориентироваться внутри исполняемого файла. Используется непосредственно для ручной модификации двоичного файла без изменения его размера.

Итак, начнем.

Отключение проверки наличия CD


Найти код, который отвечает за проверку наличия CD, нам поможет IDA. Это оказалось очень просто сделать. Достаточно проследить вызовы функций GetDriveTypeA и GetVolumeInformationA, которые используются для получения информации о приводе, как мы обнаружим функцию проверки наличия CD по адресу 4485A0h (базовый адрес 400000h, то есть физически в файле машинный код находится по адресу 485A0h), которая при удачной проверке возвращает в eax единицу.
CheckCD         proc near
    sub     esp, 214h
    push    ebx
    push    esi
    ; ...
    ; множество проверок
    ; ...
    test    eax, eax
    jz cd_check_fail
cd_check_ok:
    pop     esi
    mov     al, 1
    pop     ebx
    add     esp, 214h
    retn    4
cd_check_fail:
    pop     esi
    pop     ebx
    add     esp, 214h
    retn    4
CheckCD         endp
При этом стоит заметить, что эта функция запрашивает значение CDPath из реестра, где хранится буква диска, с которого была установлена игра. То есть игра привязывается конкретно к той букве диска, с которого она была установлена, и при наличии оригинального диска в другом приводе игра все равно не запустится. Наиболее простое решение в данном случае — это заменить команду jz cd_check_fail, которая занимает 2 байта, на 2 операции nop, чтобы после проверки диска в eax всегда возвращалась единица. Однако, функция устроена таким образом, что при отсутсвии значения CDPath в реестре, функция сразу возвращает 0, что мешает переносимости программы. Поэтому всю функцию мы заменим на 3 простые команды:
use32
    xor	eax, eax
    inc	eax
    retn	4
Для получения машинных кодов этих команд нам пригодится FASM.
fasm src.asm dst.bin
Основной плюс этого ассемблера для нас сейчас — это то, что он позволяет генерировать чистый машинный код без заголовков. Получаем (по строчке на команду):
31 C0
40
C2 04 00
То есть нам нужно поместить эти 6 байт в начало функции определения наличия CD, а остальные команды заменить на nop (код 90h).
Исходный машинный код Полученный машинный код
8B 44 24 04 81 EC 14 02
00 00 85 C0 53 56 8B D9
...
33 С0 40 С2 04 00 90 90
90 90 90 90 90 90 90 90
...
В обычном HEX редакторе заменяем начиная с смещения 485A0h указанные выше машинные коды, после чего игра больше никогда не требует для запуска CD, даже если в реестре нет необходимого ключа. При этом мы освободили 288 байт для дополнительного машинного кода, что пригодится нам в дальнейшем.

Исправление ошибки


При подключении к сетевой игре по IP игра выводит список IP и названий игр, к которым игрок подключался ранее. Однако, по каким-то причинам IP адрес часто сохранялся не полностью, обрезалось несколько его последних символов. Необходимо разобраться в чем дело и исправить ошибку.
Займемся поиском кода, отвечающего за сохранение IP адресов последних игр в реестре. Нам известно, что игра сохраняет список последних IP игр в ключах с именами вида RecentGameName%d и RecentGameAddr%d. При помощи IDA находим по 3 ссылки на эти строки. Определить где нужный код очень просто — в коде со смещением 0512116h происходит запись этих ключей, в остальных случаях — считывание. Не будем приводить найденный участок машинного кода — там около 50 инструкций, общий смысл которых можно представить в виде маленького фрагмента кода на C.
for(int i = 0; i < count; i++)
{
	char* keyname;
	sprintf(keyname, "RecentGameName%d", i);
	RegSetVal(1, keyname, gamename[i], strlen(gamename[i]));
	sprintf(keyname, "RecentGameAddr%d", i);
	RegSetVal(1, keyname, gameaddr[i], strlen(gamename[i]));
}
Для установки значения в реестре игрой используется собственная функция-обертка RegSetVal(int, char* ValueName, char* Data, int DataSize) — название функции и параметров конечно же придуманы, в машинном коде их нет. Как видно, игра сохраняет в реестре ровно столько символов IP адреса, сколько их в названии сетевой игры. Судя по всему, программист скопировал 2 строчки сохранения названия игры для сохранения адреса, но при этом забыл исправить название массива в вызове strlen.
Для исправления ошибки у нас есть 2 варианта: подставить в strlen правильную строку или вместо strlen помещать константу 16 (максимальная длина строки адреса, например «255.255.255.255»).
Как же выглядит вызов strlen(gamename[i]) в машинном коде?
call    _sprintf ; +0x1022CF
mov     edi, ebp
or      ecx, 0FFFFFFFFh
xor     eax, eax
add     esp, 0Ch
repne scasb
not     ecx
push    ecx
Компилятор оптимизировал код и заменил вызов функции strlen() вычислением длины на месте. В предыдущем вызове strlen() использовалась та же строка, в вот опять оптимизация — указатель помещается в ebp один раз при первом вызове. То есть у нас нет драгоценных пары байт для того, чтобы поместить правильный указатель в ebp. Можно, конечно, сделать jmp за пределы функции, потом обратно — но это не самый красивый метод. Поэтому остановимся пока на самом простом варианте исправления ошибки — будем всегда сохранять 16 байт адреса. Для этого заменим приведенный выше машинный код на следующий:
Ассемблерный код Машинный код
call    _sprintf ; +0x1022CF
add     esp, 0Ch
mov     ecx, 0Fh
E8 CF 22 10 00
83 С4 0С
B9 0F 00 00 00

Поддержка файла конфигурации


Игра поддерживает множество полезных параметров командной строки, которые было бы удобно сохранить где-нибудь в файле, чтобы не передавать их каждый раз при запуске. Лучший способ реализовать подобное — это заставить игру при каждом старте загружать внешнюю библиотеку и выполнять функцию инициализации. При такой организации можно добавить множество полезных вещей в конфигурационные файлы, такие как: загрузка дополнительных библиотек (модулей) без необходимости модификации исполняемого файла, перехват функций работы с реестром для организации хранения всех игровых данных в конфигурационном файле игры, а не в реестре. Не лишним будет поддержка множества профилей с различными наборами настроек с возможностью быстрого их переключения. Итак, приступим.
Наиболее удобным местом подключения внешней библиотеки оказалась функция загрузки библиотеки ebueulax.dll, отвечающей за отображение лицензионного соглашения. Она как раз вызывается практически сразу после начала работы WinMain, однако помимо загрузки библиотеки ebueulax.dll и выполнения функции EBUEula она делает много лишних действий, поэтому мы полностью перепишем ее, чтобы она загружала библиотеку config.dll и выполняла библиотечную функцию LoadConfig с указателем на расположение командной строки в памяти (для её изменения) в качестве параметра.
Ассемблерный код Машинный код
LoadConfigLib   proc near
    sub     esp, 208h
    push    esi
    push    edi
    push    ebx
    push    ecx
    push    edx
    mov     esi, ds:LoadLibraryA
    push    67B8C4h; lpLibFileName
    call    esi ; LoadLibraryA
    mov     ebx, eax
    test    ebx, ebx
    jz      short loc_587443
    push    offset aLoadconfig
    push    ebx    ; hModule
    call    ds:GetProcAddress
    mov     edi, eax
    test    edi, edi
    jz      short loc_58743C
    mov     eax, [esp+220h];**args
    push    eax
    call    edi
    jmp     short loc_587443
loc_58743C:
    push    ebx  ; hLibModule
    call    ds:FreeLibrary
loc_587443:
    pop     edx
    pop     ecx
    pop     ebx
    pop     edi
    pop     esi
    add     esp, 208h
    retn
LoadConfigLib   endp
 
81 EC 08 02 00 00
56
57
53
51
52
8B 35 E0 51 63 00
68 C4 B8 67 00
FF D6
8B D8
85 DB
74 25
68 B8 B8 67 00
53
FF 15 C8 50 63 00
8B F8
85 FF
74 0C
8B 84 24 20 02 00 00
50
FF D7
EB 07

53
FF 15 20 51 63 00

5A
59
5B
5F
5E
81 C4 08 02 00 00
C3
Приведенный код делает несколько вызовов библиотечных функций. Их адреса были подставлены вручную в машинный код. В следующей статье (если вы не будете против :) ) я постараюсь рассказать как при помощи FASM можно генерировать код, полностью готовый к вставке в исполняемый файл.
Заменяем исходную функцию (начинается со смещения 187400h) новой при помощи обычного HEX-редактора. Поскольку новая функция значительно короче исходной, не забываем заменить оставшиеся байты кодом операции nop — 90h. Мы получили еще 192 байта свободных байта для дополнительного машинного кода. Это место можно будет использовать в дальнейшем.
Исходный машинный код Полученный машинный код
81 EC 08 02 00 00 53 56 
8B 35 E0 51 63 00 57 68
CC B8 67 00 FF D6 8B D8 
85 DB 75 0A 5F 5E 5B 81
C4 08 02 00 00 C3 68 C4 
B8 67 00 53 FF 15 C8 50
63 00 8B F8 85 FF 75 13 
53 FF 15 20 51 63 00 5F
5E 33 C0 5B 81 C4 08 02 
00 00 C3 8B 84 24 18 02
00 00 50 FF D6 8B F0 85
...
81 EC 08 02 00 00 56 57
53 51 52 8B 35 E0 51 63
00 68 C4 B8 67 00 FF D6 
8B D8 85 DB 74 25 68 B8
B8 67 00 53 FF 15 C8 50 
63 00 8B F8 85 FF 74 0C
8B 84 24 20 02 00 00 50 
FF D7 EB 07 53 FF 15 20
51 63 00 5A 59 5B 5F 5E 
81 C4 08 02 00 00 C3 90
90 90 90 90 90 90 90 90 
...
Всю остальную работу берет на себя модуль config.dll. Его можно написать на C/C++/Delphi. Его задача проста — принимать от исполняемого файла указатель на командную строку приложения и в зависимости от настроек в конфигурационном файле изменять ее. Как бонус — нам пригодится возможность подгружать дополнительные модули, настраивая это в конфигурационном файле. Для этого нам нужно просто вызывать WinAPI функцию LoadLibrary именем файла модуля, которое необходимо загрузить в адресное пространство игры.

Поддержка оконного режима


Поддержка оконного режима организована в виде отдельного модуля wndmode.dll, загрузкой которого занимается config.dll. Этот модуль занимается тем, что перехватывает все вызовы DirectDraw, изменяет параметры таким образом, чтобы программа работала в окне, и только после этого передаёт управление оригинальным функциям DirectDraw.

Это реализуется путем изменения перехватываемой функции. Первые несколько байт перехватываемой функции заменяются на команду безусловного перехода к функции перехвата. Этот трюк достаточно просто реализуется в WinNT (поскольку в WinNT для каждого процесса создается своя копия образов системных библиотек), но практически нереализуем в Win9X (так как в Win9X если и можно внести изменения в образ системной библиотеки, то только в адресных пространствах всех процессов сразу).

Сам по себе модуль wndmode.dll является сильно модифицированной версией библиотеки d3dhook.dll, где реализовано:
  • Полная независимость от программы D3D Windower
  • Настройки загружаются из секции [WINDOWMODE] файла wndmode.ini
  • Настройки по умолчанию заменены для совместимости с Genie
  • Добавлен параметр Border, который включает/выключает рамку вокруг окна
  • Если игровое разрешение равно системному, автоматически убирается рамка
Теперь эта библиотека готова внедриться практически в любую DirectDraw игру для того, чтобы сделать ее оконной. Так что если кто-то будет заниматься модификацией других игр — это пригодится.

Что получилось?


Работа по модификации проделана огромная, здесь мы рассмотрели лишь некоторые изменения, поскольку описание даже небольших изменений требует огромных усилий. Остальные модификации при желании вы сможете исследовать в IDA, скачав готовый модифицированный файл.
В целом удалось добиться таких результатов:
  • Вместо ebueulax.dll (отображение лицензии) загружается config.dll (поддержка конфигурационных файлов)
  • Оконный режим работы (модуль wndmode.dll — модифицированный d3dhook.dll)
  • Код функций работы с курсором адаптирован для работы в оконном режиме (решает много неприятных проблем, вызванных тем, что игра не рассчитана на работу в окне)
  • Игра корректно работает без ее предварительной установки (достаточно скопировать файлы игры), для игры не нужен CD
  • Исправлена ошибка оригинальной игры, когда при игре по IP в списке последних игр обрезались IP адреса
  • Изменен порядок и расположение кнопок в меню «Один игрок» и «Редактор», исправлена ошибка с выделением кнопок в меню «Один игрок» (переписан внушительный участок кода)
  • Исполняемый файл может запускаться из любого подкаталога, а не только из age2_x1 или корня (практически полностью переписано начало процедуры WinMain)
  • Нет проверки наличия файла empires2.exe (его можно удалить)
  • При включенном параметре MIDIMUSIC после сворачивания мелодия начинается заново (не сбрасываются инструменты)
Все изменения работают стабильно, никаких сбоев не обнаружено. В оконном режиме осталась пока что нерешенной проблема отображения системного курсора одновременно с игровым после того, как он покинет область игрового окна и вернется назад. Однако, это вызвано лишь только тем, что игровой движок не рассчитан на запуск в окне и не предусматривает вариант, когда курсор покинет игровое окно. В ближайшей версии модификации это будет исправлено.
Логическим завершением развития данной модификации может стать внедрение в игру поддержки игровых комнат с созданием соответсвующего игрового сервера, поскольку официальные игровые комнаты Age of Empires на Zone были закрыты ещё несколько лет назад. Всё это вполне возможно реализовать, не имея при этом на руках никаких исходных кодов.

Заключение


Если вам интересно попробовать в действии то, что у меня получилось, можете скачать Age of Empires II: The Conquerors (Lite Edition) (всего 94МБ) с моего сайта.
Простите, что здесь написано обо всем и сразу, и не сильно подробно. Я старался описать общую схему. В следующих статьях можно рассматривать каждый этап модификации в отдельности, давать какие-то советы и т.д.
Евгений Врублевский @VEG
карма
351,0
рейтинг 18,4
Программист, реверс-инженер
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (120)

  • +18
    Круто, правда. Спасибо за статью.
    • +3
      Не за что :) Я буду рад, если найду людей, кому интересно копаться внутри программ. Особенно — в Age of Empires! (это отдельный разговор почему).
      • 0
        Боюсь, мне это интересно только с теоретической точки зрения, не более. Да и в AoE не играл; хотя, люблю globulation2, wc3tft, а из старых стратегий — Saga (Rage of the Vikings).
  • +1
    Age of Empires II совершенно спокойно работает просто переписавшись на другой компьютер. Я тоже в это не верил, но друг это продемонстрировал. ( да и сам это делал сутки назад )
    • 0
      Простите, я не указал конкретно о какой версии идет речь. Здесь я говорю о последней версии Age of Empires II: The Conquerors 1.0C. Она требует обязательного наличия в реестре ключа CDPath, который создается при установке игры.
      • +1
        Вот именно в него моя жена в данный момент и играет. переписал как раз на ноут. У нас что-то вроде клуба любителей Age of Empires, собираемся и играем по сети. Ностальгия…
        Хотя я, олень, не сказал, что игра пиратская и скорей всего уже с проделанными выше операциями. Прошу прощения.
        • +1
          В любом случае там нет оконного режима, конфигов и т.д. :)
          • +2
            Не могу с этим не согласиться. Спасибо. А вот за "… Логическим завершением развития данной модификации может стать внедрение в игру поддержки игровых комнат с созданием соответсвующего игрового сервера..." я проголосую обоими руками, ногами и волосами.
            • +9
              обоими волосами?(:
  • +4
    это какое-то волшебство…
  • 0
    > xor eax, eax
    > inc eax

    а не проще так?
    >mov eax, 1

    а в целом — спасибо, понравилось)
    • +12
      это 3 байта а mov eax, 1 пять байтов
      • 0
        мм… тогда понятно. спасибо. учту)
      • –16
        В век питона и Ruby по прежнему есть кодеры экономящие байты %)
        P.S. Хотя учитывая тематику этого блога… :)
        • +1
          Найдите ка аналогичную статью на Руби или Питоне ..))
        • +3
          В данной ситуации экономия не причем… здесь требуется сохранить количество байт, что бы адресацию в программе не сбить.
          • +1
            при чём тут это? мы просто экономим место. а неиспользованыt байты забиты nop'ами (90h)
            Автор пишет:
            >При этом мы освободили 288 байт для дополнительного машинного кода, что пригодится нам в дальнейшем.
          • +2
            Верно, но освободившееся место я использовал для реализации специальных функций для работы с курсором мыши с учетом оконного режима (в статье я не привел, потому что кода много). И к сожалению, отведенного места чуть-чуть не хватило на полноценную реализацию замены SetCursorPos, а разрывать на куски одинаковые по смыслу функции не хотелось :). Впрочем, это отразилось только на одном вызове этой функции в ветке кода игры, которая никогда не вызывается. Вообще я в коде игры пока разбирался обнаружил очень много принудительно отключенных веток кода и не до конца реализованных вещей, которые никак нельзя запустить из игры, но можно из отладчика.
            • 0
              а что за ветки?
              • 0
                Ветки кода :)
                Я их так называю.
                Ну там например игра может играть MP3 во время геймплея. Однако, эта функция не дописана — композиция играет один раз и не «зацикливается».…
          • 0
            Экономия как раз и причем, если не экономить, то требуемая реализация может не уместиться в освободившейся области. А адресация никуда не денется, в крайнем случае всегда можно сделать jmp на другую область там закончить и вернуться обратно.
        • 0
          Полагаю что вы себя относите именно к питону и руби %) Верно говорят что асм и все остальное это два разных мира. И проблемы одних просто не понятны другим.
        • 0
          что там байты, я как-то с 3 битами мучался :)
          • 0
            Хм. Вроде бы минимальный адресуемый объем — 1 байт. А работа с отдельными битами требует большего объема кода. Нет?
            • 0
              Наверное, я не совсем точно выразился. Мне было достаточно только 3 бит из байта, чтобы сделать нужную мне вещь (хранить статусы 3 событий в игре), но читал байты, да. Вот с реализацией возникли проблемы, из-за которых мне и пришлось выучить азы ассемблера и освоить кнопочку «attach» в ollydbg — кроме меня всем было лень решать важную для меня тогда проблему, пришлось самому.
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          А на старшие биты пофик?
          • 0
            Да, вариант не самый надежный.
            С другой стороны, скорее всего, результат функции, возвращающей 1 при успехе, сравнивается с нулем, а в этом случае старшие биты не помешают.
          • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
    • +2
      Несколько энтузиастов уже пыталось разработать OpenGenie, однако, пока что ничего не вышло. Мне же одному проще (и интереснее) модифицировать готовый исполняемый файл для достижения необходимого эффекта.
  • 0
    До такого я ещё не доходил. Самые крутые «дрова», которые я «наломал» — это был проигрыватель мультимедиа QvPro для DOS. Каким-то макаром закрыл там все нагскрины (для более старых версий и кодогенератор написал, но в последних его, по-видимому, написать было невозможно, т.к. перешли на онлайн-регистрацию).

    Ещё раз спасибо за то, что заставили меня тряхнуть стариной.
    • 0
      Раньше было все намного сложнее. Современные инструменты (я их перечислил в статье) значительно все упрощают. Так что при знании ассемблера достаточно запастись терпением — и много что можно будет сделать.
      • 0
        Но ломал-то я всё равно идой. Хоть и более старой версии.
      • 0
        P.S. Остальное — по мелочи.

        — адаптировал Prince of Persia 2 под AC'97 (зарезал странную ветвь в ISR'е звукового драйвера, зависы кончились).
        — хакнул Warcraft II патч 1.50 (правда, его я домал не идой, а Qview).
    • +1
      Да… hiew, tasm… ностальгия. Всплакнул %)
  • 0
    Фраза «автор не несёт никакой ответственности», к сожалению, не оказывает магического влияния на действующее законодетельство. А написано здорово :)
    • +2
      К сожалению, это так.
      На американском сайте heavengames.com когда я опубликовал эту модификацию фанаты сперва обрадовались обновлениям. Потом кто-то восторженно спросил, как же я это сделал, на что я (сглупил) честно ответил, что дизассемблировал, а затем внес правки в сам исполняемый файл. На что мне ответили, что это незаконно, забанили навсегда, и попросили больше этим не заниматься. Такое впечатление что сразу было не ясно, каким образом можно сделать такую модификацию :) Если бы сам не сказал — уверен, до сих пор мог бы свободно выкладывать обновления. Довели дело до абсурда…
      Надеюсь, здесь никто не будет беспокоиться о том, что мы занимаемся дизассемблированием игрушки восьмилетней давности :)
      • НЛО прилетело и опубликовало эту надпись здесь
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Да, но если ты произвёл действия, противоречащие ИХ законодательству у НАС, публично проинформировал об этом (в т.ч. на ИХ языке), а потом, хорошенько не подумав, прилетел к НИМ, скажем, на семинар или в турпоездку, велик шанс попадания не на семинар, а в совсем другое место.
      • 0
        Чтобы не нарушать законодательство можно написать loader который на лету все патчит в памяти… =)
    • +2
      если правильно помню, то в рамках действующего(РФ) как раз можно менять под себя, главное что б в пределах государства.
      • +1
        Если так, то замечательно — я, как обладатель лицензионной копии — могу спать спокойно :)
        • 0
          исправлять то вроде модно, а вот распрстранять…
          • +1
            блин, 2 ночи, пальцы заплетаются… пора спать
        • 0
      • 0
        нет.Это разрешается только для того, чтобы программа заработала. Если она и так работает — тады ой.
        • 0
          Не совсем так. тем более, что понятие «работает» довольно растяжимое. В данном случае, автор может смело сказать что имеющеся баги не позволяют ему считать программу работающей.

          И вообще, если уж совсем подходить с позиций занудства, то можно сказать что автор платил за качественный софт, а ему подсунули баги %) Соответственно можно подать в суд, моральный ущерб и т д. :)
    • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Вы просто волшебник. Здорово.
  • 0
    Функционал и функциональность — абсолютно различные вещи.
    • +1
      Спасибо, исправил.
    • +2
      Функционал помимо своего первоначального смысла еще используется в качестве короткого аналога слову «функциональность» в айтишном сленге. Та к что это не безграмотность, а просто сленг.
      • 0
        Я не говорил о «безграмотности».
        Это все хорошо, пока «сленг» не начал встречаться не только в статьях официальных оффлайн-изданий, но и white papers крупнейших софтверных и консалтинговых компаний. Функционал добавляют, разрабатывают, внедряют, расширяют, закладывают. И пишут это сотрудники пиар-отделов, а не айтишники. Не потому, что так короче, а потому что от слова отдает бизнес-новаторством, можно применить к любой стандартной разработке, и звучит ведь, и продается.
  • +2
    Всегда біло интересно — как делают NoCD к играм… Спасибо за статью!
    • +1
      Сори за «біло» — правильно — бЫло — но, в час ночи и не такое написать можно…
  • 0
    Спасибо. Очень доступно про то как сделано. И за саму игру спасибо. В своё время руки не дошли, а сейчас самое то будет на флешку записать и время от времени поигрывать.

    Только один вопрос — у меня все тексты знаками вопросов — видимо в системе какойто фонт не русский, который игра использует. Можно самой игре этот файл подсунуть, чтобы он был уже в игре?
    • 0
      У вас все надписи квадратиками или только на кнопках? И какая локаль стоит в винде? Age of Empires II — это ANSI приложение, для его нужно чтобы в системе стоял русский язык для программ по умолчанию.
      • 0
        Все знаками вопросов. Попробую переключить, машина не моя, я только вечерами там сижу и есть время. Просто подумал, что может если фонт будет лежать прямо в папке игры, она его подхватит до того, как полезет в системные. Или где в конфигах прописано и можно поменять.
        • 0
          Вероятнее всего стоит стандартная системная кодировка — не кириллица. Если так, то загрузка даже нужных скриптов не поможет. Здесь можно попробовать подсунуть игре английскую версию библиотек language*.dll. Тогда все будет по-английски :)
          • 0
            Работает. Поменял на рус. все нормально.
  • +1
    Впечатлило, вот такие статьи и ждешь от Хабра))

    p.s. Отключение проверки CD — хорошая идея. Например, в игре Driver Parallel Lines проверка CD (надо время на раскрутку привода + если диска нет в приводе, владелец диска должен тратить время на поиск и вставку диска) занимает больше времени, чем сам запуск игры! Возмутительно! Поэтому я всегда за отключение этих дурацких проверок.
  • +1
    когда я интересовался этими вопросами, моим любимым сайтом был wasm.ru/
    там много статей на аналогичную или похожую тему, а так куча инструментов и целый форум ассемблерных гиков
  • 0
    Вау, это просто легендарно. Может можно попросить вас покопаца в старкрафте дабы разрешить ему использовать нестандартные разрешения екрана?

    как ето было бы круто поиграть в него полноценно хотя бы на ноуте не говоря уже про мониторы скажем 22 и больше дюймов
    • 0
      Поскольку Starcraft очень похож на Age of Empires в техническом плане, сомневаюсь что есть возможность добавить поддержку новых разрешений экрана без перерисовки графики. Хотя добавить оконный режим вполне реально, при этом можно использовать библиотеку wndmode.dll — что-то мне подсказывает, что она справится.
      Осталось только сделать LoadLibrary(«wndmode.dll»); в WinMain вашей игры :)
    • 0
      Вот недавно появилась mod для старкравта позволяющий поставить любое разрешение:
      www.starcraftresolutionhack.de.vu/
      www.campaigncreations.org/forum/index.php?topic=1345.0
      Но он пока еще в бета версии, сам не проверял, смотрел только видео. Народ говорит что реплеи смотреть удобнее :)
      • 0
        Очень интересно. Может быть движок Starcraft более гибкий в этом плане?..
        В Age of Empires мало того, что для каждого игрового разрешения своя графика, так еще и в коде есть огромное количество switch-ей в зависимости от текущего разрешения, где определяется расположение вывода всех элементов интерфейса и т.д. И чтобы добавить новые разрешения все это нужно исправлять.
        Однако, ребята молодцы, респект им за это в любом случае :)
        • 0
          Может конечно и гибкий, но тут мне кажется больше сыграла популярность старкрафта.
          Думаю на данный момент старкрафт на порядок популярнее Age of Empires.
      • 0
        спасиб большое, щаз заценим
  • +2
    Эхх :). Вспомнил былое время :). Когда программку можно было вылечить правкой одного байта, заменой флага условного перехода :). Моим любимым занятием тогда была трассировка в ollydbg (напоминанием тому служит затертая клавиша F8 на клавиатуре :)). Отлов мессаджбоксов, breakpoint'ы… Теперь, к сожалению, уже нет свободного времени на это. Многое подзабылось :'(
    • 0
      У меня ф7 и ф8 были затёрты =) Либил я это дело годика 3-4 назад.
      Причём сам дошёл до мысли что ломать программы можно с помощью отладчика. Сначала пытался приспособить под это дело отладчик из delphi, но потом почитал статьи в инете и нашёл OllyDbg
  • 0
    Ух ты… Круто!!! Спасибо большое за статью, это очень здорово что такие тексты появляются тут на хабре.
  • 0
    Отличная статья. Жаль, что на многих старых играх стоит StarForce (чаще 3ий версии)… и первый пункт статьи занимал бы тогда раз в 20 больше места :)
  • +1
    дни cracklab.ru на хабре
  • +1
    Где же вы раньше ходили, TTD с нуля переписывать пришлось.
  • 0
    Отлично!!! Просто в 10-ку!
    Большое спасибо за статью, главное не забрасывайте эту тему! Очень интересно что и как можно сотворить без наличия исходников, да и побольше статей про реверс инженеринг и асм.
    Буду ждать следующие статьи.
  • 0
    А как одновременно пользоваться отладчиком и игрой в fullscreen? Постоянное переключение было бы очень утомительно…

    Кто бы ещё поправил такую фичу в CS 1.6, что после смерти выбранное ранее «spectator view mode» не запоминается :-)
    • +2
      Для этого нужно отладчиком найти где программа ставит для себя эксклюзивный доступ к видеобуферу и отключить эту «фичу». Это всегда происходит гарантированно до перехода игры в полноэкранный режим. Поскольку Age of Empires работает на DirectDraw, я нашел вызов:
      DrawDev->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

      И заменил его на:
      DrawDev->SetCooperativeLevel(hWnd, DDSCL_NORMAL);

      После чего игра хоть и с противными графическими артефактами (вся цветовая палитра нарушилась) потеряла эксклюзивный доступ к видеобуферу, и появилась возможность открывать программы поверх этого приложения (отладчик). Думаю, в случае с Direct3D будет очень похоже.
      В случае же с Age of Empires я постарался как можно быстрее «прикрутить» оконный режим. Так что теперь можно отлаживать игру вообще без проблем с графикой и т.д.
    • 0
      В контре могут быть проблемы с античитерскими фичами разными.
  • +3
    Хорошая статья :)
    Я тоже примерно тем же занимаюсь, только для Neverwinter Nights. :) Например, добавили поддержку MySQL/PostgreSQL/SQLite для хранения данных и объектов, поддержку Ruby как языка игровых скриптов и т.д. :)
    www.nwnx.org/
  • +3
    Для получения машинных кодов не обязательно писать сначала src.asm а потом компилить FASMом и смотреть байты. Достаточно в Hiew писать сразу на asm.
  • 0
    А каков процесс прослеживания вызовы функций?

    Это сразу видно в отладчике, где какая или …?
    • 0
      Вызовы функций из системных библиотек и функции из стандартных заголовочных файлов отображаются в IDA с нормальными именами.
  • 0
    Хотелось бы почаще видеть посты подобной тематики (ассемблер/дизассемблирование). :)
  • +1
    Сурово, есть еще кодеры!

    А может, вместо патчинга ebueulax.dll было проще добавить в импорты свою собственную DLL? Она бы подгружалась при запуске приложения.
    • 0
      Дело в том, что я из игры передаю параметры в config.dll, поэтому простым добавлением в импорты не обойдешься. Более того, для некоторых вещей может понадобиться возможность управлять программой из библиотеки — и здесь обычным вызовом DllMain при LoadLibrary не обойдешься, необходимо передавать/принимать какие-то данные в/из игры.
      Хотя это хорошая идея для подключения библиотеки wndmode.dll — чтобы наименьшей кровью сделать какое-нибудь DirectDraw приложение оконным. Спасибо за идею.
      • 0
        Не за что :-)
        С перехватом есть еще одна мысль: если вызов DirectX идет через call, и по call управление передается на jmp API (бывает такое иногда), можно просто расширить последнюю секцию, добавить в нее код, который будет корректировать параметры и делать jmp API
  • 0
    Спасибо, замечательная статья. Сам сейчас потихоньку пилю одну игрушку (тоже из 2000-го года), но т.к. ассемблерное мышление развито слабо, продвигаюсь очень медленно.
    • +1
      Главное побольше энтузиазма и терпения — и все получится! У меня тоже не сразу все получалось, над некоторыми мелочами приходилось сидеть чуть ли не сутки и т.д.
  • 0
    Спасибо за статью!
    Было интересно почитать.

    Одно время сам занимелся реверсом, для внедрения одной фишки в Starcraft, правда мои познания в области Ассемблера не такие как у Вас, но с задачей справился, правда и задача была куда проще )
    • 0
      Если не секрет, расскажите что за модификацию вы делали?
      • 0
        В движке Starcraft'a для вывода текста разным цветом, используются специальные HEX коды.

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

        В итоге разобрался с DMA (Dynamic Memory Allocation), нашел необходимые адреса, и на Delphi написал программу, которая по заданному смещению выводила текущий ник и позволяла его модифицировать (ReadProcessmemory, WriteProcessMemory).

        Дальше начал изучать программу на предмет изменения разрешения, но в тот момент не обладал необходимыми знаниями для столь серьезных изменений. Потом был занят другими задачами и к этому вопросу не возвращался.
  • 0
    Вот команда которая занимается исправление старых игр
    imasters.org.ru/

    Вот ещё обсужденее подобных проектов
    www.dtf.ru/forum/flat.php?id=20236&page=1&page_size=20
    • 0
      А вот кстати и модификация, подобная вашей
      imasters.org.ru/viewtopic.php?id=56
      • +5
        Если бы вы были внимательны, то это и есть моя модификация :)
      • +3
        *то заметили бы, что это и есть моя модификация :)
  • 0
    лучше бы топик был о нормальном программировании на ассемблере.
    по реверс инженерингу статей и книг куча.
    еще очень часто в лицезии запрещается дизассемблировать программу.
    • +2
      А про программирование на Ассемблере книг мало… :-)
      • 0
        Почему мало?
        Пирогов, Зубков, Магда, Юров, Абашев, Iczelion, Абель — далеко не полный список.
        Многие авторы выпускают также книги по реверс инжинеринг — Пирогов, Касперски.
        А если учесть забугорных авторов — можно долго перечислять…
        • 0
          Это был сарказм…
          • 0
            Пусть у нас есть разработчик с программой распространяемой по GPL лицезии (или совместимой).
            Вдруг какой-либо другой разработчик использует код в целях получения коммерческой выгоды и не сообщает создателю.
            Это хорошо?
            Нет, это наказуемо и можно судится — даже народ поддержит.
            Тогда почему нарушение лицензии («запрещается дизассемблировать программу или исследовать» итп) относительно машинного кода — это хорошо?
            Ведь топик именно о том, как нарушить лицензию?
  • 0
    Это, думаю, многим напомнило детство в квадрате — одна из первых игр и дизассемблирование — всякие crackme-программки обучающие… Дальше дело не зашло :)
    Спасибо за Творение!
  • 0
    Реально напомнила тема институтские годы.

    Вопрос же будет в другом. Скачал архив, установил, запустил — для начала игры требуется вставить диск в дисковод. XP Pro, SP2. Что я делаю не так?
    • 0
      На каком этапе запуска программы потребовало диск?
      Функция отвязки от диска проверена не один раз, все должно работать. Вы не могли вы выложить скриншот с этим сообщением?
      • 0
        Прошу пардону — диск требовался только для кампаний. К слову, есть ли возможность скачать их файлы отдельно?
        • 0
          Могу выложить, там 200 с чем-то мегабайт архив (если со всем звуковым оформлением)…
          • 0
            Да нет, пожалуй, кампании получаются великоваты.
            А за статью — ещё раз спасибо. :)
          • 0
            буду признателен
  • +1
    Статья на конкурс хабра? если чесно?
    публику и меня всегда завораживает зрелище выковыривания, особенно в АСМе

    ЗЫ. если хабранарод помнит, то в прошлом конкурсе победила статья по раскопкам тини вируса.
    ЗЫЫ. отличная статья :)
    • 0
      А что за конкурс если не секрет? Я не в курсе =)
      • +1
        на лучшую статью :) с призами, где то есть на главной
  • 0
    Здорово.
    Но не написано, как была решена задача «4. Сделать игру переносимой». Предположу из текста, что получилось это «само» в результате замены функции загрузки библиотеки ebueulax.dll — «много лишних действий» могли быть не совсем уж и лишними. Или проверкой наличия диска дело ограничилось?
  • 0
    Под wine не работает :( А уже ведь руки зачесались!
  • 0
    Отличная статья! Сам много лет занимался подобными вещами (только с Ultima Online) и использую как раз такой-же набор инструментов, за исключением Hexview, вместо него использовал всегда HIEW (очень нравится такой функциионал как поиск ссылок на текущий адрес и ассемблирование на лету). А по поводу FASM'a там помоему есть директива Virtual которая подставляет нужные смещение для функций при компиляции.
  • 0
    Я предпочитаю для таких целей использовать С/С++ с минимальными вставками (а то и без них) ассемблера. Дело в том, что очень часто можно реверснуть структуры данных игры и использовать их в Сишном проекте. В результате немного увеличивается эффективность труда.

    В свое время я сел переписывать Master of Orion 2, но дело заглохло — он был слишком криво написан и его проще было бы переписать с нуля, чем отреверсить целиком.

    Кстати, из таких вот интересных проектов могу упомянуть TTDPatch, ScummVM, OpenTTD. Последние два реверснуты ludde (Ludvig Strigeus), он же автор µTorrent.

    Вобщем, тема интересная. Только времени много забирает.
  • 0
    Статья отличная

    А можно ли заставить работать AOE2 через Хамачи или другие VPN?

    Не рабоает, сколько не бился :(
    • 0
      Извиняюсь за некропостинг, но это возможно, если выставить адаптеру Hamachi максимальный приоритет, к примеру вот таким способом.
  • 0
    Сорри за некрокомментарий, я добавил описание и решение проблемы в Community bug tracker. А вообще конечно лучше перейти на opensource клон игры . С открытым ПО не пришлось бы бинарники править.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.