1. Архитектура приложений и основы низкоуровневого программирования
Архитектура приложений и основы низкоуровневого программирования
Добро пожаловать в курс «Основы этичного хакинга и реверс-инжиниринга». Вы здесь, потому что хотите не просто нажимать на кнопки, а понимать, как эти кнопки работают изнутри, как их можно переделать под себя и где в них скрыты уязвимости.
Чтобы стать хакером или специалистом по реверс-инжинирингу (обратной разработке), нельзя оставаться на поверхности. Нужно уметь «нырять» глубоко в недра компьютера. В этой первой статье мы разберем фундамент: как устроены программы, как процессор понимает команды и как выглядит память компьютера изнутри.
Уровни абстракции: от электричества до Python
Современные компьютеры построены по принципу слоеного пирога. Обычный пользователь видит только верхний слой — красивый интерфейс. Программист видит код. Хакер должен видеть всё, вплоть до того, как данные перемещаются по проводам.
В информатике это называется уровнями абстракции. Чем ниже уровень, тем больше контроля вы имеете над системой, но тем сложнее писать код.
!Пирамида уровней абстракции от языков высокого уровня до железа
> «Чтобы взломать систему, нужно думать как система, а не как пользователь.»
Как компьютер хранит данные: Биты, Байты и Шестнадцатеричная система
Для компьютера всё есть число. Картинка, текст, звук, программа — это просто набор чисел.
Двоичная система (Binary)
В основе всего лежит бит (0 или 1). Это как выключатель: тока нет (0) или ток есть (1). Группа из 8 битов называется байтом.Математически любое число можно представить в двоичном виде. Рассмотрим формулу перевода двоичного числа в привычное нам десятичное:
Где: * — итоговое десятичное число. * — номер старшего разряда (позиция самой левой цифры минус 1). * — цифра в -й позиции (0 или 1). * — основание системы (2) в степени позиции.
Рассмотрим пример для числа (в двоичной системе):
Где — это цифры числа, а — веса разрядов.
Шестнадцатеричная система (Hex)
Читать нули и единицы человеку невозможно. Поэтому в реверс-инжиниринге используют шестнадцатеричную систему (Hex). Она компактнее.В ней используются цифры от 0 до 9 и буквы от A до F, где A=10, B=11 ... F=15. Один байт (8 бит) всегда записывается двумя символами Hex. Например, байт 11111111 в двоичной системе — это FF в Hex и 255 в десятичной.
Архитектура фон Неймана и работа процессора
Почти все современные компьютеры построены по архитектуре фон Неймана. Её суть проста: программа и данные хранятся в одной и той же памяти.
Это критически важно для хакера. Если программа и данные лежат в одном месте, значит, мы можем обмануть компьютер и заставить его прочитать наши данные (например, вредоносный код) как программу и исполнить их. Это основа многих эксплойтов.
Основные компоненты:
* CPU (Центральный процессор): Мозг. Исполняет инструкции. * RAM (Оперативная память): Временное хранилище для запущенных программ и данных. * Регистры: Сверхбыстрая память прямо внутри процессора.Память процесса: Стек и Куча
Когда вы запускаете программу, операционная система выделяет ей кусок памяти. Этот кусок делится на важные зоны. Понимание этих зон — ключ к поиску уязвимостей (например, переполнения буфера).
!Структура виртуальной памяти процесса
1. Стек (Stack)
Это область памяти для временных данных функций. Стек работает по принципу LIFO (Last In, First Out — «последним пришел, первым ушел»). Представьте стопку тарелок: вы можете взять только верхнюю тарелку.В стеке хранятся: * Локальные переменные функций. * Адреса возврата (куда программе вернуться после выполнения функции).
Именно здесь происходит классическая атака Stack Buffer Overflow. Если записать в переменную больше данных, чем она вмещает, можно «перелить» данные и перезаписать адрес возврата, заставив программу прыгнуть туда, куда нужно хакеру.
2. Куча (Heap)
Это память для динамических данных, размер которых заранее неизвестен (например, загружаемые пользователем файлы). Кучей управлять сложнее, и ошибки в работе с ней (Use-After-Free, Heap Overflow) тоже ведут к взлому.Основы Ассемблера и Регистры
Когда мы занимаемся реверс-инжинирингом, у нас часто нет исходного кода. У нас есть только готовый файл .exe. Чтобы понять, что он делает, мы используем дизассемблер, который превращает машинный код в Ассемблер.
Регистры процессора
Процессор не умеет работать с данными в оперативной памяти напрямую. Сначала он должен загрузить их в регистры — свои «карманы».Основные регистры архитектуры x86 (32-бит) и x64 (64-бит): * EAX / RAX: Аккумулятор. Используется для арифметики и возврата значений функций. * EBX / RBX: Базовый регистр. * ECX / RCX: Счетчик (для циклов). * ESP / RSP: Указатель на вершину стека (Stack Pointer). Самый важный регистр для отслеживания стека. * EIP / RIP: Указатель инструкций (Instruction Pointer). Хранит адрес следующей команды, которую выполнит процессор.
> Важно: Если вы контролируете регистр EIP/RIP, вы контролируете весь компьютер. Вы решаете, какой код выполнится следующим.
Примеры команд Ассемблера
Ассемблер выглядит страшно только на первый взгляд. Вот базовые команды:Жизненный цикл программы: Компиляция
Чтобы понять, как «разломать» программу обратно (декомпиляция), нужно знать, как она собиралась.
Реверс-инжиниринг — это попытка пройти этот путь в обратном направлении: от машинного кода к пониманию логики.
Заключение
Сегодня мы заложили фундамент. Мы узнали, что программы — это наборы инструкций в памяти, что память делится на Стек и Кучу, и что процессор слепо выполняет то, на что указывает регистр EIP/RIP.
В следующих статьях мы начнем применять эти знания: настроим лабораторию для хакинга и попробуем проанализировать нашу первую программу.
Помните: любой софт написан людьми, а людям свойственно ошибаться. Ваша задача — найти эти ошибки.