Сейчас на форуме: Magister Yoda, vasilevradislav (+5 невидимых)

 eXeL@B —› Крэки, обсуждения —› Исследование защиты Xamarin Mono/Android
<< . 1 . 2 .
Посл.ответ Сообщение

Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 07 мая 2013 16:23 · Поправил: andrique
· Личное сообщение · #1

В связи с планируемой покупкой смартфона решил научиться писать под Андроид. Давно пишу на C#; хотя до этого еще больше писал на C++, возвращаться к нему неохота, не говоря уже про жабу. Поэтому порадовался, когда нашел сабж.

Я, в общем-то, не противник покупки софта за разумную цену. Купил N-е количество средств разработки, например .NET Reflector -- посчитал сотню долл. приемлемой ценой. Но мандроид стоит немног-немал USD1899 (в топовой конфигурации; за Visual Studio минимум над косарь зеленых отдать)! Жесть... данный заоблачный прайс породил просто-таки компульсивное желание исследовать защиту и узнать, чёш там таког!

Забегая вперед, скажу, что защиту сделали интересно. На этом форуме был вопрос по мандроиду; да и на других сайтах народ активно интересуется. Имеются патчи, обладающие одним существенным недостатком - все они под строго определенную версию, и сделаны просто заменой ассемблерных команд по некоему адресу. Следовательно, при выходе новой версии надо опять искать патч. Кроме того, эти патчи просто делают триальный период до 2050 года. А хочется крякнуть так, чтобы слышно было до самого лицензионного файла ; и чтобы менялись версии, апдейтился софт, а защита так и оставалась исследованной.

На данный момент техническая часть работы выполнена процентов на 65-70, а принципиально - защита изучена. Данный пост [надеюсь, его можно будет редактировать] представляет собой отчет об этом процессе. Не только что было найдено/поменяно, но и как найдено, какие шаги предприняты для этого. Так сказать, некий кейс-стади для новичков. И кстати, хорошо, что нашелся русскоязычный сайт (этот). Писать отчет на английском не хотца - т.к., очевидно, такой отчет могут прочесть и разработчики, и защитить защиту от исследования . А это нежелательно для нас .

Введение (не смеяться!)

Весь продукт состоит из двух частей: Xamarin Android и Xamarin Studio. Первая - это SDK для разработки на C# под Android. Представляет собой плагин для студий (как вижуалки, так и своей, см. ниже). Плагин добавляет несколько новых типов проекта на C# - Андроид. Там несколько вариантов приложений можно создать. Собственно этот плагин и является платным. То есть существует и бесплатная версия, но она очень урезанная. Более полную инфу по редакциям смотрим здесь.

Вторая часть - это полноценная .NET IDE, хотя и не такая навороченная. Надо сказать, это некоторое подслащение горькой пилюли на 2K USD: работает она даже в бесплатном режиме, и может создавать нормальные проекты на C#. Ваш покорный слуга, чтоп проверить это утверждение, тольк чт создал проект консольного приложения, добавил ссылку на один из своих студийных проектов, дернул службу - прога работает, запускается, все ОК.

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

Лицензирование

Оба варианта студии привязываются на сайте Xamarin к учетке, которую над создать. Как именно происходит привязка, я не выяснял, возможно, по айпишнику. Но может и нет, для наших целей это несущественно. Пока вы работаете в Xamarin студии, или пока Вы не запустите явно активацию, плагин работает в бесплатном режиме (Starter). Как только будет открыт проект Андроид в вижуалке, плагин начнет пытаться активироваться, обратившись к веб-службе на сайте. Для активации используются следующие данные: имя, телефон, эл. почта, название компании. Активироваться можно либо в триальном режиме, либо в платном. Триал дает все возможности на месяц, а платный - навсегда, но в рамках оплаченной редакции. После истечения триального месяца, можно либо оплатить и активировать платную лицензию, либо вернуться к бесплатной редакции Starter.

Что где лежит

Файла продукта лежат в следующих местах:

C:\Program Files (x86)\Xamarin Studio\ - ксамарийная студия
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Xamarin\ - плагин для вижуалки
C:\Program Files (x86)\MSBuild\Xamarin\Android\ - мсбилдные таски для сборки андроид-проектов
C:\ProgramData\Mono for Android\License\ - лицуха!

Также продукту нужны следующие зависимости:

Android SDK
JDK
GTK#

которые могут лежать в своих собственных местах.

Общее устройство защиты

Во первых, большая часть сборок не подписана. Хотя подписывание сборок не является препятствием, оно отнимает N-е количество времени на снятие. Не подписали, и на том спасибо.

