1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
| code_seg segment
ASSUME CS:CODE_SEG,DS:code_seg,ES:code_seg
org 100h
;----------------------------------------------------------------------------
start:
jmp begin
;----------------------------------------------------------------------------
int_2Fh_vector DD ? ; адрес мультиплексорного прерывания
old_09h DD ? ; старый обработчик клавиатуры 09h
old_21h DD ? ; старый обработчик 21h
;----------------------------------------------------------------------------
win DB '=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh
DB '=',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,' ',0Eh,'=',0Eh
DB '=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh,'=',0Eh
buf DB 80*25*2 DUP(?)
;----------------------------------------------------------------------------
msglen DW 32 ; длина строки
x DW 0 ; количество нажатий на клавиши
name_pr DB 190 dup (0)
cmdline DB 128 dup (0)
;============================================================================
new_21h proc far ; новый обработчик int 21h
;в регистрах DS:DX указывается ASCIIZ-имя запускаемой программы
push SI
push DS
push DX
push CX
push DX
pop SI
mov SI, 0
mov CX, 190d
loo:
lodsb
mov CS:name_pr[SI], AL
inc si
loop loo
;
pop CX
pop DX
pop DS
pop SI
call window
jmp dword PTR CS:[old_21h]
iret
new_21h endp
;============================================================================
new_09h proc far ;новый обработчик клавиатуры
push AX
inc CS:x ; увелич. кол-во нажат. клавиш
testkey:
in AL,60h ; Введем scan-code
cmp AL,57h ; Это скен-код <F11>
je hotkey ; Yes
pop ax
jmp CS:old_09h
hotkey:
sti ; Не будем мешать таймеру
in AL,61h ; Введем содержимое порта B
or AL,80h ; Установим старший бит
out 61h,AL ; и вернем в порт B.
and AL,7Fh ; Снова разрешим работу клавиатуры,
out 61h,AL ; сбросив старший бит порта B.
call window
exi:
cli ;разрешение аппаратных прерываний
mov AL, 20h ; Пошлем
out 20h,AL ; приказ EOI
pop AX
iret
new_09h endp
;===========================================================================
window proc
push DS
push ES
push SI
push DI
push CX
push BX
push AX
push DX
push DS
push CS ;DS на наш сегмент
pop DS ; команд
mov AX, 0B800h
mov ES,AX ; ES-> на видеобуфер
mov SI, offset win ;SI= адрес источника
mov DI, 80*2*2 ;DI= адрес приёмника
mov CX,msglen ;CX-число пересылаемых битов
cld ; сброс DF - вперед
rep movsb ; пересылка в цикле
mov SI, offset win+32 ;SI= адрес источника
mov DI, 80*2*3 ;DI= адрес приёмника
mov CX,msglen ;CX-число пересылаемых битов
cld ; сброс DF - вперед
rep movsb ; пересылка в цикле
mov SI, offset win+64 ;SI= адрес источника
mov DI, 80*2*4 ;DI= адрес приёмника
mov CX,msglen ;CX-число пересылаемых битов
cld ; сброс DF - вперед
rep movsb ; пересылка в цикле
mov SI, offset name_pr ;SI= адрес источника
mov DI, 80*2*5 ;DI= адрес приёмника
mov CX,190d ;CX-число пересылаемых битов
cld ; сброс DF - вперед
rep movsb ; пересылка в цикле
mov AX, 0B800h ;DS на наш сегмент
mov ES,AX ; команд
push cs
pop ds
mov SI, offset cmdline
mov di, 80*2*3+4*3+2
y3:
mov al,byte ptr DS:[si]
mov byte ptr es:[di],al
inc di
inc di
inc si
cmp al,0
jne y3
push CS
pop DS
mov SI, 80*2*3+4*3+2 ;DI= адрес приёмника
; преобразуем наше цисло в 10 вид
mov ax,cs:x
shr ax,1
xor cx,cx
mov bx,10 ; 10 - основание СС
out_dec:
xor dx,dx
div bx ; делим на основание СС
push dx
inc cx
cmp ax,0;
jne out_dec
dmet:
pop dx
add dl,'0'
mov byte ptr es:[si],dl
inc si
inc si
loop dmet
pop ds
pop dx
pop ax
pop bx
pop cx
pop di
pop si
pop es
pop ds
ret
window endp
;============================================================================
int_2Fh proc far
cmp AH,0C7h ; Наш номер?
jne Pass_2Fh ; Нет, на выход
cmp AL,00h ; Подфункция проверки на повторную установку?
je inst ; Программа уже установлена
cmp AL,01h ; Подфункция выгрузки?
je unins ; Да, на выгрузку
jmp short Pass_2Fh ; Неизвестная подфункция - на выход
inst:
mov AL,0FFh ; Сообщим о невозможности повторной установки
iret
Pass_2Fh:
jmp dword PTR CS:[int_2Fh_vector]
;
; -------------- Проверка - возможна ли выгрузка программы из памяти ? ------
unins:
push BX
push CX
push DX
push ES
;
mov CX, CS ; пригодится для сравнения, т.к. с CS сравнивать нельзя
mov AX, 3509h ; проверить вектор 09h
int 21h ; функция 35h в AL - номер прерывания.
; возврат-вектор в ES:BX
;
mov DX,ES
cmp CX,DX
jne Not_remove
cmp BX, offset CS:new_09h
jne Not_remove
;
mov CX,CS ;
mov AX,352Fh ; проверить вектор 2Fh
int 21h ; функция 35h в AL - номер прерывания.
; возврат-вектор в ES:BX
;
mov DX,ES
cmp CX,DX
jne Not_remove
;
cmp BX, offset CS:int_2Fh
jne Not_remove
; ---------------------- Выгрузка программы из памяти ---------------------
;
push DS
;
lds DX, CS:old_09h
mov AX,2509h ; заполнение вектора старым содержимым
int 21h
;
lds DX, CS:int_2Fh_vector
mov AX,252Fh
int 21h
;
lds DX, CS:old_21h
mov AX,2521h
int 21h
;
pop DS
;
mov ES,CS:2Ch ; ES -> окружение
mov AH, 49h ; функция освобождения блока памяти
int 21h
;
mov AX, CS
mov ES, AX ; ES -> PSP выгрузим саму программу
mov AH, 49h ; функция освобождения блока памяти
int 21h
;
mov AL,0Fh ; признак успешной выгрузки
jmp short pop_ret
Not_remove:
mov AL,0F0h ; признак - выгружать нельзя
pop_ret:
pop ES
pop DX
pop CX
pop BX
;
iret
int_2Fh endp
;============================================================================
begin:
mov CL,ES:80h ; длина хвоста в PSP
cmp CL,0 ; длина хвоста=0?
je check_install ; да, программа запущена без параметров,
; попробуем установить
xor CH,CH ; CX=CL= длина хвоста
cld ; DF=0 - флаг направления вперед
mov DI, 81h ; ES:DI-> начало хвоста в PSP
mov SI,offset key ; DS:SI-> поле key
mov AL,' ' ; уберем пробелы из начала хвоста
repe scasb ; сканируем хвост пока пробелы
; AL - (ES:DI) -> флаги процессора
; повторять пока элементы равны
dec DI ; DI-> на первый символ после пробелов
mov CX, 4 ; ожидаемая длина команды
repe cmpsb ; сравниваем введенный хвост с ожидаемым
; (DS:SI)-(ES:DI) -> флаги процессора
jne check_install ; неизвестная команда - попробуем установить
inc flag_off
; проверим, не установлена ли уже эта программа
check_install:
mov AX,0C700h ; AH=0C7h номер процесса C7h
; AL=00h -дать статус установки процесса
int 2Fh ; мультиплексное прерывание
cmp AL,0FFh
je already_ins ; возвращает AL=0FFh если установлена
;----------------------------------------------------------------------------
cmp flag_off, 1d
je xm_stranno
;----------------------------------------------------------------------------
mov AX,352Fh ; получить
; вектор
int 21h ; прерывания 2Fh
mov word ptr int_2Fh_vector,BX ; ES:BX - вектор
mov word ptr int_2Fh_vector+2,ES ;
;
mov DX,offset int_2Fh ; получить смещение точки входа в новый
; обработчик на DX
mov AX,252Fh ; функция установки прерывани
; изменить вектор 2Fh
int 21h ; AL - номер прерыв. DS:DX - указатель программы обработки прер.
;============================================================================
mov AX,3509h ; получить
; вектор
int 21h ; прерывания 09h
mov word ptr old_09h,BX ; ES:BX - вектор
mov word ptr old_09h+2,ES ;
mov DX,offset new_09h ; получить смещение точки входа в новый
; ; обработчик на DX
mov AX,2509h ; функция установки прерывания
; изменить вектор 09h
int 21h ; AL - номер прерыв. DS:DX - указатель программы обработки прер.
;
;----------------------------------------------------------------------------
mov AX,3521h ; получить
; вектор
int 21h ; прерывания 21h
mov word ptr old_21h, BX ; ES:BX - вектор
mov word ptr old_21h+2,ES ;
mov DX,offset new_21h ; получить смещение точки входа в новый
; обработчик на DX
mov AX,2521h ; функция установки прерывания
; изменить вектор 09h
int 21h ; AL - номер прерыв. DS:DX - указатель программы обработки прер.
;============================================================================
mov DX,offset msg1 ; сообщение об установке
call print
;----------------------------------------------------------------------------
mov DX, offset begin ; оставить программу ...
int 27h ; ... резидентной и выйти
;============================================================================
already_ins:
cmp flag_off,1 ; запрос на выгрузку установлен?
je uninstall ; да, на выгрузку
lea DX,msg ; вывод на экран сообщения: already installed!
call print
int 20h
; ------------------ выгрузка -----------------------------------------------
uninstall:
mov AX,0C701h ; AH=0C7h номер процесса C7h, подфункция 01h-выгрузка
int 2Fh ; мультиплексное прерывание
cmp AL,0F0h
je not_sucsess
cmp AL,0Fh
jne not_sucsess
mov DX,offset msg2 ; сообщение о выгрузке
call print
int 20h
not_sucsess:
mov DX,offset msg3 ; сообщение, что выгрузка невозможна
call print
int 20h
xm_stranno:
mov DX,offset msg4 ; сообщение, программы нет, а пользователь
call print ; дает команду выгрузки
int 20h
;----------------------------------------------------------------------------
key DB '/off' ; ключ выгрузки
flag_off DB 0 ; флаг выгрузки
; сообщения:
msg DB 'already '
msg1 DB 'installed',13,10,'$'
msg4 DB 'just '
msg3 DB 'not '
msg2 DB 'uninstalled',13,10,'$'
; ---------------------------------------------------------------------------
PRINT proc near ; "ближняя" процедура
mov AH, 09h ; функция DOS - печать строки на экран
int 21h ; вызов DOS
ret
PRINT endp
; ---------------------------------------------------------------------------
code_seg ends
end start ; конец точки входа
; --------------------------------------------------------------------------- |