Простые примеры реализации демо-версий обработок на платформе «1С:Предприятие 8».

22.05.08

Разработка - Защита ПО и шифрование

Каждый из тех кто продает свой интеллектуальный труд, не раз сталкивался с необходимостью создания демо-версии разработки, дабы продемонстрировать клиенту функциональность, но при этом сохранить для клиента потребность в приобретении полнофункциональной версии. В этой статье я хотел бы рассмотреть несколько не сложных примеров создания демо-версий обработок/отчетов для платформы «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, аппаратные ключи защиты и пр. Здесь же я попытался привести несколько простых примеров в качестве основ так сказать…

См. также

Защита ПО и шифрование Программист Платформа 1С v8.3 1С:Бухгалтерия 3.0 Абонемент ($m)

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

1 стартмани

09.02.2023    2723    11    aximo    5    

2

Защита ПО и шифрование Программист Абонемент ($m)

Для установки защиты pdf документа, полученного в 1С, написано консольное приложение на c#., использующее одну зависимость pdfSharp.dll. В результате работы приложения ограничены операции над документом и записаны метаданные. С помощью аргументов командной строки можно управлять работой приложения.

2 стартмани

30.01.2023    2139    2    olevlasam    3    

3

Защита ПО и шифрование Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Универсальный синтаксический анализатор ASN.1, который может декодировать любую допустимую структуру ASN.1 DER или BER, независимо от того, закодирована ли она в кодировке Base64 (распознаются необработанные base64, защита PEM и begin-base64) или в шестнадцатеричном кодировании.

1 стартмани

