Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Ассемблер? Это просто! Учимся программировать Выпуск N 024 (Антивирус)


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

Ассемблер? Это просто! Учимся программировать
______________________________________

Выпуск N 23 (Антивирус)

Вы шумiце, шумiце, нада мною бярозы.
Калышыце, люляйце цiхай ласкай зямлю.
А я лягу-прылягу край гасцiнца старога.
Я здарожыуся трохi, я рассылку прачту...

Доброе время суток, уважаемые подписчики!

Сегодня в номере:

  • Информация для новеньких.

  • Сотрудничество.

  • Резидентный антивирус. Введение в 32-х разрядные регистры.

  • Несколько слов от автора.



  • Благодарю Вас, что подписались на рассылку "Ассемблер? Это просто! Учимся программировать". Надеюсь, что Вы не останетесь равнодушными к ней и почерпнете море полезной информации, а также повысите свой уровень в "общении" с компьютерами.

    Прежде чем приступать к изучению материала в данном выпуске, Вам необходимо внимательно ознакомиться с предыдущими. Я уверен, что Вы очень быстро и без труда догоните остальных подписчиков.

    Всю нужную информацию (предыдущие выпуски, адреса экспертов, необходимые программы, документацию, а также многое другое) можно найти на сайте http://www.Kalashnikoff.ru. Рекомендую Вам прежде ознакомиться с разделом "Информация для новых подписчиков", а тажке перекачать архив рассылки, куда входят необходимые файлы-приложения.

    Если у Вас нет выхода в Сеть, то предыдущие выпуски рассылки, информацию для новеньких и адреса экспертов можно получить по почте, направив пустое письмо по адресу AssmIssues@Kalashnikoff.ru. Информация (320 Кб) будет выслана Вам в течение двух рабочих дней с момента получения Вашего письма. Однако, пожалуйста, не злоупотребляйте этим, т. к. высылка писем подобного объема несет дополнительную нагрузку на почтовые сервера.



    Дорогие мои друзья! Я стараюсь опубликовывать в рассылке только лучшие материалы по программированию, которые мне попадаются на глаза.

    Совсем недавно ко мне пришло письмо от еще одного ведущего рассылки "" Эдуарда Дмитриева. Чем примечательна данная рассылка? Тем, что:

    • рассылка выходит довольно-таки давно, что доказало намерения автора довести дело до конца;
    • материал преподносится на доступном языке (я сам с удовольствием ознакомился с некоторыми выпусками);
    • вы без труда догоните ушедших вперед подписчиков;
    • автор рассматривает параллельно несколько языков программирования (HTML, );
    • низкий уровень отписки от рассылки, что свидетельствует о заинтересованности читателей;
    • на сайте автора собран уникальный в своем роде материал по многим языкам программирования (я даже скачал небольшую книгу по программированию на Перле, содержанием которой очень доволен);
    • автор не нарушает авторских прав лиц, чей материал опубликован на его сайте;
    • автор излагает материал на грамотном русском языке, что, безусловно, в настоящее время является редкостью в Интернете;
    • у рассылки имеются подобные нашим экспертные группы, но более широкого спектра:

      - С, С++
      - DELPHI
      - HTML, XML, XHTML, CSS, CSS2, дизайн и промоутинг
      - Linux
      - Pascal
      - Perl
      - PHP
      - Общие вопросы программирования
      - Windows

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

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

    Каковы цели сотрудничества?
    Прежде всего - объединение знаний обоих ведущих (меня и Эдуарда). Эдуард знает то, что не знаю я, а я же, в свою очередь, знаю то, что не знает Эдуард. В итоге вы, уважаемые читатели, получаете знания как мои, так и Эдуарда Дмитриева. Это разве плохо?
    Вторая цель, как я уже сказал, - объединение двух рассылок и, естественно, аудиторий, что позволит еще большему количеству людей обрести знания сразу в нескольких областях.

    Если вы заинтересовались, то - добро пожаловать! Буду рад видеть знакомые мне уже электронные адреса в рассылке Эдуарда.

    Адрес сайта автора рассылки: http://prog.agava.ru (Библиотека программиста).

    Рассылки Subscribe.Ru
    Уроки для начинающих программистов

    Знаю, что пересечение аудиторий нашей рассылки и рассылки Эдуарда Дмитриева составляет более 3.800 человек. Я рад, что вы стремитесь освоить программирование под Windows не только на Ассемблере, но и на других языках. Приступив вскоре к Win32, читатели, знакомые, например, с C++, смогут проще понять принцип программирования под эту мощную операционную систему.

    Итак, как говорится, вперед на мины!




    Antivr24.asm

    Display.asm


    Test24.asm

     

    Файл-приложение в Интернете: http://www.Kalashnikoff.ru/Assembler/Issues/Enclosures/Antivr24.rar.

    ВНИМАНИЕ!!! Наш антивирус корректно лечит только неизмененный вирус, код которого приведен в выпуске №020. Если вы добавили или убрали хоть один байт в коде вируса, то антивирус будет лечить его неверно!


    Прежде, чем приступим к расмотрению работы нашего антивируса, ознакомимся вкратце с некоторыми регистрами 80386/80486 процессора. Все очень просто! Вот таблица:

    EAX (32 разряда)
    AX (16 разрядов) AX (16 разрядов)
    AH (8 разрядов) AL (8 разрядов) AH (8 разрядов) AL (8 разрядов)

    Как видно, EAX - 32-х разрядный регистр. Он может хранить число 65535*65535 (т.е. 65535 в квадрате).

    До сих пор мы пользовались только 16-и разрядными регистрами (AX, BX, CX и пр.). Теперь надо по-тихоньку привыкать к 32-х разрядным. В принципе, острой необходимости пользоваться ими в нашем примере нет. Единственная цель - показать вам возможности 32-х разрядных регистрах, а также попробовать использовать их на практике на простейшем примере.

    В приведенной выше таблице мы рассмотрели только регистр EAX. Проводя аналогию с ним, можно добавить:

    EBX, ECX, EDX, EDI, ESI, EBP.

    Все эти регистры, как не трудно понять, 32-х разрядные. Думаю, что проблем с ними не будет...

    Единственное условие - использовать директивы:

    .386

    .486 и пр.

    но никак не

    .8086

    .286

    Это связано с тем, что 32-х разрядные регистры появились только в 80386 процессоре. Соответственно, нужно использовать и программу-ассемблер (MASM / TASM), которая поддерживает инструкции 386+ процессоров. Если при ассемблировании ассемблер выдает ошибку на первой строке (.386), то вам необходимо искать более современную программу-ассемблер. Например, TASM 5.0 или MASM 6.13 (MASM 6.13 можно взять на нашем сайте).

    Примеры:

    mov eax,0 ;EAX=0
    mov eax,15h ;EAX=15h, AX=15h
    mov ax,0FF00h ;AX=0FF00h, EAX=0FF00h
    mov eax,12345678h ;EAX=12345678h, AX=5678h

    Не стоит забывать, что данные в компьютере храняться "задом наперед". Примеры:

    ________

    (1) mov Variable,12345678h
    (2) mov eax,Variable
    (3) mov ax,word ptr Variable
    ...
    (4) Variable DD ?

    ________

    В строке (1) мы заносим в переменную Variable 32-х разрядное число 12345678h. Обратите внимание, что сама переменная должна иметь тип DD (Double Word - двойное слово) (строка (4)).

    В строке (2) мы загружаем в EAX это число. EAX будет равен 12345678h. Т.е. ничего не меняется, т.к. мы обращаемся к данной переменной как к двойному слову и читаем из нее как двойное слово.

    Однако, в памяти число 12345678h будет располагаться таким образом:

    78563412h

    т.е. "задом наперед". При загрузке же его в 32-х разрядный регистр, оно обратно как бы "перевернется".

    Другое дело, когда мы хотим получить слово из подобных 32-х разрядных переменных в 16-и разрядный регистр (например, AX). Смотрите строку (3).

    Учитывая, что число хранится в памяти "задом наперед", то после выполнения строки (3) в AX будет число 5678h. Поэкспериментируйте с этим. Т.к. только на экспериментах можно будет понять принцип храниния чисел в памяти...

    Обратите еще внимание, как мы загружаем в AX число (строка (3)). Перед Variable идет word ptr. Это указывает процессору на то, что в AX нужно занести два байта (слово). Word ptr опускается, если переменная имеет тип DW и загружаем мы в 16-и разрядный регистр. Однако, если мы хотим загрузить в 16-и разрядный регистр число из 32-х рязрядной переменной (DD), то указать word ptr нужно обязательно!

    ______

    При работе с инструкциями 386+ процессоров, возникает еще одна проблема: отладчик AFD версии 1.0 не распознает данные инструкции, естественно, 32-х разрядные регистры. Дело в том, что в момент написания этой программы еще не были придуманы 80386+ процессоры...

    Данная проблема может быть разрешена путем использования отладчика CV, который входит в комплект MASM 6.13 либо (для опытных программистов) SoftIce. Я пока постараюсь в ближайших выпусках использовать 16-и разрядные регистры, но вам необходимо по-тихоньку искать новые отладчики...

    ________

    Еще обратите внимание на строку:

    cseg segment use16 ;По умолчанию 16-и разрядные данные

    USE16 сообщает ассемблеру, что по умолчанию будут использоваться 16-и разрядные регистры, данные и пр.

    Убрав данную дерективу, программа-ассемблер будет использовать USE32 (т.е. 32-х разрядные данные) и выдавать ошибку на строках вида:

    mov dx,offset Message

    В данном случае (если мы уберем USE16) нам следует записывать

    mov edx,offset Message

    Более подробно директиву USE32 мы рассмотрим в последующих выпусках. Здесь она нужна нам, т.к. мы используем команды 80386 процессора...

    _________

    Еще момент. Почему программы, написанные на языках высокого уровня, имеют больший объем, чем аналогичные на Ассемблере.

    В нашем примере я постарался это показать. Обратите внимание, что к файлу Antivr24.asm идет уже знакомый нам файл Display.asm, взятый из оболочки. В данном файле собраны процедуры для работы с экраном и видеобуфером. Для того, чтобы заново не писать процедуру вывода окна на экран (а наш резидент выводит окошки прямым отображением в видеобуфер), я просто использовал уже готовые процедуры. Однако, в файле Display.asm существуют процедуры, которые, например, прячут курсор и восстанавливают его. Наш антивирус не будет прятать курсор. Следовательно, подобные процедуры можно убрать, тем самым сократив объем программы. Да, на Ассемблере это возможно. Но на языках высокого уровня - нет.

    Например, в С используется директива #include stdio.h (кажется, так), которая подобна ассемблерной include display.asm. Однако, программист не может посмотреть или изменить то, что находится внутри stdio.h (возможно я и ошибаюсь). А в ней есть множество процедур, которые скорее всего программист и вызывать-то не будет. Отсюда и рост размера программы.

    Обратите внимание, что я специально не убрал Hide_cursor и тому подобдные процедуры, имитируя насколько это возможно языки высокого уровня...

    Но это так, для общей информации... Если ошибся - извините. Я не спец в С... Верить мне на слово не нужно!

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

    _________

    Теперь ближе к программе.

    Все, что идет после метки Init, вам уже известно. Обращаю только ваше внимание на то, что вызывать 21h прерывание в резидентной части мы будем как int 99h, для чего скопируем оригинальный вектор 21h-ого в 99h-ый. Я полагаю, вы помните, для чего так нужно делать...

    Наш резидентный антивирус будет "сидеть" в памяти и контролировать открытие или запуск программы, которую "на лету" проверит на зараженность и, если заражен, то вылечит его (искать будем наш вирус, который писали в 20 выпуске). Для экспериментов вытащите его из 20 номера. Еще раз предупрежу: будьте осторожны!

    Т.к. наш резидент использует интенсивно стек, то лучше мы перенесем его в область PSP, во избежании переполнения стека программы, вызывающей 21h-ое прерывание.

    Смотрим:

    ______

    (1) cli ;Запретим прерывания
    (2) mov cs:[0],ss ;Сохраним сегментые регистры
    (3) mov cs:[2],sp

    (4) ;Установим стек на область PSP нашего резидента
    (5) push cs
    (6) pop ss
    (7) mov sp,0FEh

    ______

    Обратите внимание, что мы должны запретить прерывания прежде, чем менять регистры SS:SP (строка (1)).

    Как видите мы сохраняем SS:SP в нашем сегменте по смещению 0 (т.е. в PSP нашего антивируса) (строки (2) - (3)). Не будем заводить отдельные переменные, т.к. это увеличит размер программы. Все равно ведь память там свободная...

    Затем нужно настроить сегментные регистры:

    push ds
    pop es
    push cs
    pop ds

    Как известно, перед вызовом функций 4Bh (запуск программы) и 3Dh (открытие файла), DS должен указывать на сегмент, а DX на смещение имени файла. Для того, чтобы не затереть эти регистры, мы DS перенесем в ES, а сам же DS сделаем равным CS. Теперь адрес файла для запуска / открытия в ES:DX. Нужно внимательно следить за тем, чтобы сохранить DX. Можно, конечно, занести его в переменную и не волноваться, но так будет проще, да и меньше байт потребуется. Хотя, если подобных данных нужно хранить много или одно число в регистре нужно долго "хранить", то лучше завести отдельную переменную. Так будет наглядней...

    Теперь вызываем процедуру Check_prog, которая будет проверять, запускается / открывается ли com-файл или какой-то иной.

    _________

    (1) cld ;Направление - вперед!
    (2) mov di,dx ;Ищем в имени файла точку
    (3) mov al,'.'
    (4) mov cx,65 ;Всего будем просматривать 65 символов
    (5) Next_sym:
    (6) repne scasb ;Ищем пока НЕ найдем точку.
    (7) jne No_com ;Не нашли точку вообще? Тогда на выход

    _________

    Оператор SCASB ищет в строке, адрес которой должен быть в ES:DI, символ, который находится в AL. Длина строки задается в регистре CX.

    Как мы помним, в DX осталось смещение имени запускаемого/открываемого файла, в ES - сегмент. Следовательно, нам нужно в DI загрузить DX (ES у нас уже готов) (смотрите строку (2)). В AL заносим символ "." (точку), а в CX - 65 (т.е. длина строки с именем файла не должна превышать 65 байт).

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

    Только заметил недочет. Представим, что открывается файл README (без расширения). Тогда точку мы, естественно, не найдем. А что, если после имени файла идут машинные коды и один из кодов - "."? Тогда мы будем выполнять лишние команды... А если после точки идет и com, а затем ASCII 0? Тогда вообще наша программа посчитает, что это и есть имя файла...

    В общем, лучший способ - искать ASCII 0, а затем проверить три байта перед найденным нулем на "com" или "COM". Я думаю, что вы без труда переделаете программу, если будет желание...

    Вернемся к инструкции SCASB. Обратите внимание на следующее: как только данная команда нашла нужный байт, DI будет указывать НЕ на него, а на следующий за ним!

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

    это com+ASCII 0

    это COM+ASCII 0

    Как видите в Ассемблере очень важно следить за регистром (т.е. маленькие и большие символы различаются). Это как при нажатии на клавишу.

    Из приведенных выше проверок видно, что мы проверяем расширение файла плюс следующий за ним байт, которы должен быть "нуль" (т.е. ASCII 0).

    Однако, если кто-то запустит файл примерно таким образом:

    prog.cOm

    или

    prog.CoM

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

    Вот проверка:

    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. По смещению же 19 заносим атрибут для вывода имени файла в окно (так требует процедура Draw_frame). Здесь все понятно...

    Дальше читаем первые шесть байт файла. Помните, наш вирус сохранял два байта - 1122h в начале файла. Мы их (а также первый байт 68h (т.е. команда PUSH)) будем проверять...

    Если файл заражен, то его нужно лечить. Здесь следует обратить внимание на использоваение команды AND. В файле-приложении все указано...

    Лечит файл процедура Cure_file, вопросов к которой не должно возникнуть...

    В двух словах:

    Отводим блок памяти размером 64Кб. Если отвести не удалось (вдруг вся память отведена какой-то программой, как, например при попытке открытия его в оболочках DOS), то будем использовать память видеокарты, которой всего-то 28Кб. Но все-таки...

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

    Вызываем процедуру Kill_zarazu, которая убьет заразу...

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

    Дерзайте, друзья мои! Скоро будет Windows. Вам следует хорошо разобраться с DOS!

    __________

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

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

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

    Вот вроде и все!!!


    Несколько слов от автора.

    Итак, простейший вирус и антивирус мы рассмотрели. Несколько резидентов тоже (правда, научимся еще удалять резидент из памяти). Осталась только оболочка, несколько новых операторов, некоторое количество прерываний и функций DOS, а также алгоритмы... После этого со смелой душой приступим к Windows. Уже скоро! Думаю, еще 5-10 выпусков и мы переходим на новый уровень программирования.

    В связи с этим я напомню еще раз: мне нужны помощники для ведения рассылки по программированию на Ассемблере под Windows. Дополнительная информация будет указана в последующих выпусках. Если вы чувствуете, что сможете обучить людей программированию под Win32, то ждите анкету в следующих выпусках.

    __________

    Скоро весна... В связи с этим, в апреле (как только станет тепло) планируется грандиозная акция под кодовым названием "Ассемблер? Это просто! Учимся программировать". Вас ждет прекрасное времяпрепровождение, общение, знакомства, а также еще кое-что. Подробности читайте в первых апрельских выпусках...

    Всем счастливо!


    С уважением,

    Автор рассылки: Калашников Олег
    URL сайта подписчиков:
    http://www.Kalashnikoff.ru
    E-mail автора:
    Assembler@Kalashnikoff.ru
    ICQ: 68951340

    Москва, 2001.


    (C) Авторское право принадлежит автору рассылки. Использование материала из рассылки в коммерческих и иных подобных целях, а также публичное публикование без письменного согласия автора влечет ответственность за нарушение авторских прав.


    http://subscribe.ru/
    E-mail: ask@subscribe.ru
    Поиск

    В избранное