«Золотое издание» это старая игра адаптированная под современные системы, к сожалению «ХР» не поддерживается. Возникла проблема с отображением субтитров. Хоть текст изначально закодирован двумя байтами, но игра отбрасывает первый байт и использует только второй. Причём выводит только западноевропейскую латиницу. Проблема в том, что используется системный Arial и это никак нельзя изменить — ЕХЕ проверяет свою целостность, что лицензионная копия, что взломанная. Попробовал сделать грязным способом — добавил нужные коды кириллице, установил шрифт. Он добавился в набор шрифтов, и кириллица стала выводиться вместо доп. латиницы и в игре и в системе, а значит везде. Шрифт теперь можно удалить только из-под другой ОС, что очень плохо.
И, да, я проверил через «Process Monitor» — игра не обращается к arial.ttf напрямую, а через системную API его загружает. В противном случае я ей изменённый шрифт просто в папку положил бы.
К счастью, хоть название шрифта записано в защищённом ЕХЕ, но вызов функции находится в DLL, файл которой можно изменять. Наткнулся на http://leserg73.narod.ru/TUTOR/I/index.html по решению подобных проблем, но мне сложно понять где в данном случае этот параметр отвечающий за набор символов находится.
http://i.imgur.com/KBlgYFf.png
https://yadi.sk/d/BIKyMtcCsnuh3. Взломанную игру долго искал и качал пару дней, если нужна, то могу поделиться (на ХР не идёт).
Буду признателен, если кто-нибудь сможет подсказать какой байт исправить с 0 на 1, чтобы изменить набор символов перед вызовом функции. В перспективе это может пригодиться для других игр, например, «Little Big Adventure Enhenced Edition» сделана с использованием этой библиотеки, но эта игра вроде системные шрифты не использует.
А какие файлы проверяются на целостность игрой?
В той библиотеке, что ты выложил, например, используется "zlib1.dll".
Можно, как я в турке делал, подменить это библиотеку на прокси:
libcocos2d.dll -> zlib1.dll (это наша прокся) -> zlib2.dll (оригинальная библиотека)
При этом в проксе zlib1.dll ты в DllEntryPoint во время DLL_PROCESS_ATTACH ищешь уже загруженную libcocos2d.dll и патчишь её в памяти (можно, кстати, таким макаром даже .EXE файл патчить в памяти, если он себя проверят только на диске).
Насчёт параметра - у тебя я там вижу https://msdn.microsoft.com/en-us/library/windows/desktop/dd183500.aspx - см. MSDN. У неё один параметр - указатель на старуктуру https://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx, где тебе, как я понял, всего-то нужно изменить поле lfCharSet. Ну, можешь, ещё lfFaceName подменить, если другой шрифт хочешь.
libcocos2d.dll не проверяется на целостность. Зачем делать прослойку, чтобы поменять один байт в памяти, если можно без неё поменять один байт в файле? Знать бы какой.
Если не проверяется, то ок.
Попробуй, пока что, такое:
libcocos2d.dll
0005F0EC: 01 -> 00 ; DEFAULT_CHARSET (1) -> ANSI_CHARSET (0)
Если не поможет, то попробуй вместо 00 вписать CC - это RUSSIAN_CHARSET (204).
Если и так не сработает, значит в ту ветку, почему-то, управление не передаётся и можно попробовать перед самым созданием шрифта заменить качество на кодировку:
// это то, что мы выше меняли
.1005FCE9: C6 45 83 01 mov b,[ebp][-7D], 001 => mov b,[ebp+var_94.lfCharSet], 1
// а это - установка качества непосредственно перед вызовом CreateFontIndirect()
.1005FE64: C6 45 86 04 mov b,[ebp][-7A], 004 => mov b,[ebp+var_94.lfQuality], 4 ; (ANTIALIASED_QUALITY 4)
Т.е. меняешь 86 на 83 и вместо 04 пишешь 00 или CC (смещение начала этой инструкции 0005F264).
Шрифт, правда, вместо ANTIALIASED будет с обычным, простым, начертанием, зато с нужной кодировкой.
Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL.
Никогда не занимался этим. Пункты 1 и 3 сделал. Во 2-ом не могу понять откуда нужно брать lpAddress. В сети в основном уже https://exelab.ru/f/index.php?action=vthread&forum=6&topic=17825 прописаны или берутся из параметра.
Это просто адрес кода. Его можно посмотреть в HIEW или IDA например (это из другой программы):
.0040117A: E8D1FD0200 call ExitProcess ; KERNEL32
Вот это $0040117A и есть адрес в памяти загруженного процесса. Учти, что это виртуальный адрес, а не смещение в файле.
var buff, dw: DWORD;
...
if (ReadProcessMemory(pHandle, $0040117A, @buff, 4, @dw) = true) then
writeln(buff); // buff == $02FDD1E8
...
.EXE не используют relocations, так что для исполняемого файла адрес всегда будет абсолютный и одинаковый на любой системе.
А для .DLL тебе нужно будет к базе (GetModulaHandle() / LoadLibrary()) прибавлять относительный адрес (т.е. от начала модуля).
Вообще, проверить можешь - читаешь память по указаному адресу (ReadProcessMemory()) и смотришь "Arial" ли там. Если да - значит попал куда надо. (*улыбается*)
Не мог понять почему читается левое значение. Сделал простой EXE с writeln и уже его запустил и из него нормально прочитал. Похоже игра с защитой от подобных манипуляций.
Не пробовал свою программу от имени администратора запускать?
Если у тебя Windows Vista и выше, а игра установлена в Program Files, то тебе сама система может права резать.
А когда ты на своей тестовой программе проверяешь, то она у тебя, поди, рядом с изменялкой лежит?
Кстати, если у тебя ReadProcessMemory() = false, то сделай вывод GetLastError(), даже лучше так:
// устанавливаем последнюю ошибку, чтоб старая не отсвечивала
SetLastError(0);
if (ReadProcessMemory(...) = false) then writeln(GetLastError); // смотрим что там не так
И посмотри какой код ошибки возвращается - оттуда уже можно будет разбираться почему память не читает.
Ошибка — 299.
Ух, ты!
Первый раз вижу .EXE файл, который реально использует reloc'и!
$0054E2F8 => $00B0E2F8
Во всяком случае у меня оно сюда грузится.
Проверь у себя - такой же адрес будет или нет.
Если нет, то придётся тебе получать адрес, куда загружен процесс, затем прибавлять к нему $0014E2F8 ($0054E2F8 - $00400000), чтобы получить смещение до своей строки. Гугли как можно по ProcessInfo.hProcess или ProcessInfo.dwProcessId (PID) получить HMODULE / HINSTANCE (это как раз адрес загрузки).
Я попробовал строчку Arial заменить на Comic - вроде бы, ошибок нет, но и шрифт в меню и Credits не поменялся (во всяком случае на Comic не похож).
Возможно, Arial, он везде Arial, а Comic нужно было писать полным именем как "Comic Sans MS", поэтому и не сработало. Но WriteProcessMemory() возвращет True, так что всё отрабатывает без проблем.
Кстати, всё забываю сказать - у тебя дескрипторы текут - после ResumeThread() нужно обязательно его закрывать: CloseHandle(ProcessInfo.hThread); Закрытие дескриптора - это не завершение процесса.
Если кому-то интересно, ничего из описанного выше не сработало на данной игре и пришлось русифицировать её грязным способом — заменой системного шрифта. Отмечу, что на нескольких других играх данный метод работает успешно.