Хакер - Игривый Xamarin. Изучаем и взламываем мобильное приложение на С#
Содержание статьи
Программировать для Android можно не только на Java или Kotlin. Разработчики на С# имеют возможность создавать мобильные приложения с помощью платформы Xamarin. Сегодня мы поговорим о том, как исследовать такие приложения и как при необходимости их можно взломать.
Попалось мне недавно в руки мобильное приложение для Android, которое работало не совсем так, как хотелось бы. Значит, нужно хорошенько покопаться в его потрошках!
Сказано — сделано: берем свежую версию GDA, открываем наш подопытный APK и видим, что выглядит он как‑то уж слишком подозрительно. Классы всех activity содержат примерно одинаковый шаблонный код такого типа:
public class MainActivity extends BaseActivity
public static final String __md_methods;
MainActivity.__md_methods = "n_onCreate:\(Landroid/os/Bundle;\)V:GetOnCreate_Landroid_os_Bundle_Handler
_ILandroid_os_Bundle_Handler:Android.Locations.ILocationListenerInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n";
Runtime.register("Megaprogram.Activity.MainActivity, Megaprogram", MainActivity.class, MainActivity.__md_methods);
if (this.getClass() == MainActivity.class) {
Object[] objArray = new Object[0];
TypeManager.Activate("Megaprogram.Activity.MainActivity, Megaprogram", "", this, objArray);
Это наводит на мысли, что нам попался неправильный APK. Возможно, какой‑то фреймворк... Если поменять расширение .apk
на .zip
, то в глаза бросается необычная для обычных мобильных приложений папка assemblies
, содержащая кучу DLL-библиотек.
Поскольку многие библиотеки содержат в названии слово Xamarin, становится понятным, откуда взялось такое однообразие — основной код программы написан на С# и располагается в библиотеке DLL, а на Java написаны лишь шаблонные куски кода, предназначенные для связи между средой выполнения Mono и виртуальной машиной среды выполнения Android (ART).
Ну да ладно, в сторону теорию, пора браться за дело.
ВЫБИРАЕМ ИНСТРУМЕНТ
Для работы с .Net я использую три инструмента.
- dotPeek от JetBrains. Позволяет декомпилировать и исследовать файлы
.dll
и.exe
. У данного продукта самая, на мой взгляд, удобная навигация по декомпилированному коду, так что, если говорить только об исследовании алгоритма, этот инструмент самый удобный.
- dnSpy — позволяет декомпилировать, редактировать, компилировать и отлаживать сборки .Net. Следует отметить, что все функции, кроме декомпиляции, работают далеко не всегда, многое зависит от конкретной ситуации. В моем случае компиляция не заработала: софтина не смогла связать пространства имен Mono и Android.
- Simple-assembly-explorer — достаточно старый, но от этого не утративший актуальности софт. Позволяет декомпилировать
.dll
и.exe
в код на С# или CIL (Common Intermediate Language — «высокоуровневый ассемблер» виртуальной машины .NET. Промежуточный язык, разработанный фирмой Microsoft для платформы .NET Framework). Самая полезная возможность — этот инструмент умеет компилировать код на CIL, что позволяет без особого труда вносить изменения в исследуемые файлы.
Для распаковки и запаковки APK я решил использовать 7z вместо стандартного для таких случаев apktool. Ниже я объясню почему.
РАЗБИРАЕМ APK
Сначала я попытался использовать для распаковки APK известную программу apktool, но при запаковке возникла проблема из‑за того, что apktool «не знает» такой тип файлов, как .dll
, не считает его стандартным для APK. Стандартными считаются только файлы с именами из следующего массива:
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "lib", "libs", "assets", "META-INF" };.
При сборке APK все неизвестные файлы сжимаются (тип сжатия DEFLATED), а Xamarin надеется увидеть свои DLL несжатыми (STORED) и от разочарования не может нормально прочитать их. Сначала возникла мысль исправить и пересобрать apktool, но потом я решил поступить проще: распаковывать и запаковывать файлы обычным архиватором, без сжатия. Ведь декодирование манифеста или получение smali-кода мне в данной задаче не требуется, а зачем тогда усложнять себе жизнь без необходимости?
7z.exe x program.apk -oprogram_apk
После распаковки, помимо привычных для APK файлов, получаем каталог assemblies
с кучей dll
. Из них нас интересует одна библиотека, имя которой совпадает с именем приложения. Ее‑то мы и будем потрошить.
ПАТЧИМ .NET
Анализ DLL и поиск места для внесения правок выходит за рамки сегодняшней статьи, так как мыслям на эту тему будет тесно даже в книге. Остановлюсь лишь на технических моментах. Как я писал выше, dnSpy отказался компилировать исправленную библиотеку, поэтому пришлось прибегнуть к помощи Simple-assembly-explorer (SAE).
Допустим, нам необходимо, чтобы данная функция всегда возвращала true
:
ConnectivityManager connectivityManager = (ConnectivityManager)this.GetSystemService#0x0a0001d5("connectivity");
if (connectivityManager == null)
NetworkInfo activeNetworkInfo = connectivityManager.get_ActiveNetworkInfo#0x0a0002ad();
return activeNetworkInfo != null && activeNetworkInfo.get_IsConnected#0x0a0002ae();
Поскольку правки можно вносить только в IL-код, в окне SAE переключаемся на вкладку Details, где наблюдаем такую картину:
1 L_0001: ldstr "connectivity"
2 L_0006: callvirt Java.Lang.Object Android.Content.Context::GetSystemService(System.String)
3 L_000b: castclass Android.Net.ConnectivityManager
6 L_0012: brtrue.s 9 -> ldloc.0
10 L_0017: callvirt Android.Net.NetworkInfo Android.Net.ConnectivityManager::get_ActiveNetworkInfo()
13 L_001e: brfalse.s 17 -> ldc.i4.0
15 L_0021: callvirt System.Boolean Android.Net.NetworkInfo::get_IsConnected()
- Подойти к делу основательно, фундаментально, изучить язык CIL и написать необходимый код самостоятельно.
- Написать нужную функцию на C# и скомпилировать в CIL, получив тем самым нужный код автоматически.
Я выбрал второй вариант — это гораздо быстрее. Более того, немножко погуглив, можно обнаружить очень полезный сайт sharplab.io, на котором весьма удобно конвертировать код из C# в CIL.
Итак, вводим в левой вкладке следующее:
и справа среди кучи лишнего получаем:
Вставляем полученный код в библиотеку с помощью Simple assembly explorer, не забывая при этом сохранить измененную DLL. Если мы ничего не напутали и нигде не ошиблись, то пора собирать новый APK.
СОБИРАЕМ APK ОБРАТНО
Для сборки, как я уже писал выше, будем использовать 7z в режиме без сжатия. Полученный таким образом APK будет большего размера, чем исходный, ну да размер не главное:
7z.exe a -tzip -mx0 -r0 program_patched_unalign_unsigned.apk .\program_apk\*.*
Небольшое пояснение: -tzip
— формат архива, -mx0
— отсутствие сжатия, -r0
— рекурсивный обход всех подкаталогов.
Да, перед сборкой лучше удалить каталог META-INF
, содержащий старую подпись. Он не нужен, ведь нам придется подписывать APK самостоятельно. Затем нужно создать сертификат для подписи и поместить его в хранилище. Если у тебя уже есть сертификат, то этот шаг можно пропустить. Создаем сертификат с помощью утилиты keytool из состава JDK:
"c:\Android\Android Studio\jre\bin\keytool.exe" -genkey -v -keystore keys.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000
Она задаст стандартные вопросы:
What is your first and last name?
What is the name of your organizational unit?
What is the name of your organization?
What is the name of your City or Locality?
What is the name of your State or Province?
What is the two-letter country code for this unit?
Is CN=x, OU=x, O=x, L=x, ST=x, C=x correct?
Generating 2 048 bit RSA key pair and self-signed certificate (SHA256withRSA) wi
for: CN=x, OU=x, O=x, L=x, ST=x, C=x
Ну и после этого можно переходить к подписыванию:
jarsigner.exe -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore keys.keystore -signedjar program_pathed_unalign.apk program_pathed_unalign_unsigned.apk key
В результате будет создан почти готовый к установке файл program_pathed_unalign.apk
. «Почти» — потому что перед использованием его следует выровнять программой zipalign из состава build-tools SDK Android. Данная процедура гарантирует, что все несжатые файлы в архиве выровнены относительно начала файла. Это позволяет получить доступ к файлам напрямую, без необходимости копирования данных в ОЗУ, что уменьшит использование памяти твоим приложением.
zipalign.exe -v 4 program_pathed_unalign.apk program_pathed.apk
После этого можно смело устанавливать программу на телефон или эмулятор и приступать к ее тестированию.
ВЫВОДЫ
Как видишь, Xamarin’овские сборки ничуть не сложнее для анализа, чем родные приложения ОС Android, надо лишь учесть некоторые тонкости при сборке APK.
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei