Сейчас на форуме: 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

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

Создано: 07 мая 2013 16:32
· Личное сообщение · #2

Не надо на этом тормознутом говне писать

-----
SaNX


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

Ранг: 419.0 (мудрец), 647thx
Активность: 0.460.51
Статус: Участник
"Тибериумный реверсинг"

Создано: 07 мая 2013 16:33
· Личное сообщение · #3

andrique пишет:
Продолжение следует, ожидайте...

Запасаемся попкорном.




Ранг: 500.6 (!), 7thx
Активность: 0.260
Статус: Участник

Создано: 07 мая 2013 18:04
· Личное сообщение · #4

SaNX пишет:
Не надо на этом тормознутом говне писать


а что посоветуешь ?



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

Создано: 07 мая 2013 18:13 · Поправил: SaNX
· Личное сообщение · #5

жаба+НДК или просто жаба.
Дабы убедиться в тормознутости сего чуда предлагаю поставить http://4pda.ru/forum/showtopic=335952 на мобилу.

Я его юзал недельку. Запуск идет секунд 15, во время работы наблюдаются тормоза.
Перешел на чисто жабовскую anMoney - запуск секунда, причем в анмани бОльший функционал.

Как то я ставил себе моно для пробы. Написал хелло ворлд. Запускалось секунд 5, размер апк был весьма огромным. Снес нахер, пишу на жабе.

-----
SaNX




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

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

Ммм... я пока реально не кодил на мандроиде, за исключением Hello World для целей лома защиты. Но вот здесь пишут, что очень даже быстрее жабы работает!

Эх, пока сам не протестишь, не поймёшь... Сам по себе эмулятор из Android SDK работает ПИИПЕЕЦ как медленно!!! Дней через 10 возьму себе Galaxy Note 2, вот тогда и сделаю выводы...

В жабу не верю. Структур, говорят, даже нет!

А кстати, где написано, что CoinKeeper написан на мандроиде?



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

Создано: 07 мая 2013 19:20 · Поправил: SaNX
· Личное сообщение · #7

andrique пишет:
CoinKeeper написан на мандроиде?

апк открой винраром, увидишь библы

andrique пишет:
Но вот здесь пишут, что очень даже быстрее жабы работает!

нуда, статья аффтаров сего чуда. как же у них могло быть иначе?

-----
SaNX




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

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

Сделав это, я уже радостно плясал и праздновал победу, пока не увидел в выводе отлаживаемой программы слова о том, что Xamarin/Mandroid работает в триальном режиме. Тут я здорово взбесился. Думаю, коллегам чувства мои будут понятны. Было очень жалко, что сделанная работа прошла впустую. На самом деле, если публика захочет, я могу выложить пропатченные исходники на IL, но пока у меня нет уверенности, что они вообще понадобятся в окончательном варианте.

Перехват мандроида

На следующем этапе я решил разобраться, что то собственно, за зверь mandroid.exe. Т.к. это неуправляемая прога, исходного кода от него нет и получить не получается . Тогда я пошел таким путем. Я сделал программу-перехватчик. Переименовал mandroid.exe в mandroid-xamarin.exe, сделал программу под названием mandroid.exe и положил ее в папку C:\Program Files (x86)\MSBuild\Xamarin\Android. Таким образом, компоненты студии звали мою программу, а она вызывала сам мандроид, по пути записывая в лог-файл весь обмен данными. Подробно описывать здесь все это я не буду, т.к. выкладываю проект программы-перехватчика.

Собственно, как компоненты студии вызывают мандроид. Примерно так:

Code:
  1.                         //
  2.                         //    Make up command-line params
  3.                         //
  4.                         var argumentString = string.Join(" ", arguments.Select(=> string.Format(""{0}"", a)));
  5.  
  6.                         var directory = Environment.CurrentDirectory;
  7.                         //    @"C:\usr\dev\unlicense\xamarin\trunk\msbuild"; //
  8.  
  9.                         var path = Path.Combine(_msbuildDirectory, EXE_NAME);
  10.  
  11.                         //
  12.                         //    How to launch the daemon
  13.                         //
  14.                         var info = new ProcessStartInfo(path, argumentString)
  15.                         {
  16.                               RedirectStandardInput = true,
  17.                               RedirectStandardOutput = true,
  18.                               RedirectStandardError = true,
  19.                               UseShellExecute = false,
  20.                               WorkingDirectory = directory
  21.                         };
  22.  
  23.                         //
  24.                         //    Prepare process
  25.                         //
  26.                         var process = new Process
  27.                         {
  28.                               StartInfo = info,
  29.                               EnableRaisingEvents = true,
  30.                         };
  31.  
  32.                         //
  33.                         //    Subscribe to process output
  34.                         //
  35.                         process.OutputDataReceived += OnStdOutData;
  36.                         process.ErrorDataReceived += OnStdErrData;
  37.  
  38.                         try
  39.                         {
  40.                               WriteLineWithTime("mandroid.exe is being called with command line: {0}", argumentString);
  41.  
  42.                               //
  43.                               //   Start mandroid.exe
  44.                               //
  45.                               process.Start();
  46.  
  47.                               WriteLineWithTime("{0} has started", EXE_NAME);
  48.  
  49.                               //
  50.                               //   Initiate reading mandroid.exe's standard outputs
  51.                               //
  52.                               process.BeginOutputReadLine();
  53.                               process.BeginErrorReadLine();
  54.  
  55.                               string @in;
  56.  
  57.                               //
  58.                               //   Read standard input
  59.                               //
  60.                               while (null != (@in = Console.In.ReadLine()))
  61.                               {
  62.                                    WriteLineWithTime("stdin: '{0}'", @in);
  63.                                    //
  64.                                    //  And route data to mandroid.exe
  65.                                    //
  66.                                    process.StandardInput.WriteLine(@in);
  67.                               }
  68.  
  69.                               WriteLineWithTime("stdin: <eof>");
  70.                               process.StandardInput.Close();
  71.  
  72.                               process.WaitForExit();
  73.  
  74.                               WriteLineWithTime("{0} exit code is {1}.", EXE_NAME, process.ExitCode);
  75.  
  76.                               return process.ExitCode;
  77.                         }
  78.                         catch (Exception x)
  79.                         {
  80.                               WriteLineWithTime("Error: {0}", x.Message);
  81.                               return 1;
  82.                         }


Данный код - это мой, но он сделан по подобию оригинального. Итак, компоненты студии запускают мандроид, перехватывают стандартный ввод, вывод и поток ошибок, пихают в stdin команды и читают stdout и stderr. Моя мысль была в том, чтобы вмешаться в этот процесс, отдавать студии мои собственные Entitlements, команды на активацию игнорировать и говорить, что все хорошо - то есть возвращать код 0. Так я и сделал. Опять студия была счастлива, НО! при сборке моего проекта mandroid-xamarin пожаловался на фатальную ошибку. Я понял, что родной mandroid.exe в процессе сборки проверяет, сука, лицензию. И никак это не обойдешь, пока не взломаешь собственно мандроид.



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

Создано: 10 мая 2013 18:00 · Поправил: SaNX
· Личное сообщение · #9

А не проще сделать поиск по сигнатурам и патчить, как патчили на хабре (ну или где там)? Я, когда заморочился, быстро нашел нужные места и пропатчил.

-----
SaNX




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

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

Пришлось так и сделать.

Взлом mandroid.exe

Т.к. эта сволочь неуправляемая, я стал думать, что бы такое предпринять. Начал с ИДЫ, но она сделала мне файл на ассемблере в миллион (!) строк. Ясно, что с этим разбираться не надо даже пытаться...

Дальше я начал тусить на форумах, и вскоре обнаружил, что мандроид запускает некую еще программу mandroid-win.exe, которая, дескать, все и делает. И что она - УПРАВЛЯЕМАЯ!!! Мой энтузиазм увеличился, и я начал разбираться. Я задумался. Процесс монитор ничего такого не показывал, отсюда вывод: он запускает сборки прямо из памяти. Запускает рантайм, создает домен приложения, грузит туда сборки, и вперед.

Дальше моя мысль была следующая. Если неуправляемая программа запускает управляемую, налицо желание разработчиков писать все на .NET. Можно сделать вывод, что роль mandroid.exe и состоит в том, чтобы скрытно запустить управляемую прогу. То есть он, козел такой, есть простой запускатор. Значит, если получится вытащить управляемую часть, можно таким образом добраться до самого сердца защиты.

ОК, в теле mandroid.exe ничего похожего на сборки не видно. Ага, дальше я выяснил, что программа-то запакована!!! Попробовал искать распаковщики, но ничего не нашел. Все они сообщали, что прога запакована не ими. В конце концов интуитивно я нашел выход.