04.12.2022    3584    16    keyn5565`    0    

14

Защита ПО и шифрование Программист Платформа 1С v8.3 Абонемент ($m)

Демонстрация возможностей шифрования строки на основе мастер-пароля в 1С Предприятие 8.3.19. AES без zip файла, RSA, PKDF2. (c использованием библиотеки С# через com).

2 стартмани

31.08.2022    4468    9    vit59    2    

6

Защита ПО и шифрование Программист Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Обработка, позволяющая запутывать и шифровать байт-код, поставлять модули без исходных текстов и т.д. Работает только в файловом варианте с версии платформы 8.3.22.1368 из-за конструктора ГенераторСлучайныхЧисел, поскольку алгоритм был изменён.

10 стартмани

16.06.2022    12747    106    ZhokhovM    12    

45

Защита ПО и шифрование Программист Платформа 1С v7.7 Платформа 1С v8.3 Абонемент ($m)

Как уберечь конструкторскую документацию от воровства конкурентами? Недавно столкнулся с этой проблемой. Заказчик серьёзно обеспокоен утечкой информации о конструкторских разработках в адрес конкурентов, за счет подкупа исполнителей, занимающихся производством по конструкторской документации, операторов технологического оборудования и обрабатывающих центров по изготовлению деталей и сборочных единиц.

2 стартмани

09.03.2022    6138    3    ge_ni    9    

2

Защита ПО и шифрование Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Система построена на веб платформе, все управление происходит на сайте в личном кабинете пользователя.

1 стартмани

27.12.2021    5104    2    idm80    12    

9
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. support 4453 06.05.08 13:39 Сейчас в теме
Замечательная статья!
2. vasilykushnir 63 06.05.08 14:20 Сейчас в теме
Согласен с (1) - хорошая статья. А еще можно посмотреть в сторону дополнительных глобальных модулей и их тоже шифрануть...
3. coder1cv8 3477 06.05.08 14:35 Сейчас в теме
(2) Дык, я ж о восьмерке, в ней никаких дополнительных глобальных модулей нету... )
6. vasilykushnir 63 06.05.08 16:00 Сейчас в теме
(3) Не знал... (8-ку не юзаю).
7. Abadonna 3968 06.05.08 18:41 Сейчас в теме
(3)>Дык, я ж о восьмерке, в ней никаких дополнительных глобальных модулей нету...
В семерке тоже нет ;)
Это спасибо Альфу за formex - с ней они появляются
4. German 413 06.05.08 14:51 Сейчас в теме
больше всего последний абзац понравился..
а сменить серийник жесткого диска можно? чисто ради спортивного интереса.
5. coder1cv8 3477 06.05.08 15:18 Сейчас в теме
(4) Конечно можно ) Это просто пример.
8. artem666 29 07.05.08 00:19 Сейчас в теме
Респект!
Максимум до чего сам додумывался, так это на количество включений
9. kirill_sid 07.05.08 07:21 Сейчас в теме
Хорошая статья. Информация, думаю, многим будет полезна. +1
10. cs25 81 07.05.08 09:18 Сейчас в теме
11. coder1cv8 3477 07.05.08 09:52 Сейчас в теме
Спасибо всем )
У меня вопрос к support-у: почему в коде иногда вырезаются символы "\"? Т.е. вот сейчас я заметил, что везде строка "Software\1C\1Cv8\Report" у меня стала "Software1C1Cv8Report" :( Надо бы исправить!
12. pas-and 07.05.08 09:56 Сейчас в теме
Все гениальное - просто. Понравилась статья.Плюсану.
13. dima1c 46 07.05.08 15:13 Сейчас в теме
14. shachneff 07.05.08 16:28 Сейчас в теме
А можно еще и пример кода, использующего шифрованный скрипт?
15. coder1cv8 3477 07.05.08 16:39 Сейчас в теме
(14) Примеры с шифрованными скриптами будут, но несколько позже...
16. mdzen 238 08.05.08 14:13 Сейчас в теме
17. maloi_a 10.05.08 18:07 Сейчас в теме
Два мелких замечания.
1. В Процедуре ЭтоЗарегистрированнаяКопия()
Ключ=ПолучитьСерийныйНомерЖесткогоДиска("C");
пришлось поменять на
Ключ=Формат(ПолучитьСерийныйНомерЖесткогоДиска("C"),"ЧГ=");
из-за невозможности ввести неразрывный пробел с клавиатуры.

2. В Примере №2 оператор
ЭтотЗапуск=1;
перенес после
Если Значение=NULL Тогда
19. coder1cv8 3477 11.05.08 12:58 Сейчас в теме
(17) Это просто примеры, информация к размышлению, на самом деле я бы не стал использовать это "буквально", в таком виде как здесь. Но тем не менее, спасибо за замечания )
18. tormozit 7238 10.05.08 23:57 Сейчас в теме
Описаны уже устоявшиеся приемы, но разжеваны хорошо да и для 1С это в новинку. Спасибо. Плюс.
20. Stanislaw 12.05.08 07:24 Сейчас в теме
Отличные примеры. Но почему то всплывает ошибка на строчке:

RegProv=ПолучитьCOMОбъект("winmgmts:{impersonationLevel=impersonate}!\.rootdefault:StdRegProv");

Это ошибка при вызове метода. Ошибка получения СОМ-Объекта: IDispatch error #3617

Подскажите пожалуйста в чем проблема
21. coder1cv8 3477 12.05.08 09:38 Сейчас в теме
(20) Проблема в движке этого сайта, есть тут баг, искажается код... Эта строка должна выглядеть так:
RegProv=ПолучитьCOMОбъект("winmgmts:{impersonationLevel=impersonate}!\\.root\default:StdRegProv");
22. coder1cv8 3477 12.05.08 11:51 Сейчас в теме
Как и обещал, добавил пример илюстрирующий использование шифрованного скрипта.
37. eternity 06.12.13 23:23 Сейчас в теме
(22)
Очень интересная тема, спасибо.
Попробовал использовать выполнение зашифрованного скрипта, но 1С ругается на строку:
Скрипт.AddCode("#@~^ew....

Пишет: Произошла исключительная ситуация (Ошибка компиляции Microsoft VBScript): Предполагается наличие инструкции

Почему 1С не может добавить зашифрованный текст скрипта? Или что-то еще надо прописать?
Прикрепленные файлы:
23. O-Planet 6443 21.05.08 23:18 Сейчас в теме
«1С:ПредПИРЯтие 8» - это жОстко! :)
24. coder1cv8 3477 22.05.08 09:34 Сейчас в теме
(23) Спасибо ) Бывает... Хоть кто-то заметил! ))
25. coder1cv8 3477 03.06.08 17:15 Сейчас в теме
Так же на эту тему рекомендую посмотреть мою обработку "Обфускация кода 1С" :)
26. RailMen 828 17.03.09 19:10 Сейчас в теме
Я как раз разрабатываю самописные функции такой же тематики для внешних обработок. Как - нибудь выложу. Мой подход немного отличается от этого.
27. dobraleks 136 10.04.09 17:14 Сейчас в теме
+1 подчеркнул для себя кое что новенькое
28. AlecoZAV 13 22.07.09 10:57 Сейчас в теме
у меня вылезает ошибка
"Ошибка при вызове метода контекста (send): Произошла исключительная ситуация (msxml3.dll): Не удается найти указанный ресурс."
на строчке
XMLHTTP.Send();

в чем может быть дело?
29. AlecoZAV 13 23.07.09 11:37 Сейчас в теме
вместо кома MSXML2.XMLHTTP использовала winhttp и получилось
30. dardroze 26.12.11 14:04 Сейчас в теме
Попробовал ограничение по времени и количеству запусков - получилось.
Спасибо, отличный сайт!
p.s. По "пароль-ответ" почитаю еще, вдумаюсь. Может пригодится
31. adhocprog 1142 04.03.12 03:25 Сейчас в теме
Очень хорошая статья!
32. xomaq 16 08.06.12 07:19 Сейчас в теме
Полезная статья!!
Почитаю на досуге более вдумчиво и кое-чем воспользуюсь.
33. dryms 249 25.10.12 02:14 Сейчас в теме
34. mdvinfostart 37 20.11.12 17:37 Сейчас в теме
Спасибо за сэкономленное время.+
35. papami 56 20.11.12 18:07 Сейчас в теме
36. a-grinyuk 07.08.13 17:20 Сейчас в теме
У меня стоит Windows 7 Prof с включенным UAC.
Запись в реестр срабатывает, но ни чего в реестре не появляется.
Полагаю что это из-за включённого UAC. Можно ли как то вызвать стандартное окно Windows для разрешения действия записи в реестр ?
38. softgarant 62 04.04.14 20:30 Сейчас в теме
Если я правильно понял, используя зашифрованый скрипт можно в скрипт затащить проверку на совпадение неких параметров, пусть то ид винчестера и возврат в код результата Истина или Ложь. А модуль с кодом проверки обфусцировать и запаролить, верно?
39. dreadlord 16.10.14 11:32 Сейчас в теме
40. GSA3D 20.07.17 09:42 Сейчас в теме
а как JavaScript может быть выполнен в зашифрованном виде?
Оставьте свое сообщение