Калашников.ru - Ассемблер? Это просто!.. (Выпуск № 010)

InterReklama Advertising

Здравствуйте, дорогие любители Ассемблера!

Выпуск № 010

Пей пиво на заре, пей пиво перед сном,

Пей пиво на траве, пей пиво за столом,

Пей пиво натощак, пей пиво со хмеля,

Пей пиво просто так, пей как "Авария"!

Пей пиво!

"Дискотека "Авария".

Что у нас сегодня?

Приветствие

Ваши письма

Программа из прошлого выпуска

Голосование

Вирус

Резидент

Блиц-опрос

Привет, друзья мои!

Почему я с пива-то начал? Да вот почему: в настоящий момент есть четыре хорошие новости:

1. В позапрошлый понедельник (то бишь, 18 сентября 2000 года) у меня родился сын! С чем вы и можете меня и мою жену поздравить. Одним Калашниковым стало больше. Ну, и, естественно, это дело отмечалось "по полной программе". Пиво текло рекой (особенно мое любимое - "девятка")...

2. Наша рассылка продолжает выходить. Всем спасибо еще раз, кто проголосовал на сайте www.Kalashnikoff.ru. Меня очень умиляет Ваше общение в форуме. С громадным удовольствием я читал сообщения. Очень порадовали некоторые решения предыдущей программы. Просто Супер-8! Но об этом ниже...

3. Я нашел классную работу. Теперь Интернет у меня постоянный (по световому кабелю). Мне нет смысла пользоваться услугами провайдера России-Он-Лайн. В связи с этим у меня меняется адрес электронной почты. Большая просьба: кто присылал мне предыдущие сообщения на адрес oleg77@online.ru, переслать их по адресу oleg77@beep.ru. Спасибо!

Я также благодарю всех, кто присылал мне предложения по поводу трудоустройства. Дорогие мои! Низкий вам поклон и море благодарности!!!

4. Наша рассылка соответствует всем требованиям, предъявляемым к рассылкам класса "золотых". Так что, я надеюсь, что скоро мы будем в соответствующем разряде. Огромное спасибо всем, кто оставался с нами (т.е. вам всем).

Ваши письма.

Огромное спасибо всем, кто прислал мне адреса бесплатных почтовых серверов. Поверьте, проверил все, которые можно. Решил остановиться на www.beep.ru . Посмотрим, что получится...

___________________

Сообщаю несколько адресов подписчиков, которые пожелали разместить e-mail в рассылке:

baddy@fregat.mk.ua - Peter

den_nik@ukr.net - Denis

___________________

А вот ниже письмо от Леонида. Подобных писем пришло много, поэтому я отвечу на одно как всем:

Добрый день, Олег!

Хотелось бы заняться ассемблером, но не знаю с чего. Подскажи с чего начать (с нуля); если есть что-то в электронном виде, то, если не трудно, вышли.

С уважением Леонид.

__________________

Уважаемый Леонид!

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

_________________

Еще многие спрашивают, почему я не рекомендую пользоваться каким-нибудь специальным текстовым редактором. Друзья мои! Текстовых редакторов существует великое множество. Я все же настоятельно советую пользоваться DOS Navigator'ом, который можно взять на нашем сайте, т.к. эти спецредакторы имеют кучу ошибок и недоделок. Скачивайте, кому нужно!

Программа из прошлого выпуска.

Теперь по поводу предыдущего выпуска. Что у нас была за программа? Да! Она загружала саму себя в память. Т.е. поверх себя (поверх своего кода). Я не зря просил Вас назвать ее именно less009.asm. Т.к. если программа не найдет файл с данным именем (*.com), то она просто выйдет, при этом выдаст звуковой сигнал. Одна девушка, которая интересуется программированием на Ассемблере (да-да, дорогие мои! В наших рядах есть женщины, чему я очень рад!), назвала работу программы "чертовщиной". На самом деле, ничего сложного в ней нет. Надеюсь, Вы поняли, что в Ассемблере можно вытворять невероятные вещи, которые на языках высокого уровня (Бейсик, С, Паскаль) недоступны.

Мне очень понравилось объяснение Александра на форуме. Я опубликовываю (с некоторыми добавлениями. Очень надеюсь, что Александр за это не будет меня бить ногами):

 

