Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29206
Скачиваний: 1689
Глава 29. Загрузка и запуск программ
279
29.1.1
. Выделяем память
для загружаемой программы
Теперь рассмотрим, как это все происходит на практике. В листинге 29.1 и на
рис. 29.1 показан наш первый шаг.
Листинг 29.1. Урезаем основную память
...
(1) mov bx,offset Finish
(2) shr bx,4
(3) inc bx
(4) mov ah,4Ah
(5) int 21h
...
Помните, что традиционно метка
Finish
у нас является последней в коде.
Рис. 29.1. Урезаем память
Зачем необходимо урезать память перед загрузкой?
Как мы уже отмечали в предыдущих главах, после загрузки программы вся па-
мять отводится только этой программе. Следовательно, если мы попытаемся загру-
зить другую программу, то получим ошибку из-за недостатка свободной памяти.
В первой строке загружаем в регистр
bx
адрес (смещение) последнего байта на-
шей программы.
Часть III. Файловая оболочка, вирус, резидент
280
Зачем во второй строке мы сдвигаем на 4 бита вправо
это смещение?
Дело в том, что функция
4Ah
(изменение размера отведенной памяти) требует
указания в регистре
bx
блока памяти размером 16 байт. Загрузив в
bx
единицу, мы
отведем не 1 байт, а сразу 16, т. е. один параграф. Загружая в
bx
адрес последнего
байта нашей программы, мы получаем не количество параграфов, а количество
байтов. Таким образом, не разделив
bx
на 16, мы отведем памяти в 16 раз больше.
Делим же мы так: просто сдвинем число в
bx
на 4 бита вправо, что эквивалентно
делению
bx
на 16.
А для чего увеличиваем bx на единицу (3)?
Лучше отведем на 16 байт больше, чем на один меньше.
Теперь у нас
bx
содержит количество параграфов (блоков памяти по 16 байт),
которые заняла наша программа в памяти.
29.1.2. Переносим стек в область PSP
В листинге 29.2 и на рис. 29.2 показано выполнение второго шага.
Листинг 29.2. Переносим стек в область PSP (0FFh)
...
(1) mov sp,0FFh
...
Рис. 29.2. Переносим стек в область PSP
Вспомните, что при загрузке COM-программы в память смещение стека нахо-
дится в самом низу сегмента, в который загрузилась программа, т. е.
0FFFEh
. Но мы
Глава 29. Загрузка и запуск программ
281
ведь ужимаем память до метки
Finish
! Получается, что программа будет загру-
жаться в первый байт после этой метки. В таком случае мы затираем стек.
Чтобы этого не произошло, перенесем стек в область PSP. Область PSP не ис-
пользуется в нашем примере, а это лишние 256 байт, куда можно переместить ука-
затель стека.
29.1.3. Подготовка EPB
EPB (EXEC Parameter Block) — блок параметров функции загрузки файла. Ин-
формация, которая должна содержаться в этом блоке, представлена в табл. 29.1.
Таблица 29.1. Структура EPB
Смещение
Длина (байт) Значение
00h
2
Сегмент окружения DOS для порождаемого процесса
02h
4
Смещение и сегмент адреса командной строки
06h
4
Первый адрес блока FCB
0Ah
4
Второй адрес блока FCB
0Eh
2
Длина EPB
Подготовка EPB проводится так, как показано в листинге 29.3.
Листинг 29.3. Готовим EPB
...
(1) mov bx,offset EPB
(2) mov C_F,cs
...
В ассемблерном коде EPB мы обозначим следующим образом (листинг 29.4).
Листинг 29.4. Структура EPB в ассемблере
...
; === Exec Parameter Block (EPB) для функции 4Bh ===
EPB:
Env dw 0 ;Сегмент среды (окружения DOS) для загружаемой программы
C_O dw offset Comm_line ;Смещение командной строки + ...
C_F dw 0 ;... + сегмент командной строки
dd 0 ;FCB 1
dd 0 ;FCB 2
Len dw $-EPB ;Длина EPB
...
Часть III. Файловая оболочка, вирус, резидент
282
Рис. 29.3. Готовим EPB
Сравните код в отладчике из рис. 29.3 с тем, который приведен в табл. 29.1.
Еще несколько слов о системных переменных (сегменте
окружения DOS)
Мы уже знаем, что такое системные переменные (окружение DOS). Рассматри-
вали подробно данную тему в предыдущих главах. Но повторим еще раз, т. к.
в данный момент это очень важно.
Системные переменные хранят в себе настройки (текущие параметры), которые
устанавливаются при загрузке ОС (раньше они передавались в файле autoexec.bat).
Например:
C:\>set
CLIENTNAME=Console
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=MOSHOSTER
ComSpec=C:\WINDOWS\system32\cmd.exe
FARHOME=C:\Program Files\Far Manager
HOMEDRIVE=C:
LOGONSERVER=\\MOSHOSTER
NUMBER_OF_PROCESSORS=2
OS=Windows_NT
ProgramFiles=C:\Program Files
PROMPT=$P$G
SESSIONNAME=Console
windir=C:\WINDOWS
Посмотреть текущие параметры можно, выполнив внутреннюю команду
SET
в консоли.
Глава 29. Загрузка и запуск программ
283
Итак, если в поле "Сегмент окружения DOS..." находится 0, то порожденной
программе будут переданы те параметры, которые получила наша программа, т. е.
значения передаются по умолчанию.
Если же для порождаемого процесса (для загружаемой программы) мы хотим
передать собственные параметры, то нам нужно выделить блок памяти в отдельном
сегменте, внести туда необходимые значения и в EPB по смещению 0 занести
сегмент отведенного блока (как это делать — рассмотрим далее). Но, как правило,
в это поле практически все программы заносят ноль.
Для чего нужно создавать свое окружение DOS?
В разных целях... Например, некоторая антивирусная программа, запуская чу-
жую программу, может не передать текущее окружение, поскольку некоторые ви-
русы размножаются по пути (
PATH
), который они сами находят в памяти (вспомним
из прошлых глав, что найти сегмент окружения DOS можно по смещению
2Ch
сег-
мента, в который загрузилась программа; смещение всегда будет равно нулю).
В другом случае программа может дополнить окружение DOS своими парамет-
рами (например, добавить путь к своим оверлеям в переменную
PATH
).
Вроде все понятно. Однако помните, что если вы решили создать свое окруже-
ние, то нужно придерживаться определенных правил. Как именно устроены сис-
темные переменные — см. в главе 23. Там все подробнейшим образом описано.
По такому образцу вам необходимо будет создавать свое окружение для порож-
даемого процесса.
Обратите также внимание, что нам необходимо заносить только 1 байт (смеще-
ние), а не 2 (сегмент + смещение). Как уже отмечалось ранее, смещение окружения
DOS всегда будет равно нулю.
Сегмент и смещение командной строки
Здесь все просто. Создаем некий массив и заносим в это поле вначале смещение,
а затем сегмент этого массива.
Например, так (командная строка):
Comm_line db 5,' abc',0Dh
А теперь обратите внимание, что по умолчанию в EPB заносится смещение ко-
мандной строки (в процессе ассемблирования программы), а сегмент придется за-
носить самим (см. разд. 29.1.4):
...
;Заносим сегмент командной строки в изначально неопределенную переменную C_F
mov C_F,cs
...
;Область переменных
;Сегмент массива командной строки (по умолчанию равен нулю)
C_F dw 0
;Смещение массива командной строки (заносится автоматически в процессе