Я нашел отладчик OllyDbg. Очень здоровская штука. Когда я запустил мандроид под этим отладчиком, он отработал, но Олли не выключила все, как это делает студия, а просто остановилась где-то в недрах системы. Выглядело это так:





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

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

Дальше я нашел окно Memory. Оно, ни много ни мало, показывает всё виртуальное пространство процесса. Все сегменты памяти, все загруженные системные DLL. И я стал рыться в этой памяти. На мое - нет, наше! счастье разработчики не додумались очищать память перед завершением процесса. Очевидно, они не предположили, что кто-то зайдет так далеко.

Ребята, это наш большой секрет. Надо, чтобы они и не узнали. НЕ БОЛТАЙТЕ!!!

Итак, я начал искать в памяти сигнатуры EXE и DLL файлов - знаменитые MZ. И нашел, представьте мою радость!!! Что я сделал дальше? Я сохранил на диск все сегменты памяти, в которых находились эти сигнатуры. Олли позволяет это делать, и выглядит это вот так:



То есть, ясное дело, каким бы упаковщиком не был запакован мандроид, при запуске он распаковывается в памяти, и все становится доступным и беззащитным.

Дальше, я написал прогу, которая вытаскивает из дампов сегментов памяти находящиеся там исполняемые образы. Опять, много писать здесь не буду, т.к. выкладываю проект экстрактора.

В этих дампов памяти очень много чего нашлось, в том числе 76 (!) системных DLL типа user32, kernel32 и проч проч проч! Они, кстати, 64-битные, и ни чем не открываются. Найденные DLL я сохранял на диск, и проверял, не управляемые ли они. Проверял так: создавал домен приложения, и пытался грузить туда сборки. Заметьте: грузил "для отражения", это режим позволяет загрузить сборку и не учитывать зависимости. Иначе не загрузились бы. Код в студию :

Code:
  1.                  /// <summary>
  2.                  /// Сохраняет найденные исполняемые образы на диск.
  3.                  /// </summary>
  4.                  public ExtractionAgent()
  5.                  {
  6.                         var cd = AppDomain.CurrentDomain;
  7.  
  8.                         //
  9.                         //    Получаем объект-параметр, переданный в домен приложения.
  10.                         //
  11.                         var tasking = cd.GetData(typeof (ExtractionTasking).FullName) as ExtractionTasking;
  12.  
  13.                         if (null != tasking)
  14.                         {
  15.                               var segmentName = Path.GetFileNameWithoutExtension(tasking.SegmentFile);
  16.  
  17.                               Debug.Assert(null != segmentName); // гарантированно true т.к. иначе файл сегмента не был бы открыт.
  18.  
  19.                               var workingDirectory = Path.Combine(Path.GetDirectoryName(tasking.SegmentFile) ?? ".", segmentName) + ".images";
  20.  
  21.                               Directory.CreateDirectory(workingDirectory);
  22.  
  23.                               var numPEs = tasking.Extractables.Length;
  24.  
  25.                               for (int i = 0; i < numPEs; i++)
  26.                               {
  27.                                    var exe = tasking.Extractables[i];
  28.                                    //
  29.                                    //  Формируем имя образа по умолчанию.
  30.                                    //
  31.                                    exe.Name = (1 == numPEs) ? tasking.OutputName : string.Format("{0}-{1}", segmentName, i) + ".dll";
  32.  
  33.                                    //
  34.                                    //  Получаем исполняемый образ как отдельный массив.
  35.                                    //
  36.                                    var assemblyBuffer = tasking.Buffer.Skip(exe.Offset).Take(exe.Length).ToArray();
  37.  
  38.                                    var moduleType = "native image";
  39.  
  40.                                    //
  41.                                    //  Дальше пробуем загрузить образ как .NET-сборку.
  42.                                    //
  43.                                    try
  44.                                    {
  45.                                        exe.Assembly = Assembly.ReflectionOnlyLoad(assemblyBuffer);
  46.  
  47.                                        //
  48.                                        // Если сборка загружена, получаем истинное имя.
  49.                                        //
  50.                                        exe.Name = exe.Assembly.ManifestModule.ScopeName;
  51.                                        moduleType = ".NET module";
  52.  
  53.                                        //
  54.                                        // Стандартные сборки библиотеки .NET пропускаем.
  55.                                        //
  56.                                        if (exe.Name.StartsWith("System") || exe.Name.StartsWith("Microsoft"))
  57.                                        {
  58.                                           Console.WriteLine("\tSkipping FCL module '{0}' [offset: {1:X} length: {2}]", exe.Name, exe.Offset, exe.Length);
  59.                                           continue;
  60.                                        }
  61.                                    }
  62.                                    //
  63.                                    //  Давим исключение при попытке загрузить не-.NET сборку.
  64.                                    //
  65.                                    catch (BadImageFormatException) {}
  66.  
  67.                                    Console.WriteLine("\tSaving '{0}' as {1} [offset: {2:X} length: {3}]", exe.Name, moduleType, exe.Offset, exe.Length);
  68.  
  69.                                    var target = Path.Combine(workingDirectory, exe.Name);
  70.  
  71.                                    //
  72.                                    //  Записываем исполняемый образ в файл.
  73.                                    //
  74.                                    using (var writer = new BinaryWriter(File.Open(target, FileMode.Create, FileAccess.Write)))
  75.                                    {
  76.                                        writer.Write(assemblyBuffer);
  77.                                    }
  78.                               }
  79.                         }
  80.                  }


И что же? Если сборка загрузилась в домен как управляемая, значит, мне доступно ее имя. Ура, с таким именем я ее и сохраняю, как видно из кода. Да, для каждого сегмента (файл с расширением .MEM) я создавал отдельную папку, и складывал туда найденные сборки. И вот, в одной из папок нашлись такие сборки:

I18N.dll
I18N.West.dll
Ionic.Zip.dll
mandroid-win.exe
Mono.Cecil.dll
Mono.Cecil.Mdb.dll
Mono.Data.Sqlite.dll
Mono.Data.Tds.dll
Mono.Posix.dll
Mono.Security.dll
Mono.Touch.Client.dll
Mono.Touch.Common.dll
Mono.Web.dll

То есть, сцкнх, вся президентская рать!




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

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

Мандроид вроде тут разобрали уже: https://ssl.exelab.ru/f/action=vthread&forum=5&topic=19810&page=0

Или речь о разных вещах?

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




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

Создано: 10 мая 2013 18:41
· Личное сообщение · #13

4kusNick пишет:

Мандроид вроде тут разобрали уже: https://ssl.exelab.ru/f/action=vthread&forum=5&topic=19810&page=0

Или речь о разных вещах?


Об этом, да, но результата-то нет..

Ну уже скоро подхожу к концу.



Ранг: 34.1 (посетитель), 118thx
Активность: 0.040.01
Статус: Участник

Создано: 10 мая 2013 18:50
· Личное сообщение · #14

Эмм... Сдампить сборки можно было, допустим, MegaDumper'ом от SnD...



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

Создано: 10 мая 2013 19:09
· Личное сообщение · #15

nick8606 пишет:
Эмм... Сдампить сборки можно было, допустим, MegaDumper'ом от SnD...


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



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

Создано: 10 мая 2013 19:37
· Личное сообщение · #16

Ну поехали дальше. Моё предположение было в том, что если mandroid.exe запускает mandroid-win.exe, то mandroid-win.exe использует такие же команды, что и mandroid-win.exe, и общается с ним так же, через stdin, stdout, stderr.

Надо сказать, что мое предположение подтвердилось. Я скопировал его в папку C:\Program Files (x86)\MSBuild\Xamarin\Android\, переименовал в mandroid-xamarin.exe, и положил свой прокси-проект, чтобы мониторить обмен командами. Получилось, при сборке, вот что:

10.05.2013 19:09:15 mandroid.exe is being called with command line: "-d"
10.05.2013 19:09:15 mandroid-xamarin.exe has started
10.05.2013 19:09:15 stdout: 'OK Ready'
10.05.2013 19:09:15 stdin: 'edition'
10.05.2013 19:09:15 stderr: 'monodroid: error XA9999: Invalid license. Please reactivate Xamarin.Android'
10.05.2013 19:09:15 stdout: 'OK Completed'
10.05.2013 19:09:15 stdin: 'edition'
10.05.2013 19:09:15 stderr: 'monodroid: error XA9999: Invalid license. Please reactivate Xamarin.Android'
10.05.2013 19:09:15 stdout: 'OK Completed'

Вот сейчас я нахожусь на этом этапе. Для желающих поиграть со сборочками вот они.



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

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

Дальнейшие действия. В mandroid-win.exe есть класс Xamarin.Licensing.PlatformActivation, который, видимо, все и делает. Для начала я намереваюсь внести в ассемблерный (IL) код изменения - все модификаторы доступа заменить на public! Ха ха!. Напишу прогу, добавлю ссылку на сборку mandroid-win.exe, и буду вызывать метода этого класса, смотреть что он делает, придется отлаживать ассемблерный код, ну ничего, разберусь. Превратить его в код на C# не получится, по указанным выше причинам .

Для студии есть приблуда, чтобы смотреть содержимое стека, и проч, проч. У меня она есть, но не помню как называется. Если кто вспомнит, напишите, а то у меня куча софта и искать заипёшьсё. Дальше - написать класс, эмулирующий Xamarin.Licensing.PlatformActivation, с заглушками вместо реального кода. Типа, активация прошла, все свои.

Вторая идея заключается в том, чтобы, используя методы Xamarin.Licensing.PlatformActivation, сгенерить правильную лицуху и Entitlements, чтобы даже честный мандроид считал чт все ОК, и работал, работал... То есть, сделать, по типу, кейген.

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

Итак, план - сделать кейген. Это будет достойный ответ на сволочную цену в две тысячи баков. ВПЕРЕД!



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

Создано: 10 мая 2013 21:32
· Личное сообщение · #18

Выкладывай Mono.Security.dll, ставить все это говно не охото.

-----
SaNX




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

Создано: 10 мая 2013 23:48
· Личное сообщение · #19

SaNX пишет:
Выкладывай Mono.Security.dll, ставить все это говно не охото.


Ну я же уже выложил, смотри текст выше "Для желающих поиграть со сборочками" и дальше сразу линк на архив!



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

Создано: 11 мая 2013 00:07 · Поправил: SaNX
· Личное сообщение · #20

Ну, кейгена не выйдет, там RSA, паблик грузится из сертификата (ищи где-то в дистрибе) и проверяется подпись+хеши для
Code:
  1. public static void VerifyLicense()
  2. {
  3.     License license = null;
  4.     if (File.Exists(TrialPath))
  5.     {
  6.         license = LoadLicense(TrialPath);
  7.         if (!IsTrial(license.UserData.ProductId))
  8.         {
  9.             object[] args = new object[] { "Xamarin.Android" };
  10.             Diagnostic.Error(0x233c, "Invalid license. Please reactivate {0}.", args);
  11.         }
  12.         level = LicenseType.Trial;
  13.         expires = license.UserData.ExpirationDate;
  14.         if (expires < DateTime.Now)
  15.         {
  16.             Diagnostic.Error(0x2329, "Trial period has expired.", new object[0]);
  17.         }
  18.     }
  19.     else if (File.Exists(LicensePath))
  20.     {
  21.         license = LoadLicense(LicensePath);
  22.         if (license.UserData.ProductId == ProductId.None)
  23.         {
  24.             level = LicenseType.Priority;
  25.             license.UserData.ProductVersion = 0;
  26.             DateTime time = new DateTime(0x7dd, 7, 20);
  27.             if (license.UserData.ExpirationDate > time)
  28.             {
  29.                 license.UserData.ExpirationDate = time;
  30.             }
  31.         }
  32.         else if (IsTrial(license.UserData.ProductId))
  33.         {
  34.             object[] objArray2 = new object[] { "Xamarin.Android" };
  35.             Diagnostic.Error(0x233a, "Invalid license. Please reactivate {0}.", objArray2);
  36.         }
  37.         else
  38.         {
  39.             level = GetLicenseType(license.UserData.ProductId);
  40.             if (level == LicenseType.None)
  41.             {
  42.                 object[] objArray3 = new object[] { (int) license.UserData.ProductId };
  43.                 Diagnostic.Error(0x2332, "License type could not be verified ({0}). Please contact support@xamarin.com", objArray3);
  44.             }
  45.         }
  46.         expires = license.UserData.ExpirationDate;
  47.         if (expires.Ticks < BuildStamp)
  48.         {
  49.             object[] objArray4 = new object[] { expires };
  50.             Diagnostic.Error(0x2328, "This version was released after your subscription expired ({0}).", objArray4);
  51.         }
  52.     }
  53.     else
  54.     {
  55.         level = LicenseType.Starter;
  56.         if (StarterCutoffDate < DateTime.UtcNow)
  57.         {
  58.             Diagnostic.Error(0x233b, "Please contact support to receive an update. Thanks!", new object[0]);
  59.         }
  60.     }
  61.     if (license != null)
  62.     {
  63.         bool flag = false;
  64.         string str = WinNetworkInterfaces.B();
  65.         foreach (string str2 in WinNetworkInterfaces.A())
  66.         {
  67.             if (CheckHashes(license, str, str2))
  68.             {
  69.                 flag = true;
  70.                 break;
  71.             }
  72.         }
  73.         if (!flag)
  74.         {
  75.             Diagnostic.Error(0x233d, "Invalid license. Please reactivate Xamarin.Android", new object[0]);
  76.         }
  77.         if (license.UserData.ProductVersion < 0)
  78.         {
  79.             Diagnostic.Error(0x233f, "Invalid license. Please reactivate Xamarin.Android", new object[0]);
  80.         }
  81.     }
  82. }
  83.  
  84.  
  85. internal static string B()
  86. {
  87.     int num;
  88.     UnsafeNativeMethods.GetVolumeInformation(@"C:", IntPtr.Zero, 0, out num, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0);
  89.     return string.Format("{0:x}", num);
  90. }
  91.  
  92.  
  93. internal static string[] A()
  94. {
  95.     List<WinNetworkInterfaceInfo> networkInterfaces = GetNetworkInterfaces();
  96.     if (<>f__am$cache0 == null)
  97.     {
  98.         <>f__am$cache0 = t => t.Description.IndexOf("usb", StringComparison.OrdinalIgnoreCase) >= 0;
  99.     }
  100.     List<WinNetworkInterfaceInfo> second = Extract<WinNetworkInterfaceInfo>(networkInterfaces, <>f__am$cache0);
  101.     if (<>f__am$cache1 == null)
  102.     {
  103.         <>f__am$cache1 = t => t.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0;
  104.     }
  105.     List<WinNetworkInterfaceInfo> list3 = Extract<WinNetworkInterfaceInfo>(networkInterfaces, <>f__am$cache1);
  106.     if (<>f__am$cache2 == null)
  107.     {
  108.         <>f__am$cache2 = t => t.FriendlyName.IndexOf("local", StringComparison.OrdinalIgnoreCase) >= 0;
  109.     }
  110.     List<WinNetworkInterfaceInfo> first = Extract<WinNetworkInterfaceInfo>(networkInterfaces, <>f__am$cache2);
  111.     if (<>f__am$cache3 == null)
  112.     {
  113.         <>f__am$cache3 = t => t.FriendlyName.IndexOf("wireless", StringComparison.OrdinalIgnoreCase) >= 0;
  114.     }
  115.     List<WinNetworkInterfaceInfo> list5 = Extract<WinNetworkInterfaceInfo>(networkInterfaces, <>f__am$cache3);
  116.     if (<>f__am$cache4 == null)
  117.     {
  118.         <>f__am$cache4 = t => (t.Description.IndexOf("bluetooth", StringComparison.OrdinalIgnoreCase) >= 0) || (t.FriendlyName.IndexOf("bluetooth", StringComparison.OrdinalIgnoreCase) >= 0);
  119.     }
  120.     List<WinNetworkInterfaceInfo> list6 = Extract<WinNetworkInterfaceInfo>(networkInterfaces, <>f__am$cache4);
  121.     List<WinNetworkInterfaceInfo> list7 = networkInterfaces;
  122.     if (<>f__am$cache5 == null)
  123.     {
  124.         <>f__am$cache5 = t => t.MacAddress;
  125.     }
  126.     return first.Concat<WinNetworkInterfaceInfo>(list7).Concat<WinNetworkInterfaceInfo>(list5).Concat<WinNetworkInterfaceInfo>(list6).Concat<WinNetworkInterfaceInfo>(second).Concat<WinNetworkInterfaceInfo>(list3).Select<WinNetworkInterfaceInfo, string>(<>f__am$cache5).ToArray<string>();
  127. }
  128.  
  129.  
  130.  


Code:
  1. public class License
  2. {
  3.     // Fields
  4.     private const int HASHES_LENGTH = 60;
  5.     private UserData user_data;
  6.  
  7.     // Methods
  8.     private License(UserData user);
  9.     public static License LoadFromBytes(Crypto crypto, byte[] bytes);
  10.     public static License LoadFromFile(Crypto crypto, string filename);
  11.  
  12.     // Properties
  13.     public UserData UserData { get; }
  14. }


