• XSS.stack #1 – первый литературный журнал от юзеров форума

Тема реверса dex файлов

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Напомню, что dex файл содержит скомпилированные классы андроид приложения. В ранних версиях андроида, код в dex исполнялся на Dalvik. В современных версиях, вместо этого используется ART (https://source.android.com/devices/tech/dalvik). Эта рантайм система более совершенна, в отличии от JIT, ART добавляет фичу AOT.

AOT (Ahead-Of-Time) - фича, которая прекомпилирует куски кода приложения, для дальнейшего исполнения. Делает это она, с помощью утилиты dex2oat. Эта утилита запускается, когда вы открываете приложение на телефоне. В этот момент, она прекомпилирует dex файл в oat файл. Данная утилита является простым бинарником и лежит в /system/xbin.

Как это относится к теме модификации андроид приложений? Дело в том, что когда вы редактируете dex файлы, именно dex2oat производит первичную верификацию - берет из хэдера значения хэша, чексумы, длины, оффсеты и т.д. Чтобы быстрее проверить модифицированное приложение, раньше я полностью собирал apk, закидывал в эмулятор и смотрел logcat и изучал ошибки, связанные с верификацией dex. Теперь же, можно не париться со сборкой, подписанием apk, а напрямую использовать бинарник dex2oat, для проверки корректности изменений.

Можно пойти еще дальше и открыть исходники это проверки (https://android.googlesource.com/platform/art/+/master/libdexfile/dex/dex_file_verifier.cc). Это сложнее, но надеюсь в ближайшем будущем взять данный исходник, переписать его на более удобный язык и создать тем самым первичный и очень небольшой верификатор (в сети не нашел). Такой верификатор dex файлов пригодился бы при фазинге важнейших систем андроида.

Я это к чему, нашел вот такой классный доклад с Black Hat Europe (https://www.blackhat.com/docs/eu-15...es-Inside-System-Components-In-Android-wp.pdf), прочитав который я понял, что такой мини верификатор очень бы пригодился, так как они фазили и смотрели логи на самом андроиде.


Продолжение темы реверса dex файлов

Сразу к делу. Мы создадим приложение с тремя активити, назовем их MainActivity, FirstActivity и SecondActivity. MainActivity будет стартовым, наследоваться от FirstActivity и тупо его запускать. SecondActivity просто находится в приложении и никак не вызывается. Цель - пропатчить такое готовое приложение так, чтобы запускалось SecondActivity. Для начала мы создаем проект с EmptyActivity

1_create_project.png


Назовем его ,что-то вроде TestingDEX, так как эт освязанно с DEX

2_testing_dex.png


Мы просто берем и создаем вышеупомянутые три активити класса

3_activities.png


Как видите, мы тупо наследуемся от FirstActivity и вызыаем OnCreate(). Теперь собираем нашу apk, делаем unzip, в итоговой папке у нас лежит classes.dex со скомпилированными классами, открываем его в hex редакторе.

4_big_dex.png


Обратите внимание на его размер, он получился просто огромным, его тяжело анализировать и для этого мы применяем знания из статьи об уменьшении размера апк, чтобы наш DEX файл был чистеньким и готовым к реверсу. Первым делом включаем ProGurd и выкидываем ненужные ресурсы из apk

Код:
android {

`buildTypes {`

    `release {`

        `minifyEnabled true`

        `shrinkResources true`

        `proguardFiles getDefaultProguardFile(`
          `'proguard-android.txt'), 'proguard-rules.pro'`

    `}`

`}`
}

Прописываем такое и наш dex становиться меньше!

5_proguard.png


Еще у нашего приложения, из-за совместимости есть лишние библиотеки, выпилиываем их

6_deps.png


В итоге вот так

7_deps_clear.png


Соответственно мы теперь наследуемся не от AppCompatActivity, а от просто Activity

8_deps_clear_result.png


Layout тоже чистим:

9_layout.png


Также удалям XML файлы

10_to_delete.png


Теперь, чтобы наш активити хоть както функционировал, пишем такой код

Код:
TextView textView = new TextView(this); textView.setText("Hello World!"); setContentView(textView);

Правим манифест, было

11_manifest_before.png


Стало

12_manifest_post.png


Собираем приложени, посмотрите какой чистенький DEX мы получили. Маленький и понятный

13_clear.png


Изначально, я всю эту дичь анализировал в простом HEX редакторе. Одним глазом смотрел в [https://source.android.com/devices/tech/dalvik/dex-format#method-id-item](Dalvik Executable format doc), другим в сырой hex редактор. Потом я вспомнил, что существует ИДА! Напомню, что нам необходимо перенаправить открытие FirstActivity на SecondActivity. Как вы поняли, мы собрали приложение ,которое наследуется и открывает FirstActivity. Теперь, просто меняем наследование от SecondActivity и собираем заново. Выглядить MainActivity будет так

14_scond_activity.png


Теперь у нас есть два приложения, которые унаследованы от разных классов. Теперь мы распаковываем их и делаем diff dex файлов, чтобы понять, что поменялось в бинарной структуре. Diff делал через WinHex, он выдает байты, которые поменялись, вот они

15_diff.png


Байты с 8-31 это чексума и хэш dex файла, на нее не обращаем внимания, так как она и так всегда меняется. Нас интересуют последнии три строки. Почему байт 06 поменялся на 08, по оффсету 452=1С4? Дело в том, что на этом оффсете, в секции CLASSDEF лежит инфа о классах в DEX и так как у нас поменялся parent с FirstActivity на SecondActivity, мы видим изменение поля superclass

16_IDA.png


Смотрим следующий диф по офсету. У нас изменился вызов init у родителя ,что неудивительно

17_IDA.png


Следующий дифф, напомню, изменился 570-ый байт (10).

18_IDA.png


Тут видно, что поменялся вызов OnCreate(), так как мы теперь вызываем этот метод не из FirstActivity, а из SecondActivity. Итого, чтобы вызывать другой суперкласс из того-же DEX файла, нам надо поменять лишь 3 байта и понимать к чему они относятся. А что если класс находится в другом DEX'е? Ответ на этот вопрос будет в следующей части


Продолжение темы реверса dex файлов. Следующая часть.

Как и раньше, мы будем искать самый эффективный способ заражения легитимных андроид приложений. В данной части, мы создадим свой dex файл, подложим его в целевую апк и сделаем так, чтобы приложение работало дальше, как и было задумано. Рассмотрим на примере Color by Number!

1_main_page.png


Мы будем подкладывать свой DEX файл, который будет запускать наш пейлоад и потом запускать изначальный launcher активити приложения. Манифест выглядит так:

Было:
Код:
<activity android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize" android:label="@string/app_name" android:name="com.slimfitgames.drawcolor.AndroidLauncher" android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
Стало:
Код:
<activity android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize" android:label="@string/app_name" android:name="com.slimfitgames.drawcolor.MainActivity" android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize" android:label="@string/app_name" android:name="com.slimfitgames.drawcolor.AndroidLauncher" android:screenOrientation="portrait" />
Как видите, изначально у приложения launcher активити был "com.slimfitgames.drawcolor.AndroidLauncher" и стал "com.slimfitgames.drawcolor.MainActivity" - нашим внедренным классом.

После изменения манифеста, мы собираем наше приложение в нормальное apk.

Теперь открываем Android Studio и пишем наш payload, пользуясь техниками из второй части (урезаем до минимума).

Создаем свое приложение, с точно таким же package name, как и у целевого. Создаем активити, с точно таким же именем, как и у целевого, но с измененной последнй буквой. Именно эту букву мы будем патчить в DEX файле. То есть, в оригинале - AndroidLauncher, а мы назовем AndroidLaunches. В MainActivity, выполняем наш пейлоад (Log.d()), а далее, с помощью startActivity(), запускаем AndroidLaunches.

2_android_studio.png


Теперь делаем Build project, нам необходимо, чтобы Android studio создала .class файлы для нас. После этого, в папке ХХХХХХХХХХХХХХХХ\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\com\slimfitgames\drawcolor будут наши .class файлы. Нам это необходимо, чтобы отдельно скомпилировать класс в один dex файл.
Код:
d8 --release --min-api 16 --no-desugaring MainActivity.class --output .

min-api обязательно должен быть такой же, как и у целевого приложения. Посмотреть его можно в apktool.yml, после декодирования.

Полученый DEX файл мы просто подкладываем в целевую apk.


АВТОР @OrderOfSixAngles
https://github.com/thatskriptkid
Орфография и пунктуация автора сохранены
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх