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

InterReklama Advertising

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

______________________________________

Выпуск N 019 (Резидент)

Сегодня в рассылке:

Новости рассылки и сайта

Ваши письма

Резидент вкратце

Новости рассылки и сайта Дорогие мои подписчики! Как видите, у нас изменился внешний вид рассылки. Если у вас есть что сказать по этому поводу (стало хуже, плохо печатать на ч/б принтере и т.п.), то пишите. Я обязательно исправлю все изъяны.

___________

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

___________

Посоветовавшись с некоторыми подписчиками, я все же пришел к выводу, что рассылку нужно открыть свова (теперь она видна в каталоге рассылок). Так что наши ряды вновь пополняются!

___________

Наш сайт уже второй раз поменял адрес. Теперь мы находимся на http://www.Kalashnikoff.ru. Думаю, что это окончательный вариант. Вскоре (после Нового года, а может и раньше) будет и своя Гостевая книга там (скрипты уже нашел кое-какие. Надо только кое-чего подкорректировать в них). Заходите, отмечайтесь! Надеюсь, что попасть на этот сайт будет гораздо проще, чем на newmail!

Более того, нужно освоиться с электронными адресами, которые у меня появились. Будет что-то вида oleg@kalashnikoff.ru и пр. Их количество неограниченно. Думаю, что к выходу следующего выпуска я все настрою и сообщу вам дополнительные возможности, которые откроются для вас.

___________

Предыдущий выпуск № 18 (про оболочку) вышел под номером 17 по моей ошибке. Если вы удалили его, то возьмите на нашем сайте либо напишите мне письмо с просьбой его выслать.

Ваши письма Новости для пользователей программы Commands Алексея Старчикова.

В программе собираются команды Ассемблера, которые мы рассматриваем в рассылке.

Ниже приведено письмо Алексея:

Здравствуйте!

Хочу сообщить вам, что я сделал сайт, посвященный моей программе.

Адрес: http://www.vunder.newmail.ru/.

Там вы можете найти некоторую информацию о программе и скачать ее последнюю версию.

С уважением,

Старчиков Алекей. ( vunder@spb.cityline.ru )

_________

Благодарности экспертам.

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

Кстати, была ошибка (точнее, упущение) с моей стороны, которая заключалась в том, что никто не мог отправить письмо экспертам напрямую, т.к. у меня на eGroups стояла "галочка", которая запрещала отправлять письма экспертам, если отправитель не входит в ту или иную экспертную группу. Теперь все исправил. Можете отправлять. Чтобы получить адреса экспертов, необходимо отправить мне письмо по адресу assmbler@beep.ru?Subject=Experts. Обратите внимание на то, что в поле "Тема" вашего письма должно быть слово "Experts". В таком случае адреса экспертов будут высланы вам автоматически, что ускорит ответ.

Тем не менее, можно подвести кое-какие результаты. Но прежде хочу поблагодарить всех экспертов, которые отвечали на вопросы подписчиков. Всего было отправлено 25 ответов (что не так и много!).

Первое почетное место:

Больше всего "досталось" эксперту с именем Slava V. ( debug_inc@mailru.com ). На его счету 11 ответов, причем, ответов грамотных и подробных, которые изложены на простом языке. Поздравляю тебя, Слава!!! Надеюсь, что и впредь ты будешь в нашей экспертной группе.

Второе почетное место:

На мой взгляд второе место получают Михаил Юрьевич ( micks@azov.donpac.ru ) и K.A. Nick ( ILUH_1@mail.ru ). На их счету по два полных ответа. Попрошу вас, Михаил и K. A. Nick, выслать мне информацию, которую Вы бы хотели разместить в рассылке для подписчиков.

Третье почетное место:

Мне кажется, что третье место можно разделить между:

Pavel Bakhtin ( pavel@ccc.kcn.ru );

Denis Sizikov ( dsizikov@mail.kz );

Zakker ( zaccer@altavista.net );

Владимир ( mefistofel@nm.ru );

Seam ( seam@aport.ru );

Artos ( artos@run.ru ).

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

Резидент  