Основная сборка вижуального плагина (а начал я с него) - Mono.Android.VisualStudio.dll. Быстрая пробежка по рефлекторному коду показала, что при решении вопроса о состоянии активации эта сборка обращается к программе mandroid.exe, которая оказалась... ой! ой!!! -- НЕУПРАВЛЯЕМАЯ! Блин, это нечестно! - я очень расстроился...

В парадигму защиты Xamarin входит: продукт (MonoAndroid), редакция (XamarinEdition) - которая бывает Starter, Indie, Business и Priority, она же Enterprise. Также еще отдельная редакция называется Trial. В последнем случае у нее есть срок действия (expiration).

Итак, сборки просят мандроид дать им нечто под названием Entitlements, то есть "права" - что пользователю положено. Entitlements представляет собой строчку следующего вида:

04e5fd6b801c5914be8d1bb302a4738b28039656
MonoAndroid
Priority
2050-01-01T00:00:00

Четыре строки, разделенные "\n". Первая строка - это хеш, вторая - название продукта, третья - редакция, четвертая - expriation. Формируются эти строчки следующим кодом:

Code:
  1.                         const string product = "MonoAndroid";
  2.                         const string edition = "Priority";
  3.                         const string expiration = "2050-01-01T00:00:00";
  4.  
  5.                         var machineName = Environment.MachineName;
  6.  
  7.                         string secret = product + expiration + edition + machineName + "nlJ2/Tj\fn,Xi(4rVq!A";
  8.                         byte[] bytes = Encoding.UTF8.GetBytes(secret);
  9.                         byte[] buffer = SHA1.Create().ComputeHash(bytes);
  10.  
  11.                         var builder = new StringBuilder(buffer.Length * 2);
  12.                         foreach (byte num in buffer)
  13.                         {
  14.                               builder.Append(num.ToString("x2"));
  15.                         }
  16.  
  17.                         var hash = builder.ToString();
  18.                         var entitlements = string.Format("{0}\n{1}\n{2}\n{3}", hash, product, edition, expiration);
  19.  
  20.                         return entitlements;


Так вот. Получив от мандроида эти самые строчки, компоненты студии их проверяют. В проверку входит много чего, начиная от хеша и кончая проверкой даты файла, в котором хранятся Entitlements. Если проверка проходит, компоненты приступают к работе. Если нет - они просят мандроид произвести повторную активацию. До активации мы еще дойдем. Дальше пошла

Собственно работа

Первой моей идеей было: внести изменения в сборки, чтобы .NET-часть просто не спрашивала неуправляемую прогу ни о чем. На тот момент я еще не знал точно, что это за прога и какая у нее роль.

Изначальный подход был такой. Получить исходники сборок при помощи рефлектора, внести нужные изменения, и снова собрать. Но не тут-то было. Дело в том, что рефлектор выдает код "как есть", то есть не компилящийся на C#. Данная мысль требует пояснения.

Когда мы пишем на C#, допустим, анонимные делегаты или лямбда-выражения, компилятор создает анонимный класс, у него делает метод, и этот метод подставляет туда, где мы используем эту самую лямбду. Все это оттого, что анонимные делегаты и лямбды - это в парадигме C#, а не CLR. Рантайм про это знать не знает.

Идем дальше. Всем известно, что такие символы как '<' '>' '-' и проч. в идентификаторах использовать нельзя. Угу, в идентификаторах C#... Но на ассемблере (IL) - можно. Каковым фактом компилятор радостно и пользуется. Чесн говоря, я не знаю, чем руководствовались разработчики C#, но сделал они так.

Допустим, вы пишите такой код:

Code:
  1.                         var data = new[] {1, 2, 3, 4, 5, 7, 8};
  2.  
  3.                         var filtered = data.Where(=> d%2 == 0);


В этом случае компилятор создаст вот такой метод - статический член класса Program:

Code:
  1. [CompilerGenerated]
  2. private static bool <Main>b__0(int d)
  3. {
  4.     return ((% 2) == 0);
  5. }


Вполне понятно, что C# такое не скомпилит. К сожалению, .NET Reflector вместе со своим плагином FileDisassembler именно такой код и создает. На эту тему я собираюсь создать отдельный топик, т.к. это не дело. Отсутствие надежного инструмента - тревожная ситуация.

Ну, а в сборке размером пол-гигабайта таких мест, понятно, выше крыши. Что же делать? Вариант 1: запастись терпением на пару месяцев, и строчка за строчкой исправлять все каки. Вариант, на самом деле, плохой, т.к. за два месяца они выпустят новую версию и все над будет начинать сначала. Вариант второй: дизассемблировать сборку через ILDASM, и вносить изменения в код на IL. Отличный вариант, в управляемом мире ILDASM генерирует отличный код, который собирается без ошибок, одно только "но": кто у нас свободно пишет на IL? Ха ха.

