    3. КАК ЗАЩИТИТЬСЯ ОТ РАЗМНОЖЕНИЯ
                            (идентификация ПЭВМ).
         С развитием отечественного рынка программ возрастает значение их
    защиты от несанкционированного копирования (НСК). Разработчики просто
    опускают руки перед фатальной неизбежностью пиратского распространения
    своего детища, ведь кража этой интеллектуальной собственности проста,
    занимает считанные минуты и остается незаметной, хотя доходы приносит
    вполне приличные. Правда, корпорации-монстры все же предпочитают не
    защищать собственную продукцию, ибо общий оборот их средств намного
    превышает убытки от воровства, которые, кстати, частично покрываются
    такой бесплатной рекламой. Однако, для подавляющего большинства фирм
    и организаций, занимающихся разработкой ПО, продажа копий (зачастую с
    единственной товарной программы) - основное средство существования.
    Пираты же изменяют не только название продукта, но и
    фирму-изготовителя, тем самым добавляя к моральным потерям появление
    конкурирующего товара с аналогичными потребительскими свойствами.
    Поэтому каждый разработчик, несомненно, рано или поздно сталкивается с
    проблемой защиты ПО от НСК.
        Первая дилемма, возникающая на этом пути: придумывать ли защиту
    самому или же приобрести существующий пакет контрдействий, которых,
    к слову сказать, появилось у нас великое множество. Обычно выбор
    определяется важностью и стоимостью защищаемой информации, но,
    пожалуй, решающее значение играет квалификация программиста.
    Профессионал чаще приступает к созданию оригинальной защиты, ибо
    большинство ныне существующих представляют собой так называемый
    пристыкованный блок, который, чего греха таить, является чистым
    надувательством. Ведь опытные хакеры снимают его за считанные минуты,
    даже не удостаивая изучением (например, с помощью утилиты CATCHER,
    рекламируемой центром САПР Ассоциации Наука). Кроме того,
    профессионал никогда не отдаст на откуп другому такую интересную
    задачу, как создание защиты. А любитель выберет уже существующие
    охранные программы. Бывают еще случаи привлечения программистов со
    стороны, но, поскольку передача исходных текстов сопряжена с утечкой
    информации (от которой как раз и стремятся застраховаться), это не
    типично для нашего рынка.
         Сейчас, выражаясь на жаргоне программистов, существуют три типа
    пресечения НСК: по дискете, по машине и по пользователю. Первый
    - проверяет характеристики и информацию ключевой дискеты, которая
    служит, как правило, и носителем защищаемого ПО. Второй - следит за
    совпадением некоторых заранее определенных характеристик допущенного
    для работы компьютера. О третьем и, пожалуй, самом интересном способе
    охраны речь шла в двух предыдущих главах.
         Наиболее эффективен второй путь, так как проверка компьютера
    проста и непродолжительна, может часто повторяться по ходу работы, не
    снижая общего быстродействия. Если же режим реального времени не
    обязателен и возможны многократные обращение к медленным устройствам
    типа гибких дискет или проверка клавиатурного почерка пользователя
    (конечно, когда он участвует в работе программы), то и остальные типы
    охраны могут быть встроены в блок защиты.
         Разберем алгоритмы проверки компьютера. Программу удобнее
    привязать к следующим характеристиками машины:
        1) быстродействие: процессор, память, контроллеры и т.д.; скорость
    вращения двигателей дисководов; скорость реакции на внешние
    воздействия;
        2) конфигурация: тип микропроцессора (МП) и разрядность шины
    данных; наличие и тип контроллеров для внешних устройств и самих
    устройств (жесткие и гибкие диски, сопроцессор);
        3) особенности: контрольная сумма BIOS; содержимое CMOS памяти;
    длина конвейера шины данных; аномальные явления в ходе его работы.
        Их разделение на группы обусловлено лишь похожими алгоритмами
    определения и применения, а вообщем-то, оно весьма условно.
        Легко заметить, что быстродействие (первая группа) в наибольшей
    степени отражает индивидуальные отличия машин - они, пожалуй,
    эффективнее других привяжут ПО к компьютеру. Правда, из-за
    нестабильности электронных элементов схемы, нестабильны и показатели
    его узлов. Незнание способов корректировки таких накладок чаще всего и
    отпугивает программистов.
        Один из методов определения быстродействия компьютера представлен
    в процедуре Sample (рис. 3.1), который фиксирует отсчет таймера за
    время выполнения фрагмента 16 - 20. В регистр AX заносится для
    дальнейшего использования результат. Напомним, непосредственное его
    сравнение с некоторой эталонной величиной может привести к ошибке
    из-за нестабильности задающего генератора ПЭВМ. Отметим также, что
    реализация аналогичного алгоритма на языке BASIC даст еще больший
    разброс значений - это общий недостаток почти всех языков высокого
    уровня. Для исключения грубых ошибок и повышения точности необходимо
    провести многократные измерения и воспользоваться алгоритмом на рис.
    1.1 (глава Идентификация пользователя: свой-чужой?).
         Время выполнения одного и того же участка программы на разных
    компьютерах скорее всего будет отличаться, что и позволит выделить
    определенную ПЭВМ из ряда аналогичных.
         Тот же пример (рис. 3.1) годится и для измерения скорости работы
    оперативного запоминающего устройства (ОЗУ). Его электрическая схема
    набирается из микросхем (МС), объемом по 16, 32 или 64 Кб (килобит). В
    зависимости от типа, 8 - 16 таких МС составляют 1 блок (электронщики
    называют их блоком, а программисты страницей), емкостью 64 КБ
    (килобайт). Значит, в стандартном адресном пространстве IBM PC/XT в
    640 КБ - 10 блоков МС, причем каждый имеет собственные характеристики,
    чуть-чуть отличающиеся от других. То есть быстродействие страниц ОЗУ у
    каждого компьютера различно. На участке 16 - 20 осуществляется простая
    перезапись содержимого области памяти (ее регенерация). Время
    регенерации всех страниц составит ряд из 10 чисел, значения и
    последовательность которых характерны только для данной ПЭВМ.
        Скорость вращения двигателей дисководов определяется аналогично
    (например, замер по таймеру операции чтения/записи некоторого сектора
    или дорожки дискеты, как это делает COPYLOCK).
        Под скоростью реакции на внешние воздействия понимается время,
    необходимое компьютеру на отклик после получения команды внешнего
    устройства, или размер паузы между выдачей команды, например, в
    контроллер накопителя гибких магнитных дисков (НГМД), и приходом
    сигнала готовности (аппаратное прерывание IRQ7 для НГМД). Измерения
    проводятся по отсчетам таймера, но можно использовать и свой
    программный счетчик, как это делает BIOS при дисковых операциях.
         Если речь идет о компьютерах одной партии, то информация о типе и
    конфигурации не уникальна, хотя, как дополнительный элемент привязки к
    характеристикам ПЭВМ, не повредит. Ее можно получить через прерывание
    BIOS 11h (или по адресу 40h:0010h ОЗУ), а более исчерпывающую - из
    CMOS-памяти. Гораздо сложнее определить программным путем тип МП.
        Характеристики третьей группы, очевидно, не всегда индивидуальны у
    конкретной машины. Общеизвестно, что в одной партии конрольная сумма
    BIOS одинакова (если, конечно, это не так называемая белая сборка).
    Энергонезависимая память CMOS, содержащая часы реального времени и
    информацию о конфигурации, также зачастую одинакова. К сожалению,
    формат CMOS различен на разных типах машин, а значит единого способа
    привязки нет. Если же расчет строится на определенный тип компьютера,
    то доступ к CMOS вполне возможен (с условием, что конфигурация не
    будет меняться в процессе эксплуатации программы).
        Алгоритм чтения/записи байтов в ячейки CMOS приведен на рис. 3.2.
    Кстати, процедуру подсчета контрольных сумм можно усложнить, если
    арифметическую операцию сложение заменить на логическую или добавить
    к ней еще что-нибудь.
        А на рис. 3.3 более интересный алгоритм, шифрующий и одновременно
    привязывающий программу к конкретному компьютеру. На определенные
    участки защищаемой программы накладывают некоторую область CMOS
    (например, операцией XOR). При запуске программа сама осуществит
    обратную процедуру, дешифрируя свой код (удобнее использовать область,
    защищенную контрольной суммой, байты 10h - 20h). Естественно, что на
    другом компьютере константа CMOS будет отличаться и, значит, процесс
    дешифровки испортит программу. Кстати, здесь годится и собственная
    информация, записанная в резервные ячейки энергонезависимой памяти,
    если, конечно, ее формат позволяет это делать, как, например, у
    компьютеров фирмы WIPRO Information Technology Limited (допускающих
    достаточно вольное обращение с CMOS: в том числе и с ячейками,
    защищенными контрольной суммой, с последующей корректировкой по
    адресам 2Eh,2Fh). А компьютеры SystemPro фирмы Compaq, хотя и не дают
    программисту возможности воспользоваться этим методом защиты, но
    обладают (как и некоторые другие на базе МП 80386 и выше) таким
    интересным свойством, как пользовательский пароль, который занесен в
    байты 38h - 3Fh и защищен от чтения и записи.
        Последние две особенности третьей группы характеристик ПЭВМ, на
    наш взгляд, наиболее перспективны для защиты ПО от исследования и
    поэтому рассматриваются в следующей главе (Защита от исследований).
         Независимо от выбранного способа идентификации, больше всего
    вопросов вызывает сама передача программ покупателю. Ведь в этот
    момент они уже должны содержать в себе эталонные характеристики ПЭВМ
    пользователя, чтобы проводить соответствующие проверки. Хорошо, если
    автор может прийти и лично настроить свои программы, а как быть с
    иногородними покупателями?
         Действия по настройке лучше всего поручить специальной
    инстолирующей программе, которая может храниться на одной дискете с
    передаваемым пакетом. Инстолятору поручают разархивацию продукции
    (расшифровку и приведение в рабочее состояние), перезапись с дискеты
    на винчестер, определение используемых характеристик компьютера и
    вписывание их в известные одному автору места программ (конкретные
    адреса для этих значений должны быть предусмотрены заранее). Попутно
    проверяется - не является ли ключевая дискета незаконной копией и
    соответствует ли название организации-покупателя упоминаемому в
    договоре купли-продажи. По завершению работы инстолятор может стереть
    сам себя с дискеты или сделать отметку об успешно проведенной
    инстоляции (чтобы самоликвидироваться после исчерпания оговоренного
    договором лимита).
         Такую схему передачи можно применять даже при пересылке
    программных продуктов по почте - после самоуничтожения инстолятора
    владение ключевой дискетой становится бесполезным.

            ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
            і                        Ассемблер:                          і
            і                        ДДДДДДДДДД                          і
            і 1 0000          code    segment para public                і
            і 2                       assume cs:code,ds:code             і
            і 3                                                          і
            і 4 0000          sample  proc                               і
            і 5                                                          і
            і 6 0000  FA          cli                                    і
            і 7 0001  BA 0043     mov dx,43h      ; включить 0-й канал   і
            і 8 0004  B0 34       mov al,34h      ; таймера              і
            і 9 0006  EE          out dx,al                              і
            і10 0007  B2 40       mov dl,40h      ; задать начальное     і
            і11 0009  8A C6       mov al,dh       ; значение счетчика    і
            і12 000B  EE          out dx,al                              і
            і13 000C  EE          out dx,al                              і
            і15                ;=======================================  і
            і16 000D  33 F6         xor si,si        ;                   і
            і17 000F  8B FE         mov di,si        ; Здесь может быть  і
            і18 0011  B9 8000       mov cx,8000h     ; расположен любой  і
            і19 0014  FC            cld              ; ваш текст         і
            і20 0015  F3> A5        rep movsw           ;                і
            і21                ;=======================================  і
            і23 0017  BA 0043   mov dx,43h   ; зафиксировать текущее     і
            і24 001A  B0 04     mov al,4     ; значение счетчика         і
            і25 001C  EE        out dx,al                                і
            і26 001D  B2 40     mov dl,40h   ; считать значение счетчика і
            і27 001F  EC        in  al,dx    ; в AX                      і
            і28 0020  8A E0     mov ah,al                                і
            і29 0022  EC        in  al,dx                                і
            і30 0023  86 E0     xchg ah,al                               і
            і31 0025  FB        sti                                      і
            і32                                                          і
            і33        ; здесь должна быть проверка считанного значения  і
            і34                                                          і
            і35 0026  B8 4C00        mov ax,4c00h                        і
            і36 0029  CD 21          int 21h                             і
            і37                                                          і
            і38 002B         sample  endp                                і
            і39 002B         code    ends                                і
            і40              end     sample                              і
            і                                                            і
            і                        BASIC:                              і
            і                        ДДДДДД                              і
            і100     OUT     &H43, &H34                                  і
            і110     OUT     &H40, 0                                     і
            і120     OUT     &H40, 0                                     і
            і        . . . . . . . . . . . . . . . . . . .               і
            і                                                            і
            і        ' Текст замеряемого участка программы               і
            і                                                            і
            і        . . . . . . . . . . . . . . . . . . .               і
            і300     OUT     &H43, 4                                     і
            і310     X% = INP ( &H40 ) + INP ( &H40 ) * 256              і
            і320     PRINT X%                                            і
            АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                                      рис. 3.1

            ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
            і1)  чтение:                                                 і
            і    Ассемблер:                         BASIC:               і
            і    ДДДДДДДДДД                         ДДДДДД               і
            і      . . .                           . . .                 і
            іmov al,номер байта CMOS    300  OUT &H70, номер байта CMOS  і
            і  out 70h,al                 310  X% = INP ( &H71 )         і
            і  jmp $+2                                                   і
            і  in al,71h                               . . .             і
            і     . . .                                                  і
            і2   запись:                                                 і
            і        Ассемблер:                     BASIC:               і
            і        ДДДДДДДДДД                     ДДДДДД               і
            і        . . .                          . . .                і
            і  mov al,номер байта CMOS    300  OUT &H70, номер байта CMOSі
            і  out 70h,al                 310  OUT &H71, новое значение  і
            і  jmp $+2                                                   і
            і  mov al,новое значение               . . .                 і
            і  out 71h,al                                                і
            і   . . .                                                    і
            АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                                      рис. 3.2

            ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
            і    Ассемблер:              BASIC:                          і
            і    ДДДДДДДДДД              ДДДДД                           і
            і  . . .                     . . .                           і
            і  mov ax,0f800h         500  DEF SEG = &Hf800               і
            і  mov es,ax             510  S = 0                          і
            і  xor ax,ax             520  FOR I = 0  TO  32766  STEP 2   і
            і  mov bx,ax             530  S = S + PEEK(I) + PEEK(I+1)*256і
            і  mov cx,4000h          540  NEXT                           і
            іrpt:                    550  PRINT S                        і
            і  add ax,es:[bx]                                            і
            і  inc bx                   . . .                            і
            і  inc bx                                                    і
            і  loop rpt                                                  і
            і   . . .                                                    і
            АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                                  рис. 3.3
вверх