;RESID19.ASM - программа к рассылке № 19 ; (С) Авторское право принадлежит подписчикам рассылки "Ассемблер? Это просто! Учимся программировать" ; Автор рассылки: Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru) ; http://www.Kalashnikoff.ru ; --- Ассемблирование --- ;При использовании MASM: ;ML.EXE resid19.asm /AT ;При использовании TASM: ;TASM.EXE resid19.asm ;TLINK.EXE resid19.obj /t/x ;В итоге получаем resid19.COM, а НЕ resid19.EXE! ;______________________________________________________ ; === Начало программы: === .286 cseg segment assume cs:cseg, ds:cseg, ss:cseg, es:cseg org 100h Begin: jmp Init ; на метку инициализации ; === Обработчик 21h-ого прерывания === Int_21h_proc proc cmp ax,9889h jne Next_step xchg ah,al iret Next_step: pusha;Сохраним регистры... push ds push es mov bx,ds;BX=DS push cs;Настроим сегментные регистры push cs pop es pop ds cmp ax,4B00h;Это запуск файла на выполнение? je Start_f cmp ah,39h;Это создание каталога? je Create_dir cmp ah,3Ah;Это удаление каталога? je Delete_dir cmp ah,3Bh;Это смена каталога? je Change_dir cmp ah,3Ch;Это создание файла? je Create_file cmp ax,3D02h;Это открытие файла для чтения/записи? je Open_fl cmp ah,41h;Это удаление файла? je Delete_file jmp short Go_21h ;Если что-то другое, то передадим управление 21h-ому... Start_f: mov si,offset Start_filemess ;Строка для записи в наш log-файл. call Move_string ;Готовим строку и записываем ее в файл... jmp short Go_21h ;Передадим управление 21h-ому прерыванию... Create_dir: mov si,offset Create_dirmess call Move_string jmp short Go_21h Delete_dir: mov si,offset Delete_dirmess call Move_string jmp short Go_21h Change_dir: mov si,offset Change_dirmess call Move_string jmp short Go_21h Create_file: mov si,offset Create_filemess call Move_string jmp short Go_21h Open_fl: mov si,offset Open_filemess call Move_string jmp short Go_21h Delete_file: mov si,offset Delete_filemess call Move_string Go_21h: pop es;Восстановим регистры... pop ds popa jmp dword ptr cs:[0FCh] ;Передаем управеление 21h-ому Int_21h_proc endp ;=== Переносим строку и пишем информацию в файл === Move_string proc mov di,2 ;DS:SI указывают на строку ;ES:DI - на место в памяти, где будет формироваться строка... lodsw;Получим длину строки (первый байт строки) mov cx,ax ;Длину строки в CX rep movsb ;Переместили строку по адресу ES:DI (Текущий сегмент:0002h) push ds mov ds,bx ;DS указывает на сегмент, где находится имя файла mov si,dx ;SI - на смещение Next_char: lodsb ;Получаем очередной символ or al,al;Это конец строки с именем файла? Проверка на 0... jz Zero_found ; stosb ;Если еще не конец - заносим его в нашу формирующуюся строку jmp short Next_char ;Следующий символ... Zero_found: pop ds;Имя файла перенсли! Восстановим DS mov ax,0A0Dh ;Добавим возврат каретки/переод строки. stosw dec di dec di mov word ptr cs:[0],di ;Занесем по 0-ому смещению длину готовой строки call Save_file;Запишем готовую строку в наш log-файл... ret Move_string endp ;=== Пишем в файл === Save_file proc call Check_file ;Проверим, существует ли наш log-файл или нет... mov al,02h;Открываем файл для чтения/записи call Open_file mov ax,4202h ;Устанавливаем указатель на конец файла xor cx,cx xor dx,dx int 3 mov ah,40h;Функция записи в файл mov cx,cs:[0] ;Количество записываемых байт mov dx,2;Откуда будем писАть (DS:DX) int 3 call Close_file ;Закрываем файл... ret Save_file endp ;=== Проверяем: существует ли нужный файл === Check_file proc xor al,al;Пробуем открыть наш log-файл call Open_file jnc File_exists ;Если файл существует, то на метку File_exists ; === Атрибуты файла === ;00001 - только чтение ;00010 - спрятанный ;00100 - системный ;01000 - метка тома ;010000 - подкаталог ;100000 - архивный mov ah,3Ch;Если файл не существует, то создадим его mov cx,100010b ;атрибут - архивный, спрятанный mov dx,offset File_name ;DS:DX указывают на имя файла int 3 jc Error_create ;Ошибка?.. mov Handle,ax ;Если успешно создали, то запомним номер файла File_exists: call Close_file ;Закрываем файл... Error_create: ret File_name db 'C:\report.txt',0;Наш log-файл Check_file endp ;=== Открытие файла === Open_file proc mov dx,offset File_name mov ah,3Dh int 3 jc Error_open mov bx,ax mov Handle,ax Error_open: ret Handle dw 0FFFFh Open_file endp ;=== Закрытие файла === Close_file proc pusha pushf cmp Handle,0FFFFh ;Нечего закрывать?.. je No_close mov ah,3Eh mov bx,Handle int 3 mov Handle,0FFFFh ;Отметим то, что нет открытых файлов... No_close: popa popf ret Close_file endp ;--- Сообщения резидента --- Start_filemess dw Start_filemessl db 'Запуск файла---> ' Start_filemessl equ $-Start_filemess-2 Create_dirmess dw Create_dirmessl db 'Создание каталога ---> ' Create_dirmessl equ $-Create_dirmess-2 Delete_dirmess dw Delete_dirmessl db 'Удаление каталога ---> ' Delete_dirmessl equ $-Delete_dirmess-2 Change_dirmess dw Change_dirmessl db 'Смена каталога на ---> ' Change_dirmessl equ $-Change_dirmess-2 Create_filemess dw Create_filemessl db 'Создание файла---> ' Create_filemessl equ $-Create_filemess-2 Open_filemess dw Open_filemessl db 'Открытие файла для чтения/записи ---> ' Open_filemessl equ $-Open_filemess-2 Delete_filemess dw Delete_filemessl db 'Удаление файла---> ' Delete_filemessl equ $-Delete_filemess-2 ; === Инициализация (подготовка и настройка резидента) === Init: mov ax,9889h ;проверим, в памяти ли мы уже или еще нет int 21h cmp ax,8998h jne Set_resident mov ah,9 ;если в памяти, то выведем соответствующее сообщение mov dx,offset In_memory int 21h ret ;...и вернемся в DOS Set_resident: ;если нас в памяти нет, то установим наш резидент ; 21h-ое... mov ax,3521h int 21h ;получим и сохраним адрес (вектор) 21h прерывания mov word ptr cs:[0FCh],bx mov word ptr cs:[0FEh],es mov ax,es;Установим старый вектор 21h-прерывания на 3... push 0 ;(вырубим отладчик) pop es mov es:[3*4],bx mov es:[3*4+2],ax mov ax,2521h mov dx,offset Int_21h_proc int 3;"повесим" нашу процедуру на 21h прерывание call Check_file ;А есть ли наш log-файл? mov ah,9 mov dx,offset Mess_hello int 21h mov dx,offset Init int 27h;оставим программу резидентной в памяти. In_memory db 'Программа уже загружена в память!!!!',0Ah,0Dh,0Ah Mess_hello db 'Резидент к рассылке № 019 "Ассемблер? Это просто! Учимся программировать".',0Ah,0Dh,0Ah db 'Автор: Калашников Олег Александрович (Assembler@Kalashnikoff.ru),',0Ah,0Dh db 'http://www.Kalashnikoff.ru, Россия, Москва, 2000 год.',0Ah,0Dh,'$' cseg ends end Begin