В результате был выбран вариант промежуточный: сборка разбирается ILDASM'ом, затем на C# пишется код-заглушка, которую надо вставить в сборку. Затем этот код компилится, разбирается ILDASM'ом, и нужный кусок на IL вставляется в код исходной сборки. Таким образом, мы получаем нужное нам изменение (патч), при этом процесс разборки-сборки проходит вполне надежно.

Таким образом, мною были внесены изменения в следующие сборки:

Mono.Android.VisualStudio
Mono.VisualStudio.Extension2
Mono.VisualStudio.Shell
Xamarin.Components.Ide
Xamarin.Android.Build.Tasks

Видимо, мое сообщение превысило какой-то размер, т.к. то, что я пишу дальше, не сохраняется. Продолжение будет в ответных постах.

| Сообщение посчитали полезным: lsreg, Abraham, 4kusNick

Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 12 мая 2013 01:56
· Личное сообщение · #2

Вот имеется следующий код:

Code:
  1. public static License LoadFromBytes(Crypto crypto, byte[] bytes)
  2. {
  3.     if (crypto == null)
  4.     {
  5.         throw new ArgumentNullException("crypto");
  6.     }
  7.     if (bytes == null)
  8.     {
  9.         throw new ArgumentNullException("bytes");
  10.     }
  11.     if (bytes.Length > 0x8000)
  12.     {
  13.         throw new ArgumentException("Buffer is too big", "bytes");
  14.     }
  15.     bytes = crypto.Verify(bytes);
  16.     MemoryStream input = new MemoryStream(bytes);
  17.     input.Position = 60L;
  18.     BinaryReader reader = new BinaryReader(input);
  19.     string str = reader.ReadString();
  20.     string str2 = reader.ReadString();
  21.     string str3 = reader.ReadString();
  22.     int num = reader.ReadInt32();
  23.     if (num > 0x8000)
  24.     {
  25.         throw new Exception("Invalid input");
  26.     }
  27.     MemoryStream output = new MemoryStream();
  28.     BinaryWriter writer = new BinaryWriter(output);
  29.     writer.Write(str);
  30.     writer.Write(str2);
  31.     writer.Write(str3);
  32.     writer.Flush();
  33.     if ((num - 60) != output.Position)
  34.     {
  35.         object[] objArray1 = new object[] { "Invalid input: ", num, " ", output.Position };
  36.         throw new Exception(string.Concat(objArray1));
  37.     }
  38.     output = null;
  39.     int num2 = (((bytes.Length - num) % 2) != 1) ? 0 : 1;
  40.     byte[] dst = new byte[((bytes.Length - num) - 4) - num2];
  41.     Buffer.BlockCopy(bytes, num + 4, dst, 0, dst.Length);
  42.     UserData user = UserData.FromBytes(crypto.DecryptAndVerify(dst));
  43.     if (((user.Name != str) || (user.Email != str2)) || (!string.IsNullOrEmpty(user.Company) && (user.Company != str3)))
  44.     {
  45.         throw new Exception("Invalid input (name, email empty)");
  46.     }
  47.     user.H1 = new byte[20];
  48.     Buffer.BlockCopy(bytes, 0, user.H1, 0, 20);
  49.     user.H2 = new byte[20];
  50.     Buffer.BlockCopy(bytes, 20, user.H2, 0, 20);
  51.     user.H3 = new byte[20];
  52.     Buffer.BlockCopy(bytes, 40, user.H3, 0, 20);
  53.     for (int i = 0; i < 4; i++)
  54.     {
  55.         int dstOffset = i * 5;
  56.         Buffer.BlockCopy(bytes, i * 15, user.H1, dstOffset, 5);
  57.         Buffer.BlockCopy(bytes, (* 15) + 5, user.H2, dstOffset, 5);
  58.         Buffer.BlockCopy(bytes, (* 15) + 10, user.H3, dstOffset, 5);
  59.     }
  60.     return new License(user);
  61. }


Прошу кого-нибудь разобраться: как сделать обратную операцию - из объекта License получить массив байтов, который бы, при подаче на вход указанного выше метода, порождал правильную лицензию.

Да! В сборках, которые хранятся в mandroid-win.exe, неправильность - Mono.Touch.Common ссылается на Mono.Security 2.0.0.0, а сама сборка - 4.0.0.0.

Вот здесь архив с исправленными сборками.

Очень прошу, кто-нибудь, разберитесь! Для этого нужна жопная усидчивость, а у мну ее нет...



Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 12 мая 2013 02:36
· Личное сообщение · #3

Оххх... кажется, здесь не только жопная усидчивость, но и понимание криптографии над... этого у меня точно нет!



Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 12 мая 2013 02:48
· Личное сообщение · #4

Тут я почитал комменты выше и понял, что не имеет смысла рыться в этом коде. Т.к. чтоп зашифровать, над иметь приватный ключ

