![]() |
Добро пожаловать, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
Siberian GRemlin |
![]()
Сообщение
#1
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
«Золотое издание» это старая игра адаптированная под современные системы, к сожалению «ХР» не поддерживается. Возникла проблема с отображением субтитров. Хоть текст изначально закодирован двумя байтами, но игра отбрасывает первый байт и использует только второй. Причём выводит только западноевропейскую латиницу. Проблема в том, что используется системный Arial и это никак нельзя изменить — ЕХЕ проверяет свою целостность, что лицензионная копия, что взломанная. Попробовал сделать грязным способом — добавил нужные коды кириллице, установил шрифт. Он добавился в набор шрифтов, и кириллица стала выводиться вместо доп. латиницы и в игре и в системе, а значит везде. Шрифт теперь можно удалить только из-под другой ОС, что очень плохо.
И, да, я проверил через «Process Monitor» — игра не обращается к arial.ttf напрямую, а через системную API его загружает. В противном случае я ей изменённый шрифт просто в папку положил бы. К счастью, хоть название шрифта записано в защищённом ЕХЕ, но вызов функции находится в DLL, файл которой можно изменять. Наткнулся на интересную статью по решению подобных проблем, но мне сложно понять где в данном случае этот параметр отвечающий за набор символов находится. ![]() Сама библиотека. Взломанную игру долго искал и качал пару дней, если нужна, то могу поделиться (на ХР не идёт). Буду признателен, если кто-нибудь сможет подсказать какой байт исправить с 0 на 1, чтобы изменить набор символов перед вызовом функции. В перспективе это может пригодиться для других игр, например, «Little Big Adventure Enhenced Edition» сделана с использованием этой библиотеки, но эта игра вроде системные шрифты не использует. |
-=CHE@TER=- |
![]()
Сообщение
#2
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
А какие файлы проверяются на целостность игрой?
В той библиотеке, что ты выложил, например, используется "zlib1.dll". Можно, как я в турке делал, подменить это библиотеку на прокси: libcocos2d.dll -> zlib1.dll (это наша прокся) -> zlib2.dll (оригинальная библиотека) При этом в проксе zlib1.dll ты в DllEntryPoint во время DLL_PROCESS_ATTACH ищешь уже загруженную libcocos2d.dll и патчишь её в памяти (можно, кстати, таким макаром даже .EXE файл патчить в памяти, если он себя проверят только на диске). Насчёт параметра - у тебя я там вижу CreateFontIndirect - см. MSDN. У неё один параметр - указатель на старуктуру LOGFONT, где тебе, как я понял, всего-то нужно изменить поле lfCharSet. Ну, можешь, ещё lfFaceName подменить, если другой шрифт хочешь. |
Siberian GRemlin |
![]()
Сообщение
#3
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
libcocos2d.dll не проверяется на целостность. Зачем делать прослойку, чтобы поменять один байт в памяти, если можно без неё поменять один байт в файле? Знать бы какой.
|
-=CHE@TER=- |
![]()
Сообщение
#4
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Если не проверяется, то ок.
Попробуй, пока что, такое: 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 |
![]()
Сообщение
#5
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL.
|
-=CHE@TER=- |
![]()
Сообщение
#6
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Печально, но ни один из вариантов не помог. Может игра как-то иначе субтитры выводит, не через эту функцию / DLL. Наверное.Насчёт .EXE и "Arial", попробуй так (малой кровью проверить): 1) Пишешь программу, которая через CreateProcess() создаёт процесс игры в спящем (CREATE_SUSPENDED) режиме. 2) Патчишь своё "Arial" в памяти (WriteProcessMemory()) на что нужно (не забудь права на память поменять и обратно - VirtualProtectEx()) или что ты там хотел изменить. 3) "Отпускаешь" процесс на исполнение через ResumeThread(). Если этот финт с ушами пройдёт (игра не проверят свой код в памяти и после изменения начала видеть русские буквы), то можно, в принципе, так в виде запускалки и оставить. Спасибо сказали:
|
Siberian GRemlin |
![]()
Сообщение
#7
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Никогда не занимался этим. Пункты 1 и 3 сделал. Во 2-ом не могу понять откуда нужно брать lpAddress. В сети в основном уже константы прописаны или берутся из параметра.
|
-=CHE@TER=- |
![]()
Сообщение
#8
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Это просто адрес кода. Его можно посмотреть в 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 |
![]()
Сообщение
#9
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Не мог понять почему читается левое значение. Сделал простой EXE с writeln и уже его запустил и из него нормально прочитал. Похоже игра с защитой от подобных манипуляций.
|
-=CHE@TER=- |
![]()
Сообщение
#10
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Не пробовал свою программу от имени администратора запускать?
Если у тебя Windows Vista и выше, а игра установлена в Program Files, то тебе сама система может права резать. А когда ты на своей тестовой программе проверяешь, то она у тебя, поди, рядом с изменялкой лежит? Кстати, если у тебя ReadProcessMemory() = false, то сделай вывод GetLastError(), даже лучше так: // устанавливаем последнюю ошибку, чтоб старая не отсвечивала SetLastError(0); if (ReadProcessMemory(...) = false) then writeln(GetLastError); // смотрим что там не так И посмотри какой код ошибки возвращается - оттуда уже можно будет разбираться почему память не читает. |
Siberian GRemlin |
![]()
Сообщение
#11
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Ошибка — 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=- |
![]()
Сообщение
#12
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
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 |
![]()
Сообщение
#13
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Попробуй добавить флаг отладки при создании процесса (похоже, что под Vista и выше прав нехватает): Ошибка та же, но игра не запускается. То есть сам процесс запускается, но после readln завершается, если верить диспетчеру задач...., CREATE_SUSPENDED or DEBUG_PROCESS, ... Ещё проверь что у тебя VirtualProtectEx() возвращает: 487.1) Игра в Program Files стоит? Если да - попробуй скопировать исполняемый файл игры и все необходимые ему бибилиотеки в какой-нибудь другой каталог и запусти патч оттуда. Если чтение памяти проканает, значит надо с правами в Program Files разбираться. Никогда не устанавливаю игры в Program Files. Под игры отдельная папка.2) От имени администратора свой патч пробовал запускать? Я и так являюсь администратором. Но запустил через пункт в выпадающем меню от имени админа — ошибки те же.3) А в режиме совместимости Windows XP или 98? У чего и зачем? Игре совместимость не нужна, моей проге тоже.Кстати, у меня «Windows 7». |
-=CHE@TER=- |
![]()
Сообщение
#14
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Ошибка та же, но игра не запускается. То есть сам процесс запускается, но после readln завершается, если верить диспетчеру задач. Походу если игру пытаются дебажить, она закрывается. Антиотладочный механизм, скорее всего. А, возможно (не разбирался), и саму программу Windows завершает после того как завершил работу отладчик - поробуй readln после ResumeThread() сунуть.487 Набираем в командной строке Windows и видим:QUOTE C:\>net helpmsg 487 Отсюда понятно, почему она прочитать не может.Попытка обращения к неверному адресу. Ты точно адрес верно указал? Возможно, конечно, тоже какие-то антиотладочные механизмы... А! Вот ещё что хотел узнать: игра 32 или 64 бита? У ней может быть два экзешника и если ты пытаешься править 64-ый из 32-ой программы, то я не уверен, будет ли такой финт ушами работать вообще... Можешь исполняемый файл игры вместе со всеми необходимыми библиотеками куда-нибудь залить поглядеть (надеюсь это всё не занимает сотни мегабайт)? Никогда не устанавливаю игры в Program Files. Под игры отдельная папка. Это ты молодец, но я таких подробностей не знал, поэтому и спросил.Я и так являюсь администратором. Но запустил через пункт в выпадающем меню от имени админа — ошибки те же. Понятно, жаль.У чего и зачем? Игре совместимость не нужна, моей проге тоже. Дело не в том нужна или не нужна совместимость, а в том что при её использовании Windows закрывает глаза на некоторые вещи, которые при обычном раскладе молча и сурово рубит. Эмулируется множество всяких костылей, часть из которых, возможно, поможет хаку сработать. Т.к. хрен знает из-за чего оно не работает, я и пытаюсь нащупать направление в котором может хоть что-то сдвинется с мёртвой точки.Кстати, у меня «Windows 7». |
Siberian GRemlin |
![]()
Сообщение
#15
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Можешь исполняемый файл игры вместе со всеми необходимыми библиотеками куда-нибудь залить поглядеть (надеюсь это всё не занимает сотни мегабайт)? Вот.Спасибо сказали:
|
-=CHE@TER=- |
![]()
Сообщение
#16
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,355 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 311 раз(а) ![]() |
Ух, ты!
Первый раз вижу .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 |
![]()
Сообщение
#17
|
![]() Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 533 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) ![]() |
Если кому-то интересно, ничего из описанного выше не сработало на данной игре и пришлось русифицировать её грязным способом — заменой системного шрифта. Отмечу, что на нескольких других играх данный метод работает успешно.
Спасибо сказали:
|
![]() ![]() |
Упрощённая версия | Сейчас: 13th May 2024 - 05:13 |