IPB

Добро пожаловать, гость ( Вход | Регистрация )

 
Reply to this topicStart new topic
> The Last Express Gold Edition, набор символов шрифта
Siberian GRemlin
Jun 26 2016, 06:32
Сообщение #1


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



«Золотое издание» это старая игра адаптированная под современные системы, к сожалению «ХР» не поддерживается. Возникла проблема с отображением субтитров. Хоть текст изначально закодирован двумя байтами, но игра отбрасывает первый байт и использует только второй. Причём выводит только западноевропейскую латиницу. Проблема в том, что используется системный Arial и это никак нельзя изменить — ЕХЕ проверяет свою целостность, что лицензионная копия, что взломанная. Попробовал сделать грязным способом — добавил нужные коды кириллице, установил шрифт. Он добавился в набор шрифтов, и кириллица стала выводиться вместо доп. латиницы и в игре и в системе, а значит везде. Шрифт теперь можно удалить только из-под другой ОС, что очень плохо.

И, да, я проверил через «Process Monitor» — игра не обращается к arial.ttf напрямую, а через системную API его загружает. В противном случае я ей изменённый шрифт просто в папку положил бы.

К счастью, хоть название шрифта записано в защищённом ЕХЕ, но вызов функции находится в DLL, файл которой можно изменять. Наткнулся на интересную статью по решению подобных проблем, но мне сложно понять где в данном случае этот параметр отвечающий за набор символов находится.



Сама библиотека. Взломанную игру долго искал и качал пару дней, если нужна, то могу поделиться (на ХР не идёт).

Буду признателен, если кто-нибудь сможет подсказать какой байт исправить с 0 на 1, чтобы изменить набор символов перед вызовом функции. В перспективе это может пригодиться для других игр, например, «Little Big Adventure Enhenced Edition» сделана с использованием этой библиотеки, но эта игра вроде системные шрифты не использует.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 26 2016, 09:20
Сообщение #2


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



А какие файлы проверяются на целостность игрой?
В той библиотеке, что ты выложил, например, используется "zlib1.dll".
Можно, как я в турке делал, подменить это библиотеку на прокси:

libcocos2d.dll -> zlib1.dll (это наша прокся) -> zlib2.dll (оригинальная библиотека)

При этом в проксе zlib1.dll ты в DllEntryPoint во время DLL_PROCESS_ATTACH ищешь уже загруженную libcocos2d.dll и патчишь её в памяти (можно, кстати, таким макаром даже .EXE файл патчить в памяти, если он себя проверят только на диске).

Насчёт параметра - у тебя я там вижу CreateFontIndirect - см. MSDN. У неё один параметр - указатель на старуктуру LOGFONT, где тебе, как я понял, всего-то нужно изменить поле lfCharSet. Ну, можешь, ещё lfFaceName подменить, если другой шрифт хочешь.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 26 2016, 10:18
Сообщение #3


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



libcocos2d.dll не проверяется на целостность. Зачем делать прослойку, чтобы поменять один байт в памяти, если можно без неё поменять один байт в файле? Знать бы какой.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 26 2016, 11:22
Сообщение #4


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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

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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 26 2016, 12:12
Сообщение #5


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 26 2016, 13:00
Сообщение #6


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 26 2016, 16:45
Сообщение #7


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



Никогда не занимался этим. Пункты 1 и 3 сделал. Во 2-ом не могу понять откуда нужно брать lpAddress. В сети в основном уже константы прописаны или берутся из параметра.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 26 2016, 18:28
Сообщение #8


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 27 2016, 06:22
Сообщение #9


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



Не мог понять почему читается левое значение. Сделал простой EXE с writeln и уже его запустил и из него нормально прочитал. Похоже игра с защитой от подобных манипуляций.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 27 2016, 13:02
Сообщение #10


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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

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

И посмотри какой код ошибки возвращается - оттуда уже можно будет разбираться почему память не читает.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 28 2016, 10:59
Сообщение #11


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



Ошибка — 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;
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 28 2016, 15:57
Сообщение #12


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jun 28 2016, 16:45
Сообщение #13


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



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».
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jun 29 2016, 09:32
Сообщение #14


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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 закрывает глаза на некоторые вещи, которые при обычном раскладе молча и сурово рубит. Эмулируется множество всяких костылей, часть из которых, возможно, поможет хаку сработать. Т.к. хрен знает из-за чего оно не работает, я и пытаюсь нащупать направление в котором может хоть что-то сдвинется с мёртвой точки.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Jul 12 2016, 19:49
Сообщение #15


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jul 13 2016, 10:45
Сообщение #16


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,188
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 286 раз(а)



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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Siberian GRemlin
Mar 19 2018, 14:52
Сообщение #17


Advanced Member
***

Группа: CTPAX-X
Сообщений: 472
Регистрация: 4-February 08
Пользователь №: 2
Спасибо сказали: 200 раз(а)



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


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0 -

 



Упрощённая версия Сейчас: 20th February 2019 - 11:09