Версия для печати темы

Нажмите сюда для просмотра этой темы в оригинальном формате

CTPAX-X _ Русификаторы _ The Last Express Gold Edition

Автор: Siberian GRemlin Jun 26 2016, 06:32

«Золотое издание» это старая игра адаптированная под современные системы, к сожалению «ХР» не поддерживается. Возникла проблема с отображением субтитров. Хоть текст изначально закодирован двумя байтами, но игра отбрасывает первый байт и использует только второй. Причём выводит только западноевропейскую латиницу. Проблема в том, что используется системный 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» сделана с использованием этой библиотеки, но эта игра вроде системные шрифты не использует.

Автор: -=CHE@TER=- Jun 26 2016, 09:20

А какие файлы проверяются на целостность игрой?
В той библиотеке, что ты выложил, например, используется "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 подменить, если другой шрифт хочешь.

Автор: Siberian GRemlin Jun 26 2016, 10:18

libcocos2d.dll не проверяется на целостность. Зачем делать прослойку, чтобы поменять один байт в памяти, если можно без неё поменять один байт в файле? Знать бы какой.

Автор: -=CHE@TER=- Jun 26 2016, 11:22

Если не проверяется, то ок.
Попробуй, пока что, такое:

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 будет с обычным, простым, начертанием, зато с нужной кодировкой.

Автор: Siberian GRemlin Jun 26 2016, 12:12

Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL.

Автор: -=CHE@TER=- Jun 26 2016, 13:00

QUOTE(Siberian GRemlin @ Jun 26 2016, 12:12) *
Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL.
Наверное.
Насчёт .EXE и "Arial", попробуй так (малой кровью проверить):
1) Пишешь программу, которая через CreateProcess() создаёт процесс игры в спящем (CREATE_SUSPENDED) режиме.
2) Патчишь своё "Arial" в памяти (WriteProcessMemory()) на что нужно (не забудь права на память поменять и обратно - VirtualProtectEx()) или что ты там хотел изменить.
3) "Отпускаешь" процесс на исполнение через ResumeThread().
Если этот финт с ушами пройдёт (игра не проверят свой код в памяти и после изменения начала видеть русские буквы), то можно, в принципе, так в виде запускалки и оставить.

Автор: Siberian GRemlin Jun 26 2016, 16:45

Никогда не занимался этим. Пункты 1 и 3 сделал. Во 2-ом не могу понять откуда нужно брать lpAddress. В сети в основном уже https://exelab.ru/f/index.php?action=vthread&forum=6&topic=17825 прописаны или берутся из параметра.

Автор: -=CHE@TER=- Jun 26 2016, 18:28

Это просто адрес кода. Его можно посмотреть в 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" ли там. Если да - значит попал куда надо. (*улыбается*)

Автор: Siberian GRemlin Jun 27 2016, 06:22

Не мог понять почему читается левое значение. Сделал простой EXE с writeln и уже его запустил и из него нормально прочитал. Похоже игра с защитой от подобных манипуляций.

Автор: -=CHE@TER=- Jun 27 2016, 13:02

Не пробовал свою программу от имени администратора запускать?
Если у тебя Windows Vista и выше, а игра установлена в Program Files, то тебе сама система может права резать.
А когда ты на своей тестовой программе проверяешь, то она у тебя, поди, рядом с изменялкой лежит?
Кстати, если у тебя ReadProcessMemory() = false, то сделай вывод GetLastError(), даже лучше так:

// устанавливаем последнюю ошибку, чтоб старая не отсвечивала
SetLastError(0);
if (ReadProcessMemory(...) = false) then writeln(GetLastError); // смотрим что там не так

И посмотри какой код ошибки возвращается - оттуда уже можно будет разбираться почему память не читает.

Автор: Siberian GRemlin Jun 28 2016, 10:59

Ошибка — 299.

CODE
var
  StartUpInfo: TStartUpInfo;
  ProcessInfo: TProcessInformation;
  OldProtect: longword;
  BytesToRead, BytesRead: LongWord;

  adr,i: dword;
begin
  BytesToRead:=4;
  FillChar(StartUpInfo, SizeOf(TStartUpInfo), 0);
  StartUpInfo.cb:= SizeOf(TStartUpInfo);
  StartUpInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
  StartUpInfo.wShowWindow := SW_SHOWNORMAL;
  if CreateProcess('TheLastExpressSteam.exe', '', nil, nil, false, CREATE_SUSPENDED, nil, nil, StartUpInfo, ProcessInfo) then begin
    adr:=$0054e2f8;
    VirtualProtectEx(ProcessInfo.hProcess,pointer(adr),BytesToRead,PAGE_READWRITE,OldProtect);
    SetLastError(0);
    if (ReadProcessMemory(ProcessInfo.hProcess,pointer(adr),@i,BytesToRead,BytesRead) = false) then writeln('error: ',GetLastError);
    Writeln(inttohex(i,8));
    VirtualProtectEx(ProcessInfo.hProcess,pointer(adr),BytesToRead,OldProtect,OldProtect);
    readln;
    ResumeThread(ProcessInfo.hThread);
  end;
end;

Автор: -=CHE@TER=- Jun 28 2016, 15:57

QUOTE
C:\>net helpmsg 299

Запрос ReadProcessMemory или WriteProcessMemory был выполнен только частично.
Хм. Интересно, как он может быть выполнен частично?

У структуры "StartUpInfo" обязательное только поле "cb", остальное можно игнорировать (тем более, что ты флаги заполнил, а связанные с ними структуры - нет и не используешь).

Погуглил на скорую руку с запросом:
CreateProcess CREATE_SUSPENDED readprocessmemory ERROR_PARTIAL_COPY 299

