Перекрытие кода. Часть 8.

Дата публикации 9 апр 2019 | Редактировалось 17 май 2019
Хороший программист не брезгует ассемблером. А тот, кто умеет использовать прием "перекрытие кода", тот уже близок к профессионалу. Осталось к уже изученному освоить приемы скрытия вызова функций, самомодификации кода, исполнения кода в стеке, шифрование кода или его части и еще чуть чуть – и вы профессионал или программист-фокусник!

Суть метода перекрытия кода состоит в том, что часть одной машинной команды может быть другой командой. Например, команда mov может загрузить в регистр число, которое на самом деле является кодом операции другой команды. Затем, другой командой необходимо в команде mov необходимо начало выполнения кода поставить на требуемый байт данных, которые посчитать кодом операции. При этом, необходимо учесть, что числа в памяти располагаются в таком порядке: сначала младшие части с меньшими адресами, а затем – старшие части со старшими (большими) адресами (в тексте программы – наоборот).

В ассемблерной программе можно задавать не абсолютные адреса, а смещение относительно текущего адреса:
Код (ASM):
  1. jmp $ + 25  ;  переход на 25h байт «вперёд»;
  2. jmp $ - 15   ;  переход на 15h байт «назад»

Идентификатор $ – это значение текущего счетчика адреса строки кода,
в которой располагается этот символ. А выражение «$-» обозначает разницу между адресом строки кода, в которой располагается этот символ и того значения, которое указано за ним (или другой операции, которое применено к идентификатору $.
Например
Код (ASM):
  1. mas1 DD 20 dup(1,2,4,6) ; резервирование ячеек памяти для mas1
  2.   dd 16 dup(1)  ; 80+16=96
  3. len1 equ ($-mas1) ; число байтов в mas1
обозначает, что переменной len1 будет присвоено число, которое высчитывается как разница между текущим адресом, по которому располагается переменная $ и значением адреса переменной с именем mas1. А т.к. каждый байт адресуется своим адресом, то практически переменная len1 равняется числу байтов, которые отводятся для хранения массива mas1.

Если после строк
Код (ASM):
  1. mas1 DD 20 dup(1,2,4,6) ; резервирование ячеек памяти для mas1
  2.    dd 16 dup(1)
и перед строкой
Код (ASM):
  1.    len1 equ ($-mas1)
расположить одну или несколько строк другого кода, то идентификатор посчитает результирующее число байтов на весь блок кода.

Рассмотрим блок кода:
Код (ASM):
  1. mov ax,05EBh
  2. jmp $ - 2
В памяти команда mov ax,05EBh запишется машинным кодом: 66:B8 EB05. Причем, значения 05EBh поменялись местами. В память программы числа записываются по правилу «младший байт – по младшему адресу».
Так же необходимо помнить, что каждый байт в машинном коде имеет адрес и к любому байту по их адресу можно обратиться.
Следовательно, команда jmp $ - 2 обозначает, что из адреса строки, в которой указан идентификатор $ будет вычтено 2. Это значит, что будет пропущено 2 байта справа предыдущей строки кода 66:B8 EB05 и выполнится команда с кодом операции EB и операндом 05.

Перекрытие кода применяют к уже готовой программе при открытии ее ехе-файла в отладчике.
Алгоритм перекрытия кода заключается в следующем:
  1. Открывается ехе-файл программы в отладчике (в данном случае отладчик x64Dbg);
  2. Анализируется код в отладчике на предмет поиска мест применения перекрытия кода;
  3. Вставляется команда jmp $ с отрицательным или положительным приращением в соответствии с количеством байтов соседствующих команд. В этом случае, становится уместным применение «мусорного» кода;
  4. Компилируется программа и проверяется правильность применения перекрытия кода;
  5. Возврат к пункту 2 до тех пор, пока не выполнятся предъявляемые к программе требования.

0 2.671
Alex81524

Alex81524
New Member

Регистрация:
12 фев 2008
Публикаций:
5