Не секрет, многие из нас в детстве пытались разобрать игрушку, чтобы понять, как она устроена изнутри. Эта привычку некоторые пронесли через всю жизнь, применяя любопытство уже в своей профессии. По этому же примеру кодеры пытаются «разобрать» устройство программы, чтобы исправить ошибки либо усовершенствовать ее.
Что же из себя представляет реверс-инжиниринг в it?
Реверс-инжиниринг (Reverse Engineering) или, как его еще называют, обратная разработка, а иногда — обратное проектирование — это процесс анализа приложения для определения его функциональных характеристик, внутренней архитектуры и, собственно, его работы: модулей, функций, алгоритмов. Реверс-инжиниринг используется в IT в различных целях:
- улучшение функциональности приложения в случаях, когда компания, разработавшая его, перестала существовать или связаться с ней нет возможности;
- анализ вирусов, «червей», троянских программ для выделения их сигнатур и создания средств защиты (антивирусного программного обеспечения);
- расшифровка форматов файлов для улучшения совместимости (форматы файлов платных популярных приложений для Windows, не имеющих Linux-аналогов, например, Open Office или Gimp);
- обучение и многое другое.
Однако Реверс-инжиниринг зачастую используется «не по назначению». Ведь изучив архитектуру приложения или получив исходный код, можно внести в него изменения и использовать в своих «корыстных» целях. Вот несколько примеров:
Бесконечное использование пробных версий приложения. Скажем, у нас есть продукт, которым мы можем бесплатно пользоваться на протяжении месяца. При запуске приложения происходит проверка даты установки относительно текущей. Удалив эту проверку или заменив ее функцией, которая всегда будет возвращать нужный результат, приложение навсегда останется в режиме пробного использования.
Кража информации или кода. Целью злоумышленника может стать не само приложение, а его модуль или часть. Такая тактика актуальна для конкурирующих компаний по разработке ПО.
Обход технических средств защиты авторских прав. Целью взломщика является снятие защиты от копирования аудио и видео файлов, компьютерных игр, электронных книг для последующего свободного распространения.
Целью злоумышленника могут стать как «настольные», так и мобильные приложения. В контексте реверс-инжиниринга совершенно не имеет значения, написано ли приложение для работы на смартфоне или на персональном компьютере, потому как методы взлома зависят в большей степени от языка программирования и внедренных механизмов защиты. Ведь, если разобраться, мобильное приложение – это архив, который состоит из конфигурационных файлов, библиотек и файлов скомпилированного программного кода. Поэтому в общем виде подходы к «взлому» мобильных и настольных приложений будут одинаковыми.
Процесс получения исходного кода зависит от языка программирования и платформы, так как является процессом обратной компиляции. Например, приложения, разработанные в .Net framework, сначала компилируются в промежуточный язык Common Intermediate Language (CIL), а затем преобразуются в машинный код посредством Common Language Runtime (CLR) во время выполнения. Аналогично работает и компиляция Java и Python приложений: высокоуровневый код сначала компилируется в промежуточный язык низкого уровня — байт-код, а затем преобразуется в машинный код just-in-time компилятором.
Такая организация обеспечивает кроссплатформенность, а также позволяет писать различные части приложения на разных языках в рамках одного фреймворка. Однако, с точки зрения реверс-инжиниринга, из промежуточного языка (как CIL, так и байт-кода) можно получить информацию о классах, структурах, интерфейсах и т.д. и восстановить исходную архитектуру. Для этого существуют готовые утилиты, такие как .Net Reflector, MSIL Disassembler, ILSpy, dotPeek для .Net приложений, Javap, JAD, DJ для восстановления Java из байт-кода и pyREtic, pycdc, Uncompyle2 для работы с Python-приложениями.
Если злоумышленник в достаточной степени знаком с CIL или байт-кодом, то рано или поздно он сможет внести в него изменения, заново скомпилировать и заставить приложение работать в своих целях.
Реверс-инжиниринг приложений традиционных языков программирования (например, С, С++ илиObjectiveC) является более сложной задачей. Приложения, написанные на них, сразу компилируются в исполняемый машинный код, который не хранит в себе никакой информации о структуре исходного приложения: имен классов, названий функций или переменных и т.д.
Дополнительным препятствием является то, что представление низкого уровня не содержит конструкций ветвления (if, forи т.п.), а для их восстановления требуется построения графа потока управляющих конструкций программы. Это требует значительных временных затрат. Но и это не может гарантировать сохранность исходного кода приложений. Имея глубокие знания в Assembler и навыки программирования, задача восстановления исходного кода (или идентичного по функциональности) становится лишь вопросом времени.
О том, как обезопасить приложение, читайте во
второй части статьи.