Иннополис 28 ноября 2018

Евгений Казаев, RusEm — о том, как работает реверс-инженер и что нужно любить в чужом коде

Далее

Обратная разработка или реверс-инжиниринг –– это уже устоявшийся термин. Фактически реверс-инженеры могут не только восстановить из готовой программы или устройства все этапы его создания, но и создать аналогичный продукт без прямого копирования, в том числе и с недокументированными возможностями. Это позволяет сэкономить на разработке значительные средства и время. Кроме того, обратная разработка играет существенную роль в поиске уязвимостей ОС и при создании антивирусного ПО. Евгений Казаев из RusEm рассказал в рамках конференции PartyHack в Иннополисе, как работают реверс-инженеры, об их главных инструментах и о том, что он любит в чужом коде.

Любить чужой код

Цель реверс-инженера — получить исходный код из уже готовой и скомпилированной программы. В этом нам помогает дизассемблер. Текст на языке ассемблера — минимум, который мы можем получить при работе с данной программой. В таком случае декомпилятор на голову выше дизассемблера, так как он «позволяет», опять же, в кавычках, поскольку здесь зависит от его уровня, работать уже непосредственно с программой. Дизассемблер в зависимости от того, на каком языке программа была написана, старается привести машинный код программы к исходному коду на этом же языке для облегчения понимания. Не будем же мы переделывать приложение, пускай даже мегабайт на ассемблере, это тяжкий и неимоверный труд. А отладчики, например, используют больше для динамического анализа. То есть они позволяют нам исследовать программу в моменты запуска, во время работы, смотреть состояние регистра, стека и всего прочего.


Reverse Engineering, обратная разработка –– исследование устройства или программы с целью:

  • понять принцип работы;
  • обнаружить недокументированные возможности;
  • сделать изменение или воспроизвести устройство или программу с аналогичными функциями, но без прямого копирования.


Инструменты, которые использует обратный инженер:

  • Декомпилятор — программа, транслирующая обратный код на языке высокого уровня.
  • Дизассемблер — транслятор, преобразующий машинный код, объектный файл или библиотечные модули в текст программы на языке ассемблера.

Для меня Java, если речь идет о стартапе, — это фиаско. Помимо этого декомпилятора, я обожаю APKTOOL. Он позволяет не только разбирать, но и собирать назад. Есть небольшая NOVI-оболочка к нему, которая декомпилирует наше приложение в smali-код. Smali-код — это текстовые представления байт-кода java-машины.


Что я как реверс-инженер люблю в чужом коде:

  • строки;
  • имена функций и методов;
  • условные переходы;
  • локальную валидацию;
  • константы;
  • безусловное доверие входным данным.

Строки наше все

Программисты в основном пишут с учетом того, как бы они сделали это со своей позиции, облегчая логику и упрощая разработку, но редко кто пишет со стороны защиты. Представим, что вы стартап и написали гениальнейшее приложение, хотите его продавать и начинаете думать о защите. Но нужно продать не одну копию программы, а, например, столько копий, сколько у вас пользователей. После этого думаете: раз мы хотим продать одно приложение одному юзеру, хотя бы для одного устройства, то будем стараться привязать его к устройству. Есть приложение, есть устройство, нам нужно продать копию. Логично, что нужно защитить приложение, чтобы оно работало только на этом устройстве. Как же нам определить устройство и выделить из многих? Это можно сделать по серийному номеру. И мы будем использовать серийный номер. Его могут поменять, но это противозаконно. Дальше думаем: у нас есть IMEI, чтобы он не был таким очевидным, зашифруем его. Пишем некоторую функцию — хэш или соль, без разницы, назовем ее Akrypt.

Все зависит от уровня программиста или сложности. Из полученного возьмем часть и назовем это кодом — это будет с нулем шесть символов, и сделаем следующую систему — пользователь присылает свой серийный номер, по данной схеме отправляем ему код валидации. Мы хотим анализировать приложение, необходимо от чего-то отталкиваться. От чего? Вспомним, что я люблю в чужом коде. В первую очередь, смотрю строки. Строки наше все.

Строки –– маяки в море кода. Строки в открытом виде –– наша радость.

Евгений Казаев

Что мне нравится, так это читабельность. Вы пишете, например, метод проверки. То, что удобнее понимать и писать, называете этот метод проверкой. Зачастую программисты, которые впервые пишут защиту, делают это так, что результаты проверки лицензии, файлы лицензии, коды регистрации используются только для проверки. Лицензия ради проверки лицензии. Код регистрации ради проверки кода регистрации. Защита от самого себя — защита от дурака. Банальная условная проверка показывает, что результат проверки сам метод не использует больше нигде. Мы просто проверяем, прошла она или не прошла. И у меня есть не вредный совет: не надо делать так. Используйте результат проверки не просто как проверку. Воспользуйтесь шифрованием, посмотрите, прошло оно или нет, а результат шифрования используйте где-то в приложении, — и чтобы он был критичен для работы приложения. Тогда никакое изменение не спасет того, что приложение будет падать без нужных данных.

Думайте не как программист

В реверсинге есть два пути — это запатчить приложение, когда ты просто изменяешь код, и создать генератор ключей. Это высшая каста. Вы сами генерируете ключи пользователю. Метод «проверка» берет текст, введенный пользователем user-код, заводит переменную rite-код, и ей присваивают значение, полученное из gen-кода. Это из локальной валидации, когда код введен и валидируется в этом же приложении. Вот вам мой совет: сами проверяем и сами считаем. В случае с генератором ключей приложение при этом не трогается. Чем это хорошо? Пока не смените алгоритм валидации, все ваши версии уже зарелизены. А проверку можно обойти легко. Если будет 500 таких вызовов, нужно изменить результаты функции методом «проверка». Здесь можно просто пропатчить методом, и он всегда будет возвращать истину, вне зависимости от того, что там внутри, и неважно, сколько будет проверок, все пройдут. И если мы стремимся в высшую касту и хотим сделать генератор, нас отделяет от генератора только одна неизвестная функция — метод Encode.

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

Евгений Казаев

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

Многие начинающие программисты, когда думают о защите, смотрят в сторону платных продуктов — протекторов. Они позволяют, можно сказать, без усилий сделать защиту на свое приложение. На первых порах, пока вы не сделаете свою защиту, более-менее стойкую, забудьте про протекторы. Если не в паблике, а в привате, почти на любой протектор есть анпротектор, темная сторона. Если вы будете программировать защиту, думайте не как программист, а как человек на той стороне.