; Программа выполняет запись самой себя в то место памяти, куда она

; уже загружена.

CSEG segment

assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG

org 100h

Begin:

mov dx,offset File_name ; Открываем файл

call Open_file ; с помощью спецпроцедуры (см. ниже).

jc Error_file ; Переход на метку Error_file при неудаче.

mov bx,ax ; Сохраняем идентификатор файла и

mov ah,3Fh ; начинаем его читать (то бишь файл).

mov cx,offset Finish-100h ; Записываем длину нашей программы (кол-во читаемых байт),

mov dx,offset Begin ; и читаем файл в память,

int 21h ; начиная с указанного адреса. ВЕРНО!!!!! (прим. - О. К.)

call Close_file ; Закрываем файл с помощью спецпроцедуры (см. ниже).

mov ah,9 ; Выводим сообщение об удачном завершении.

mov dx,offset Mess_ok

int 21h

ret

 

; Если файл с указанным именем не нашли (File_name db 'less009.com',0), то пищим и выходим. (прим. - О. К.)

Error_file:

mov ah,2

mov dl,7

int 21h

ret

Open_file proc ; Процедура открытия файла для чтения,

cmp Handle,0FFFFh ; в которой выясняется открыт ли файл,

jne Quit_open ; и если не открыт - открываем его.

mov ax,3D00h

int 21h

mov Handle,ax

ret

Quit_open:

stc ; Устанавливаем флаг переноса в 1, необходимый

ret ; для подтверждения факта открытия файла (для jc).

Handle dw 0FFFFh

Open_file endp

 

Close_file proc ; Процедура закрытия файла,

cmp Handle,0FFFFh ; при условии, что он был открыт.

je No_close

mov ah,3Eh

mov bx,Handle

int 21h

mov Handle,0FFFFh

No_close:

ret

Close_file endp

File_name db 'less009.com',0

Mess_ok db 'Всё нормально!',0Ah,0Dh,'$' ; 0Ah,0Dh - переход в начало следующей строки,

; типа writeln или puts().

Finish equ $ ; Признак (адрес) конца кода программы.

 

CSEG ends

end Begin

 

Подробнее мы рассмотрим принцип работы подобных программ позже.

Голосование.

Большинство из вас проголосовало за изучение Ассемблера таким образом:

быстро DOS, а затем Windows. Я полагаю, что это интереснее и целесообразнее будет, чем просто изучить DOS, либо сразу перейти к Windows. Таким образом, мы начинаем изучать DOS.

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

1. Оболочка типа Norton Commander;

2. Вирус;

3. Резидент.

На первое место все же вышла оболочка, но не на много обогнав вирус.

Сегодня же у нас экспериментальный выпуск. Попробуем проходить тему быстрее положенного. Если что-то не усвоите - пишите. Заходите на форум на сайте. Пишите мне. В конце рассылки я специально провожу опрос.

Итак, начнем.

Вирус.

Что такое вирус? Вирус - это программа, написанная, как правило, на Ассемблере (хотя есть вирусы, написанные на Pascal, С и Visual Basic). Эта программа может сама размножаться, заражая другие программы без участия программиста, который сам же и написал этот вирус. Как так может быть? Элементарно!

Писать вирус на Ассемблере - милое дело. В свое время я писал вирусы как резидентные (постоянно находящиеся в памяти), так и нерезидентные. Более того, я писал и антивирусы (против своих же вирусов, естественно).

Прежде чем перейти к изучению структуры вируса, я хотел бы предупредить Вас об уголовной ответственности за распространение вирусоподобных программ. Если Вы напишите вирус, а затем выпустите его "в свет", то Вас смогут отправить в "места не столь отдаленные" (по Российским законам); например, на Колыму.

Кто пишет вирусы? Да все кому не лень! Прежде всего - это программисты, которые только-только изучили Ассемблер, и не видят иной возможности, как только написать какой-нибудь вирус и напакостить своему другу, соседу и т.д., тем самым проявив себя. Например, у знакомого стоит большой Пень-433, а у Вас - маленькая "тройка". И Вы горите желанием его Пень "заломать".

