В 2014 году появилась защита от пиратства, которая позже станет одной из самых узнаваемых, — Denuvo. Она пришла на смену SecuROM и связана с одним действующим лицом — Рейнгардом Блауковичем. Пару лет назад я уже писал о том, как я однажды разреверсил SecuROM, разгромив защиту Блауковича в пух и прах. Сегодня я покажу, как проделал то же с Denuvo. Встречай новую серию «Тибериумного реверсинга»!
Публикуется в память о Крисе Касперски и в поддержку Voksi.
Да, эту статью можно было написать и раньше, но в жизни много других важных вещей. Работа в лаборатории, перемещения, моя муза и ее красный Ford Focus II за окном. На его капоте мирно таял свежий снег, когда начинался 2019 год. Мне же в голову начали лезть мысли о корпорации Electronic Arts, магазине Origin, игрушках Unravel и Battlefield 4, реализации EA DRM, Denuvo, VMProtect, и… все завертелось.
Если по Steam в Google можно наяндексить все что угодно — от кастомок до эмуляторов, то в связи с клиентом Origin вспоминается разве что динамическая библиотека ItsAMe_Origin.dll
, которая вместо оригинала сама сабмитит запросы от клиента. Собственно, 100% пабликовых взломов Origin (3DM, CPY и другие) именно так и работают.
Прямо здесь начинается первый секрет: для взлома Origin вовсе не обязательно копировать систему ответов-запросов «клиент-сервер» (чаще всего это около десяти уникальных ID сообщений)! Потребуется чуть-чуть пореверсить клиент и поближе познакомиться с таким термином, как EA handle (далее — EAH). Но обо всем по порядку.
За рекламирование всякой ерунды, непомерные требования к ресурсам и вытекающую отсюда слоупочность официальный пакет Origin не ругает только ленивый, но мы пойдем дальше и покажем его уязвимую суть. На момент написания статьи вышла версия 10.5.31, а разбирать мы будем клиент 9.10.1.7. Принципиальной разницы между ними нет — EAH и там и там одинаков.
На наше счастье, клиент Origin SDK (который запихивается в саму игрушку) имеет много ошибок — как мелких, так и весьма серьезных. Например, при его работе остаются открытые хендлы объектов, для которых SDK почему-то забывает вызывать функции WinAPI RegCloseKey
и CloseHandle
. На это можно было бы закрыть глаза, но вот на вызов адреса с нулевым указателем можно смело сабмитить багрепорты.
Думаю, виной тому откровенная запутанность EAH: перегруженность критическими секциями и семафорами, а также фирменная рекурсия указателей на данные. В такой суматохе запросто можно забыть освободить выделенный блок памяти. Благо процедура уничтожения EAH срабатывает при выходе из игрушки (читай — вызове функции TerminateProcess
), что, по мнению буржуйских разработчиков, автоматом избавляет их от этой проблемы.
Вот теперь минутка лулзов, леди и джентльмены! Сказ о том, как Denuvo Software Solution навешивала anti-tamper уже на саму Origin SDK. Делали они это весьма неумело, так как не курили мануалов и не представляют, что именно требуется защитить от посягательства пиратов. Всю мякотку я вынес в отдельную часть статьи.
К сожалению, в отличие от SecuROM в код Denuvo Блаукович не вставлял анекдотов. Однако если следовать традиции, то здесь была бы уместна история про ковбоя, который на спор обмочил весь бар, но ни разу не попал в бутылку.
Вот что делает защита Origin SDK:
MD5_Update
в процедуре отправки запроса;Зачем все это? Зачем ей все шелка, цветные облака… зачем?! У нас ведь есть EAH и целая функция инициализации Origin SDK, о которой Denuvo почему-то не знает.
Не отстают от Denuvo Software Solution и наши спортсмены-игроделы. Количество контекстов VMProtect достигло сорока для каноничной второй версии и десяти для третьей. Причем сначала они утрамбовали старую вторую, а сверху повесили третью для защиты целостности второй. Это примерно как если StarForce защищать при помощи SecuROM.
Признаться, в первый раз я несколько прифигел, когда автоматом накрыл все сорок контекстов VMP 2.x за один раз. Однако после проследования станции метро OEP (Original Entry Point), ближе к перегону загрузки kit-файлов игрушки Unravel (Unravel _dump_SCY_dump.exe
) тулза Denuvo_Profiler
собственной сборки начала сигнализировать о перезаписи патченных хендлов старого импорта каким-то сторонним кодом. For great justice — последние версии Denuvo так и защищали, что вывело новую породу гибридных протекторов.
Первое, с чем придется столкнуться при взломе и отвязке игрушки от Origin, — это EA DRM. Опознать его легко по точке входа, которая катапультирует нас (jmp) в библиотеку Activation.dll
или Activation64.dll
— смотря какой разрядности винда. Вот как это выглядит у меня:
.ooa:0000000142D46000 public start .ooa:0000000142D46000 start: .ooa:0000000142D46000 nop .ooa:0000000142D46001 jmp cs:Core_Activation64_100
При наличии купленной игрушки в библиотеке EA DRM снимается не сложнее, чем распаковывается UPX. Вся процедура сводится к тому, что SDK получает AES-ключик для расшифровки контента. Если ключ верный, то дальше SDK сам восстанавливает секции и делает импорт. Дальнейший переход в OEP защищаемой EA игрушки обычно выполняется ближе к концу вызываемой процедуры (в моем примере это call r9
по адресу 000007FEF1687412), либо перед этим вызывается функция GetModuleHandleW
.
000007FEF16873E4 call qword ptr ds:[<&GetModuleHandleW>] 000007FEF16873EA lea rcx,qword ptr ss:[rbp+0x10] 000007FEF16873EE mov rsi,rax 000007FEF16873F1 call <activation64_original.Verify_and_GetModuleHalde> 000007FEF16873F6 mov rbx,rax 000007FEF16873F9 test rax,rax 000007FEF16873FC je activation64_original.7FEF168741B 000007FEF16873FE nop 000007FEF1687400 mov r9,qword ptr ds:[rbx] 000007FEF1687403 test r9,r9 000007FEF1687406 je activation64_original.7FEF168741B 000007FEF1687408 xor r8d,r8d 000007FEF168740B mov rcx,rsi 000007FEF168740E lea edx,dword ptr ds:[r8+0x1] 000007FEF1687412 call r9 000007FEF1687415 add rbx,0x8 000007FEF1687419 jne activation64_original.7FEF1687400 000007FEF168741B call rdi 000007FEF168741D lea rcx,qword ptr ss:[rbp+0x6A0]
Исходники отреверсенных потрохов Origin SDK ищи на exelab.ru.
Здесь сложности могут возникнуть разве что при перехвате управления. Дело в том, что игрушку с определенным каналом (/SMOID= %хендл от CreateFileMapping%
) должен вызывать сам Origin.exe
, да еще иногда по нескольку раз. Пока мы будем аттачиться к процессу — пропустим момент выхода на OEP из Activation(64).dll
.
Лайфхак прост — сделать подмену библиотеки Activation(64).dll на свою с редиректом вызовов в оригинал. При подхвате управления выводим радостный MessageBox
и ожидаем аттача. Прокачаться в этой теме можно в статье «Deleaker, не болей! Ломаем защиту в обход VMProtect и пишем proxy DLL».
Общая стратегия взлома Origin SDK (который инклудится в игрушку) имеет два разных сценария в зависимости от того, что ты хочешь получить в итоге. Первый вариант сложный, очень палевный и приватный. Он требуется для сетевых игр и обеспечивает возможность играть на официальных серверах. Через цепочку OriginGetDefaultUser() — OriginRequestAuthCode ("имя сервера", ex: GOS-BlazeServer-BF4-PC)
, нужно получить код авторизации, а затем постучать этим AuthCode на сервер. Короче, это тема для отдельной статьи.
Второй вариант гораздо проще. Он пригоден для прохождения одиночных кампаний на локальном компе и никак тебя не запалит в сети. Его мы и рассмотрим подробнее.
Для начала отыщем в коде игрушки процедуру инициализации Origin SDK. Она получает от Origin.exe (в доках он часто называется OriginCore) данные о версии сервера, пользователе и другую подобную инфу, необходимую для дальнейшего запуска игрушки. Если же во время инициализации произойдет ошибка, то процесс попросту завершится, что не входит в наши планы.
Самое главное — эта подпрограмма создает EAH, а всю присланную инфу OriginSDK сливает в эту структуру. Обнаружить код инициализации Origin SDK можно по следующим признакам:
getenv
из библиотеки msvcr_xxx.dll
(рантайма);ContentId
, EAConnectionId
, OriginStartup entered
;typedef struct struct_EA_ACCESS_request { char* ContentId; // 1031469 (идентификатор контента) char* Title; // Unravel (название игры) char* MultiplayerId; // 1031469 (идентификатор пользователя для сетевой игры) char* Language; // en_US } EA_ACCESS_request, *pEA_ACCESS_request; // Идентификационная карточка приложения
К примеру, в последней на момент написания статьи версии Battlefield 4 (1.8.2.48475) вход в процедуру инициализации Origin SDK выглядел так:
0000000140DDB59B call <bf4_dump_scy.sub_140DDD1D0> 0000000140DDB5A0 lea rcx,qword ptr ss:[rsp+0x38] 0000000140DDB5A5 call <bf4_dump_scy.origin_startup> // А вот и вход! 0000000140DDB5AA movzx eax,al 0000000140DDB5AD test eax,eax 0000000140DDB5AF jne bf4_dump_scy.140DDB5B8 0000000140DDB5B1 xor al,al 0000000140DDB5B3 jmp bf4_dump_scy.140DDB669
В Unravel он выглядел так:
00000001416EBC2D lea rcx,qword ptr ss:[rsp+0x30] 00000001416EBC32 call <unravel_dump_scy.sub_1417A5B80> 00000001416EBC37 call <unravel_dump_scy.origin_startup>// Вход! 00000001416EBC3C test al,al 00000001416EBC3E jne <unravel_dump_scy.loc_1416EBC50> 00000001416EBC40 mov eax,0xC346A20F 00000001416EBC45 lea eax,dword ptr ds:[rax+0x3CB95E01] 00000001416EBC4B jmp <unravel_dump_scy.loc_1416EBDA4>
Во всех случаях бенефициантом является EAH, который при вызове этих процедур воплотится в куче (heap) как структура размером 968 байт (mov ecx, 0x3C8
).
Материализовавшись, EAH послужит тем Солсберийским шпилем, возле которого будет виться остальной OriginSDK. Нельзя пройти мимо сигнатурного обращения к ней — сначала OriginSDK интересуется: «А не ноль ли там?» Если нет, то только тогда тащит оттуда значение:
0000000140DE30D0 xor eax,eax is_EAH_init 0000000140DE30D2 cmp qword ptr ds:[<EAH>],rax 0000000140DE30D9 setne al // setne = Set if Not Equal. Эта инструкция как раз устанавливает байт в указанном операнде в значение 1, если нулевой флаг был очищен 0000000140DE30DC ret 0000000140DE3DB0 mov rax,qword ptr ds:[<EAH>] get_EAH 0000000140DE3DB7 ret
Адреса EAH:
Внимание, фокус! Делаем заглушку на процедуре инициализации EAH (mov eax, 1 & ret
), запускаем и видим, что логи отладчика заспамлены гневными сообщениями: «Origin Error: update fail The Origin SDK was not running». Это как раз происходит из-за того, что теперь EAH равен нулю и перестало выполняться ключевое условие — флаг готовности сетевого соединения в его дочерней структуре WSA_socket
не взведен:
0000000141989FD0 cmp qword ptr ds:[rcx+50],FFFFFFFFFFFFFFFF is_connection_established 0000000141989FD5 setne al 0000000141989FD8 ret
Кажется, у нас проблемы? Вовсе нет! Юмор в том, что это отнюдь не препятствие: после тщетных попыток связаться со своими из OriginCore хакнутая игрушка все равно соглашается запуститься. Занавес и выход на бис!
Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.
Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке
1 год7490 р. Экономия 1400 рублей! |
1 месяц720 р. 25-30 статей в месяц |
Уже подписан?
Читайте также
Последние новости