Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система MS-DOS

© Александр Фролов, Григорий Фролов
Том 1, книга 3, М.: Диалог-МИФИ, 1992.

[Назад] [Содеожание] [Дальше]

6.1. Ограничение доступа при загрузке MS-DOS

Операционная система MS-DOS не содержит каких-либо средств разграничения доступа. Однако если компьютером пользуется несколько человек, или если возможен доступ к вашему компьютеру посторонних лиц, желательно использовать программу, запрашивающую пароль при загрузке операционной системы.

Одним из примеров коммерческой системы разграничения доступа для MS-DOS может служить системный администратор ADM. Эта система обеспечивает разграничение доступа к отдельным логическим дискам для нескольких пользователей. Логический диск может быть предоставлен пользователю с правом на чтение, чтение/запись или полностью "спрятан" от пользователя. Для создания логических дисков используется нестандартная схема разделов диска, поэтому, загрузив операционную систему с дискеты, вы "увидите" только диск C:, остальные диски будут для вас недоступны.

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

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

Как же можно доработать MS-DOS, для того, чтобы она обеспечивала ограничение доступа при загрузке?

Для ответа на этот вопрос вспомним, как выполняется загрузка операционной системы.

После тестирования аппаратуры и инициализации векторов прерываний BIOS происходит попытка выполнить чтение самого первого сектора на нулевой дорожке и нулевой стороне диска А: или, при отсутствии дискеты в дисководе А:, первого сектора нулевой дорожки нулевой стороны накопителя на жестком диске С:. В любом случае, содержимое сектора записывается в оперативную память по адресу 7C00:0000, после чего по этому же адресу передается управление.

Если загрузка операционной системы выполняется с жесткого диска, считанный сектор содержит главную загрузочную запись - Master Boot Record и таблицу разделов диска.

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

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

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

В первый сектор (на место главной загрузочной записи) записывается специальная программа и таблица имен пользователей и их, разумеется зашифрованные, пароли.

После передачи управления эта программа переписывает себя в другое место оперативной памяти и запрашивает имя и пароль пользователя. Если имя и пароль указаны правильно, программа считывает главную загрузочную запись в память по адресу 7C00:0000 и там (в памяти, а не на диске) расшифровывает таблицу разделов. После этого управление передается главной загрузочной записи по адресу 7C00:0000 и загрузка продолжается обычным образом.

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

Используя указанную выше схему защиты от НСД, не забывайте о такой программе, как Norton Disk Doctor. Эта программа сможет восстановить и таблицу разделов, и корневые каталоги, и все остальное...

Вы можете усложнить приведенную выше схему, добавив специальный драйвер. Этот драйвер, переназначив дисковые прерывания (INT 13h и INT 40h - используется MS-DOS вместо INT 13h) и прерывания для работы с каталогами, будет отслеживать все обращения к каталогам и расшифровывать их при необходимости. Однако при этом производительность системы может несколько снизиться.

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

Приведем пример такого драйвера. Вы можете записать его на диск С: и первой строкой в файле CONFIG.SYS записать:

device=c:\stop.sys

Для продолжения загрузки введите пароль sys.

          .MODEL tiny
          .CODE        ; Драйвер состоит из одного
                                ; сегмента кода

          org 0        ; Эта строка может отсутствовать

          include sysp.inc

;===========================================================
stop    PROC far         ;драйвер - это FAR-процедура
;===========================================================

E_O_P:              ;Метка конца программы,
                                ;устанавливаем ее в начало
                                ;драйвера, т.к. нам не надо
                                ;оставлять драйвер резидентно
                                ;в памяти

; Заголовок драйвера

          dd   0ffffffffh       ;адрес следующего драйвера
          dw   8000h            ;байт атрибутов
          dw   dev_strategy     ;адрес процедуры стратегии
          dw   dev_interrupt    ;адрес процедуры прерывания
          db   'STOP    '       ;имя устройства (дополненное пробелами)

;===========================================================
; Программа стратегии

dev_strategy:
                mov  cs:req_seg,es
                mov  cs:req_off,bx
                ret

; Здесь запоминается адрес заголовка запроса

req_seg         dw ?
req_off         dw ?

;===========================================================
;Обработчик прерывания

dev_interrupt:
        push es     ;сохраняем регистры
        push ds
        push ax
        push bx
        push cx
        push dx
        push si
        push di
        push bp

; Устанавливаем ES:BX на заголовок запроса

        mov  ax,cs:req_seg
        mov  es,ax
        mov  bx,cs:req_off

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

        mov  al,es:[bx]+2
        shl  al,1

        sub  ah,ah            ; Обнуляем AH
        lea  di,functions     ; DI указывает на смещение таблицы
        add  di,ax            ; Добавляем смещение в таблице
        jmp  word ptr [di]    ; Переходим на адрес из таблицы

functions   LABEL  WORD  ; Таблица функций

   dw   initialize
   dw   check_media
   dw   make_bpb
   dw   ioctl_in
   dw   input_data
   dw   nondestruct_in
   dw   input_status
   dw   clear_input
   dw   output_data
   dw   output_verify
   dw   output_status
   dw   clear_output
   dw   ioctl_out
   dw   Device_open
   dw   Device_close
   dw   Removable_media

