Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > как защитить программу?


Автор: Gadski Gad 20.7.2004, 13:53
как сделать чтобы програма через 30 дней вылетать начала, если не введен пароль, и если вводишь пароль чтоб она перестала вылетать? notify.gif

Автор: Monty 20.7.2004, 13:54
Используй ASProtect smile.gif ... ищи его тут http://wasm.ru

Автор: Alex 20.7.2004, 14:45
Цитата(Monty @ 20.7.2004, 14:54)
Используй ASProtect smile.gif ... ищи его тут http://wasm.ru

Ну и к чему ты это сказал?

Автор: Pakshin A. S. 20.7.2004, 17:57
Ручками надо...
Запомни первый запуск где-нибудь (лучше зашифруй). Далее сам поймёшь, надеюсь...

Автор: oleg1973 20.7.2004, 21:11
а я время назад переведу smile.gif)))

Автор: Monty 20.7.2004, 21:33
Цитата
Ну и к чему ты это сказал?

Тяжело догадаться? Что я дал за программу? Это Протектор для исполняемых модулей, тоесть программ smile.gif и он умеет создавать триал smile.gif

Автор: Pathfider 20.7.2004, 22:15
Цитата
а я время назад переведу

А вот на такой случай сделай где нибудь независимый от винды счетчик (лучше тоже шифрованый ну или хорошо замаскированый)!

Автор: MacTep 21.7.2004, 00:12
А для начанающего "защитника" информации? Подробнее, пожалуйста...

Автор: Maverick 21.7.2004, 09:02
при первом запуске создаешь в windows\system32 страшный файл mscdriver.dll... а при остальных запусках проверяешь дату его создания.... сам подумай, у кого рука подымется стереть файл из системной директории?

Автор: Pakshin A. S. 21.7.2004, 13:09
У меня.... biggrin.gif
Если он не очень похож на dll, то без сожаления удалю!!!!!!!!!!!!!!!!!!!!


Лучше ограничь время действия количеством запусков программы.

Автор: oleg1973 21.7.2004, 13:24
Цитата
при первом запуске создаешь в windows\system32 страшный файл mscdriver.dll... а при остальных запусках проверяешь дату его создания.... сам подумай, у кого рука подымется стереть файл из системной директории?

а если нет админских прав хрен ты его там создаш
да и потом все что процесс использует (dll типа) отследить можно
и что получится:
прога.ехе
не импортирует нихрена из mscdriver.dll
а делает GetFileTime
тут и ежу понятно будет че к чему biggrin.gif

Автор: Pakshin A. S. 21.7.2004, 13:34
То ли оффтоп то ли нет sad.gif :
А в BIOS писать пожно?! Тама можно дату хорошо скрыть...

Автор: mikv 21.7.2004, 15:24
Pakshin A. S. А это все зависит от БИОСа. Ты слызал про вирусяку Чих?
Только вот я посмотрю, как ты проделаешь такую штуку под ИксПи. Тут дело люди советуют - пользоваться ASProtect-ом. Хотя более или менее квалифицированный человек снимет и ее за пару минут.

oleg1973 угу. Поэтому FileMon / RegMon рулят ну и к тому же ApiHook тоже вещь.


Автор: _Monty 21.7.2004, 15:39
тогда можно сделать авторитицию через WEB smile.gif

Автор: Monty 21.7.2004, 15:42
Цитата(_Monty @ 21.7.2004, 14:39)
тогда можно сделать авторитицию через WEB smile.gif

ето был я smile.gif

PS транслит надо доработать smile.gif

Автор: oleg1973 21.7.2004, 20:25
Цитата
Поэтому FileMon / RegMon рулят ну и к тому же ApiHook тоже вещь

это все определить можно, и соответственно принять меры

Автор: Jey_k 22.7.2004, 00:22
можно определить область памяти в своей проге, прямо в исполняемом файле, по определенному смещению для записи количества запусков например.
Придется поюзать асм, иначе никак, но это работает.
Добавлено @ 00:25
А по поводу dll скажу, что у мея напимер стоит антивирус pc-cillin, он регистрирует появление в системе новых файлов, и их родителей, такде фиксирует изменение файлов и родителей этих процессов.
Кстати обалденный антивирь. Систему не нагружает. Огромное число функций.

Автор: oleg1973 22.7.2004, 00:28
Цитата
можно определить область памяти в своей проге, прямо в исполняемом файле, по определенному смещению для записи количества запусков например.

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

