В 2014 году появилась защита от пиратства, которая позже станет одной из самых узнаваемых, — Denuvo. Она пришла на смену SecuROM и связана с одним действующим лицом — Рейнгардом Блауковичем. Пару лет назад я уже писал о том, как я однажды разреверсил SecuROM, разгромив защиту Блауковича в пух и прах. Сегодня я покажу, как проделал то же с Denuvo. Встречай новую серию «Тибериумного реверсинга»!

INFO

Публикуется в память о Крисе Касперски и в поддержку 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 в процедуре отправки запроса;
  • использует константы Origin и игрушки для вставки инструкций cpuid/ret;
  • для отдельных указателей ret (return С++) в процедурах SDK выполняет переход в динамику с дальнейшей обфускацией Denuvo.

Зачем все это? Зачем ей все шелка, цветные облака… зачем?! У нас ведь есть EAH и целая функция инициализации Origin SDK, о которой Denuvo почему-то не знает.

Виталий Кличко устроился работать в Electronic Arts
Виталий Кличко устроился работать в Electronic Arts

Не отстают от 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 так и защищали, что вывело новую породу гибридных протекторов.

Denuvo_Profiler: именно этими данными формируется Denuvo HWID для твоей машины, плюс расшифровка файла лицензии EA Origin и последующее извлечение секретной таблицы Denuvo
Denuvo_Profiler: именно этими данными формируется Denuvo HWID для твоей машины, плюс расшифровка файла лицензии EA Origin и последующее извлечение секретной таблицы Denuvo
 

EA DRM, OEP, dump

Первое, с чем придется столкнуться при взломе и отвязке игрушки от 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]

WWW

Исходники отреверсенных потрохов Origin SDK ищи на exelab.ru.

Здесь сложности могут возникнуть разве что при перехвате управления. Дело тут в том, что игрушку с определенным каналом (/SMOID=%хендл_от_CreateFileMapping%) должен вызывать сам Origin.exe, да еще иногда по нескольку раз. Пока мы будем аттачиться к процессу — пропустим момент выхода на OEP из Activation(64).dll.

Лайфхак прост — сделать подмену библиотеки Activation(64).dll на свою с редиректом вызовов в оригинал. При подхвате управления выводим радостный MessageBox и ожидаем аттача. Прокачаться в этой теме можно в статье «Deleaker, не болей! Ломаем защиту в обход VMProtect и пишем proxy DLL».

 

EA Origin SDK: Give me the handle and I’ll crack this!

Общая стратегия взлома Origin SDK (который инклудится в игрушку) имеет два разных сценария в зависимости от того, что ты хочешь получить в итоге. Первый вариант сложный, очень палевный и приватный. Он требуется для сетевых игр и обеспечивает возможность играть на официальных серверах. Через цепочку OriginGetDefaultUserOriginRequestAuthCode («имя сервера», ex: GOS-BlazeServer-BF4-PC) нужно получить код авторизации, а затем постучать этим AuthCode на сервер. Короче, это тема для отдельной статьи.

Второй вариант гораздо проще. Он пригоден для прохождения одиночных кампаний на локальном компе и никак тебя не запалит в сети. Его мы и рассмотрим подробнее.

Для начала отыщем в коде игрушки процедуру инициализации Origin SDK. Она получает от Origin.exe (в доках он часто называется OriginCore) данные о версии сервера, пользователе и другую подобную инфу, необходимую для дальнейшего запуска игрушки. Если же во время инициализации произойдет ошибка, то процесс попросту завершится, что не входит в наши планы.

Самое главное — эта подпрограмма создает EAH, а всю присланную инфу OriginSDK сливает в эту структуру. Обнаружить код инициализации Origin SDK можно по следующим признакам:

  • использование функции getenv из библиотеки msvcr_xxx.dll (рантайма);
  • появление строк ContentId, EAConnectionId, OriginStartup entered;
  • указание характерных констант ошибок Origin SDK (например, 0xa0020008 ORIGIN_ERROR_CORE_NOT_INSTALLED или 0xa0010000 ORIGIN_ERROR_SDK_NOT_INITIALIZED);
  • работа с «карточкой» игрушки. Это такая специальная структура, код которой приводится ниже:
typedef struct struct_EA_ACCESS_request
{
char* ContentId; // 1031469 (ID контента)
char* Title; // Unravel (название игры)
char* MultiplayerId; // 1031469 (ID пользователя для сетевой игры)
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 

INFO

Адреса EAH:

  • Battlefield 4 (1.8.2.48475) — 0000000142789C80
  • Unravel — 0000000141344680

Внимание, фокус! Делаем заглушку на процедуре инициализации 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 хакнутая игрушка все равно соглашается запуститься. Занавес и выход на бис!

Продолжение доступно только подписчикам

Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.

Подпишись на «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

2 комментария

  1. Аватар

    r0uly

    21.04.2019 at 21:42

    Вот после таких статей понимаешь, что не зря купил подписку на хакер 🙂

  2. Аватар

    r0uly

    21.04.2019 at 21:52

    Понравились забавные сравнения про то как защищать StartForce с помощью SecuROM и про распаковку UPX 😀

Оставить мнение

Check Also

Внутри x86-64 SystemV ABI. Как говорить с ядром Linux на его языке

Абстракция — основа программирования. Многие вещи мы используем, не задумываясь об их внут…