Теперь представим другую ситуацию: у фирмы X есть конкурент - фирма Y. Как сделать так, чтобы на время фирме Y доставить хлопот? А почему бы их компьютеры не заразить вирусом "собственного производства", который такого-то числа или при таких-то обстоятельствах удалял бы всю информацию на винчестере? Пишется вирус сотрудником фирмы X, а затем он (вирус) заносится в компьютер к конкуренту. И все! Как правило заражаются компьютеры не только фирмы Y, но и другие (сотрудник переписал зараженный файл и приес к себе домой; у него переписал этот же файл знакомый и т.д.).

Естественно, есть т.н. антивирусы (DrWeb, Aidstest, Norton Antivirus, Microsoft Antivirus и пр.). Однако, они пишутся только для тех вирусов, котрые знакомы автору данного антивируса. Если, допустим, я напишу свой вирус, то уверяю Вас, что ни один антивирус его не обнаружит (максимум, что может быть - это то, что антивирус напишет сообщение о возможном заражении файла, но вылечить его не сможет!).

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

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

Сколько занимает вирус в памяти? Все зависит от фантазии программиста (что он хочет сделать с компьютером/файлами). Средний размер вируса - 500 - 600 байт. Хотя есть умельцы, у которых вирус занимает 100 - 150 байт, а есть и такие, у которых простейший вирус занимает 1,5 - 3 и более килобайт.

Что может вирус? Все, что угодно! Например, удалить всю информацию с винчестера за 0,5 - 1 секунду (по принципу работы Fdisk), спалить монитор, физически испортить винчестер и даже убить пользователя (хотя такого не встречал пока)! Все зависит от фантазии программиста...

Какой вирус мы будем изучать? Мы будем рассматривать нерезидентный вирус, заражающий *.com-файлы (самый простой). Что он будет делать? Я думаю, ничего особенного, кроме как размножения и создания какой-либо незначительной помехи для пользователя.

Как оформить вирус? Обычно:

CSEG segment

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

org 100h

Start:

... ;здесь находится тело вируса.

CSEG ends

end Start

Т.е. формат обычного *.com-файла, который Вам уже известен. Можно создать и *.exe-файл, однако, его размер будет больше.

Я думаю, что на сегодня с вирусом хватит. Тем более, что по результатам ваших опросов, вирус - это не то, на что бы Вы хотели сделать акцент при изучении Ассемблера.

Резидент.

Приступаем к самому сложному разделу. Будет действительно сложно. Кто сможет разобраться - будет настоящим героем!

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

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

Прерывание - это своего рода процедура (подпрограмма), которая имеет не название (например, print_string), а номер. В компьютере есть 256 различных номеров прерываний. Некоторые номера зарезервированы BIOS (ПЗУ) компьютера (например, 16h; помните: mov ah,10h / int 16h?) или операционной системой (MS-DOS, PC-DOS, OS/2) (например, 21h: mov ah,9 / mov dx,offset String / int 21h).

Тем не менее, ничего не мешает программисту перехватить, скажем, 21h прерывание, тем самым контролировать кто и что делает с ним.

Ну например. Выведем на экран строку:

mov ah,9

mov dx,offset Our_string

int 21h

...

Our_string db 'Привет!$'

Процессор (MS-DOS) выведет на экран сообщение "Привет". А мы можем перехватить 21h прерывание и, проследив, что кто-то пытается вывести строку (не важно, какую), мы заносим в DX адрес нашей строки. В таком случае, все, что бы не выводилось на экран путем вызова функции 09 прерывания 21h, на экране будет появляться наша и только наша строка. Это можно сделать так:

;представим, что это кусок нашего обработчика 21h прерывания.

...

cmp ah,9

je Out_str

Go_21h:

; здесь передаем управление "настоящему" 21h.

Out_str:

mov dx,offset My_string

jmp Go_21h

...

Здесь мы проверяем, вызывается ли функция вывода строки на экран (09) или какая-либо другая. Если вызывается другая функция (например, 3Dh), то мы просто предаем управление оригинальному обработчику.

Что же такое обработчик прерывания? Это процедура, постоянно (или на время) находящаяся в памяти, которая принимает управление первой, делает что хочет, а затем передает управление оригинальному обработчику (т.е. процедуре, которая уже находилась в памяти до загрузки нашего обработчика). Та может также выполнить некоторые действия, а затем передать управление другому обработчику и т.д.

