Защита разработок на платформе 1С Предприятие 8

Защита разработок на платформе 1С Предприятие 8

Перед тем как приступить, собственно, к сути вопроса, хотелось бы сделать небольшое отступление для «крутых хакеров». Как известно, штатные возможности 1С, не представляют достаточно надежных средств для защиты исходного кода, поэтому приведенные здесь примеры – это исключительно защита от ПОЛЬЗОВАТЕЛЯ и ничего более. Да и в целом, по моему глубокому убеждению, открытость кода в 1С – это одно из важнейших (если не самое важное) её достоинств. Поэтому я сторонник «установки пароля на модуль, поставки без исходного текста», только в случае демо-версии разработки. А при приобретении обработки, клиент приобретает её ЦЕЛИКОМ, в том числе и исходный код.

Для начала, немного общих моментов. Для того что бы ограничить использование нашего «уникального» функционала, будь-то алгоритм проведения документа или процедура формирования отчета, необходимо вынести код в модуль объекта и скрыть его от пользователя. Это можно достичь двумя путями. Во-первых установка пароля на модуль объекта. Что бы установить пароль, откройте модуль объекта, далее в меню «Текст» выберите пункт «Установить пароль». Во-вторых поставка без исходного кода. Что бы получить обработку/отчет без исходного кода, необходимо сначала создать поставку включающую в себя наш отчет без исходного кода, а затем сохранить его как внешний. Настройка поставки производится в диалоге «Конфигурация > Поставка конфигурации > Настройка поставки».

Итак, пример № 1. Ограничение по времени использования. Заключается в том, что функционал работает в течении определенного, ограниченного времени, например 10 дней. Для этого, нам надо как-то «запомнить» дату первого запуска, сделаем это с помощью реестра Windows.

Функция СрокДемоЗакончился()
  Перем Значение;
  RegProv=ПолучитьCOMОбъект(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”);
  // 2147483649 – раздел реестра HKEY_CURRENT_USER
  RegProv.GetStringValue(“2147483649″,”Software\1C\1Cv8\Report”,”StartDate”,Значение);
  Если Значение=NULL Тогда // Ключ ещё не создан, считаем этот запуск первым
    // Создадим ключ, установив значение в текущую дату
    RegProv.CreateKey(“2147483649″,”Software\1C\1Cv8\Report”); // создание раздела
    // установка значения для ключа
   RegProv.SetStringValue(“2147483649″,”Software\1C\1Cv8\Report”,”StartDate”,Строка(Формат(ТекущаяДата(),”ДФ=ггггММддЧЧммсс”)));
    Возврат Ложь;
  Иначе
    // проверка срока использования демо-версии
    ДатаСтарта=Дата(Значение);
    КонецПериода=ДатаСтарта+60*60*24*10; // 10 дней
    ТекДата=ТекущаяДата();
    Возврат НЕ (ТекДата>ДатаСтарта И ТекДата<=КонецПериода);
  КонецЕсли;
КонецФункции

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

Процедура СформироватьОтчет() Экспорт
  Если СрокДемоЗакончился() Тогда
   Возврат;
  КонецЕсли;

КонецПроцедуры

Для особо хитрых пользователей, можно сделать запрос точного времени из Интернета, что бы защититься от изменения системного времени. Например, так:

