Это первый урок о реверс-инжиниринге (RE).

Зачем нам это нужно? Обычно для использования двоичных файлов (взлом приложений) или анализа вредоносных программ (чтобы узнать, как работают вредоносные программы). Кроме того, он используется для исправления ошибок, но очень мало программистов, которые используют отладку (исправление ошибок с помощью бинарного анализа). В общем, используя RE, чтобы понять, как работает бинарная программа, получите ее нормальный код (C ++, Python, Java). Итак, откроем двоичный файл (скомпилированную программу) в блокноте:

Очень много странных символов. Это результат работы компилятора. Процессор (ЦП) получает символы как двоичные, поймите это и работайте, используя что-то вроде данных, кода ... Давайте рассмотрим весь путь от обычного кода до двоичного:

Обычная часть кода используется программистами. Двоичный файл выполняется процессором. Ассемблер и упаковка понятны реверс-инженерам и программистам (очень немногие программисты используют ассемблер). Мы научимся понимать код ассемблера, некоторые бинарные концепции. Давайте начнем.

Чтобы попасть в RE, вы должны понимать, как вообще работает процессор. Трудно только на первый взгляд. ЦП получает информацию только из памяти в регистры или из регистров в память. Регистр - это особый участок памяти внутри самого процессора, длиной от 8 до 64 бит, который используется для промежуточного хранения информации, обрабатываемой процессором. Некоторые регистры содержат только определенную информацию. Работает с этой информацией по командам и возвращает результат. И одно хочу сказать - мы будем изучать только архитектуры x86 и amd64. Это все.

Посмотрим на регистры. Регистры - это глобальные переменные фиксированного размера в процессоре. Возможно, вы когда-нибудь слышали о 64-битном процессоре или 32-битном. Это означает, что регистры в процессоре могут содержать 32 бита, 32 нуля и единицы. 1 единица - бит. 4 - клев. 8 - байт, нужно только это запомнить. Первый процессор, который мы рассмотрим, - это Intel 8080 (8-битный процессор). Как видите, у него было только 8 бит в каждом регистре и всего 4 регистра общего назначения: AL, CL, DL, BL. Регистры общего назначения - это регистры, которые ВЫ МОЖЕТЕ использовать в качестве памяти.

Но этой памяти мало. Итак, в 1978 году Intel выпустила новый 16-битный процессор Intel 8086, имевший 8 регистров AX, CX, DX, BX, SI, DI, BP и SP. Это, наверное, самый популярный процессор того времени. И в этом была особенность. AX, BX, CD, DX - 16-битные, разделены на два 8-битных регистра. Итак, AX делится на AH и AL, DX на DH и DL и так далее. буква H означает высокий регистр. Итак, AH и AL имеют по одному байту, AH - 2 байта (или слова).

Следующий процессор - 32-битный Intel 80386 (1983). Регистры: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP. Они 32-битные и также разделены на две части, нижние из которых - AX, BX, CD, DX, SI, DI, BP, SP. Здесь просто добавлена ​​буква «Е» (32-битная).

(Intel Pentium - 1993) У 64-битных процессоров такая же ситуация, как и у 32-битных. Но вместо «E» будет «R». Также 64-битная версия имеет дополнительные регистры общего назначения: R8 - R15.

В целом:

  • AX - аккумулятор (AH / AL)
    CX - счетчик (CH / CL)
    DX - данные (DH / DL)
    BX - база (BH / BL)
    Si - Индекс источника
    Di - Индекс назначения
    Bp - Базовый указатель
    Sp - Указатель стека

Каждый из них вы можете изменить вручную (с помощью кода). В процессе вы поймете, почему и что они содержат.

Кроме регистров общего назначения у нас есть сегментные регистры:

  1. CS (Code Segment) - содержит адрес сегмента размером 64 КБ с инструкциями процессора. Процессор использует сегмент CS для всех обращений к инструкциям, на которые ссылается регистр указателя инструкций (IP) (см. Ниже).
  2. DS (Data Segment) - хранит начальный адрес сегмента данных. Сегмент данных содержит данные, константы и рабочие области. Например, строковые ссылки.
  3. SS (Stack Segment) - хранит начальный адрес стека. Сегмент стека содержит данные и адреса возврата процедур или подпрограмм. Он реализован в виде «стековой» структуры данных.
  4. ES (Extra Segment) - указатель на дополнительные сегменты, не может использоваться программой.

У нас есть другие регистры, которые мы не можем «легально» редактировать:

Регистры смещения - EIP, ESP, EBP, ESI, EDI. Эти регистры 32-битные, нижняя половина которых доступна как регистры IP, SP, BP, SI, DI.

  • EIP - указатель команды, и содержит смещение (значение смещения относительно начала программы) в строке кода, которая будет выполняться следующей. Другими словами, полный адрес следующей исполняемой строки кода будет CS: EIR.
  • Регистр ESP указывает адрес вершины стека (адрес, по которому следующая переменная будет введена командой PUSH). Регистр EBR содержит адрес, с которого информация вводится или переносится в стек (или глубина стека). Параметры функции имеют положительный сдвиг относительно EBP, локальные переменные имеют отрицательный сдвиг, и полный адрес этого раздела памяти будет SS: EBP.
  • Регистр ESI является адресом источника и содержит адрес начала блока информации для операции перемещения блока (полный адрес DS: SI).
  • И регистр EDI является адресом назначения в этой операции (полный адрес ES: EDI).

Регистры флагов - это специализированные регистры, отражающие текущее состояние процессора. Многие из их битов устанавливаются после выполнения операций и указывают тип полученного результата.

  • CF flag - флаг переноса для арифметических операций.
  • PF flag - флаг четности результата.
  • Флаг AF - дополнительный флаг передачи.
  • ZF flag - флаг нулевого результата.
  • SF flag - флаг знака.
  • TF flag - флаг пошагового режима (для отладки)
  • Флаг IF - для разрешения аппаратных прерываний
  • DF flag - флаг направления для строковых операций
  • Флаг OF - переполнение

Флаги могут содержать только одно битовое значение. Они однобитовые.

Хорошо. Сегодня все. Увидимся ;)