Безопасность IOS-приложений (часть 26) – Патчинг приложений при помощи IDA Pro и Hex Fiend

Безопасность IOS-приложений (часть 26) – Патчинг приложений при помощи IDA Pro и Hex Fiend

В предыдущих статьях мы рассматривали подмену методов при помощи Cycript во время работы приложения. Кроме того, мы научились изменять логику работы программы без манипуляций с кодом, когда изменяли значения регистров при помощи GDB. Все эти вещи служат лишь для одной цели – заставить приложение  работать так, как мы захотим.

Автор: Пратик Джианчандани (Prateek Gianchandani)

В предыдущих статьях мы рассматривали подмену методов при помощи Cycript во время работы приложения. Кроме того, мы научились изменять логику работы программы без манипуляций с кодом, когда изменяли значения регистров при помощи GDB. Все эти вещи служат лишь для одной цели – заставить приложение работать так, как мы захотим. Недостатком вышеупомянутых методов является то, что когда мы повторно запускаем приложение, нам нужно вновь выполнять все эти техники, что может слегка надоесть, если это происходит многократно. В этом случае мы можем прибегнуть к патчингу файлов приложения. Плюс этого метода в том, что при внесении изменений, они остаются навсегда, и вам не нужно повторять один и тот же процесс снова и снова. После того, как бинарный файл пропатчен, вы можете запустить его на джейлбрейковом устройстве с измененной логикой.

В этой статье мы будем экспериментировать все с тем же самым приложением GDB-Demo. Если вы еще не успели забыть, в одной из предыдущих статей мы изменили логику работы метода, который вызывается при нажатии на кнопку Login, так, чтобы обойти алгоритм аутентификации. В этой статье мы сделаем так, чтобы новая логика работала постоянно.

Для начала вам необходимо скачать демо версию IDA Pro с этого вебсайта. IDA Pro – прекрасный мультипроцессорный дизассемблер и отладчик. После загрузки запустите файл и выберите Go, после чего IDA откроется сам по себе без предварительного выбора бинарного файла. Обратите внимание, что при запуске приложения в симуляторе Xcode оно компилируется под архитектуру i386, а при запуске приложения на устройстве – под архитектуру ARM. Демо версия IDA Pro поддерживает обе эти архитектуры, но в этом руководстве мы будут компилировать приложение под архитектуру i386 (то есть мы будем запускать его в симуляторе), чтобы сэкономить время и не копировать бинарный файл с устройства на компьютер.

Рисунок 1: Настройка параметров симулятора Xcode

Теперь откройте Xcode и запустите приложение GDB-Demo в симуляторе, при этом убедившись в том, что программа скомпилировала корректно. После запуска приложение появится в папке /Users/$username/Library/Application Support/iPhone Simulator/$ios version of simulator/Applications/. В моем случае приложение находится в директории Users/Prateek/Library/Application Support/iPhone Simulator 6.1/Applications/. Теперь вам необходимо найти папку с приложением при помощи команды ls al, которая выведет папки с датой последней их модификации. Директория с самой последней датой изменения – это и есть папка с нашим приложением.

Рисунок 2: Содержимое папки Applications

Далее введите команду open DirectoryName (DirectoryName – директория с приложением), после чего папка откроется в приложении Finder.

Рисунок 3: Содержимое папки приложения

Кликните правой кнопкой мыши на папке GDB-Demo.app (это пакет приложения) и выберите Show Package contents. Внутри этой директории вы найдете бинарный файл с именем GDB-Demo, который мы будем изучать в IDA Pro.

Рисунок 4: Содержимое пакета приложения (нужный файл выделен синим цветом)

Теперь перетащите бинарный файл приложения в IDA Pro. Кликните ОК. Перед вами откроется дизассемблированный код.

Рисунок 5: Дизассемблированный бинарный файл

Как вы помните, тестовое приложение представляет собой форму авторизации, и чтобы обойти проверку учетных данных, мы модифицировали метод -(IBAction)loginButtonTapped:(id)sender (подробнее см. двадцать вторую статью этой серии).

Рисунок 6: Внешний вид приложения

В IDA Pro окно с функциями отображается слева. Выберите любую функцию и нажмите Ctrl+F. Найдите функцию loginButtonTapped, после чего дважды кликнув по ней, вы увидите в правой стороне окна дизассемблированный код этой функции.

Рисунок 7: Дизассемблированный код функции loginButtonTapped

Чтобы увидеть графическое представление кода, дважды кликните на имени функции (в окне с функциями), а затем нажмите пробел. Графическое представление значительно облегчает понимание логики работы функции. Если вы хотите убрать графическое представление, снова нажмите пробел.

Рисунок 8: Графическое представление алгоритма работы функции

Прокрутив вниз графическое представление, вы увидите, что в функции могут выполняться разные блоки в зависимости от определенных условий. Совершенно очевидно, что где-то здесь происходит проверка введенных имени пользователя и пароля, в зависимости от результатов которой происходят дальнейшие действия (завершение процесса авторизации или отказ пользователю). Прокрутив немного вниз, мы увидим интересный блок (см. рисунок ниже). В правой стороне окна находится ссылка на класс UIAlertView, а в левой – строка adminPage.

Рисунок 9: В зависимости от результатов проверки выполняется соответствующая ветка кода

Инструкция, которая решает на какой блок переходить, - test cl, 1.

Рисунок 10: Блок инструкций, отвечающих за переход на соответствующую ветвь

Далее идет строка jnz loc_2CBC, где loc_2CBC – метка, а jnz – инструкция, отвечающая за переход, если нулевой флаг не установлен (Jump if not zero). Левая ветвь содержит вышеуказанную метку.

Рисунок 11: Левая ветвь алгоритма функции

Наша задача сделать так, чтобы выполнение алгоритма всегда проходило через левую ветку, то есть вне зависимости от информации, введенной на форме, аутентификация завершалась успешно. Это можно сделать, если поменять инструкцию jnz на jz.

Небольшое отступление: в платной версии IDA вы бы сразу смогли поменять инструкцию jnz на jz, однако у нас демо версия, и поэтому потребуется сделать чуть больше телодвижений, но с другой стороны при этом вы немного углубите свои знания по шестнадцатеричной арифметике. В следующей статье мы поговорим об утилите Hopper, альтернативе IDA, которая не так дорога, но в плане функциональности также хороша как и IDA. Итак, для начала нам нужно узнать адрес инструкции jnz, для чего необходимо дважды кликнуть на инструкции так, чтобы она пожелтела.

Рисунок 12: Выделяем инструкцию, у которой мы хотим узнать адрес

Теперь нажмите пробел.

Рисунок 13: Перечень инструкций с абсолютными адресами

Как видно из рисунка выше, адрес нашей инструкции - 00002CB1. Однако мы не можем взять и просто изменить этот адрес, поскольку он абсолютный и изменяется при каждом запуске приложения. Нам необходимо вычислить относительное смещение инструкции относительно начала бинарного файла. Так как наша инструкция будет изменяться внутри секции кода, смещение инструкции относительно бинарного файла можно вычислить по следующей формуле:

(Смещение секции кода относительно бинарного файла) + (Абсолютный адрес инструкции – Начальный адрес секции кода)

На данный момент мы знаем абсолютный адрес инструкции. Остальные два компонента формулы можно найти при помощи утилиты otool. Зайдите в папку /Users/Prateek/Library/Application Support/iPhone Simulator/6.1/Applications/1804F89F-AD44-4782-BB29-47F5C521D10D/GDB-Demo.app (это папка с приложением, в вашем случае она может быть другой) и введите команду, показанную на рисунке ниже.

Рисунок 14: Общие параметры бинарного файла приложения

Ищем секцию __text.

Рисунок 15: Параметры секции __text

Как видно из рисунка выше, начальный адрес секции - 0x000026f0(Hex), а смещение - 5872(Decimal). В вашем случае эти параметры могут быть другими.

Теперь вычисляем смещение нашей инструкции:

5872(Decimal) + (0x00002CB1(Hex)- 0x000026f0(Hex)) = 0x1cb1

Теперь нам нужно поменять инструкцию jnz на jz. По этой ссылке можно найти опкоды этих инструкций. У инструкции jnz опкод OF 85, у jz - OF 84.

Далее вам потребуется утилита Hex Fiend. Загрузите ее, откройте и перетащите в нее бинарный файл.

Рисунок 16: Содержимое бинарного файла в шестнадцатеричном формате

Теперь кликните на Edit –> Jump to Offset и введите смещение 0x1cb1, после чего вы перейдете к инструкции jnz.

Рисунок 17: Место, где находится искомая инструкция

Теперь найдите опкод OF 85 и замените его на опкод 0F 84, как показано на рисунке ниже.

Рисунок 18: Меняем один опкод OF 85 на OF 84

Сохраните изменения и выйдите из Hexfiend. Как вы помните, мы компилировали приложение для симулятора. Запустите IOS-симулятор, закройте приложение GDB-Demo и откройте его заново. Кликните на кнопку Login (без ввода имени пользователя и пароля), и вы окажетесь на странице администратора.

Рисунок 19: Процесс авторизации прошел успешно

В следующей статье мы рассмотрим утилиту Hopper, и как при помощи нее можно патчить IOS-приложения. 

Устали от того, что Интернет знает о вас все?

Присоединяйтесь к нам и станьте невидимыми!