Здравствуйте. Есть задание на курсовую - написать резидент, запрещающий удаление файлов определённого расширения. Программа должна быть написана под ДОС, 16-битный COM. В принципе, со всем уже разобрался, кроме самого главного - защиты от удаления. Нашёл в справочнике функцию 41h прерывания ДОС 21h - удаление файла. В DX - ASCIIZ-строка с именем файла. Предположил, что при удалении файла в ДОС (например, командой del e:\test.txt) вызывается именно это прерывание, поэтому решил написать собственный обработчик. Однако обнаружил, что даже в этом случае файлы всё равно удаляются. При этом сам алгоритм, вроде бы, правильный - проверял пошагово в эмулятора emu8086 Может быть, это делается как-то по-другому? На всякий случай, участок кода с обработчиком (он не дописан до конца, в отладке) и с необходимыми переменными прилагаю. Код (Text): extensions db 'asmbinbatcomdatdocexeinimp3nfoobjtxtsys' ex_len = $ - extensions new_21h proc cmp AH, 41h ;функция удаления je work ;работаем по нашей функции jmp exit_21h ;иначе уход в старый обработчик без возврата work: push CS pop DS push AX push BX push CX push SI push DI mov SI, DX ;адрес имени удаляемого файла search_null: ;перемещение на конец строки mov AL, [SI] inc SI cmp AL, 0h jne search_null sub SI, 2h ;в SI содержится адрес последнего символа имени файла mov BX, SI ;копируем SI в BX - понадобится при поиске mov AX, offset extensions ;адрес extensions add AX, ex_len ;длина std ;флаг DF = 1 - движение назад search_string: dec AX ;на первой итерации AX и DI содержат адрес последнего символа в extensions mov DI, AX ;на последующих - продвижение на 1 символ назад cmp DI, offset extensions + 1 ;дошли до второго символа, а совпадений не найдено je delete_file ;файл можно удалять mov CX, 3h ;ожидаемая длина расширения repe cmpsb ;сравниваем содержимое SI - имя файла и DI - блокируемые расширения mov SI, BX ;возвращаем SI в предыдущее состояние cmp CX, 0h ;найдено совпадение je found jmp search_string found: not_delete_file: cli pop DI pop SI pop CX pop BX pop AX mov AL, 20h ;EOI out 20h, AL iret delete_file: pop DI pop SI pop CX pop BX pop AX mov AL, 20h ;EOI out 20h, AL exit_21h: jmp DWPTR CS:[old_21h] new_21h endp
В процессе отладки обнаружил вот ещё что. При вызове команды del действительно срабатывает прерывание 21h, но не функция 41h, а какая-то другая. В участке кода: Код (Text): cmp AH, 41h ;функция удаления je work ;работаем по нашей функции jmp exit_21h ;иначе уход в старый обработчик без возврата work: ... Программа идёт не по ветке work, а на ветку exit_21h.
Einior 1) Перед началом обработки не происходит сохранение регистра DS, теряется исходное значение. 2) Команда cmpsb сравнивает значения по указателям DS:[SI] и ES:[DI], но значение сегментного регистра ES не сохраняется и не инициализируется. Значение сегментного регистра DS изменено и не соответствует переданным функции данным, а значит не указывает на переданный путь к файлу. 3) Команды mov AL, 20h; out 20h, AL используют для завершения аппаратного прерывания. В данном случае они не требуются. 4) Перед переходом к системному обработчику затирается исходное значение регистра AL. 5) Тоже самое происходит при выходе из собственного обработчика. При невозможности выполнить операцию системная функция выставляет флаг CF и возвращает код ошибки в регистре AX. Было бы хорошо, также сообщать об отказе удаления файла.
Einior Будет лучше, если разделить задачу на две части. Сначала сделать нерезидентную программу, которая будет проверять имя файла на необходимые условия, затем сделать резидентную часть, которая будет полностью блокировать функцию 41h (AX=5), и только после этих подготовительных этапов объединить эти две части.
Хм, по большей части понял все ошибки. Правда, не совсем разобрался с сегментными регистрами. Надеюсь, я правильно их инициализировал и сохранил в новой версии. Код (Text): new_21h proc cmp AH, 41h ;функция удаления je work ;работаем по нашей функции jmp exit_21h ;иначе уход в старый обработчик без возврата work: call clear push AX push BX push CX push DI push SI push DS push ES push CS pop ES mov SI, DX ;адрес имени удаляемого файла search_null: ;перемещение на конец строки mov AL, [SI] inc SI cmp AL, 0h jne search_null sub SI, 2h ;в SI содержится адрес последнего символа имени файла mov BX, SI ;копируем SI в BX - понадобится при поиске mov AX, offset CS:extensions ;адрес extensions add AX, ex_len ;длина std ;флаг DF = 1 - движение назад search_string: dec AX ;на первой итерации AX и DI содержат адрес последнего символа в extensions mov DI, AX ;на последующих - продвижение на 1 символ назад cmp DI, offset CS:extensions + 1 ;дошли до второго символа, а совпадений не найдено je delete_file ;файл можно удалять mov CX, 3h ;ожидаемая длина расширения repe cmpsb ;сравниваем содержимое SI - имя файла и DI - блокируемые расширения mov SI, BX ;возвращаем SI в предыдущее состояние cmp CX, 0h ;найдено совпадение je found jmp search_string found: not_delete_file: pop ES pop DS pop SI pop DI pop CX pop BX pop AX iret delete_file: pop ES pop DS pop SI pop DI pop CX pop BX pop AX exit_21h: jmp DWPTR CS:[old_21h] new_21h endp И всё равно не работает. Кроме того, можно заметить, что сразу после метки вставлен вызов процедуры clear, которая очищает экран. Т.о. очистка должна производится при любом вызове функции 41h. Но этого не происходит. Т.е. программа по ветке work не идёт, о чём я уже писал выше. В качестве тестового примера используется файл e:\asm\test.txt Программу запускал через cmd, Volkov Commander, FAR (ходят слухи, что через эти файловые менеджеры запускать программы, написанные под ДОС, предпочтительней; почему - не пойму). И ещё я совсем не понял, что имеется ввиду здесь: При чём здесь AX=5?
То есть вы все это под виндой таки делаете? а удалять файл как пробуете? Поясню: перехваченное прерывание остается перехваченным только пока не закрыто окно консоли... То есть возможно валидной будет проверка "под Volkov Commander'ом установить резидента, и тут же не закрывая VC, средствами VC (а не в проводнике) - попытаться что-нибудь удалить". Вопрос конечно из разряда "а не чайник ли ты", но убедиться надо
Да, всё именно так. Например, под cmd запускается >e:\asm\asm1.com Затем пробуем удалить >del e:\asm\test.txt
не-е, все-таки в Волкове попробуйте. cmd - это НЕ ДОС. И del там вовсе не через int 21h работает. Есть у меня такое предчувствие...
Волков пробовал, всё так же - файлы удаляются. Но опять же вопрос, может, через него по-другому как-то нужно запускать? У меня Волков версии 4.99.08. Запускаю из винды волковский com и там уже работаю.
Einior Если не получается удалить файл, то обработчик выставляет флаг CF и возвращает код ошибки в AX, среди которых: 2 - Файл не найден. 5 - Нет доступа. В случае, когда твой обработчик будет блокировать удаление файла, было бы хорошо поступать также, как это делает системный обработчик. Перед вызовом прерывания флаги сохраняются в стеке, а после извлекаются командой iret, поэтому надо в стеке изменить значение флага CF, а в регистр AX записать необходимый код ошибки. Посмотри какой возвращает системный обработчик, но по документации - это 5. Код (Text): not_delete_file: ... ; Подготавливаем указатель push BP push SP pop BP ;[bp+0] bp ;[bp+2] ip ;[bp+4] cs ;[bp+6] flags ; Устанавливаем флаг CF mov AL, 1 or [BP+6], AL ; Восстанавливаем регистр BP и устанавливаем код ошибки. pop BP mov AX, 5 iret
Хорошо, это понял. Но тем не менее, программа не идёт на ветку work, а сразу уходит в старый обработчик. Т.е. при удалении, судя по всему, не отлавливается функция 41h (и 7141h тоже).
Есть только два нормальных варианта : 1) запускать волкова из себя, чтобы перехват int 21 работал. 2) Использовать чистый ДОС - проще всего Dosbox -------------------------------------- Про Волкова: Имеет систему управления резидентными программами (вызывается по "Alt+F5") с возможностью удалять резидентные программы (функциональность этой системы довольно мала из-за ущербности DOS). Поэтому легко проверить осталась твоя прога в памяти или в Винде все не так как в ДОС.
Попробовал сейчас запустить и Волкова из себя же, а из него уже программу, и через Досбокс - результат один, удаляет файл. Точнее с досбоксом забавная штука - если удаляемый файл существовал до запуска Досбокс, то файл удаляется. Если же создан уже после запуска, то не удаляется. Но это никак не зависит от загрузки в память програмы. Кстати, Alt+F5 в Волкове почему-то не работает.
попробуйте в command.com cmd - 32 битная командная строка. command.com - 16 битная, почти что дос. может быть волков тоже перехватывает это прерывание..
Устанавливается правильно. Есть такой участок кода в обработчике clear - процедура очистки экрана. Добавлена для отладки. Так вот, если её перенести в начало обработчика - она срабатывает.
Раз в Досбоксе работает - значит Волков что-то химичит. А под Волковым экран-то гаснет? А не удаляет свежий - наверно кешируется что-то или ты или Волков не освобождаете файл и он не удаляется...
Я сейчас смутно вспоминаю, что в ДОС есть два класса файловых прерываний : старые и новые. Рой в этом направлении.