; Выход из драйвера, если функция не поддерживается

check_media:
make_bpb:
ioctl_in:
nondestruct_in:
input_status:
clear_input:
output_verify:
output_status:
clear_output:
ioctl_out:
Removable_media:
Device_open:
Device_close:
output_data:
input_data:

        or   es:word ptr [bx]+3,8103h
     jmp  quit

;===========================================================
quit:
        or   es:word ptr [bx]+3,100h
        pop bp
        pop di
        pop si
        pop dx
        pop cx
        pop bx
        pop ax
        pop ds
        pop es
   ret

;===========================================================
; Процедура выводит на экран строку
; символов в формате ASCIIZ

dpc proc near
        push si
dpc_loop:
        cmp  ds:byte ptr [si],0
        jz   end_dpc
        mov  al,ds:byte ptr [si]
        @@out_ch al
        inc si
        jmp dpc_loop

end_dpc:
        pop si
        ret
dpc endp

;===========================================================
hello db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+'
         db 13,10,'¦  *STOP*   (C)Frolov A., 1990   ¦'
      db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+'
         db 13,10
         db 13,10,'Enter password...'
         db 13,10,0

;===========================================================
initialize:

   lea  ax,E_O_P      ;смещение конца программы в AX
   mov  es:word ptr [bx]+14,ax   ;помещаем его в заголовок
   mov  es:word ptr [bx]+16,cs   ;

; Стираем экран

        mov   dh,18h
        mov   dl,80h

        xor   cx,cx
        mov   bh,7
        xor   al,al
        mov   ah,6
        int   10h

; Устанавливаем курсор в левый верхний угол экрана

        mov   bh,0
        xor   dx,dx
        mov   ah,2
        int   10h

; Выводим сообщение

        mov ax,cs
        mov ds,ax
        mov si,offset hello
        call dpc

; Ожидаем ввода правильного пароля

loop_password:

        mov   ax,0
        int   16h
        cmp   al,'s'
        jne   loop_password

        mov   ax,0
        int   16h
        cmp   al,'y'
        jne   loop_password

        mov   ax,0
        int   16h
        cmp   al,'s'
        jne   loop_password

        jmp  quit

stop ENDP

        END stop

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

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

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

Одна из готовых программ, которая может быть использована для шифрования данных - архиватор PKZIP. Эта программа кроме шифрования файлов еще и уплотняет их, что полезно и само по себе. После образования зашифрованного архива программа PKZIP удаляет исходные файлы. К сожалению, эти файлы можно легко восстановить, например, утилитой Нортона QU. Для того, чтобы удалить эти файлы окончательно, можно в конце рабочего дня запускать утилиту Нортона WIPEINFO, которая прописывает сектора свободных кластеров нулями (при вызове с соответствующими параметрами).

Для удобства шифрования файлов программой PKZIP мы подготовили две программы (соответственно, для шифрования и дешифрования).

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

Программа шифрования всех файлов текущего каталога:

#include <stdio.h>
#include <conio.h>
#include <process.h>

void main(int argc, char *argv[])
{
         char passw[80], filebuf[80], parms[100], ch;

         _searchenv( "pkzip.exe", "PATH", filebuf );
         if(!(*filebuf) ) {
                printf("PKZIP not found.\n");
                exit(-2);
         }

         printf( "Enter password: " );
         getpw(passw, 80);
         sprintf(parms,"-m -s%s %s",passw,argv[1]);
         execl( filebuf, parms, parms, NULL );

         exit(-1);
}

int getpw( char *buf, int size) {

        int i;
        char ch;

        for(i=0; i<size; ) {
                ch = getch();
                if(ch == 0) ch=getch();
                putch('.');
                *buf = ch;
                if(*buf == 0xd) break;
                i++;
                buf++;

        }
        *buf = 0;
}

Программа дешифрования:

#include <stdio.h>
#include <conio.h>
#include <process.h>

void main(int argc, char *argv[])
{
         char passw[80], filebuf[80], parms[100], ch;

         _searchenv( "pkunzip.exe", "PATH", filebuf );
         if(!(*filebuf) ) {
                printf("PKUNZIP not found.\n");
                exit(-2);
         }

         printf( "Enter password: " );
         getpw(passw, 80);
         sprintf(parms,"-s%s %s",passw,argv[1]);
         execl( filebuf, parms, parms, NULL );

         exit(-1);
}

int getpw( char *buf, int size) {

        int i;
        char ch;

        for(i=0; i<size; ) {
                ch = getch();
                if(ch == 0) ch=getch();
                putch('.');
                *buf = ch;
                if(*buf == 0xd) break;
                i++;
                buf++;

        }
        *buf = 0;


}

В качестве параметра программам надо задать имя образуемого архива (можно без расширения). Если это имя не указывать, используется имя (NULL) - на эту строку указывает неинициализированный параметр argv[1].

[Назад] [Содеожание] [Дальше]