Вообще оригинальные (скажем так, первичные) обработчики MS-DOS 20h - 28h прерываний находятся в файле io.sys / msdos.sys. До того момента (пока они не загрузились) эти прерывания, грубо говоря, пустые. Почему Microsoft решила выбрать именно эти адреса - смотрите здесь: http://www.microsoft.ru . Возможно, там есть ответ. Я, честно говоря, не знаю.

Если что-либо не понятно - не отчаивайтесь! Это действительно очень сложно! Очень скоро все станет на свои места.

Теперь перейдем к обработчику (читайте внимательно описания после точки с запятой):

_______________

Программа N 01

CSEG segment

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

org 100h

Start:

;Переходим на метку инициализации. Нам нужно будет перехватить прерывание 21h, а также оставить программу резидентной в памяти

jmp Init

; Ниже идет, собственно, обработчик 21h прерывания (он будет резидентный). После того, как программа выйдет, процедура Int_21h_proc останется в памяти и будет контролировать функцию 09 прерывания 21h. Он у нас будет жирным.

Int_21h_proc proc

pushf ;сохраним в стеке регистр флагов

cmp ah,9 ;проверим: это функция 09h?

je Ok_09

popf ;восстановим регистр флагов

jmp dword ptr cs:[Int_21h_vect] ;Если нет, прейдем на оригинальный обработчик прерывания 21h. Все. На метку Ok_09 программа уже не вернется

Ok_09:

push ds ;Сохраним регистры

push dx

push cs ;Адрес троки должен быть DS:DX

pop ds

mov dx,offset My_string

pushf ;так надо! Позже рассмотрим

call dword ptr cs:[Int_21h_vect] ;Вывели нашу строку вместо той, которую надо было

pop dx ;восстановим использованные регистры

pop ds

popf

iret ;продолжим работу (выйдем из прерывания)

Int_21h_vect dd ? ;переменная для хранения оригинального адреса обработчика 21h

My_string db 'Моя строка!$'

int_21h_proc endp

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

Init:

;установим наш обработчик (Int_21h_proc) (адрес нашего обработчика, если быть точнее) на 21h прерывание. Это позволяет сделать функция 25h прерывания 21h. Но прежде нам нужно запомнить оригинальный адрес этого прерывания. Для этого используется функция 35h прерывания 21h:

mov ah,35h ;AH содержит номер функции (это понятно)

mov al,21h ;AL указывает номер прерывания, адрес (или вектор) которого нужно получить

int 21h ;тепрь в ES:BX адрес (вектор) 21h прерывания (ES - сегмент, BX - смещение)

mov word ptr Int_21h_vect,bx

mov word ptr Int_21h_vect+2,es ;обратите внимание на запись

;итак, адрес сохранили. Теперь перехватываем прерывание:

mov ax,2521h

mov dx,offset Int_21h_proc ;DX должен указывать на наш обработчик (т.е. Int_21h_proc)

int 21h

;Все! Теперь, если какая-либо программа вызовет 21h, то вначале компьютер попадет на наш обработчик (Int_21h_proc). Что осталось? Завершить программу, оставив ее резидентной в памяти (чтобы никто не затер наш обработчик. Иначе компьютер просто зависнет!)

mov dx,offset Init

int 27h

; Функция 27h прерывания 21h выходит в DOS (как 20h), при этом оставив нашу программу резидентной. DX должен указывать на последний байт, остающийся в памяти (это как раз метка Init).

CSEG ends

end Start

_______________

Рассмотрим должным образом новые прерывания и операторы.

Функция 35h прерывания 21h: получить адрес (вектор) прерывания:

Вход: AH =35h Выход: ES = сегментный адрес вектора прерыванияBX=смещение

_________

Функция 25h прерывания 21h: установить вектор прерывания:

Вход: AH =25hDS=сегмент нашего обработчика

DX=его смещение

Выход: Ничего _________

Прерывание 27h: оставить программу резидентной в памяти:

Вход: DX=последний байт, оставляемый в памяти Выход: Ничего (выход в DOS) _________

Название Перевод Команда Процессор Pushf Push Flags (втолкнуть флаги) Сохранить флаги 8086 _________

Название Перевод Команда Процессор Popf Pop Flags (вытолкнуть флаги) Восстановить флаги 8086 _________