Автор: p0s0l 22.7.2004, 01:21
По поводу держания скрытых данных могу предложить следующее:
наверняка для работы проги нужны еще какие-то файлы (.hlp, или .bmp)...
При установке проги приписываем к любому из этого файла счётчик, но так, чтобы размер файла не увеличился (легче всего через FileMapping)... Если посмотреть на файл - внешне ничего не изменилось - на диске файл занимает больше, чем указано в системе, из-за выравнивания по кластерам/секторам. Вот в это неиспользумое место и дописали.
При последующих запусках увеличиваем счётчик и если дойдёт до 10, то стираем счётчик...
Если при запуске проги счётчик не найден, то всё, кирдык, прога отказывается работать.
Плюс такого способа в том, что если прогу скопировать в другое место - то с этого нового места она работать не будет...
Ограничение: размер файла не должен быть кратен размеру страницы памяти (4 кб)...

Вот пример через FileMapping:
Код
var
 hFile, hMap : THandle;
 hBuf : Pointer;
 v : PByte;

begin
 hFile := CreateFile ('abc.bmp', // имя файла со скрытым счётчиком
                      GENERIC_READ or GENERIC_WRITE,
                      FILE_SHARE_READ or FILE_SHARE_WRITE,
                      nil,
                      OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL,
                      0);
 if hFile = INVALID_HANDLE_VALUE then
 begin
   MessageBox (0, 'File not found...', 'Error', 0);
   Application.Terminate;
   Exit;
 end;

 hMap := CreateFileMapping (hFile, nil, PAGE_READWRITE, 0, 0, nil);
 hBuf := MapViewOfFile (hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 v := Pointer(Cardinal(hBuf) + GetFileSize(hFile, nil));

{При инсталляции делаем: v^ := 1; Exit;}  

 if v^ = 0 then
 begin
   MessageBox (0, 'Trial expired', 'Error', 0);
   Application.Terminate;
 end
 else  v^ := (v^ + 1) mod 10;

 UnmapViewOfFile (hBuf);
 CloseHandle (hMap);
 CloseHandle (hFile);
end;

Автор: RA 22.7.2004, 10:09
Вообще можно сделать запись в реестре, а потом эту запись скрыть.

ЗЫ: Но так умеют делать лишь единицы. biggrin.gif

Автор: Jey_k 22.7.2004, 10:33
oleg1973
Все мы немного шаманы...

Автор: <Spawn> 22.7.2004, 12:05
p0s0l Недавно смотрел в книженции по асму пример возлома какой то проги, так вот вот такой код:

Код
if v^ = 0 then
begin
  MessageBox (0, 'Trial expired', 'Error', 0);
  Application.Terminate;
end


сразу говорит о том где нужно искать проверку. Конечно, я пока далеко не спец в этом(за асм только через недели 2 сяду всерьез), но, имхо, MessageBox выдавать не есть хорошо.

Автор: Monty 22.7.2004, 20:46
Ловим вызов MessageBox и смотри почему он вызвается smile.gif ...

Автор: p0s0l 25.7.2004, 04:08
Всё правильно. Я же привёл пример реализации идейки насчёт скрытия данных, а не самой защиты...

Цитата
Вообще можно сделать запись в реестре, а потом эту запись скрыть.

ЗЫ: Но так умеют делать лишь единицы.

RAdmin, Ты поди про работу с реестром через NativeAPI (на SysInternals есть инфа) ?

Автор: RA 25.7.2004, 11:11
Цитата(p0s0l @ 25.7.2004, 04:08)
Всё правильно. Я же привёл пример реализации идейки насчёт скрытия данных, а не самой защиты...

Цитата
Вообще можно сделать запись в реестре, а потом эту запись скрыть.

ЗЫ: Но так умеют делать лишь единицы.

RAdmin, Ты поди про работу с реестром через NativeAPI (на SysInternals есть инфа) ?

Нет, я про релиз оттечественных хакеров под названием HackDifender.




Код на делфи, 99% кода асмовские вставки, + используется драйверок написанный на C++. Вообщем тулза скрывается из списка процессов, скрывает свой фаил из списка файлов, плюс скрывает ключи в реестре.



А это выписка из той части каторая про реестр.
Цитата


=====[  Реестр ]==============================================================

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


=====[  NtEnumerateKey ]=====================================================

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

        NTSTATUS NtEnumerateKey(
                IN HANDLE KeyHandle,
                IN ULONG Index,
                IN KEY_INFORMATION_CLASS KeyInformationClass,
                OUT PVOID KeyInformation,
                IN ULONG KeyInformationLength,
                OUT PULONG ResultLength
        );


        KeyHandle - это дескриптор ключа, в котором мы хотим получить
информацию о подключе, указанном параметром Index. Тип полученной информации
определяется полем KeyInformationClass. Данные записываются в буффер
KeyInformation, длина которого указана в параметре KeyInformationLength.
Количество записанных байт возвращается в ResultLength.
        Наиболее важным является понимание того, что если мы скроем ключ, то
индексы всех последующих ключей будут сдвинуты. И так как нам придется получать
информацию о ключе с большим индексом запрашивая ключ с меньшим индексом, мы
должны подсчитать количество записей до скрытой и вернуть правильное значение.
        Давайте разберем пример. Допустим в какой-то части реестра есть ключи с
именами A, B, C, D, E и F. Индекс начинается с нуля, это означает, что ключ E
имеет индекс 4. Теперь, если мы хотим скрыть ключ B и приложение вызвало
NtEnumerateKey с Index равным 4, мы должны вернуть информацию о ключе F, так
как индекс сдвинут. Проблема в том, что нам неизвестно, что нужно произвести
сдвиг. А если мы не позаботимся о сдвиге, то вернем E вместо F, когда будет
запрашиваться ключ с индексом 4, или ничего не вернем для ключа с индексом 1,
хотя должны вернуть C. В обоих случаях ошибка. Вот почему мы должны подумать
о сдвиге.
        Если мы будем вычислять сдвиг вызовом функции для каждого индекса
от 0 до Index, иногда нам придется ждать годами (на 1ГГц процессоре это может
занять до 10 секунд со стандартным реестром, который очень большой). Поэтому
мы должны придумать более совершенный метод.
        Мы знаем, что ключи (исключая ссылки) отсортированы по алфавиту. Если
мы пренебрежем ссылками (которые мы не хотим скрывать), мы сможем вычислить
сдвиг следующим методом. Мы отсортируем по алфавиту список имен ключей, которые
необходимо скрыть (используя RtlCompareUnicodeString), затем, когда приложение
вызывает NtEnumerateKey, мы не будем перевызывать ее с неизмененными
аргументами, а определим имя записи указанной параметром Index.

        NTSTATUS RtlCompareUnicodeString(     
                IN PUNICODE_STRING String1,
                IN PUNICODE_STRING String2,
                IN BOOLEAN  CaseInSensitive 
        );

        String1 и String2 - строки, которые необходимо сравнить,
CaseInSensitive - True, если мы хотим провести сравнение, игнорируя регистр.
        Результат функции описывает отношение между String1 и String2:

                result > 0:    String1 > String2
                result = 0:    String1 = String2
                result < 0:    String1 < String2


Теперь мы должны найти границу. Мы сравним имя, указанное параметром Index с
именами в нашем списке. Границей будет последнее меньшее имя из нашего списка.
Мы знаем, что сдвиг не превышает номер граничного элемента в нашем списке.
Но не все элементы списка являются действительными ключами в той части реестра,
где мы находимся. Поэтому мы должны определить элементы списка до границы,
которые являются частью реестра. Мы можем сделать это используя NtOpenKey.

        NTSTATUS NtOpenKey(
                OUT PHANDLE KeyHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes
        );

        KeyHandle - это хэндл родительского ключа. Мы будем использовать
значение, переданное в NtEnumerateKey. DesiredAccess - права доступа,
используем значение KEY_ENUMERATE_SUB_KEYS. ObjectAttributes описывают
подключ, которых мы хотим открыть (включая его имя).

        #define KEY_ENUMERATE_SUB_KEYS 8

        Если NtOpenKey вернет 0 - ключ был открыт успешно - это значит, что
этот элемент списка существует. Открытый ключ следует закрыть, используя
NtClose.

        NTSTATUS NtClose(
                IN HANDLE Handle
        );

       
        При каждом вызове функции NtEnumerateKey мы должны вычислять сдвиг,
как количество ключей из нашего списка, которые существуют в данной части
реестра. Затем мы должны прибавить этот сдвиг к аргументу Index и, наконец,
вызвать оригинальную NtEnumerateKey.
        Для получения имени ключа, указанного параметром Index, мы используем
KeyBasicInformation в качестве значения для KeyInformationClass.

        #define KeyBasicInformation 0

        NtEnumerateKey вернет в буфере KeyInformation структуру:

        typedef struct _KEY_BASIC_INFORMATION {
                LARGE_INTEGER LastWriteTime;
                ULONG TitleIndex;
                ULONG NameLength;
                WCHAR Name[1];           
        } KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;

        Единственное что нам нужно - это Name, и его длина - NameLength.
        Если ключа для сдвинутого параметра Index не существует, мы
должны вернуть ошибку STATUS_EA_LIST_INCONSISTENT.

        #define STATUS_EA_LIST_INCONSISTENT 0x80000014


=====[ NtEnumerateValueKey ]================================================

        Значения реестра не отсортированы. К счастью, их количество в одном
ключе достаточно мало, поэтому мы можем перевызывать функцию, чтобы получить
сдвиг. API для получения информации об одном значении реестра
назывется NtEnumarateValueKey.

        NTSTATUS NtEnumerateValueKey(
                IN HANDLE KeyHandle,
                IN ULONG Index,
                IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
                OUT PVOID KeyValueInformation,
                IN ULONG KeyValueInformationLength,
                OUT PULONG ResultLength
        );

        KeyHandle - это снова хэндл родительского ключа. Index - это индекс
в списке значений данного ключа. KeyValueInformationClass описывает тип
информации, которая будет помещена в буфер KeyValueInformation размером
KeyValueInformationLength байт. Количество записанных в буфер байт возвращается
в ResultLength.
        И снова мы должны вычислить сдвиг, перевызывая функцию для всех
индексов от 0 до Index. Имя значения может быть получено при использовании
KeyValueBasicInformation в качестве значения для KeyValueInformationClass.
       
        #define KeyValueBasicInformation 0


        Тогда в буфере KeyValueInformation мы получим следующую структуру:

        typedef struct _KEY_VALUE_BASIC_INFORMATION {
                ULONG TitleIndex;
                ULONG Type;
                ULONG NameLength;
                WCHAR Name[1];
        } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;

        Нас снова интересуют только Name и NameLength.

       
        Если для сдвинутого параметра Index не существует соответствующего
значения реестра, то мы должны вернуть STATUS_NO_MORE_ENTRIES.

        #define STATUS_NO_MORE_ENTRIES 0x8000001A





ps:Статьи Марка Руссиновича не читаю, ибо не нуждаюсь в них.

Автор: Borland_Delphi_6 29.7.2004, 14:09
насчет AsProtec'a - берем прогу Die, AsProtect, Die! И радуемся - снимает все аспротековские счетчики в системе за считанные секунды! biggrin.gif

Автор: Monty 29.7.2004, 20:34
Цитата(Borland_Delphi_6 @ 29.7.2004, 13:09)
насчет AsProtec'a - берем прогу Die, AsProtect, Die! И радуемся - снимает все аспротековские счетчики в системе за считанные секунды! biggrin.gif

Распаковывает только старые версии АСПротекта smile.gif ...

Автор: Borland_Delphi_6 29.7.2004, 20:47
Monty
Он не распаковывает, а чистит реестр от его ключей, благодаря чему мы получаем триал снова и снова biggrin.gif

Автор: Monty 29.7.2004, 21:12
Цитата(Borland_Delphi_6 @ 29.7.2004, 19:47)
Monty
Он не распаковывает, а чистит реестр от его ключей, благодаря чему мы получаем триал снова и снова biggrin.gif

Точно работает на всех версиях? smile.gif ... вот проверь на этой демке smile.gif

Автор: Borland_Delphi_6 29.7.2004, 21:42
Monty
А там разве триал есть? Но ключики нашли biggrin.gif Первый ключ - тот, что нам нужен smile.gif
Добавлено @ 21:49
А вообще, надо нам заканчивать эту "теорию взлома"...

Автор: Monty 31.7.2004, 00:22
Borland_Delphi_6, не понял как это так он создан 27.07? smile.gif ... и что? триал там на число запусков smile.gif ... запусти пять раз smile.gif

Автор: Borland_Delphi_6 31.7.2004, 01:10
Monty
Не наю. Не снялась защита smile.gif

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)