Как переписать файл-приложение в DOS-файл (так, как мы скачивали с сайта раньше)?

Для этого:

отметьте "мышкой" все, что находится в приведенном выше окне;

нажмите Ctrl+Insert;

запустите DOS Navigator или FAR;

нажмите Shift+F4;

введите имя файла RESID19.ASM;

нажмите Shift+Insert;

нажмите F2;

выходите в DOS и ассемблируйте!

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

Итак, после загрузки в память, резидент перехватывает 21h-ое прерывание. Затем отслеживает некоторые действия программ (функции, которые они вызывают) и записывает информацию в свой так сказать log-файл. А функции следующие:

AX = 4B00h ;Запуск файла на выполнение

AH = 39h ;Создание каталога

AH = 3Ah ;Удаление каталога

AH = 3Bh ;Смена каталога

AH = 3Ch ;Создание файла

AX = 3D02h ;Открытие файла для чтения/записи

AH = 41h ;Удаление файла

Для выполнения всех этих функций 21h-ого прерывания в регистрах DS:DX должно быть указано имя файла или каталога. Поэтому мы выполняем одни и те же действия, если какая-либо функция вызвалась. Постарайтесь запомнить приведенные выше функции!

Примеры:

Создание каталога:

mov ah,39h

mov dx,offset Directory

int 21h

Удаление файла:

mov ah,39h

mov dx,offset File

int 21h

и т.д. кроме функции 4B00h. Помимо указания файла для запуска в DS:DX, нужно еще подготовиться хорошо. Но это позже рассмотрим...

Что конкретно мы делаем?

