Найти в Дзене
Junior Coder

Ассемблер. Резидентные программы, для чего они нужны, и как они работают.

Эта статья будет полезна каждому пользователю персонального компьютера, который хотел бы иметь какое-то представление о том, как он работает, а для тех, кто изучает программирование, с нею просто необходимо ознакомиться, на мой взгляд.

Резидентная программа - это небольшой участок кода, который постоянно находится в оперативной памяти компьютера. Ее предназначение, это перехват определенных прерываний компьютера, выполнение каких-то собственных установок, затем программа может передать управление старому обработчику, или просто выйти из прерывания. Такие программы полезны тем программистам, которые пишут драйвера, разработчикам антивирусов, ну и конечно же, это один из самых любимых инструментов хакеров. С помощью резидентной программы можно, например, отключить обработчик ошибок, перехватить управление устройствами типа cdrom-a или принтера, ну и проделать еще кучу разных полезных штук, которые нельзя проделать другими способами. Если перехватить прерывание с высоким приоритетом, то ни компьютер, ни антивирус, ни пользователь, на машине которого установлена резидентная программа, не поймут, что в какой-то момент, компьютер "отвлекся" на выполнение незапланированного кода.

Прерывания (interrupt) происходят в компьютере постоянно, например, прерывание под номером 8 (irq0) от системного таймера происходит (в зависимости от настроек) около 20 раз в секунду, прерывание под номером 9 (irq1) происходит в том случае, если пользователь нажал на какую-то клавишу на клавиатуре. Процессор в этот момент заносит значения регистров CS и IP (EIP) в стек, то есть запоминает на какой позиции он прервал выполнение текущей программы, заносит в буфер клавиатуры скан-код и ASCII значение, полученные из порта клавиатуры (60h), затем возвращается к выполнению текущей программы. Если в Windows набрать в меню пуск/выполнить msinfo32.exe, то в открывшемся окне можно посмотреть, какие аппаратные прерывания (irq) есть на вашей машине.

Для того, чтобы разобраться с тем, как работают резидентные программы, рассмотрим код небольшой программы, которая перехватывает 21-е прерывание DOS и меняет строку символов, которую выводит функция под номером 9-ть 21-го прерывания.

Код программы в com-формате:

-2

В строке 18 мы при помощи функции 35-ть 21-го прерывания получаем вектор этого прерывания и сохраняем его в переменной [old_21] (строки 20,21), затем, с помощью функции 25-ть 21-го прерывания устанавливаем вектор на нашу подпрограмму "int21", строки 22, 23, 24. В заключение при помощи прерывания 27h мы сохраняем в памяти резидентную часть нашей программы, эта та часть кода, которая выше метки "main". Теперь если скомпилировать этот код при помощи компилятора fasm в DOS или его эмуляторе, то в памяти компьютера появится резидент, который будет подменять любую строку выводимую с помощью функции 9 21-го прерывания, но чтобы увидеть как это работает, нам надо написать еще одну маленькую програмку, которая обновляет экран в синем цвете и выводит традиционное, среди программистов, привествие "Hello, World!". Эту программу я назвал "Hello.com".

-3

Вот результат ее работы, но если командой

C:\> int21.com

запустить нашего резидента, то результат работы "Hello.com" будет другим:

-4

то есть резидентная программа подменяет строку "Hello, world!" на "The is rezident!".

Но резидентная программа перехватывающая какое-то конкретное прерывание может быть не одна, в этом случае управление получает тот резидент, который был запущен первым, затем, выполнив свои установки, он передает управление следующему резиденту, и так далее... Прерывания перехватывают обычно для того, контролировать все инструкции, которые исполняются данным прерыванием, поэтому хочется быть уверенным в том, что именно наш резидент первым получил управление вектором необходимого прерывания.

Здесь необходимо немного отвлечься от темы...

Вектором называется совокупность двух значений, одно из которых хранится в сегментном регистре, другое в пользовательском, обозначают вектор обычно так 0000:0000, если мы знаем, что вектор хранится в регистрах es и bx, то записать можно так es:bx. В DOS каждый вектор занимает в памяти четыре байта, поэтому, если мы хотим получить доступ к вектору прерывания 21h, то необходимо писать es:21h*4.

... возвращаемся к нашему резиденту.

Итак, как перехватить прерывание, и быть уверенным в том, что именно мы его контролируем в первую очередь? Для этого необходимо записать прямо в таблицу векторов прерывания ссылку на наш обработчик. В представленной ниже программе, можно увидеть как это делается.

-5

Сам обработчик выглядит так же как и в предыдущей программе, но вектор мы получаем другим способом:

-6

В строке 24, командой CLI мы запрещаем прерывания, для того, чтобы исключить прерывания по тому вектору, который мы хотим изменить, в противном случае может произойти сбой работы компьютера. В строке 26 мы заносим в сегментный регистр ES значение 0, так как таблица прерываний находится в первом секторе, затем в строках 27 и 28, мы получаем значение вектора, и в строках 29, 30 сохраняем его в наших переменных. В строках 33 и 34 мы записываем ссылку на наш обработчик, и в строке 35 разрешаем прерывания. Все, осталось только в строке 36 указать метку, до которой записан код резидентной части программы и в строке 37 прерыванием int 27h выйти из программы оставив резидента в памяти.

Программы написаны на компиляторе fasm, для эмуляции пользуйтесь программой DosBox.

#ассемблер #резидентная программа #программирование