Функция ТочноеВремяПоГринвичу()
  XMLHTTP=Новый COMОбъект(“MSXML2.XMLHTTP”);
  XMLHTTP.Open(“get”,”http://ntp.greenwichmeantime.com/time/scripts/clock-7/x.php”,Ложь);
  XMLHTTP.Send();
  UTC=Цел(XMLHTTP.Responsetext/1000); // в секундах
  Возврат ‘19700101000000’+UTC+60*60*4; // по Москве, летнее время
КонецФункции

Пример №2. Ограничение по количеству выполнений. То есть к примеру, отчет в демо-версии можно сформировать не более 5-ти раз. Делается аналогично предыдущему варианту, разница заключается лишь в том, что в реестр на этот раз будем записывать номер текущего запуска.

Функция СрокДемоЗакончился()
  Перем Значение;
  RegProv=ПолучитьCOMОбъект(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”);
  RegProv.GetDWORDValue(“2147483649″,”Software\1C\1Cv8\Report”,”Count”,Значение);
  ЭтотЗапуск=1;
  Если Значение=NULL Тогда
    RegProv.CreateKey(“2147483649″,”Software\1C\1Cv8\Report”);
  Иначе
    ЭтотЗапуск=Значение+1;
  КонецЕсли;
  Если ЭтотЗапуск<=5 Тогда
    RegProv.SetDWORDValue(“2147483649″,”Software\1C\1Cv8\Report”,”Count”,ЭтотЗапуск);
    Возврат Ложь;
  Иначе
    Возврат Истина;
  КонецЕсли;
КонецФункции

Пример №3. Реализация защиты «пароль-ответ». Недостаток предыдущих способов, заключается в том, что полнофункциональная версия является отдельной разработкой, которую клиенту необходимо переслать, привести, установить и т.д. При использовании же, следующего способа, всё что потребуется для получения полной версии разработки – это зарегистрировать обработку, т.е. ввести правильный код.

Суть этого способа состоит в том, что при запуске у клиента формируется некий уникальный ключ, для которого, по только нам известному алгоритму, можно сформировать «ответный пароль». И в случае совпадения пары ключ-ответ обработка считается успешно зарегистрированной.

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

Функция ПолучитьСерийныйНомерЖесткогоДиска(Диск)
  ФСО=Новый COMОбъект(“Scripting.FileSystemObject”);
  ФСО_Диск=ФСО.GetDrive(Диск);
  Возврат ФСО_Диск.SerialNumber;
КонецФункции

Алгоритм получения «ответного значения» по ключу, ограничен лишь Вашей фантазией. Здесь же, в качестве примера, я буду использовать простую перестановку символов в обратном порядке.

Функция ПолучитьОтветПоКлючу(Ключ)
  н=СтрДлина(Ключ);
  Результат=””;
  Пока н<>0 Цикл
    Результат=Результат+Сред(Ключ,н,1);
    н=н-1;
  КонецЦикла;
  Возврат Результат;
КонецФункции

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

Функция ЭтоЗарегистрированнаяКопия()
  Перем Значение,Ответ;
  RegProv=ПолучитьCOMОбъект(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”);
  RegProv.GetDWORDValue(“2147483649″,”Software\1C\1Cv8\Report”,”Registered”,Значение);
  Если Значение=NULL Тогда // необходима регистрация копии
    Регистрация=Ложь;
    Ключ=ПолучитьСерийныйНомерЖесткогоДиска(“C”);
    Если ВвестиСтроку(Ответ,”Ключ: “+Ключ) Тогда
      Если Ответ=ПолучитьОтветПоКлючу(Ключ) Тогда
        // подтвердим регистрацию
        RegProv.SetDWORDValue(“2147483649″,”Software\1C\1Cv8\Report”,”Registered”,1);
        Регистрация=Истина;
      Иначе
        Предупреждение(“Регистрационный код введен неверно!”);
      КонецЕсли;
    КонецЕсли;
    Возврат Регистрация;
  Иначе // эта копия уже зарегистрированна
    Возврат Истина;
  КонецЕсли;
КонецФункции

Осталось только вставить проверку регистрации в нашу основную процедуру:

Процедура СформироватьОтчет() Экспорт
  Если НЕ ЭтоЗарегистрированнаяКопия() Тогда
    // работа в демо-режиме
    …
  КонецЕсли;
  …
КонецПроцедуры

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

Начиная с Windows Script 5.0, появилась возможность чтения зашифрованных сценариев машинами сценариев. Поэтому любой сценарий написанный на VBScript или JavaScript, может быть выполнен в зашифрованном виде. Что бы преобразовать код на VBScript в зашифрованный вид, воспользуемся бесплатной утилитой «Windows Script Encoder», которую можно скачать с сайта Microsoft. В результате, например скрипт создания в реестре Windows раздела «HKEY_CURRENT_USER\Software\1C\1Cv8\Report», будет выглядеть следующим образом:

#@~^ZAAAAA==jY~UtVV{ZMnlD+64N+^OvJU^DbwYcj4+^Vr#@#@&j4VsR”noqDrOPJuF;jw?KWDhCM+ ‘FZ’F;-%’InwKDOwr~\(HE^V@#@&hyAAAA==^#~@

Приведу пример функции, осуществляющей проверку введенного пользователем регистрационного кода, с использованием шифрованного скрипта:

Функция ПроверитьРегистрационныйКод(Код)
  Скрипт=Новый COMОбъект(“MSScriptControl.ScriptControl”);
  Скрипт.Language=”VBScript.Encode”;
  Скрипт.AddCode(“#@~^ewAAAA==o!x^DkKxP;t”+Символ(127)+”^3v|nX*@#@&7zx/SnD{4wCs/”+Символ(127)+”@#@&d(0~F”+Символ(127)+”XxJ9^+Rl{qOv0q*rPPt”+Символ(127)+”U,bUkh”+Символ(127)+”D’74:.E”+Символ(127)+”P3x9P(W@#@&d;4+13’zUdh”+Символ(127)+”D@#@&3x[~wEUmDrW hyQAAA==^#~@ “);
  Возврат Скрипт.CodeObject.Check(Код);
КонецФункции

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

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

 

Автор: Андрей Скляров.

Источник: http://nashe1c.ru/materials-view.jsp?id=282