Информационные технологииStfw.Ru 🔍

Защита программ на жестком диске

Под DOS.
🕛 21.04.2010, 13:23
Последний шаг необходим для того, чтобы защищенный от копирования программный пакет стало невозможно перенести на другой компьютер, используя программы копирования файлов или разгрузки дисков на дискеты или магнитные ленты с последующим восстановлением на жестком диске другого компьютера.

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

Программа установки, пользуясь таблицей размещения файлов FAT, определяет список кластеров, распределенных файлу и записывает этот список в конец защищаемого файла или в отдельный файл. Можно использовать, например, файл конфигурации, предназначенный для хранения текущих параметров программного пакета. Список кластеров можно зашифровать, сложив его, например, с использованием логики "ИСКЛЮЧАЮЩЕЕ ИЛИ", с каким-либо числом.

После запуска программный пакет определяет расположение защищенного файла на диске и сравнивает его с записанным при установке. Если расположение изменилось - запущена незаконная копия программного пакета.

Какие недостатки у этого способа?

Прежде всего, невозможна оптимизация диска такими программами, которые могут изменить расположение файлов на диске, например, Norton Speed Disk.

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

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

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

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

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

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

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

Мы приведем несколько примеров программ, демонстрирующих использование некоторых из перечисленных выше методов.

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

К сожалению, непосредственное чтение диска - единственная документированная возможность получения списка кластеров, распределенных файлу.

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

Напомним, что для каждого открытого файла эта таблица содержит, кроме всего прочего, номер первого кластера, распределенного файлу, и номер кластера файла, к которому только что выполнялось обращение - last_clu.

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

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

Приведем пример программы, которая проделывает все это и выводит на экран содержимое таблицы файлов и список кластеров для файла, путь которого передается программе в качестве параметра:

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include "sysp.h"

void main(int argc, char *argv[]);
void show(DFCB far *);

void main(int argc, char *argv[]) {

CVT far *cvt;
DFT far *dft;
unsigned i,j,k;
DFCB far *dfcb, far *file_dfcb;
int handle, flag, disk;

BOOT far *boot_rec;
int status;
char *buf;

char drive[_MAX_DRIVE], dir[_MAX_DIR];
char fname[_MAX_FNAME], ext[_MAX_EXT];
char name[12];

printf("Информация о расположении файла\n"
"Copyright Frolov A. (C),1990\n");

printf("Исследуем расположение файла '%s'\n", argv[1]);

// Открываем файл, для которого будем получать список кластеров

handle = open(argv[1], O_BINARY);
if(handle == 0) {
printf("Ошибка при открытии файла!\n");
exit(-1);
}

// Разбиваем путь файла на составляющие компоненты:
// - буква диска;
// - каталог;
// - имя файла;
// - расширение имени

_splitpath(argv[1], drive, dir, fname, ext);

// Комбинируем строку из имени и расширения

strcpy(name,fname);
for(i=0; i<8; i++) {
if(name[i] == 0) break;
}
for(; i<8; i++) name[i] = ' ';
name[8] = 0;
strcat(name, &ext[1]);

// Преобразуем строку имени в заглавные буквы

strupr(name);

// Вычисляем номер дисковода

drive[0] = toupper(drive[0]);
disk = drive[0] - 'A';

printf("%s - %s - %s - %s : %s\n",
drive, dir, fname, ext, name);


cvt=get_mcvt(); // Адрес векторной таблицы связи
dft=get_fdft(cvt); // Адрес начала таблицы файлов

// Сбрасываем флаг поиска файла

flag = 0;

for(;;) {
if(dft == (DDCB far *)0) break; // Конец таблицы файлов

i=dft->file_count;

for(j=0;j<i;j++) { // Цикл по файловым управляющим блокам

dfcb=(&(dft->dfcb))+j; // Адрес DFCB файла

// Ищем файл в таблице открытых файлов

k = memcmp(name,dfcb->filename,11);
if(k == 0) {

printf("Файл найден!\n");
printf("\nDFCB файла: %Fp\n\n",dfcb);

// Запоминаем адрес таблицы для найденного файла

file_dfcb = dfcb;

// Показываем содержимое таблицы для найденного файла

show(file_dfcb);
flag = 1;
break;
}

}
dft=get_ndft(dft);

if(flag == 1) break;
}

if(flag == 0) {
printf("Файл не найден");
close(handle);
exit(-1);
}

// Заказываем буфер для чтения BOOT-записи.
// Адрес буфера присваиваем FAR-указателю.

boot_rec = malloc(sizeof(*boot_rec));

// Читаем загрузочную запись в буфер

status = getboot((BOOT far*)boot_rec, disk);

// Вычисляем размер кластера в байтах

i = boot_rec->bpb.clustsize * boot_rec->bpb.sectsize;
printf("\nРазмер кластера, байтов : %d",i);

// Если произошла ошибка (например, неправильно указано
// обозначение диска), завершаем работу программы

if(status) {
printf("\nОшибка при чтении BOOT-сектора");
close(handle);
exit(-1);
}

buf = malloc(i);

printf("\nСписок кластеров файла:\n");

// Читаем файл по кластерам, выводим номер
// последнего прочитанного кластера, который
// берем из таблицы файлов

for(;;) {

read(handle, buf, i);
if(eof(handle)) break;
printf("%d ",file_dfcb->last_clu);

}

close(handle);
free(boot_rec);
free(buf);
exit(0);
}

// Функция для отображения содержимого таблицы файлов

void show(DFCB far *dfcb) {

int k;

printf("Имя файла: ");
for(k=0;k<11;k++) {
putchar(dfcb->filename[k]);
}

printf("\nКоличество file handles: %d\n"
"Режим доступа: %d\n"
"Поле reserv1: %04X\n"
"Информация об устройстве: %04X\n"
"Адрес драйвера: %Fp\n"
"Начальный кластер: %d\n"
"Время: %04X\n"
"Дата: %04X\n"
"Размер файла в байтах: %ld\n"
"Текущее смещение в файле: %ld\n"
"Поле reserv2: %04X\n"
"Последний прочитанный кластер: %d\n"
"Сегмент PSP владельца файла: %04X\n"
"Поле reserv7: %d\n"
"-\n\n",
dfcb->handl_num,
dfcb->access_mode,
dfcb->reserv1,
dfcb->dev_info,
dfcb->driver,
dfcb->first_clu,
dfcb->time,
dfcb->date,
dfcb->fl_size,
dfcb->offset,
dfcb->reserv2,
dfcb->last_clu,
dfcb->ownr_psp,
dfcb->reserv7);
}

DOS   Теги:

Читать IT-новости в Telegram
Информационные технологии
Мы в соцсетях ✉