Но с другой стороны, если мы быстренько найдем формулу N-го простого числа, сможем хакать любую криптографию...




Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 12 мая 2013 09:36
· Личное сообщение · #5

Поздравляю, конечно, и всё такое, но всё же.
Пользуйся кнопкой "Правка", не создавай сообщения подряд.



Ранг: 456.3 (мудрец), 340thx
Активность: 0.280.02
Статус: Участник
Android Reverser

Создано: 12 мая 2013 10:46
· Личное сообщение · #6

Key: Sun RSA public key, 1024 bits
modulus: 105058480234217718053231999449463314753625499531651098244053797170408749153657159900960593477541464800731383856798694470683862822154259702841937499562524641279950673130699715511279934940722904572440244135895955334975629653396328222414248625221832772211969580034028257494655492594202502455937865242537816929851
public exponent: 17

Арчи, такая маленькая экспонента не дает плюсов?

-----
SaNX





Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 12 мая 2013 10:53
· Личное сообщение · #7

Там в основном атаки на наименьшую экспоненту, которая 3. Да и те связаны с тем, что 1 сообщение шлётся нескольким адресатам, после этого можно восстановить открытый текст. Вряд ли такая атака имеет тут применение. Так что сходу профита не вижу.



Ранг: 456.3 (мудрец), 340thx
Активность: 0.280.02
Статус: Участник
Android Reverser

Создано: 12 мая 2013 10:57
· Личное сообщение · #8

Ну я так и думал. Значит, остаеццо забить.

-----
SaNX





Ранг: 748.2 (! !), 390thx
Активность: 0.370
Статус: Участник
bytecode!

Создано: 12 мая 2013 16:30
· Личное сообщение · #9

Я верно понимаю, что все эти изыскания исключительно про андроидную версию, т.к. под iOS на маке надо билдить?

-----
Флэш, ява, дотнет - на завтрак, обед и ужин. Unity3D на закуску.




Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 13 мая 2013 02:41 · Поправил: andrique
· Личное сообщение · #10

4kusNick пишет:
Я верно понимаю, что все эти изыскания исключительно про андроидную версию


О да! Яблоко мну не интересует совсем. Можно канеш заморочиццо, тем более чт механизьм зашыты один итотж. Анад?

4kusNick пишет:
под iOS на маке надо билдить?


нефакт. на вин тоже ставится некий софт ксамарин иос, такчт можт и на пк можн билдеть ))

Вопщем так. Еслинад, пусть ктонить поставит у себя это чудо, и напишет, как проверять сбилденную прогку. Эмулятр иоса какойнить должен быть чтоли? И опишет это здесь в паре предложений кратенько. Потом я так понимаю здешнюю политику - должен быть еще запрос на взлом? И тогда я постараюсь иосу тоже крякнуть.



Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 14 мая 2013 04:51
· Личное сообщение · #11

ATTN коллеги,

Я написал письмо в Xamarin -- сообщил о своем взломе и предложил услуги: консультации по защите продукта. В письме обещал не публиковать кряки.

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



Ранг: 85.4 (постоянный), 51thx
Активность: 0.090
Статус: Участник

Создано: 14 мая 2013 15:02
· Личное сообщение · #12

ну ты это, жди визита, суши сухари, учи сленг



Ранг: 0.9 (гость), 5thx
Активность: 0.010
Статус: Участник

Создано: 14 мая 2013 19:54
· Личное сообщение · #13

drone пишет:
ну ты это, жди визита, суши сухари, учи сленг


Ну сленг я итак знаю . А ни одного закона я не нарушил, включая даже гражданское и административное законодательство!

В ответном письме Xamarin меня поблагодарил за честность и написал, что они в курсе, чт защита слабовата, но рассчитывают на честность людей.

Теперь мне предстоит огорчить их, сообщив, что последнее не распространяется на 1/6 часть суши



Ранг: 85.4 (постоянный), 51thx
Активность: 0.090
Статус: Участник

Создано: 15 мая 2013 16:05
· Личное сообщение · #14

значит они толковые ребята и не стараются, как некоторые, улучшить защиту взамен функционала, а правоверные купят в любом случае



Ранг: 3.4 (гость)
Активность: 0.010
Статус: Участник

Создано: 20 ноября 2013 23:28
· Личное сообщение · #15

Отличный детектив. Автору респект и увага!
Достаточный материал, даже без проектов и сборок, для того чтобы состряпать собственный патч на очередную версию монодроида )

ЗЫ. И самое главное я так и не услышал. monodroid.exe является собственно самим компилятором.


<< . 1 . 2 .
 eXeL@B —› Крэки, обсуждения —› Исследование защиты Xamarin Mono/Android
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати