Swift-source-Protect-Obfuscate-Lipasite

Эта статья про обфускацию исходного кода в Swift.
Я перепробовал множество инструментов, но с тех пор, как стал использовать Receigen, который интегрируется в xCode, прекратил поиск. Цель обфускации — усложнить взлом исходного кода хакерами. Как же это сделать? Не следует думать, что если программа просто скомпилирована, то исходный код трудно прочитать. В современных языках программирования, Swift в том числе, скомпилированный код содержит в себе большое количество информации, которое упрощает хакеру поиск слабых мест, например, при вызове функции для валидации рецептов (Receipt Validation).

Платеж iTunes представляет так называемый рецепт. Рецепт — это кодированный в base64 JSON-объект данных платежной транзакции. Для верификации платежа или подписки через сервис App Store нужно передать их рецепт, который сообщает клиентское приложение. В ответ получите статус рецепта и некоторые данные платежа.

Вспоминаю времена 20-летней давности (еще до эры интернета), когда для защиты софта от копирования использовались «usb-донглы», флешки. Приходилось таскать с собой этот ключ-донгл везде, пока он не случайно не потеряется. Это жутко неудобно. Мне потребовалось около 10 минут, чтобы высянить слабые места в коде, где происходит вызов функций для проверки ключа, и заменить эти вызовы NOP-инструкциями. Донгл больше не нужен, приложение взломано. Кстати, донглы используются и сейчас, например, Guardant.

Если учесть, что я не хакер, то в данном случае я пошел длинным трудоемким путем. Настоящий хакер бы взломал программу гораздо быстрее. Современные хакеры обладают скриптами и утилитами, которые позволяют им без труда взламывать систему защиты любого софта. Думаю, что и программа на Swift может быть с легкостью хакнута с помощью такой утилиты даже без обращения к услугам хакера.

Например, в коде я использую Apple Root Certificate (ARC) — это обычный файл. Если бы мне пришло в голову написать утилиту для автоматического взлома проги, то я бы просканировал прогу на наличие рутового сертификата и заменил бы его своим сертификатом. Далее утилита создала бы новый рецепт, подписанный фейковым корневым сертификатом, и заменила бы существующий рецепт в бандле.

Переименование рутового сертификата — хорошая идея, но бесполезная. Так как хакер знает как устроена последовательность байтов в ARC, он просто отсканирует ее. Даже если встроить эту последовательность байтов в исходники — не поможет. Что же делать? Лучший вариант — зашифровать ARC простой собственной схемой шифрования и добавить этот зашифрованный ARC как hex-дамп в исходный код.

Кроме того, все строки кода, которые используются для валидации и доступны, должны быть также зашифрованы.

Валидация модулей

Сложный аспект — это запуск самой программы. Любая валидация, которая заканчивается перед запуском программы, уязвима. Если хакер обнаружит момент запуска приложения, он сможет просто пропустить все проверки в коде и прыгнуть прямо в момент старта. Таким образом, момент запуска приложения должен быть скрыт максимально возможно. Например, можно скрыть его в списке вызовов функций и затем динамически выбирать из него нужный.

Еще лучше — осуществить повторную валидацию для оставшихся модулей программы. Или добавить маркеры валидации к модулям, которые требуют этого. Например, можно сделать расчет динамического значения перед валидацией корневого сертификата, затем изменить это значение и записать результат в другую переменную. Далее в основном приложении (например, в цикле выполнения (Run Loop)) вы сравниваете значения этих двух переменных, в соответствии с алгоритмом изменения значения. Таким образом, вы будете знать, что проверка корневого сертификата была выполнена. А хакер, который запустит приложение без валидации, потерпит неудачу. Если сделать подобное в 50 разных местах программы, то хакеру придется реально попотеть, чтобы что-то сломать. Да, он взломает программу, но времени на взлом он потратит гораздо больше (хотя, чем круче вы придумали защиту, чем больше времени хакер потратил на взлом, тем большее удовлетворение он испытает после).