Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 16.02.2019

Просмотров: 29206

Скачиваний: 1689

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Глава 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

 адрес (смещение) последнего байта на-

шей программы. 


background image

 

Часть 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

. Но мы 


background image

Глава 29. Загрузка и запуск программ 

281 

ведь  ужимаем  память  до  метки 

Finish

!  Получается,  что  программа  будет  загру-

жаться в первый байт после этой метки. В таком случае мы затираем стек. 

Чтобы этого не произошло, перенесем стек в область PSP.  Область PSP не ис-

пользуется в нашем примере, а это лишние 256 байт, куда можно переместить ука-
затель стека. 

29.1.3. Подготовка EPB 

EPB  (EXEC  Parameter  Block) —  блок  параметров  функции  загрузки  файла.  Ин-

формация, которая должна содержаться в этом блоке, представлена в табл. 29.1. 

Таблица 29.1. Структура EPB 

Смещение 

Длина (байт)  Значение 

00h 

Сегмент окружения DOS для порождаемого процесса 

02h 

Смещение и сегмент адреса командной строки 

06h 

Первый адрес блока FCB 

0Ah 

Второй адрес блока FCB 

0Eh 

Длина 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 
... 


background image

 

Часть 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

  

в консоли. 


background image

Глава 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 

;Смещение массива командной строки (заносится автоматически в процессе