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

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

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

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

Добавлен: 16.02.2019

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

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

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

 

Часть III. Файловая оболочка, вирус, резидент 

244 

Оператор 

scasb

 ищет в строке, адрес которой должен быть в 

es:di

, символ, на-

ходящийся  в 

al

.  Максимальная  длина  строки  для  поиска  задается  в  регистре 

cx

Как мы помним, в 

dx

 осталось смещение имени запускаемого/открываемого файла, 

в 

es

 — сегмент. Следовательно, нам нужно в 

di

 загрузить содержимое регистра 

dx

 

(

es

 у нас уже готов) (смотрите строку (2)). В 

al

 заносим символ точки (.), а в 

cx

 — 

число 65, т. е. длина строки с именем файла не должна превышать 65 байт. Почему 
именно 65? Дело в том, что в DOS имя файла с полным путем к нему (т. е. имя дис-
ка + каталоги + имя файла + расширение) не должны превышать 65 байт. 

Обратите внимание, что, как только инструкция 

scasb

 находит точку, 

di

 будет 

содержать смещение не на нее, а на следующий за ней байт. 

Здесь  стоит  рассмотреть  один  недочет,  который  часто  допускают  новички. 

Представим, что открывается файл readme (без расширения). Тогда оператор 

scasb

 

точку, естественно, не найдет. Может получиться, что в пределах 65 байт, в кото-
рых будет происходить поиск разделителя, идут машинные коды и один из них — 
com+ASCII0. Тогда наша программа посчитает, что это и есть файл с расширением 
com, а это не верно.  

В данном случае лучший способ — искать сперва ASCII 0, а затем проверить, не 

являются  ли  три  байта  перед  найденным  нулем  "com"  или  "COM".  Тем  не  менее  
в  файле-приложении  используется  описанный  выше  способ.  Вы  же  можете  без 
труда усовершенствовать наш антивирус, если будет в этом необходимость. 

Итак,  нашли  точку  в  имени  файла.  Это  может  быть  точка  как  каталога,  так  

и  файла.  Чтобы  удостовериться, что это имя файла, нам нужно проверить четыре 
байта, идущие за точкой + ASCII 0: 

это    com+ASCII 0    ? 
это    COM+ASCII 0    ? 

Как  видите,  в  ассемблере  очень  важно  следить  за  регистром  (т. е.  строчные  

и прописные символы различаются), точно так же, как и при нажатии клавиши. 

Из  приведенных  выше  проверок  видно,  что  мы  проверяем  расширение  файла 

плюс следующий за ним байт, который должен быть "нулем" (т. е. ASCII 0). Одна-
ко, если пользователь запустит файл примерно таким образом:  

prog.cOm 

или 

prog.CoM 

то наша программа "не поймет", что это COM-файл. В данном примере мы не бу-
дем проверять все варианты. Можно сделать все очень просто: все символы пред-
ставить ПРОПИСНЫМИ либо строчными и далее проверять только один вариант. 
Для этого изучите таблицу кодов и символов ASCII, приведенную в приложении 3
а  затем,  используя  логические  команды, напишите процедуру, которая будет пре-
образовывать  любую  строку  в  верхний  или  нижний  регистр,  игнорируя  цифры, 
знаки  препинания  и пр.  Подобное  упражнение  заставит  вас  немного  поломать  го-
лову  и  научит  не  только  пользоваться  логическими  командами  процессора,  но  
и составлять довольно интересные алгоритмы.  

В листинге 24.4 приведен фрагмент кода, который проверяет расширение файла. 


background image

Глава 24. Резидентный антивирус 

245 

Листинг 24.4. Проверка расширения имени файла 

... 

mov ebx,es:[di] 

;Занесем в ebx четыре байта расширения файла+0 

cmp ebx,006D6F63h    ;Это 'com'0 ? 

je Got_file          ;Да! 

cmp ebx,004D4F43h    ;Может, тогда 'COM'0 ? 

jne Next_sym         ;Нет! Это было не расширение файла 

... 

Как видите, здесь мы в качестве демонстрации 32-битных регистров загрузили че-

тыре байта в 

ebx

, а затем произвели проверку. Посмотрите внимательно, как мы это 

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

cmp

 должен быть расположен соответ-

ствующим образом, хотя в памяти храниться будет как "com". Еще раз подчеркиваем: 
очень сложно объяснить это на словах, но просто понять принцип на практике. Пута-
ница никогда не возникает. Главное — привыкнуть и понять принцип.  

Следующий  шаг.  Если  оказывается,  что  запускаемый/открываемый  файл — 

COM, то нужно проверить его на зараженность. Это делает процедура 

Check_file

В первых ее строках мы переносим имя запускаемого/открываемого файла в сегмент 
нашего антивируса по смещению 

20

 (листинг 24.5). 

Листинг 24.5. Перенос имени найденного файла 

... 

push es        ;Настроим сегментные регистры... 

pop ds 

push cs 

pop es 

mov cx,65      ;Перенос 65 символов файла... 

mov si,dx 

mov di,20      ;... в PSP, начиная с 20-го байта. 

rep movsb      ;Так для программиста гораздо удобнее. 

push cs        ;Восстановим измененные регистры 

pop ds 

... 

По смещению же 

19

 заносим атрибут для вывода имени файла в окно (так тре-

бует процедура 

Draw_frame

). Здесь все понятно.  

Дальше  читаем  первые  6 байт  файла.  Помните,  наш  вирус  сохранял  2 байта — 

1122h

 в начале файла. Мы их (а также первый байт 

68h

 (т. е. команду 

push

)) и бу-

дем проверять (листинг 24.6). 


background image

 

Часть III. Файловая оболочка, вирус, резидент 

246 

Листинг 24.6. Проверка на зараженность нашим вирусом 

... 
mov bx,ax          ;В bx — номер уже открытого файла 

mov Handle,ax 

mov ah,3Fh 

mov cx,6 

mov dx,10 

int 99h            ;Читаем первые шесть байтов. 

jc Not_infected    ;Ошибка чтения! 

 

mov ah,3Eh         ;Закроем файл. 

mov bx,Handle 

int 99h 

 

cmp byte ptr cs:[10],68h     ;Первый байт - 68h (команда push)? 

jne Not_infected             ;Нет - тогда файл не заражен! 

 

mov eax,dword ptr cs:[12]    ;Берем следующие байты... 

and eax,0FFFFFF00h           ;Обнулим один байт 

 

;Проверяем: это метка нашего вируса (в обратном порядке, причем 

;первый байт аннулирован)? 

cmp eax,1122C300h 

jne Not_infected             ;Нет! Файл чистый! 

 

call Cure_file               ;Файл заражен нашим вирусом. Лечим его... 

... 

Перед  лечением  файла  следует  обратить  внимание  на  использование  команды 

and

,  которая  обнуляет  один  "лишний"  байт  (см. листинг 24.6).  Лечит  файл  про- 

цедура 

Cure_file

, которая проста и не требует дополнительных пояснений. Алго-

ритм работы следующий: 
1.  Отводим блок памяти размером 64 Кбайт. Если отвести не удалось (может быть 

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

2.  Как  только  отвели  память,  занесем  ее  сегмент  в 

es

,  а  количество  возможных 

байтов для чтения — в переменную 

Bytes_read

. Вызываем процедуру 

Kill_zarazu

которая вылечивает файл. 
Как это практически происходит, думаю, вы без труда разберетесь, т. к. в файле-

приложении достаточно описаний.  


background image

Глава 24. Резидентный антивирус 

247 

24.3. Резюме 

В принципе, из данной главы вы почерпнули не так много нового для себя. Тем 

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

 


background image

 

 

 

Глава 25 

 

Работа с сопроцессором 

 

25.1. Ответы на некоторые вопросы 

1.  Что такое сопроцессор? 

Сопроцессор  (FPU,  Floating  Point  Unit —  устройство  для  работы  с  плавающей 
точкой) — это специальное устройство, устанавливаемое либо на материнскую 
плату,  либо  встраиваемое  внутрь  основного  процессора  (располагающееся  на 
одном кристалле с ним). 

2.  Для чего нужен сопроцессор? 

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

3.  Как определить наличие сопроцессора в компьютере? 

В  старых  машинах  сопроцессор  устанавливался  на  материнскую  плату  как  от-
дельное  устройство.  Начиная  с  80486DX,  сопроцессор  встраивается  внутрь  ос-
новного  процессора.  Можно  с  уверенностью  сказать,  что  если  на  вашем  столе 
стоит как минимум Pentium, то сопроцессор в нем присутствует. 

4.  А  если  нужно  произвести  сложные  математические  расчеты,  можно  ли  не 

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

5.  Сложно ли программировать сопроцессор на ассемблере? 

В общем-то, нет. Главное — навык. 

6.  А  почему мы начали рассматривать сопроцессор в данной главе? Что, на-

ша оболочка будет работать только с ним? 
Да. 

7.  А зачем? Можно ведь обойтись без него. 

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