Вот чего нашёл:
_ttps://forum.antichat.ru/threads/97043/

Попробуй добавить флаг отладки при создании процесса (похоже, что под Vista и выше прав нехватает):
..., CREATE_SUSPENDED or DEBUG_PROCESS, ...

Ещё проверь что у тебя VirtualProtectEx() возвращает:

SetErrorCode(0);
if (VirtualProtectEx(...) = false) then writeln('VPE_error: ',GetLastError);

Возможно, как-то ещё придётся себе права поднимать. Пока что попробуй так.
И я так и не получил ответы на свои вопросы выше:
1) Игра в Program Files стоит? Если да - попробуй скопировать исполняемый файл игры и все необходимые ему бибилиотеки в какой-нибудь другой каталог и запусти патч оттуда. Если чтение памяти проканает, значит надо с правами в Program Files разбираться.
2) От имени администратора свой патч пробовал запускать?
3) А в режиме совместимости Windows XP или 98?

Автор: Siberian GRemlin Jun 28 2016, 16:45

QUOTE(-=CHE@TER=- @ Jun 28 2016, 22:57) *
Попробуй добавить флаг отладки при создании процесса (похоже, что под Vista и выше прав нехватает):
..., CREATE_SUSPENDED or DEBUG_PROCESS, ...
Ошибка та же, но игра не запускается. То есть сам процесс запускается, но после readln завершается, если верить диспетчеру задач.

QUOTE(-=CHE@TER=- @ Jun 28 2016, 22:57) *
Ещё проверь что у тебя VirtualProtectEx() возвращает:
487.

QUOTE(-=CHE@TER=- @ Jun 28 2016, 22:57) *
1) Игра в Program Files стоит? Если да - попробуй скопировать исполняемый файл игры и все необходимые ему бибилиотеки в какой-нибудь другой каталог и запусти патч оттуда. Если чтение памяти проканает, значит надо с правами в Program Files разбираться.
Никогда не устанавливаю игры в Program Files. Под игры отдельная папка.

QUOTE(-=CHE@TER=- @ Jun 28 2016, 22:57) *
2) От имени администратора свой патч пробовал запускать?
Я и так являюсь администратором. Но запустил через пункт в выпадающем меню от имени админа — ошибки те же.

QUOTE(-=CHE@TER=- @ Jun 28 2016, 22:57) *
3) А в режиме совместимости Windows XP или 98?
У чего и зачем? Игре совместимость не нужна, моей проге тоже.

Кстати, у меня «Windows 7».

Автор: -=CHE@TER=- Jun 29 2016, 09:32

QUOTE(Siberian GRemlin @ Jun 28 2016, 16:45) *
Ошибка та же, но игра не запускается. То есть сам процесс запускается, но после readln завершается, если верить диспетчеру задач.
Походу если игру пытаются дебажить, она закрывается. Антиотладочный механизм, скорее всего. А, возможно (не разбирался), и саму программу Windows завершает после того как завершил работу отладчик - поробуй readln после ResumeThread() сунуть.

QUOTE(Siberian GRemlin @ Jun 28 2016, 16:45) *
487
Набираем в командной строке Windows и видим:
QUOTE
C:\>net helpmsg 487

Попытка обращения к неверному адресу.
Отсюда понятно, почему она прочитать не может.
Ты точно адрес верно указал?
Возможно, конечно, тоже какие-то антиотладочные механизмы...
А! Вот ещё что хотел узнать: игра 32 или 64 бита? У ней может быть два экзешника и если ты пытаешься править 64-ый из 32-ой программы, то я не уверен, будет ли такой финт ушами работать вообще...
Можешь исполняемый файл игры вместе со всеми необходимыми библиотеками куда-нибудь залить поглядеть (надеюсь это всё не занимает сотни мегабайт)?

QUOTE(Siberian GRemlin @ Jun 28 2016, 16:45) *
Никогда не устанавливаю игры в Program Files. Под игры отдельная папка.
Это ты молодец, но я таких подробностей не знал, поэтому и спросил.

QUOTE(Siberian GRemlin @ Jun 28 2016, 16:45) *
Я и так являюсь администратором. Но запустил через пункт в выпадающем меню от имени админа — ошибки те же.
Понятно, жаль.

QUOTE(Siberian GRemlin @ Jun 28 2016, 16:45) *
У чего и зачем? Игре совместимость не нужна, моей проге тоже.
Кстати, у меня «Windows 7».
Дело не в том нужна или не нужна совместимость, а в том что при её использовании Windows закрывает глаза на некоторые вещи, которые при обычном раскладе молча и сурово рубит. Эмулируется множество всяких костылей, часть из которых, возможно, поможет хаку сработать. Т.к. хрен знает из-за чего оно не работает, я и пытаюсь нащупать направление в котором может хоть что-то сдвинется с мёртвой точки.

Автор: Siberian GRemlin Jul 12 2016, 19:49

QUOTE(-=CHE@TER=- @ Jun 29 2016, 16:32) *
Можешь исполняемый файл игры вместе со всеми необходимыми библиотеками куда-нибудь залить поглядеть (надеюсь это всё не занимает сотни мегабайт)?
https://yadi.sk/d/dHr6l8u4tEr76.

Автор: -=CHE@TER=- Jul 13 2016, 10:45

Ух, ты!
Первый раз вижу .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); Закрытие дескриптора - это не завершение процесса.

Автор: Siberian GRemlin Mar 19 2018, 14:52

Если кому-то интересно, ничего из описанного выше не сработало на данной игре и пришлось русифицировать её грязным способом — заменой системного шрифта. Отмечу, что на нескольких других играх данный метод работает успешно.