beatcracker: (Default)
Давно заметил за собой, что ковыряться в игрушках, мне порою гораздо интересней, чем играть в них. В этот раз, в мои руки попал Need for Speed: Carbon - очередное творение программистов из EA BlackBox.

Имевшаяся у меня версия игры, была собрана криворукими пиратами, как бог на душу положит. Вот куски из лога инсталлера:

File Overwrite: C:\XP\system32\msvcrt.dll
File Overwrite: C:\XP\system32\mfc42.dll

поскипано

Self-Register: C:\XP\system32\mfc42.dll
Self-Register: C:\XP\system32\xmlinst.exe
Self-Register: C:\XP\system32\vp6dec.ax
Self-Register: C:\XP\system32\olepro32.dll
Self-Register: C:\XP\system32\oleaut32.dll
Could not Self-Register: C:\XP\system32\msxml4r.dll
Could not Self-Register: C:\XP\system32\msxml4a.dll
Self-Register: C:\XP\system32\msxml4.dll
Could not Self-Register: C:\XP\system32\msxml3a.dll
Self-Register: C:\XP\system32\msvbvm60.dll
Self-Register: C:\XP\system32\msvbvm50.dll
Self-Register: C:\XP\system32\MSINET.OCX
Self-Register: C:\XP\system32\MSCOMCTL.OCX
Could not Self-Register: C:\XP\system32\mfc70u.dll
Could not Self-Register: C:\XP\system32\mfc70.dll
Self-Register: C:\XP\system32\MCI32.OCX
Self-Register: C:\XP\system32\Comdlg32.ocx
Self-Register: C:\XP\system32\Camiseta.ocx
Self-Register: C:\XP\system32\AniGIF.ocx



За такое надо бить по рукам! Наивные попытки зарегистрировать сишный рантайм, копирование никому не нужного декодера VP6 (в игре он встроенный), а также абсолютно не нужных дельфийному авторану Camiseta.ocx и шароварного AniGIF.ocx. Автором последнего является жадный китайский программист Jin Hui. Это не говоря, про то, что тот же авторан настойчиво предлагает установить кодеки Intel Indeo, а на диске валяется подборка Windows Media кодеков и что,самое интересное, драйвера для PhysX! А вот для видеокарт драйверов почему-то нет ... Явный недосмотр.

Двигаемся дальше. Игра установлена, sfc /scannow , для восстановления баланса dll в системе успешно отработала и можно приступать к самому интересному - собственно игре.

Как и все игры серии NFS (начиная с Hot Pursuit 2) эта разрабатывается одновременно на несколько платформ (PC, XBox, PlayStation), что накладывает на неё определенный отпечаток. В частности в коде встречаются упоминания PS3 и XBOX360, работы с геймпадами и картами памяти. Кстати, распространенное мнение, о том, что игры с 6 по 10 части разрабатываются на одном движке, не совсем соответствует действительности. На самом деле движок 6 части это нечто промежуточное между 5 и 7 и стоит особняком, а вот уже начиная с 7 части (NFS: Underground) движок менялся слабо. Из заметных глазом различий, в 8 части разработчики ушли от видео в проприетарном формате mad и стали использовать прогрессивный mpeg4 кодек vp6 от ON2. Не то, что бы mad сильно плох, но как и большинство старых игровых видеоформатов он гораздо более заточен под скорость воспроизведения, чем под качество картинки.

Не вдаваясь в подробности, первое, что меня огорчило - это отсутствие субтитров в видеовставках, о наличии в игре которых недвусмысленно говорила папка SUBTITLES. Правда позже выяснилось, что собственно сами файлы лежащие там,субтитрами не являются, но это несущественно. Достаточно продолжительные поиски в различных форумах выявили, что в природе существуют русификаторы, в которых субтитры есть. Отбросив сумасшедшую мысль, что русифекализаторы пережали все vp6 с наложенными субтитрами, я скачал русификатор от ENPY Studio и установил. После этого все стало предельно ясно. Субтитры в игре действительно есть, но лишь в любой локали, отличной от английской, где они тоже имеют место быть, но не отображаются. Изначально NFS: Carbon поддерживает (в имеющейся у меня версии) 16 языков, языковые файлы для котрых лежат в папке LANGUAGES. Язык используемый игрой, определяется ключом в реестре:

