Метка: reverse engineering
Reverse engineering: как на самом деле разбирают чужой бинарный код
Что такое reverse engineering
Reverse engineering — это не какая-то «магия взлома», а вполне прикладной процесс: у тебя есть программа, но нет исходников, и тебе нужно понять, что она делает и как именно она это делает.
В отличие от обычной разработки, здесь ты двигаешься в обратную сторону. Вместо того чтобы писать код и получать бинарник, ты берёшь бинарник и пытаешься восстановить логику, которая за ним стоит. Причём важно понимать: полностью восстановить исходный код невозможно. Можно лишь приблизиться к пониманию поведения.
Именно поэтому reverse engineering — это не про «восстановить C++ как был», а про ответ на конкретные вопросы:
- почему программа ведёт себя так
- где именно принимается решение
- что нужно изменить
С чего всё начинается на практике
Почти всегда всё начинается не с ассемблера, а с банального любопытства: «почему это работает именно так».
Ты открываешь бинарник и сначала смотришь на него как на структуру. Например, если это Windows-приложение, ты понимаешь, что перед тобой PE-файл, со своими секциями, импортами и точкой входа. Уже на этом этапе можно многое понять: какие библиотеки используются, есть ли сетевое взаимодействие, как вообще устроен запуск.
Дальше неизбежно приходится идти глубже — к коду. И тут начинается самое интересное.
Дизассемблер — это не про удобство, а про точность
Когда ты смотришь на дизассемблированный код, это максимально честное представление того, что реально выполняется процессором. Никаких «удобных» абстракций, никаких имён переменных — только инструкции и переходы.
mov eax, 1
cmp eax, 0
jne short loc_continue
С одной стороны, это неудобно читать. С другой — здесь нет лжи. Всё, что ты видишь, действительно исполняется.
Именно поэтому опытные люди часто доверяют дизассемблеру больше, чем декомпилятору. Потому что декомпилятор уже начинает «додумывать».
Почему декомпиляция вводит в заблуждение
Декомпилятор выглядит как спасение: он показывает что-то похожее на C или C++. Но важно держать в голове простую вещь — он не знает, как выглядел исходный код. Он делает предположения.
Иногда эти предположения удачные. Иногда — нет. Особенно когда:
- код сильно оптимизирован
- используются нетривиальные конструкции
- активно применяются указатели
В результате ты можешь видеть «красивый» код, который на самом деле не совсем соответствует реальности. И если на него опираться без проверки, легко уйти не туда.
Где на самом деле теряется время
Самая большая ошибка новичков — пытаться понять всё сразу.
В реальности reverse engineering почти всегда делается точечно. Тебя не интересует весь бинарник. Тебя интересует конкретный кусок: проверка лицензии, обработка запроса, запись в файл.
И вот тут начинается работа:
- найти это место
- понять, как туда попадает управление
- разобраться в условиях
Это уже не «анализ программы», а скорее расследование.
Почему без понимания архитектуры никуда
Очень быстро становится ясно, что без понимания архитектуры процессора ты просто смотришь на набор символов.
Например, та же x86 со своей переменной длиной инструкций и сложной логикой переходов. Если ты не чувствуешь, как работает стек, как передаются параметры, как устроены вызовы функций — ты будешь теряться на каждом шаге.
Reverse engineering — это не про инструменты. Это про модель выполнения кода.
Связь с patch и hooking
Практически всегда reverse engineering делается не ради самого анализа.
Обычно цель вполне конкретная: что-то изменить.
Ты находишь нужное место в коде, понимаешь, где принимается решение — и дальше уже можешь:
- заменить условие
- вставить переход
- перехватить вызов
Без предварительного анализа это превращается в угадайку. С анализом — в точечную операцию.
Почему это сложно
Главная проблема — потеря контекста. В бинарнике нет имён, нет типов, нет структуры проекта. Есть только последствия работы компилятора.
А компилятор, в свою очередь, делает всё, чтобы код исполнялся быстрее:
- объединяет функции
- выкидывает лишнее
- перестраивает логику
В итоге ты смотришь не на «чистую» программу, а на результат оптимизаций.
Если к этому добавить обфускацию, задача становится ещё интереснее.
Итог
Reverse engineering — это не отдельная дисциплина, а продолжение системного программирования, только в обратную сторону.
Ты работаешь с тем же самым кодом, тем же процессором, той же памятью — просто без исходников и без подсказок.
И довольно быстро становится понятно:
чем лучше ты понимаешь, как код исполняется, тем меньше тебе нужны инструменты
Всё остальное — это уже техника и опыт.