Steam CEG от Valve и с чем его едят. Все сложное — просто

в 14:48, , рубрики: Steam, valve software, Программирование, реверс-инжиниринг

image

Добрый час, %USERNAME%! В моей предыдущей статье "Steam CEG от Valve и с чем его едят. Введение" было дано лишь абстрактное понимание и принципы работы технологии CEG. В этой статье будет по абсолютному минимуму теории и преобладающее большинство практики. Сегодня и сейчас мы рассмотрим, можно ли «отучить» от этой защиты заветный исполняемый файл.

Шаг I. Выбор «жертвы» и ее анализ

Наличие CEG, причем любой версии, можно легко обнаружить по наличию в заголовке файле секции .version и первых четырех байтов в ней же (78 56 34 12):

image

Заведомо зная эту информацию и немного порыскав в библиотеке Steam, мой выбор пал на HD переиздание легендарной Age of Mythology c приставкой "Extended Edition". После успешного завершения загрузки, подождав пару секунд, пока CEG подпишет исполняемый файл, открываем его в нашем отладчике, в моем случае в x64dbg. Ах да, стоит отметить, что товарищ CEG использует некоторые средства анти-отладки, поэтому будем использовать плагин ScyllaHide со следующими настройками:

image

Итак, открыв исполняемый файл, видим что он не накрыт сторонними упаковщиками, поэтому можем смело переходить ко второму шагу.

Шаг II. Разбор полетов

Абсолютно в любой версии CEG существует одна функция, которая производит общий расчет нужных значений. Выглядит она следующим образом:

image

Зная это, ставим бряк либо на инструкции

mov eax, dword ptr ds:[ecx]
,
либо на следующей:

mov dword ptr ds:[ecx],eax
:

image

Нажимаем "Run" (F9) и видим, что бряк сработал! «И что же это нам дало ?» — спросите Вы, отвечаю: точное значение EAX в буфере. В этом можно убедиться, посмотрев в правую колонку напротив вкладки "CPU":

image

Как видно из изображения, мы получили значение EDB88320. Скопируем его в буфер обмена и пойдем дальше. Нажимаем "Step Over" (F8) два раза и оказываемся внутри одной из функций, используемой CEG. И вот на этом этапе стоит сказать пару слов о существующих видах таких функций. Собственно, всего их может быть три типа:

1. Функции с константным значением (Constant) — возвращают константное значение, которое всегда будет одинаковым. Патчатся как:

mov eax, <значение> ret
;
2. Функции со случайным значением (Random) — возвращают любое целое значение. Патчатся как:

mov eax, <значение> ret
(используются лишь на новейших версиях CEG);
3. Защитные функции (Protect) — являются указателем, которые ведут к истинной функции Патчатся как:

jmp <адрес>
.

Теперь давайте вернемся к нашей игре. Мы внутри желанной функции и у нас в буфере правильное значение. Теперь мы должны определить вид нашей функции. Прокрутив пару инструкций вниз, мы увидим, что используется инструкция

lea eax, dword ptr ds[esi+ebx]
:

image

И это может означать только одно — мы имеем дело с функцией, которая возвращает константное значение. Вообще, следует запомнить, что если в буфере EAX оказываются значения типа: EDB88320, 11, 5, 3f и т.д., то сразу будет понятно, что функция, которая использует это значение — будет константной. Поэтому, двигаемся в самое начало функции и корректируем ее, меняя на

mov eax, EDB88320
ret
:

image

Итак, что же дальше? А дальше мы снова все повторяем (разумеется, имея все тот же бряк на функции, которая вычисляет значения) до тех пор, пока игра не запустится (Profit!), что означает, что мы прошли все проверки CEG. Все ?! Ну давайте посмотрим. Сохраняем файл с проделанными патчами и пробуем запустить на другом ПК (на который уже заведомо была скачана игра). И тут… облом. Игра не хочет запускаться! Ах да, мы забыли про еще одну немаловажную деталь! Дело в том, что CEG, как говорилось в первой статье, использует так называемые файловые проверки. Снова открыв отладчик, мы сможем легко обнаружить эти проверки по наличию характерных функций замечательного WinAPI: GetFileInformationByHandle, CreateFileW, OpenFileById, StringFromGUID2, RegOpenKeyExW, SystemFunction036 и lstrcmpiW. В нашей игре — присутствует только одна такая проверка, найти ее можно сразу вбив GetFileInformationByHandle в поиск "References":

image

Идем в начало и ищем функцию, которая вызывает данную проверку (ПКМ -> Find references -> To Selected Address (es), либо сочетанием клавиш CTRL+R). Будет она выглядеть следующим образом:

image

Ну что же, давайте сделаем это! Хотя это можно сделать и более изощренным способом, но мы поступим проще, используя

mov eax, 1 ret

image

Сохраняем результат проделанной работы и тестируем второй раз и о Боги, игра запустилась на другом аккаунте Steam и на другом ПК!

Шаг III. Полная отвязка игры от Steam (Yarr! Edition)

Разумеется, после полученного удовольствия, захотелось больше экстрима. А что, если я хочу просто поиграть с другом по локалке без всякого там Steam как в бородатые времена? Ну не вопрос. Для этого я скачал отличный эмулятор Steam с частичной поддержкой оверлея (!) под названием SmartSteamEmu. Настроив его, я запустил игру без включенного Steam. И что же я вижу — создался файл *.STEAMSTART и игра повисла в процессах. Подумав около тридцати секунд, игра таки запустилась и работала исправно. Но почему? Мы же все вроде сделали, ведь так? Да, это так, но мы забыли об одном маленьком штрихе. Дело в том, что этот файл события создается, когда процесс Steam не запущен и по сути является последней микро-проверкой. Ну что же, открываем отладчик в третий раз и ищем все функции с CreateFileA. Не стесняясь, ставим бряки на все функции (в данном случае их всего две). При запуске игры бряк сработал:

image

STEAMSTART, мы видим Вас! Итак, для того, чтобы покончить с этим недоразумением, просто меняем верхний JE на JNZ или JMP:

image

Сохраняем патч, снова пробуем запустить игру без Steam скрестив пальцы. И вуаля — игра запустилась в считанные секунды! Мы сделали с тобой это, CEG, ты уж прости нас.

Собственно, вывод

Попавшийся CEG в игре Age of Mythology: Extended Edition был не сложным. В этой игре не было ни Protect, ни Random функций, лишь одни Constant, что значительно упростило задачу. Так же в этой игре не было минорных проверок, в виде старого доброго CRC или новейших проверок ID процессора либо серийного номера жесткого диска.
В будущем, надеюсь, я смогу осилить эти две новые проверки и написать новую статью, а пока — до скорых встреч!

Автор: RESTORATiON

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js