HKLM\Software\Electronic Arts\Need for Speed Carbon\Language

Все остальные упоминания о локали в реестре самой игрой игнорируются и возможно нужны для работы EA support tools (их я не смотрел и могу ошибаться)

Русификаторы всего-лишь установили немецкую локаль, поправили соответствующие файлы немецкой локали и перерисовали шрифты. Субтитры включились автоматически. Отсюда у меня родился следующий метод включения субтитров:

Берем из папки LANGUAGES файлы

English_Frontend.bin
English_Global.bin
English_InGame.bin


Переименовываем их в соответственно в:

German_Frontend.bin
German_Global.bin
German_InGame.bin


и прописываем в реестре "Language"="German"., Сработало. Однако красивым такое решение не назовешь. Плюс ко всему кое-где проглядывает немецкий текст, например сообщение о удачной загрузке после показа вступительных роликов. Также для показа видео, необходимо будет переименовать в папке VIDEO все файлы по маске, заменив english на german. Поняв, что классическим методом тыка дальше не продвинуться я решил зайти с тыла.

Засовываем nfsc.exe в IDA и ждем. Наконец, IDA сообщает, что автоматический анализ файла закончен и мы можем приступать непосредственно к изучению внутренностей игры. Первым делом меня интересуют ссылки в коде на различные строки. По прошлому опыту я знаю, что в Need for Speed интерфейс игры базируется на системе скриптов. Попробуем найти их и здесь: В этой версии игры скрипты имеют расширение fng. Вот, что мне удалось получить:


DEMO_SPLASH.fng
FeOnlinePlayerStats.fng
FeOnlineLeaderboard.fng
FeGameRoomEditSettings.fng
FeGameRoomPlayerDetails.fng
FeOnlineGameRoom.fng
FeOnlineGameType.fng
FEOnlineTOS.fng
FeOnlineDisconnect.fng
FeOnlineFeedback.fng
FeOnlineMessengerInvitePopup.fng
FeOnlineMessengerChatPopup.fng
FeOnlineMessengerUserPopup.fng
FeOnlineMessenger.fng
FeOnlineChatDialog.fng
FEPCOnlineForgotAccount.fng
FEPCOnlineAccountTaken.fng
FEPCOnlineCDKey.fng
FEPCOnlineCreateAccount.fng
FEPCOnlineLogin.fng
MC_List.fng
FeSaveGhostDialog.fng
BUSTED_OVERLAY.fng
FeBusted.fng
FEPostPursuitRewards.fng
FePostStages.fng
FePostRaceResults.fng
Loading.fng
LS_LangSelect.fng
loading_boot.fng
Loading_Tips.fng
DEMO_PSA.fng
WS_LS_Splash.fng
LS_Splash.fng
FeBackdrop.fng
FeBlackScreen.fng
FeChyron.fng
FeQuickRaceWingman.fng
FeCarSelect.fng
FeRewardCard.fng
FESubtitler.fng
FEAnyMovie.fng
FeComingSoonM3.fng
FePhotoMode.fng
FeComingSoonM2.fng
ScreenPrintf.fng
Keyboard_PS3.fng
Keyboard.fng
InGameDialog.fng
Chyron_IG.fng
EA_Trax.fng
FeDialog.fng
DiscError.fng
FeGarageMain.fng
FeChallengeSeries.fng
FeRaceStatistics.fng
FeStatisticsStatsListing.fng
FePressStart.fng
FeQuickRaceOptions.fng
Options_PC_Controller.fng
FEJukebox.fng
FeOptionsScreen.fng
FeCustomizeAutozone.fng
FeVinylTransform.fng
FeCrewLogoColourChooser.fng
FeColourChooser.fng
FeVinylSelection.fng
FeLayerManagement.fng
FeShowcase.fng
FeMyCarsManager.fng
UI_DebugCarCustomize.fng
FeVisualRideHeight.fng
FeVisualWindowTint.fng
FEAutosculptTop.fng
FEAutosculptWheel.fng
FEAutosculptSpoiler.fng
FEAutosculptRoof.fng
FEAutosculptHood.fng
FEAutosculptExhaust.fng
FEAutosculptSkirt.fng
FEAutosculptRearBumper.fng
FEAutosculptFrontBumper.fng
FePerformanceSlider.fng
FeCustomizePerformance.fng
FeCustomizeParts.fng
FeCustomizeVisuals.fng
FeCustomizeMain.fng
FeCrewCar.fng
FeGameWon.fng
FeGameOver.fng
FeBonusCards.fng
FeCrewManagement.fng
FeCarClassSelect.fng
FeCrewLogo.fng
ControllerUnplugged.fng
FeSmsMessage.fng
FeSmsMailbox.fng
HUD_SingleRace.fng
Fe_WorldMap_RandomEncounter.fng
Fe_WorldMap_DefenceRace.fng
Fe_WorldMap_World_View.fng
FeWorldMapQuickList.fng
WorldMapMain.fng
Credits.fng
FePauseOptionsMain.fng
FePauseMain.fng
FeWidgetScroller.fng
FeTextScroller.fng
FeWidgetMenu.fng
FeMenuScreen.fng
FeArrayScroller.fng
FeIconScroller.fng
FeMainMenu_Sub.fng
FeMainMenu.fng
Fe_WorldMap_Acquisitions.fng


Как видите, названия вполне говорящие. особенно меня заинтересовали эти: LS_LangSelect.fng и FESubtitler.fng. Сразу скажу, что FESubtitler.fng меня ни к чему не привел, а вот с LS_LangSelect.fng всё гораздо интереснее. Вот кусок кода из IDA, интересные места выделены жирным, неинтересные поскипаны:



.text:005BD26E ; ---------------------------------------------------------------------------
.text:005BD271 align 10h
.text:005BD280
.text:005BD280 ; --------------- S U B R O U T I N E ---------------------------------------
.text:005BD280
.text:005BD280
.text:005BD280 sub_5BD280 proc near ; DATA XREF: .rdata:009D2654 o
.text:005BD280 ; .rdata:009E8C64 o
.text:005BD280
.text:005BD280 var_4= dword ptr -4
.text:005BD280
.text:005BD280 push ecx
.text:005BD281 push esi
.text:005BD282 mov esi, ecx
.text:005BD284 mov eax, [esi+4]
.text:005BD287 inc eax
.text:005BD288 cmp eax, 0Bh ; switch 12 cases
.text:005BD28B ja near ptr unk_5BD423
.text:005BD291 jmp ds:off_5BD428[eax*4] ; switch jump
.text:005BD298
.text:005BD298 loc_5BD298: ; DATA XREF: .text:005BD428 o
.text:005BD298 mov eax, [esi+0D4h] ; case 0x1
.text:005BD29E push 1
.text:005BD2A0 push 12h
.text:005BD2A2 push offset aAttract ; "Attract"
.text:005BD2A7 mov ecx, esi
.text:005BD2A9 mov [esi+0D0h], eax
.text:005BD2AF call sub_593730
.text:005BD2B4 pop esi
.text:005BD2B5 pop ecx
.text:005BD2B6 retn

.text:005BD2D4 ; ---------------------------------------------------------------------------
.text:005BD2D4
.text:005BD2D4 loc_5BD2D4: ; CODE XREF: sub_5BD280+11 j
.text:005BD2D4 ; DATA XREF: .text:005BD428 o
.text:005BD2D4 push 0Dh ; case 0x3
.text:005BD2D6 push offset aFeblackscreen_ ; "FeBlackScreen.fng"
.text:005BD2DB mov ecx, esi
.text:005BD2DD call sub_5936B0
.text:005BD2E2 pop esi
.text:005BD2E3 pop ecx
.text:005BD2E4 retn
.text:005BD2E5 ; ---------------------------------------------------------------------------