Code:
  1. public class UserData
  2. {
  3.     // Fields
  4.     public string Field1;
  5.     public string Field2;
  6.     public byte[] H1;
  7.     public byte[] H2;
  8.     public byte[] H3;
  9.  
  10.     // Methods
  11.     public UserData();
  12.     public UserData(UserData from, bool keep_extras);
  13.     public void Deserialize(byte[] bytes);
  14.     public static UserData FromBytes(byte[] bytes);
  15.     public byte[] Serialize();
  16.     public static byte[] ToBytes(UserData user_data);
  17.     public override string ToString();
  18.  
  19.     // Properties
  20.     public string ActivationCode { get; set; }
  21.     public string Company { get; set; }
  22.     public string DataFile { get; set; }
  23.     public string Email { get; set; }
  24.     public DateTime ExpirationDate { get; set; }
  25.     public string Name { get; set; }
  26.     public string Opaque { get; set; }
  27.     public string Phone { get; set; }
  28.     public ProductId ProductId { get; set; }
  29.     public int ProductVersion { get; set; }
  30.     public string UpgradeCode { get; set; }
  31. }

Хотя, если подменить сертификат, можно генерить ключи

юзердата пошифровано Rijndael.

-----
SaNX




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

Создано: 11 мая 2013 01:00
· Личное сообщение · #21

Я пока рассказываю свой прогресс. Итак, я дизассемблировал mandroid-win.exe, получил код на IL. Теперь мне надо было сделать свою версию класса PlatformActivation.

Для этого я сделал отдельный проект, назвал его mandroid-win-emulation. И перетащил в него этот самый класс, и все остальное, что для него нужно. Соответственно все неймспейсы там были такие же, и результирующий код на IL можно было радостно вставлять в большой ассемблерный файл вместо изначального класса.

Вот, собсн, артефакты:

Проект mandroid-win-emulation. Как сказано выше, его назначение - порождать взломанную версию класса PlatformActivation. После компиляции этот проект дизассемблируется ILDASM'ом, после чего оттуда вынимается код и вставляется в большой код самого mandroid-win.exe. Последний компилится ILASM'ом, после чего копируется в директорию MSBUILD. Я его копирую в файл mandroid-xamarin.exe, а вместо mandroid.exe, который в конечном счете и зовется, использую свою прокси-программу (см. выше). Таким образом, я вижу в файле лога, в который я все пишу, весь обмен - команды и ответы.

Все файлы для сборки ломаной версии оригинального mandroid-win.exe лежит здесь.

И вот что получается в результате: я выложил лог-файл, который показывает обмен с манроидом. Как видно, сначала все идет хорошо, от отвечает, что активирован, и Entitlements он выдает правильные. Но! В конце концов, после последней команды "create-package -v --nosign ..." он не отвечает "OK Completed", а где-то зависает

На этом на сегодня мой мозг отказывается работать... целый день сижу с этой херней. Тлять! Почти все сделано. Да, кстати, когда я запускаю мандроид-вин без прокси-программы, ничего не меняется то есть дело не в ней.

Ребята, может кто глянет? Где-то что-то я упустил. Еще выкладываю проект mandroid-win, это версия, которая была получена рефлектором, и немного причесана, чтобы компилилась. Запускать ее я не советую, ничего хорошего не выйдет. Она просто для информации. Рекомендую посмотреть отличия класса PlatformActivation в моем эмуляторе и в ней. Вот этот проект.

Ну, надеюсь на вас, коллеги. А нет - ну опять придется самому. Мне не привыкать



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

Создано: 11 мая 2013 01:37
· Личное сообщение · #22

Ура, тля!!! Разобрался в чем причина зависания!!! Мой mandroid-win.exe, переменованый в
mandroid-xamarin.exe, ПРОСТО, ТУПО! ЭЛЕМЕНТАРНО - ПААДААЕТ!!! ха ха ха ха

Я сотрю - бл, процесса-то нет! И процесс монитор показывает выход процесса, и в системном журнале написано, что приложение упало.

Теперь поставлю обработчик необработанных исключений, и найду причину!!!



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

Создано: 11 мая 2013 02:07
· Личное сообщение · #23

Народ, произошло что-то странное!!!

Я добавил такой код:

Code:
  1.                         AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);


и такой:

