Привязка проги к железу

Тема в разделе "WASM.WIN32", создана пользователем SnugForce, 5 сен 2005.

  1. SnugForce

    SnugForce New Member

    Публикаций:
    0
    Регистрация:
    2 май 2005
    Сообщения:
    373
    Адрес:
    Из домУ
    Как реализовать защиту проги на такой привязке? Есно, чтоб "никто" не сломал :) Ну и плюс к этому - как узнать начинку компа не прибегая к реестру т.е. напрямую?
     
  2. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


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

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





    Пиши драйвер. Только тебе надо защитить сам драйвер от дизассемблирования/отладки и защитить его взаимодействие с железкой и приложением. Главное реши к чему будешь привязываться.
     
  3. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    Сейчас я начну расказывать о защите, очень похожей на ту, что реализованна в pinch2.5*.

    Что ее нельзя сломать, мягко говоря, не верно - сегодня мой друган "поломал" ее простым ArtMoney :)).

    Однако в целом она достаточно сложная. В добавок я укажу на ошибки автора.



    Привязка к железу осуществляется с помощью функции GetVolumeInformation. Ее параметры:

    1) Указатель на строку с именем диска. например "c:\",0

    2) Указатель на буфер, куда поместится имя диска

    3) Размер буфера

    4) Указатель на двойное слово. Сюда поместится номер этого диска. Кажется, он задается производителем железа, но в любом случае для каждого харда он индивидуален.

    5,6) Еще двойные слова. Нас не интересуют

    7) Указатель на буфер, куда поместится имя файловой системы диска

    8) Размер буфера



    Нас больше всего интересует параметр 4. Именно он (прохэшенный, на что-нибудь проксоренный и тп) является "Hardware Fingerprint".

    Теперь мы пишем прогрмму, бесплатная версия которой урезанна по функциональности. Функции, доступные в оплаченной версии зашифрованны каким-нибудь rc4( а до этого упакованны) или blowfish.

    Чтобы получить ключ дешифрования нужно сложить имя пользователя с Fingerprint, прохешировать и проксорить на серийник. Затем код расшифровывается, функции доступны.



    Прошу заметить, что функцию хеширования можно выбрать простую:

    ;eax, ebx, esi, edi - хешируемые данные

    xor ecx, ecx

    not cx

    hash_loop:

    push ecx

    xor ecx, eax

    xor ecx, ebx

    xor ecx, esi

    xor ecx, edi



    add eax, ecx

    rol eax, 1



    xchg eax, ebx

    xchg ebx, esi

    xchg esi, edi



    pop ecx

    loop hash_loop

    ;eax, ebx, esi, edi - хэш



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

    1) программа относительно дешовая

    2) ее пользователи - злые хакерюги :)



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



    Как это ломают?

    Берут регистрационные данные, вбивают их в поля ввода, а фингерпринтс меняют лоадером. вот и все.



    Я вижу 5 способов противостоять взлому:

    1) Задумываться о соотношении уровень защиты/цена

    2) Думать, кто пользуется твоей программой

    3) Хранить Fingerprint, разбросанным по всей программе (4 буффера по 1 байту каждый) - тогда их будет почти тяжело найти ))

    4) Не принебрегать навесной защитой

    5) не писать shareware :lol:
     
  4. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


    Смех просто а не защита. Такое любой новичек сломает за пару минут. Если идет расшифровка функций, то надо валидные ID апаратуры еще знать.







    А нафиг мне их искать? Я могу либо пропатчить проверку, либо если программа запускается на моем железе, то просто заменю вызываемые для идентификации железа функции своим кодом который всегда будет возвращать одно и тоже. Такой прием просто увеличит время взлома с 5 минут до 10.





    Прибавим еще от 5 минут до нескольких недель в зависимости от сложности протекта.



    Неплохая защита получиться при полной интеграции протектора в программу и проверки апаратуры на уровне портов. При этом нельзя забывать защитить КАЖДЫЙ элемент этой проверки, так как тут есть куча потенциально слабых мест. Неплохих результатов в этом направлении удалось достигнуть StarForce, но все равно ломают (хоть и очень нечасто).



    Короче, от взлома пока еще ничего не придумали.

    Как вариант - держать программу на сервере, а у клиента будет только оболочка. Но такой вариант в большинстве случаев неприемлим.
     
  5. Swing

    Swing New Member

    Публикаций:
    0
    Регистрация:
    18 май 2005
    Сообщения:
    25
    Как реализовать защиту проги на такой привязке? Есно, чтоб "никто" не сломал :) Ну и плюс к этому - как узнать начинку компа не прибегая к реестру т.е. напрямую?



    Обычная привязка к железу бессмысленна, одного единственного экземпляра приложения достаточно, чтобы навсегда "отвязать" прогу от защиты. Лучше попробуй привязываться к электронным ключам, гораздо надежнее…
     
  6. Swing

    Swing New Member

    Публикаций:
    0
    Регистрация:
    18 май 2005
    Сообщения:
    25
    И еще касательно защит. У меня появилась мысль, использовать набор символов ключа или серийника, как байт-коды для виртуального процессора, строящего граф вызова функций программы.

    Такой серийник нельзя пропатчить или отключить, т.к. он неотемлимая часть алгоритма программы.



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





    [​IMG] 1529753218__SuperClock.zip
     
  7. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"




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







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

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





    Значит надо делать какую-то проверку на валидность. Если пользователь ошибется при вводе серийника и программа от этого будет глючить, то он ее просто выбросит.
     
  8. OLS

    OLS New Member

    Публикаций:
    0
    Регистрация:
    8 янв 2005
    Сообщения:
    322
    Адрес:
    Russia
    По моему субъектиному мнению еще не придумано надежных систем защиты, кроме

    1) исполнения части кода внутри аппаратного модуля,

    2) исполнения части кода на сервере в Интернете.



    Причем эта часть кода должна нести ключевую функциональность программного продукта и быть невосстановимой конкурентами (к сожалению, она еще должна быть небольшой, чтобы не нагружать чип или сервер, и иметь небольшой объем входных и выходных параметров, чтобы не создавать huge-трафик)
     
  9. yureckor

    yureckor New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2004
    Сообщения:
    494
    Адрес:
    Russia
    Возьми готовый протектор и не парься. Большинство из новоявленных кулхацкеров об него зубы сломают, узнав разве только что название защиты.

    А абсолютной защиты нет, тебе правильно заметили. Нужно просто чтоб цена программы не превышала стоимость работы крякера, который сможет взломать протектор.
     
  10. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    Ms Rem

    ты прекрасно рассуждаешь, но

    1) Я не говорил что эта защита надежна. Если ты заметил, я сразу оговорился что она взломана обычным генератором трейнеров.

    2) Понятное дело что по одиночки такие защиты ничего не стоят.

    3) По поводу "человеческого фактора" ты почему-то ничего не сказал, посему буду считать что в этом направлении я мыслю верно.



    Исходя из пункта (3) мы предпологаем, что взломщику тяжело получить серийник, username и fingerprints. посему он не расшифрует часть кода, доступную только в платной версии.



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



    Станут ли ломать программу стоимостью 5$, если ею пользуются 10 "платежеспасобных" человек, а программа защищена морфером, виртуальной машиной и описанным мною способом?
     
  11. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    drmist

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

    А если программой пользуется весь мир, то ее обязательно сломают не зависимо от того, какая там была защита.
     
  12. riban

    riban New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2005
    Сообщения:
    51
    Адрес:
    Russia
    Контроллер на пике или атмеге, к которому время от времени обращается функция f(a), контроллер отдаёт пару байт, кот. затем исполняет прога.

    +некоторые не очень замороченные (арифметические и пр.) функции отдать самому контроллеру.

    Сломать будет оч. сложно.
     
  13. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    riban

    С этих микроконтроллеров срипают любую микропрограмму. Так что это просто перенос поля боя на слабый аппаратный уровень.
     
  14. riban

    riban New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2005
    Сообщения:
    51
    Адрес:
    Russia
    alpet

    Если будет произведён постоянный обмен данными с большим кол-вом команд - то долго слизывать будут.

    Не хватает одного контроллера - поставь два в связке.

    А если и этого мало то есть ещё ПЛИС. Аппаратный уровень слабым я бы не стал называть.
     
  15. SnugForce

    SnugForce New Member

    Публикаций:
    0
    Регистрация:
    2 май 2005
    Сообщения:
    373
    Адрес:
    Из домУ
    Я тут вот подумал, что надо можно сделать вот так, только вопрос а нужно?

    Метод (смешно конечно, но интересно мнение спецов):

    На основе железа формируем каждый раз из конкретной железки выдираем инфу о ней и формируем ключ.



    Допустим имеется n пользовательских функций.

    Получаем адреса вызовов всех функций.

    Так же необходимо определить размер кода функции.

    Это можно сделать:

    - Вставив пустые функции для определения конца предыдущей функции

    - Конец определить по следующей функции

    Рассмотрим процесс для одной функции.

    Выделяем буфер под размер функции.

    Открываем процесс.

    Читаем память с адреса начала функции в буфер до конца функции.

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

    Затем в файле .exe заменяем код функции на что угодно, хоть на нули.

    Аналогично для каждой функции.

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

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

    - Адрес вызова

    - Код функции

    Теперь необходимо произвести след. действия с файлом:

    - Шифруем код функции на ключе "адрес"

    - Заменяем адрес в таблице хэш значением адреса

    !Замечание2: Все хэши должны быть различны.

    В итоге получили файл-таблицу след. содержания:

    - Хэш адреса вызова

    - Зашифрованный код функции на ключе "адрес"



    Теперь относительно самих вызовов в программе.

    До вызова любой зашифрованной функции идет вызов функции "заполнения", которая обеспечивает расшифровку кода функции.

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



    Так же загружаем файл-таблицу "кода".



    От всяких бряков на чтение можно в паре "нужных" потоков периодически считывать его.

    А где-н в нужном месте проверять существование потока и в случае чего "ругаться".



    Допустим был вызов функции "заполнения".

    - В качестве параметров ей передается адрес необходимой функции

    - Далее получаем хэш адреса

    - Ищем в файл-таблице по хэшу необходимый код и загружаем его по переданному адресу



    Вызов функции "Очистка".

    - В качестве параметров ей передается адрес необходимой функции

    - Далее получаем хэш адреса

    - Ищем в файл-таблице по хэшу необходимый код и чистим по переданному адресу в процессе
     
  16. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"




    Значит главное найти эти функции.

    А бряки на них не обязательно ставить с помощью CC, если там крутые проверки кода имеються, то можно и bpr воспользоваться. Хотя проще будет занопить проверки в дополнительных потоках.

    Подобные ыещи давео уже применяются в протекторах и как показала практика хватает их ненадолго.



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

    Так что эффективность защиты зависит от ее самого слабого звена.
     
  17. SnugForce

    SnugForce New Member

    Публикаций:
    0
    Регистрация:
    2 май 2005
    Сообщения:
    373
    Адрес:
    Из домУ
    Короче, как я понял, я ничего не знаю :dntknw:

    Поэтому вопрос: Где можно почитать о защите, не считая статьи wasm.ru
     
  18. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"




    cracklab.ru (для начинающих)

    xtin.km.ru (есть весьма неплохие статьи)



    и зайди в раздел "ссылки" на краклабе, может еще что-нить интересное попадется.

    А после прочтения статей желательно самому что-нить покопать.

    И чем больше узнаешь про защиту, тем больше разубеждаешся в возможности создать что-то неломаемое.
     
  19. SnugForce

    SnugForce New Member

    Публикаций:
    0
    Регистрация:
    2 май 2005
    Сообщения:
    373
    Адрес:
    Из домУ
    Ms Rem

    а все-таки как защитить подобной привязкой к железу на скорую руку. (время поджимает :dntknw: ). Я уверен, что данная программа не попадет в руки суперкрякеров, максимум - это будут любители.
     
  20. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Вот код получающий серийный номер первого HDD:


    Код (Text):
    1. function GetIdeDiskSerialNumber: string;
    2. type
    3.   TSrbIoControl = packed record
    4.     HeaderLength: ULONG;
    5.     Signature: array[0..7] of Char;
    6.     Timeout: ULONG;
    7.     ControlCode: ULONG;
    8.     ReturnCode: ULONG;
    9.     Length: ULONG;
    10.   end;
    11.   SRB_IO_CONTROL = TSrbIoControl;
    12.   PSrbIoControl = ^TSrbIoControl;
    13.  
    14.   TIDERegs = packed record
    15.     bFeaturesReg: Byte;
    16.     bSectorCountReg: Byte;
    17.     bSectorNumberReg: Byte;
    18.     bCylLowReg: Byte;
    19.     bCylHighReg: Byte;
    20.     bDriveHeadReg: Byte;
    21.     bCommandReg: Byte;
    22.     bReserved: Byte;
    23.   end;
    24.   IDEREGS = TIDERegs;
    25.   PIDERegs = ^TIDERegs;
    26.  
    27.   TSendCmdInParams = packed record
    28.     cBufferSize: DWORD;
    29.     irDriveRegs: TIDERegs;
    30.     bDriveNumber: Byte;
    31.     bReserved: array[0..2] of Byte;
    32.     dwReserved: array[0..3] of DWORD;
    33.     bBuffer: array[0..0] of Byte;
    34.   end;
    35.   SENDCMDINPARAMS = TSendCmdInParams;
    36.   PSendCmdInParams = ^TSendCmdInParams;
    37.  
    38.   TIdSector = packed record
    39.     wGenConfig: Word;
    40.     wNumCyls: Word;
    41.     wReserved: Word;
    42.     wNumHeads: Word;
    43.     wBytesPerTrack: Word;
    44.     wBytesPerSector: Word;
    45.     wSectorsPerTrack: Word;
    46.     wVendorUnique: array[0..2] of Word;
    47.     sSerialNumber: array[0..19] of Char;
    48.     wBufferType: Word;
    49.     wBufferSize: Word;
    50.     wECCSize: Word;
    51.     sFirmwareRev: array[0..7] of Char;
    52.     sModelNumber: array[0..39] of Char;
    53.     wMoreVendorUnique: Word;
    54.     wDoubleWordIO: Word;
    55.     wCapabilities: Word;
    56.     wReserved1: Word;
    57.     wPIOTiming: Word;
    58.     wDMATiming: Word;
    59.     wBS: Word;
    60.     wNumCurrentCyls: Word;
    61.     wNumCurrentHeads: Word;
    62.     wNumCurrentSectorsPerTrack: Word;
    63.     ulCurrentSectorCapacity: ULONG;
    64.     wMultSectorStuff: Word;
    65.     ulTotalAddressableSectors: ULONG;
    66.     wSingleWordDMA: Word;
    67.     wMultiWordDMA: Word;
    68.     bReserved: array[0..127] of Byte;
    69.   end;
    70.   PIdSector = ^TIdSector;
    71.  
    72. const
    73.   IDE_ID_FUNCTION = $EC;
    74.   IDENTIFY_BUFFER_SIZE = 512;
    75.   DFP_RECEIVE_DRIVE_DATA = $0007C088;
    76.   IOCTL_SCSI_MINIPORT = $0004D008;
    77.   IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501;
    78.   DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE;
    79.   BufferSize = SizeOf(SRB_IO_CONTROL) + DataSize;
    80.   W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16;
    81. var
    82.   hDevice: THandle;
    83.   cbBytesReturned: DWORD;
    84.   pInData: PSendCmdInParams;
    85.   pOutData: Pointer;
    86.   Buffer: array[0..BufferSize - 1] of Byte;
    87.   srbControl: TSrbIoControl absolute Buffer;
    88.  
    89.   procedure ChangeByteOrder(var Data; Size: Integer);
    90.   var
    91.     ptr: PChar;
    92.     i: Integer;
    93.     c: Char;
    94.   begin
    95.     ptr := @Data;
    96.     for i := 0 to (Size shr 1) - 1 do
    97.     begin
    98.       c := ptr^;
    99.       ptr^ := (ptr + 1)^;
    100.       (ptr + 1)^ := c;
    101.       Inc(ptr, 2);
    102.     end;
    103.   end;
    104.  
    105. begin
    106.   Result := '';
    107.   FillChar(Buffer, BufferSize, #0);
    108.   begin
    109.     hDevice := CreateFile('\\.\Scsi0:', GENERIC_READ or GENERIC_WRITE,
    110.       FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    111.     if hDevice = INVALID_HANDLE_VALUE then
    112.       Exit;
    113.     try
    114.       srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
    115.       System.Move('SCSIDISK', srbControl.Signature, 8);
    116.       srbControl.Timeout := 2;
    117.       srbControl.Length := DataSize;
    118.       srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
    119.       pInData := PSendCmdInParams(PChar(@Buffer) + SizeOf(SRB_IO_CONTROL));
    120.       pOutData := pInData;
    121.       with pInData^ do
    122.       begin
    123.         cBufferSize := IDENTIFY_BUFFER_SIZE;
    124.         bDriveNumber := 0;
    125.         with irDriveRegs do
    126.         begin
    127.           bFeaturesReg := 0;
    128.           bSectorCountReg := 1;
    129.           bSectorNumberReg := 1;
    130.           bCylLowReg := 0;
    131.           bCylHighReg := 0;
    132.           bDriveHeadReg := $A0;
    133.           bCommandReg := IDE_ID_FUNCTION;
    134.         end;
    135.       end;
    136.       if not DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, @Buffer,
    137.         BufferSize, @Buffer, BufferSize, cbBytesReturned, nil) then
    138.         Exit;
    139.     finally
    140.       CloseHandle(hDevice);
    141.     end;
    142.      if not DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, pInData,
    143.         SizeOf(TSendCmdInParams) - 1, pOutData, W9xBufferSize,
    144.         cbBytesReturned, nil) then
    145.         Exit;
    146.   end;
    147.   with PIdSector(PChar(pOutData) + 16)^ do
    148.   begin
    149.     ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));
    150.     SetString(Result, sSerialNumber, SizeOf(sSerialNumber));
    151.   end;
    152. end;




    Но поможет это только от начинающих.

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