.text:005BD323 ; ---------------------------------------------------------------------------
.text:005BD323
.text:005BD323 loc_5BD323: ; CODE XREF: sub_5BD280+11 j
.text:005BD323 ; DATA XREF: .text:005BD428 o
.text:005BD323 push 0FFFFFFFFh ; case 0x6
.text:005BD325 push 0FFFFFFFFh
.text:005BD327 push 0FFFFFFFFh
.text:005BD329 lea ecx, [esp+14h+var_4]
.text:005BD32D push ecx
.text:005BD32E push 13BEh
.text:005BD333 mov ecx, offset unk_A8AD30
.text:005BD338 mov [esp+1Ch+var_4], 0
.text:005BD340 call sub_4A0490
.text:005BD345 mov eax, [esp+8+var_4]
.text:005BD349 test eax, eax
.text:005BD34B push 1
.text:005BD34D mov ecx, esi
.text:005BD34F push 13h
.text:005BD351 jz short loc_5BD360
.text:005BD353 push offset aEa_bumper_ws ; "EA_Bumper_WS"
.text:005BD358 call sub_593730
.text:005BD35D pop esi
.text:005BD35E pop ecx
.text:005BD35F retn
.text:005BD360 ; ---------------------------------------------------------------------------
.text:005BD360
.text:005BD360 loc_5BD360: ; CODE XREF: sub_5BD280+D1 j
.text:005BD360 push offset aEa_bumper ; "EA_Bumper"
.text:005BD365 call sub_593730
.text:005BD36A pop esi
.text:005BD36B pop ecx
.text:005BD36C retn
.text:005BD36D ; ---------------------------------------------------------------------------
.text:005BD36D
.text:005BD36D loc_5BD36D: ; CODE XREF: sub_5BD280+11 j
.text:005BD36D ; DATA XREF: .text:005BD428 o
.text:005BD36D push 1 ; case 0x7
.text:005BD36F push 14h
.text:005BD371 push offset aEahd_bumper ; "EAHD_Bumper"
.text:005BD376 mov ecx, esi
.text:005BD378 call sub_593730
.text:005BD37D pop esi
.text:005BD37E pop ecx
.text:005BD37F retn
.text:005BD380 ; ---------------------------------------------------------------------------
.text:005BD380
.text:005BD380 loc_5BD380: ; CODE XREF: sub_5BD280+11 j
.text:005BD380 ; DATA XREF: .text:005BD428 o
.text:005BD380 mov eax, dword_A99C60 ; case 0x9
.text:005BD385 push 10h
.text:005BD387 push offset aLs_langselect_ ; "LS_LangSelect.fng"
.text:005BD38C mov ecx, esi
.text:005BD38E mov [esi+0C4h], eax
.text:005BD394 call sub_5936B0
.text:005BD399 pop esi
.text:005BD399 ; ---------------------------------------------------------------------------

.text:005BD425
.text:005BD426 align 4
.text:005BD428 off_5BD428 dd offset unk_5BD41A ; DATA XREF: sub_5BD280+11 r
.text:005BD428 dd offset loc_5BD298 ; jump table for switch statement
.text:005BD428 dd offset loc_5BD2B7
.text:005BD428 dd offset loc_5BD2D4
.text:005BD428 dd offset loc_5BD2E5
.text:005BD428 dd offset loc_5BD2FD
.text:005BD428 dd offset loc_5BD323
.text:005BD428 dd offset loc_5BD36D
.text:005BD428 dd offset loc_5BD2C1
.text:005BD428 dd offset loc_5BD380
.text:005BD428 dd offset unk_5BD39C
.text:005BD428 dd offset unk_5BD3D1


В привычном виде эта конструкция выглядела бы так:

Select Case X
Case 1
Call Attract
Case 2
Call FeBlackScreen.fng


etc..

С Attract и EA_Bumper всё ясно. Это ролики, лежащие в папке VIDEO. А вот скрипты FeBlackScreen.fng и LS_LangSelect.fng интригуют. Запустив NFS под отладчиком, встроенным, в IDA я увидел, что первым выполняется FeBlackScreen.fng. Название свое он оправдывает, экран действительно черный. Далее идут EA_Bumper'ы, собствено загрузка UI игры. До LS_LangSelect.fng дело не доходит. Что ж попытаемся это исправить. Опять запускаем отладку, и в момент перехода на FeBlackScreen.fng меняем EIP, так, чтобы он указывал на код выполняющий LS_LangSelect.fng. Удача улыбается нам и мы видим следующую картину:

NFSC built-in language selector aka LS_LangSelect.fng

Однако наше счастье неполно. Во первых доступны всего два языка, английский и испанский, а во вторых, в английском нет долгожданных субтитров :( ... Ситуацию с недостающими языками можно было бы исправить редактированием LS_LangSelect.fng. В Hot Pursuit 2, скрипты были в текстовом виде и легко подвергались модификации. Вот например скрипт, рисующий одно из диалоговых окон настроек:

[01jump.ToggleButton]
ToggleButton.mDataEnum=kOptionsJumpCam
CHILDREN=pc\pc.cnt.toggle
GUI.mTabOrder=2
GUI.mStyle=GS_TAB|GS_MOUSEFOCUS|GS_NOTIFY
GUI.mBounds=[300, 57] 233, 20
GUI.mFont=Pmedium
GUI.mPalette=P_TOGGLE
GUI.mColor=[255, 255, 255, 88]
GUI.mText=kTxtJumpCam
GUI.mZOrder=5
ToggleButton.mListName=<ON_OFF>


[02360.ToggleButton]
ToggleButton.mDataEnum=kOptions360Cam
CHILDREN=pc\pc.cnt.toggle
GUI.mZOrder=4
GUI.mTabOrder=3
GUI.mStyle=GS_TAB|GS_MOUSEFOCUS|GS_NOTIFY
GUI.mBounds=[300, 87] 233, 20
GUI.mFont=Pmedium
GUI.mPalette=P_TOGGLE
GUI.mColor=[255, 255, 255, 88]
GUI.mText=kTxt360Cam
ToggleButton.mListName=<ON_OFF>


[03asav.ToggleButton]
ToggleButton.mDataEnum=kOptionsAutoSave
CHILDREN=pc\pc.cnt.toggle
GUI.mZOrder=7
GUI.mTabOrder=4
GUI.mStyle=GS_TAB|GS_MOUSEFOCUS|GS_NOTIFY
GUI.mBounds=[300, 117] 233, 20
GUI.mFont=Pmedium
GUI.mPalette=P_TOGGLE
GUI.mColor=[255, 255, 255, 88]
GUI.mText=kTxtAutoSave
ToggleButton.mListName=<ON_OFF>


Как видите все вполне понятно. Однако с 7 части формат скриптов стал бинарным и модифицировать его практически невозможно. Да и формат игровых архивов изменился значительно. Единственная утилита, работающая с ним это плагин для Total Commander - Game Archive UnPacker, но в случае с бинарными скриптами и от неё немного толку.

К сожалению, дальнейшие мои изыскания, так и не помогли мне найти, где именно включаются\отключаются субтитры. Однако нет худа без добра. В процессе отладки я нашел пару мест, в которых игра ищет оригинальный DVD. Делается это путем перебора всех доступных системе дисков через GetDriveTypeA, что в моем случае приводило к дребезжанию флоппи-дисковода при запуске игры. Огорченный невозможносью включить субтитры, я решил сделать хоть что-то полезное :) ... В итоге по результатам моего исследования, я сделал два патча, один из которых включает селектор языков, а второй отключает поиск дисков.  Забираем тут.

З.Ы. Английские субтитры всё таки возможны :) ... Для этого необходимо использовать no-DVD exe от японской версии, найти который можно на gamecopyworld.com. Однако его исследование затруднено из-за Securom'овского фарша внтури. Такое впечатление, что он был не снят, а заинлайнен.

З.З.Ы. Мои патчи поддерживают no-DVD для версии 1.2 от RAZOR1911 и для верcии 1.3 от V!TAL!TY. Японский exe не поддерживается, по причинам, указанным выше ...

If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

March 2021

M T W T F S S
1234567
891011121314
151617181920 21
22232425262728
293031    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Monday, 5 January 2026 20:26
Powered by Dreamwidth Studios