Как вы уже знаете, программы типа *.com начинаются со смещения 100h. От 0 до 0FFh находится т.н. PSP (Prefix Program Segment). Некоторые поля PSP вы уже знаете. Например, по смещению 0 находится команда INT 20h, а по смещению 80h - DTA и изначально командная строка. Оставляя резидент в памяти, мы оставляем и PSP (т.е. "лишние" 100h байт). Получается, что 100h байт постоянно висит в памяти... Вы уже, возможно, заметили, что наши предыдущие резиденты занимали памяти больше, чем их реальный размер. Это-то как раз и связано с тем, что в памяти "висит" PSP программы (плюс еще строка окружения, но об этом попозже).

У нас есть несколько способов избежать размещения лишних байт в памяти:

1. Сделать так, чтобы программа в памяти начиналась не со смещения 100h, а со смещения 0. Однако, здесь возможны некоторые проблемы. Об этом позже.

2. Разместить в нашей свободной области стек (временно, т.е. на то время, пока работают наши обработчики прерываний). Тоже можно...

3. Сделать в области PSP буфер (т.е. задействовать эту память для временного хранения данных, которые не превышают 100h байт).

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

Как я уже говорил, мы перехватываем указанные выше функции 21h-прерывания и фиксируем действия программ, которые вызывают данное прерывание в нашем log-файле (c:\report.txt).

Теперь смотрим, что делает обработчик 21h-прерывания:

cmp ax,4B00h

je Start_f

cmp ah,39h ;Это создание каталога?

je Create_dir

...

jmp short Go_21h ;Если что-то другое, то передадим управление 21h-ому...

 

Start_f:

mov si,offset Start_filemess ;Строка для записи в наш log-файл.

call Move_string ;Готовим строку и записываем ее в файл...

jmp short Go_21h ;Передадим управление 21h-ому прерыванию...

Create_dir:

mov si,offset Create_dirmess

call Move_string

jmp short Go_21h

...

Здесь мы вначале проверили, запускает ли кто-то файл на выполнение или нет. Затем проверяем другие функции, которые могут вызываться. Допустим, некто пытается создать каталог (функция 39h). Тогда мы передаем управление на метку Create_dir (создание каталога). Это видно на приведенном выше примере. Затем в SI заносится адрес строки Create_dirmess:

Create_dirmess dw Create_dirmessl

db 'Создание каталога ---> '

Create_dirmessl equ $-Create_dirmess-2

Как видите, первые два байта адреса, который заносится в SI содержат длину строки. Обратите внимание, как мы просто получаем длину строки! Вместо Create_dirmessl программа-ассемблер (MASM / TASM) поставят длину строки, которая вычисляется таким способом:

Create_dirmessl equ $-Create_dirmess-2

Т.е. $ (текущее смещение) минус смещение Create_dirmess минус два (т.к. первые два байта - и будут указывать на длину строки). После этого временная переменная (которая не будет занимать памяти; она нужна только для MASM / TASM) (Сreate_dirmessl) будет равна длине строки. Пожалуйста, внимательно изучите приведенные выше примеры! Вы должны понять принцип...

Как только занесли в SI адрес троки (первые два байта корой будут указывать на длину строки), вызываем процедуру Move_string. При этом в BX будет находиться сегмент строки, которую передала некая программа.

В общем, принцип такой: процедура Move_string заносит по смещению 0 сегмента, в котором находится наш резидент (т.е. в область PSP) соответствующую строку (например, "Создание каталога ---> "), после нее заносится имя файла (то, что получаем в регистрах DS:DX. Это может быть как только имя файла, так и полный путь к файлу, т.е. диск:\ каталог\имя_файла - c:\My_dir\file.ext.). Вот это мы и записываем по смещению 0 сегмента, в котором находится наша программа. Вот, что мы получим в итоге:

Допустим, кто-то создает каталог c:\assm\directory:

Создание каталога ---> c:\assm\directory.

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

Что нужно вынести вам из этого урока?

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

Отмечу лишь некоторые аспекты.

Мы перехватываем 21h-прерывание, помещая его адрес в 03h-прерывание. Это значит, что многие отладчики просто "обломаются". Обратите внимание, как мы вызываем 21h-ое прерывание в нашем обработчике...

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

Более подробно работу данного резидента мы рассмотрим в следующем веке...

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

____________

Данный выпуск предпраздничный. Поэтому буду краток.

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

С уважением,

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

URL сайта подписчиков: http://www.Kalashnikoff.ru

E-mail для вопросов: Assembler@Kalashnikoff.ru

UIN: 68951340

Москва, 2000.

(C) Авторское право. Запрещается использование материала из рассылки в коммерческих целях без письменного согласия автора. [Следующий выпуск] [На главную страницу]

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("

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