Что такое флаги вы помните? На всякий случай рассмотрим кратко на примере еще раз:

...

(1) cmp ax,23

(2) je Ok_ax

...

Здесь после выполнения строки (1) установится/сбросится флаг нуля. В строке (2) проверяем этот самый флаг. Если он установлен, значит команда сравнения верна (т.е. AX=23). Если же не установлен, то AX <> (не равен) 23.

Теперь обратите внимание на самое начало процедуры Int_21h_proc. Что мы видим:

cmp ah,9

je Ok_09

Мы нарушаем работу программы (изменяем флаг нуля). Это может привести к довольно-таки серьезным изменениям в ходе работы программы, которая вызвала 21h прерывание. Для этого, собственно, мы и сохраняем флаги в стеке. Надеюсь, вы поняли, что в обработчике прерывания (в нашем случае - Int_21h_proc) необходимо сохранять ВСЕ используемые регистры, включая регистр флагов.

_______

Теперь рассмотрим следующую строку:

Int_21h_vect dd ? ;переменная для хранения оргинального адреса обработчика 21h

Данная переменная может хранить двойное слово (Define Double word - определить двойное слово) (четыре байта). Вспоминаем, что один 16-и разрядный занимает 2 байта (одно слово) (DX, AX, ES, SS и т.д., но не AH, DL, BH - это 8-и разрядные регистры, которые занимают один байт!).

Если мы хотим загрузить в данную переменную слово (два байта), то нам необходимо указать это таким образом:

mov word ptr Int_21h_vect,ax

Если же мы хотим загрузить один байт, то пишем так:

mov byte ptr Int_21h_vect,ah

Вспоминаем, что word - это слово, а byte - это байт. Что-нибудь прояснилось?

______

Как проверить работу программы? В данном случае нам понадобится отладчик, который способен заходить внутрь прерываний. Например, AFD и пр., но не как не CodeView. То, что нам сейчас нужно! Если у вас нет AFD, то возьмите, пожалуйста, на нашем сайте: http://www.Kalashnikoff.ru

Затем создайте простейшую программу, которая будет выводить на экран некоторую строку путем вызова 09 функции 21h прерывания. Например, так:

Программа N 02

CSEG segment

assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG

org 100h

Begin:

mov ah,9

mov dx,offset String

int 21h

int 20h

String db 'My string.$'

end Begin

CSEG ends

Запускаем сперва Программу N 01. После того, как он вернется в DOS (в Norton Commander, DOS Navigator, Far и пр. оболочки), запускайте Программу N 02. Что вы увидите?

Теперь запустите Программу N 02 в отладчике. Заходите смело "внутрь" 21h-ого прерывание. Что вы видите теперь?

Блиц-опрос.

Ну что, дорогие мои! Сложно?

1. Все внимательно прочитал несколько раз, но ничего не понял.

oleg77@beep.ru?Subject=1

______

2. Плохо объясняешь. "Дошло" на третьи сутки.

oleg77@beep.ru?Subject=2

______

3. "Дошло" с трудом. Желательно объяснять поподробнее. А так все нормально.

oleg77@beep.ru?Subject=3

______

4. Тяжело, но интересно. Продолжай в том же духе!

oleg77@beep.ru?Subject=4

______

5. Все отлично! Классно объясняешь!

oleg77@beep.ru?Subject=5

______

6. Элементарщина! Скорее бы к Windows перейти...

oleg77@beep.ru?Subject=6

На сегодня все! Оболочку рассмотрим на следующей неделе (байт не хватит). Удачного программирования вам!

Автор рассылки: Калашников Олег

E-mail: oleg77@beep.ru?Subject=Assembler

URL: http://www.Kalashnikoff.ru

UIN (Тетя Ася): 68951340

[Следующий выпуск] [На главную страницу]

u="u496.71.spylog.com";d=document;nv=navigator;na=nv.appName;p=1; bv=Math.round(parseFloat(nv.appVersion)*100); n=(na.substring(0,2)=="Mi")?0:1;rn=Math.random();z="p="+p+"&rn="+rn;y=""; y+=""; y+=""; y+=""; d.write(y);if(!n) { d.write("

Соседние файлы в папке Выпуски