Code:
  1.                  private static string GetFullExceptionMessage(Exception source)
  2.                  {
  3.                         string message = string.Empty;
  4.  
  5.                         Exception current = source;
  6.                         while (null != current)
  7.                         {
  8.                               if (!string.IsNullOrEmpty(message))
  9.                                    message += ": ";
  10.  
  11.                               message += current.Message;
  12.  
  13.                               current = current.InnerException;
  14.                         }
  15.  
  16.                         return message;
  17.                  }
  18.  
  19.                  private static string GetFullExceptionStack(Exception source)
  20.                  {
  21.                         string message = string.Empty;
  22.  
  23.                         Exception current = source;
  24.                         while (null != current)
  25.                         {
  26.                               if (!string.IsNullOrEmpty(message))
  27.                                    message += Environment.NewLine;
  28.  
  29.                               message += current.StackTrace;
  30.  
  31.                               current = current.InnerException;
  32.                         }
  33.  
  34.                         return message;
  35.                  }
  36.  
  37.                  
  38.                  static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
  39.                  {
  40.                         using (var writer = new StreamWriter(@"C:\mandroid-win.exception.log", false))
  41.                         {
  42.                               writer.WriteLine(GetFullExceptionMessage((Exception)e.ExceptionObject));
  43.                               writer.WriteLine(GetFullExceptionStack((Exception)e.ExceptionObject));
  44.                         }
  45.                  }
  46.  


предполагалось, что он сообщит об исключении, запишет то есть в лог, и упадет как обычно. Но нет! Он просто начал работать!! На команду create-package ответил ОК, построил и запустил прогу на эмуляторе. При этом никаких вопросов о лицензии!!!

УРА !! ПОЛУЧИЛОСЬ!! ПРАВДА ПОКА НЕ ЗНАЮ КАК!!!

Завтра разберусь!!!

Поздравьте меня, что ли!!!

| Сообщение посчитали полезным: daFix


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

Создано: 11 мая 2013 12:17 · Поправил: 4kusNick
· Личное сообщение · #24

Поздравляю! Всегда приятно видеть когда человек решается нырнуть в пучину неизведанного и сам во всем разбирается. Сразу молодость вспоминается


Гы гы... молодость?? А мне междупроч 45 лет какбэ

Ну да, моя же молодость вспоминается, а не ваша

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




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

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

4kusNick пишет:
Сразу молодость вспоминается


Гы гы... молодость?? А мне междупроч 45 лет какбэ



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

Создано: 12 мая 2013 00:43
· Личное сообщение · #26

4kusNick пишет:
Ну да, моя же молодость вспоминается, а не ваша


Я имел ввиду, что чтобы "нырнуть в пучину" и разобраться, необязательно быть молодым (по возрасту). Я и в молодости такой был, и сейчас такой )))



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

Создано: 12 мая 2013 00:45
· Личное сообщение · #27

andrique пишет:
Для студии есть приблуда, чтобы смотреть содержимое стека, и проч, проч. У меня она есть, но не помню как называется


Вспомнил! Эта хня наз. SOS.DLL, живет в папке фреймворка.



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

Создано: 12 мая 2013 00:55
· Личное сообщение · #28

SaNX пишет:
А не проще сделать поиск по сигнатурам и патчить, как патчили на хабре (ну или где там)? Я, когда заморочился, быстро нашел нужные места и пропатчил.


Не пояснишь мысль? Чт ткъ "поиск по сигнатурам"? Ну то есть что такое поиск, понятно А по каким сигнатурам? То есть я совершенно не понял, что за процесс ты описал в этих трех словах?



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

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

ELF_7719116 пишет:
Запасаемся попкорном.


Ну чт, попкорн-то весь слопали?

Хочется услышать единомышленников. Особенно на тему все-таки кейгена. Я так понимаю, что блоб лицензии на стороне клиента нигде не генерируется, и нет кода, чтобы этот алгоритм воспроизвести?

Спрашиваю потому, что сам еще не разбирался.



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

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

Так, коллеги. К вопросу о кейгене.

Рассмотрим следующий код:

Code:
  1.                         var crypto = new Crypto(Certificates.Server, Certificates.Client, null);
  2.  
  3.                         var path = @"C:\home\dev\unlicense\xamarin\trunk\programdata\License\monoandroid.trial.licx";
  4.                         byte[] tlic = new byte[791];
  5.  
  6.                         using (var rdr = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read)))
  7.                         {
  8.                               rdr.Read(tlic, 0, 791);
  9.                         }
  10.  
  11.                         var l = License.LoadFromBytes(crypto, tlic);


Данный код выдает правильную лицензию, которая была мне и выдана Xamarin'ом. Все это наводит на мысль, что раз у нас есть сертификаты - клиентский, и серверный, можно попробовать эту самую лицензию новую сделать и зашифровать и будет счастье.


. 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 » Выход » ЛС
   Для печати Для печати