itkvariat

    Как запрограммировать флешку - "ключ" для защиты приложения




    В своём блоге я обещал рассказать, как определиться с флешкой, служащей ключом защиты приложения. Вначале флешку-ключ надо поименовать, как "HARD_KEY". Или присвоить другое имя, которое придумаете. Делается это с помощью проводника. Вставьте флешку, найдите её проводником, нажмите "Переименовать". Переименуйте и нажмите клавишу Enter. Удивительно, но мало кто знает, как переименовать флешку.

    Фишка в том, что Windows от XP до «десятки» прописывает буквы примонтированных накопителей в системном реестре, чем и воспользуемся. Для начала приведу пару вспомогательных функций. Здесь и далее я использовал коды C++ системы разработки Embarcadero, но не беспокойтесь – ничего визуального, лишь пару классов – строки и списки строк. Можно было бы обойтись и без них, но, знаете ли, привычка.

    Вспомогательная функция. Она определяет, есть ли признак флешки в байтовом буфере:

    bool IsBufFS(char *Buf, int size)
            {
    int i,j;
    bool res;
    char* bf = new char[size/2+1];
            for(i=0; i<size/2+1; i++)
                    bf[i]=0;
            for(i=0,j=0; i<size; i++)
                    {
                    if(i%2==0)
                            bf[j++] = Buf[i];
                    }
    String S = AnsiString(bf);
            if( S.Pos("STOR")!=0 || S.Pos("USB")!=0)
                    res = true;
            else
                    res = false;
            delete[] bf;
            return res;
            }

    Ещё одна вспомогательная функция. Она читает из системного реестра смонтированные флешки (именно флешки, а не все накопители) в глобальный строковый список letters_sl букв. Если возвращает true, то информация из реестра прочитана правильно.

    bool fill_letters_sl(void)
            {
    bool res;       
    TRegIniFile *Reg = new TRegIniFile("SER_NUM");
    TStringList  *sl = new TStringList;
    TStringList  *dd_sl = new TStringList;
    TStringList  *s_sl = new TStringList;
    TStringList  *vs_sl = new TStringList;
    int i,j,siz;
    char Buf[512];
    int bytes;
    extern TStringList* letters_sl;  // список букв смонтированных флешек, глобал
            letters_sl->Clear();    
                    {
                    Reg->RootKey =  HKEY_LOCAL_MACHINE;
                    if (!Reg->OpenKey( "SYSTEM\\MountedDevices", false) )
                            res = false;
                    else
                            {
                            Reg->GetValueNames(sl);
                            for(i=0; i<sl->Count; i++)
                                    {
                                    if(sl->Strings[i].Pos("DosDevices"))
                                            dd_sl->Add(sl->Strings[i]);
                                    }
                            if(dd_sl->Count != 0)
                                    {
                                    for(i=0; i<dd_sl->Count; i++)
                                            {
                                            if( dd_sl->Strings[i].Pos("A:") )
                                                    continue;
                                            if( dd_sl->Strings[i].Pos("B:") )
                                                    continue;
                                            if( dd_sl->Strings[i].Pos("C:") )
                                                    continue;
                                            s_sl->Add(dd_sl->Strings[i]);  // подозрительные строки
                                            }
                                    }
                            if(s_sl->Count != 0)
                                    {
                                    // надо проверить: носитель -- флешка или нет?
                                    for(i=0; i<s_sl->Count; i++)
                                            {
                                            siz = Reg->GetDataSize(s_sl->Strings[i]);
                                            if(siz<32)
                                                    continue;
                                            // читаем содержимое:
                                            bytes = Reg->ReadBinaryData(s_sl->Strings[i], Buf, siz);
                                            if( IsBufFS(Buf, bytes) )
                                                    vs_sl->Add(s_sl->Strings[i]);
                                            }
                                    }
                            if(vs_sl->Count != 0)
                                    {
                                    for(i=0; i<vs_sl->Count; i++)
                                            letters_sl->Add(vs_sl->Strings[i].SubString(13,1));
                                    }
                            }
                    }
            catch(...)
                    {
                    res = false;
                    }
            delete Reg;
            delete sl;
            delete dd_sl;
            delete s_sl;
            delete vs_sl;
            if(letters_sl->Count > 0)
                    return true;
            }

    Ваша защищаемая софтина при запуске должна вызвать функцию SelectKeyLetterOnName() и запомнить в char KeyLetter[2], где находится флешка-ключ:

    bool SelectKeyLetterOnName(void)
            {
    extern TStringList* letters_sl;  // список букв смонтированных флешек
    bool res;
            if( !fill_letters_sl() )
                    return false;
            if(letters_sl->Count == 0)
                    return false;
    TStringList  *search_sl = new TStringList;
    DWORD SerialNum;
    DWORD a, b;
    char VolumeName[MAX_PATH];
    char SysNameBuffer[MAX_PATH];
    DWORD Result;
    String Letter, RealKeyName;
    char szRealKeyName[32];
            KeyLetter[0] = 0;
            KeyLetter[1] = 0;       // предв. сброс буквы флешки-ключа
            res = false;
            for(int i=0; i<letters_sl->Count; i++)
                    {
                    Result = 0;
                    Letter = letters_sl->Strings[i]+":\\";
                    if (GetVolumeInformation(Letter.c_str(), VolumeName, sizeof(VolumeName),
                            &SerialNum, &a, &b, SysNameBuffer, sizeof(SysNameBuffer) ) )
                            Result = SerialNum;
                    if(Result==0)
                            continue;
                    // номер флешки прочитан, определяем её имя:
                    strcpy(szRealKeyName, VolumeName);
                    RealKeyName = AnsiString(szRealKeyName);
                    if(RealKeyName=="HARD_KEY")
                            {
                            strcpy(KeyLetter, letters_sl->Strings[i].c_str() );
                            search_sl->Add(letters_sl->Strings[i]);
                            }
                    }
            if(search_sl->Count==1 && KeyLetter[0]!=0)
                    res = true;
            delete search_sl;
            return res;
            }

    Но, чтобы убедиться, что это ключ не фейк, по мере выполнения программы, читая стэмп, следует проверять его серийный номер. Это выполняет вот такая функция:

    bool SelectKeyLetterOnNmr(void)
            {
    extern TStringList* letters_sl;  // список букв смонтированных флешек (для поиска ключа)
    bool res;
            if( !fill_letters_sl() )
                    return false;
            if(letters_sl->Count == 0)
                    return false;
    TStringList  *search_sl = new TStringList;
    DWORD SerialNum;
    DWORD a, b;
    char VolumeName[MAX_PATH];
    char SysNameBuffer[MAX_PATH];
    DWORD Result;
    String Letter;
            KeyLetter[0] = 0;
            KeyLetter[1] = 0;       // предв. сброс буквы флешки-ключа
    TIniFile* ini;
            ini = new TIniFile(IniFileName);
    DWORD   KeyNmr = ini->ReadInteger("ApplAttr", "KeyNmr", 0);// прочитать номер ключа
            delete ini;
            res = false;
            for(int i=0; i<letters_sl->Count; i++)
                    {
                    Result = 0;
                    Letter = letters_sl->Strings[i]+":\\";
                    if (GetVolumeInformation(Letter.c_str(), VolumeName, sizeof(VolumeName),
                            &SerialNum, &a, &b, SysNameBuffer, sizeof(SysNameBuffer) ) )
                            Result = SerialNum;
                    if(Result != 0 && Result == KeyNmr)   // подставить !!!
                            {
                            strcpy(KeyLetter, letters_sl->Strings[i].c_str() );
                            search_sl->Add(letters_sl->Strings[i]);
                            }
                    }
            if(search_sl->Count==1 && KeyLetter[0]!=0)
                    res = true;
            delete search_sl;
            return res;
            }

    В данном случае для иллюстрации "серийник" флешки-ключа тупо читается из ини-файла приложения. Так вообще-то не следует делать. Лучше "серийник" держать в реестре и держать не сам "серийник", а его хэш-код. Откуда он там возьмётся? При активации приложения.

    Чтобы пользователь ничего не мог записать в флешку-ключ, забейте её случайными числами под завязку. А при активации запишите байты стэмпа железа, например, 1-ый байт – в 10-ый байт случайного содержимого, 2-ой – в 20-ый или в 21-ый, вообщем, проявите фантазию.

    Копирование флешки-ключа ничего не даст: флешка содержит стэмп железа, на котором установлена ваша софтина. Скопировать-то можно, а толку? Ключ-копия сможет работать только на той машине, из которой был извлечён ключ-оригинал. В дальнейшем я расскажу, как сделать флешку-ключ нечитаемой. Ну не вообще, а всякими проводниками, коммандерами, приложениями и проч. Нечитаемой ничем, кроме вашего приложения. Подсказка: на флешке будет чужая для Windows файловая система.


    Михаил Гурчик





    Подписывайтесь и читайте новости от ITквариат раньше остальных в нашем Telegram-канале !



    Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!  




    И еще об интересном...
  • LG G6: большой тест - обзор
  • AppleTV: консоль, медиапроигрыватель или…
  • Бюджетный и производительный. Компактный NAS-сервер Thecus N2810
  • Материнская плата ASRock Fatal1ty H170 Performance/Hyper. Skylake опять можно разгонять
  • Вольный обзор языков программирования
  • Java — великий и могучий
  • Струйное многофункциональное устройство Canon PIXMA G3400

  • А что вы об этом думаете? Напишите нам!
    1. Очень познавательно, спасибо

    2. только не флэшку а флешку
      В названии правильно написано, а в тексте везде - флЭшка.
      Просто в Сети намного чаще встречается именно написание флешка, а потому ключи-теги могут не работать эффективно.
      и здесь на сайте везде - "флеш"

    3. "в Сети намного чаще встречается именно написание флешка" - именно об этом я и писал в комментах на KV.by :), впрочем, еще не поздно свериться с wordstat.yandex.ru...

    4. Сделал снова. В первый раз, наверное, забыл сохранить изменения.


    А что вы думаете? Напишите в комментариях!
    Кликните на изображение чтобы обновить код, если он неразборчив



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

    Полная версия правил

Самое популярное
    
Проверьте скорость вашего интернета!


Что бывало...
Наши друзья
Сервисный центр Five Service

Магазин кабелей и аксессуаров UGREEN

Самоклейкин

Смарт



Как запрограммировать флешку - "ключ" для защиты приложения




В своём блоге я обещал рассказать, как определиться с флешкой, служащей ключом защиты приложения. Вначале флешку-ключ надо поименовать, как "HARD_KEY". Или присвоить другое имя, которое придумаете. Делается это с помощью проводника. Вставьте флешку, найдите её проводником, нажмите "Переименовать". Переименуйте и нажмите клавишу Enter. Удивительно, но мало кто знает, как переименовать флешку.

Фишка в том, что Windows от XP до «десятки» прописывает буквы примонтированных накопителей в системном реестре, чем и воспользуемся. Для начала приведу пару вспомогательных функций. Здесь и далее я использовал коды C++ системы разработки Embarcadero, но не беспокойтесь – ничего визуального, лишь пару классов – строки и списки строк. Можно было бы обойтись и без них, но, знаете ли, привычка.

Вспомогательная функция. Она определяет, есть ли признак флешки в байтовом буфере:

bool IsBufFS(char *Buf, int size)
        {
int i,j;
bool res;
char* bf = new char[size/2+1];
        for(i=0; i<size/2+1; i++)
                bf[i]=0;
        for(i=0,j=0; i<size; i++)
                {
                if(i%2==0)
                        bf[j++] = Buf[i];
                }
String S = AnsiString(bf);
        if( S.Pos("STOR")!=0 || S.Pos("USB")!=0)
                res = true;
        else
                res = false;
        delete[] bf;
        return res;
        }

Ещё одна вспомогательная функция. Она читает из системного реестра смонтированные флешки (именно флешки, а не все накопители) в глобальный строковый список letters_sl букв. Если возвращает true, то информация из реестра прочитана правильно.

bool fill_letters_sl(void)
        {
bool res;       
TRegIniFile *Reg = new TRegIniFile("SER_NUM");
TStringList  *sl = new TStringList;
TStringList  *dd_sl = new TStringList;
TStringList  *s_sl = new TStringList;
TStringList  *vs_sl = new TStringList;
int i,j,siz;
char Buf[512];
int bytes;
extern TStringList* letters_sl;  // список букв смонтированных флешек, глобал
        letters_sl->Clear();    
                {
                Reg->RootKey =  HKEY_LOCAL_MACHINE;
                if (!Reg->OpenKey( "SYSTEM\\MountedDevices", false) )
                        res = false;
                else
                        {
                        Reg->GetValueNames(sl);
                        for(i=0; i<sl->Count; i++)
                                {
                                if(sl->Strings[i].Pos("DosDevices"))
                                        dd_sl->Add(sl->Strings[i]);
                                }
                        if(dd_sl->Count != 0)
                                {
                                for(i=0; i<dd_sl->Count; i++)
                                        {
                                        if( dd_sl->Strings[i].Pos("A:") )
                                                continue;
                                        if( dd_sl->Strings[i].Pos("B:") )
                                                continue;
                                        if( dd_sl->Strings[i].Pos("C:") )
                                                continue;
                                        s_sl->Add(dd_sl->Strings[i]);  // подозрительные строки
                                        }
                                }
                        if(s_sl->Count != 0)
                                {
                                // надо проверить: носитель -- флешка или нет?
                                for(i=0; i<s_sl->Count; i++)
                                        {
                                        siz = Reg->GetDataSize(s_sl->Strings[i]);
                                        if(siz<32)
                                                continue;
                                        // читаем содержимое:
                                        bytes = Reg->ReadBinaryData(s_sl->Strings[i], Buf, siz);
                                        if( IsBufFS(Buf, bytes) )
                                                vs_sl->Add(s_sl->Strings[i]);
                                        }
                                }
                        if(vs_sl->Count != 0)
                                {
                                for(i=0; i<vs_sl->Count; i++)
                                        letters_sl->Add(vs_sl->Strings[i].SubString(13,1));
                                }
                        }
                }
        catch(...)
                {
                res = false;
                }
        delete Reg;
        delete sl;
        delete dd_sl;
        delete s_sl;
        delete vs_sl;
        if(letters_sl->Count > 0)
                return true;
        }

Ваша защищаемая софтина при запуске должна вызвать функцию SelectKeyLetterOnName() и запомнить в char KeyLetter[2], где находится флешка-ключ:

bool SelectKeyLetterOnName(void)
        {
extern TStringList* letters_sl;  // список букв смонтированных флешек
bool res;
        if( !fill_letters_sl() )
                return false;
        if(letters_sl->Count == 0)
                return false;
TStringList  *search_sl = new TStringList;
DWORD SerialNum;
DWORD a, b;
char VolumeName[MAX_PATH];
char SysNameBuffer[MAX_PATH];
DWORD Result;
String Letter, RealKeyName;
char szRealKeyName[32];
        KeyLetter[0] = 0;
        KeyLetter[1] = 0;       // предв. сброс буквы флешки-ключа
        res = false;
        for(int i=0; i<letters_sl->Count; i++)
                {
                Result = 0;
                Letter = letters_sl->Strings[i]+":\\";
                if (GetVolumeInformation(Letter.c_str(), VolumeName, sizeof(VolumeName),
                        &SerialNum, &a, &b, SysNameBuffer, sizeof(SysNameBuffer) ) )
                        Result = SerialNum;
                if(Result==0)
                        continue;
                // номер флешки прочитан, определяем её имя:
                strcpy(szRealKeyName, VolumeName);
                RealKeyName = AnsiString(szRealKeyName);
                if(RealKeyName=="HARD_KEY")
                        {
                        strcpy(KeyLetter, letters_sl->Strings[i].c_str() );
                        search_sl->Add(letters_sl->Strings[i]);
                        }
                }
        if(search_sl->Count==1 && KeyLetter[0]!=0)
                res = true;
        delete search_sl;
        return res;
        }

Но, чтобы убедиться, что это ключ не фейк, по мере выполнения программы, читая стэмп, следует проверять его серийный номер. Это выполняет вот такая функция:

bool SelectKeyLetterOnNmr(void)
        {
extern TStringList* letters_sl;  // список букв смонтированных флешек (для поиска ключа)
bool res;
        if( !fill_letters_sl() )
                return false;
        if(letters_sl->Count == 0)
                return false;
TStringList  *search_sl = new TStringList;
DWORD SerialNum;
DWORD a, b;
char VolumeName[MAX_PATH];
char SysNameBuffer[MAX_PATH];
DWORD Result;
String Letter;
        KeyLetter[0] = 0;
        KeyLetter[1] = 0;       // предв. сброс буквы флешки-ключа
TIniFile* ini;
        ini = new TIniFile(IniFileName);
DWORD   KeyNmr = ini->ReadInteger("ApplAttr", "KeyNmr", 0);// прочитать номер ключа
        delete ini;
        res = false;
        for(int i=0; i<letters_sl->Count; i++)
                {
                Result = 0;
                Letter = letters_sl->Strings[i]+":\\";
                if (GetVolumeInformation(Letter.c_str(), VolumeName, sizeof(VolumeName),
                        &SerialNum, &a, &b, SysNameBuffer, sizeof(SysNameBuffer) ) )
                        Result = SerialNum;
                if(Result != 0 && Result == KeyNmr)   // подставить !!!
                        {
                        strcpy(KeyLetter, letters_sl->Strings[i].c_str() );
                        search_sl->Add(letters_sl->Strings[i]);
                        }
                }
        if(search_sl->Count==1 && KeyLetter[0]!=0)
                res = true;
        delete search_sl;
        return res;
        }

В данном случае для иллюстрации "серийник" флешки-ключа тупо читается из ини-файла приложения. Так вообще-то не следует делать. Лучше "серийник" держать в реестре и держать не сам "серийник", а его хэш-код. Откуда он там возьмётся? При активации приложения.

Чтобы пользователь ничего не мог записать в флешку-ключ, забейте её случайными числами под завязку. А при активации запишите байты стэмпа железа, например, 1-ый байт – в 10-ый байт случайного содержимого, 2-ой – в 20-ый или в 21-ый, вообщем, проявите фантазию.

Копирование флешки-ключа ничего не даст: флешка содержит стэмп железа, на котором установлена ваша софтина. Скопировать-то можно, а толку? Ключ-копия сможет работать только на той машине, из которой был извлечён ключ-оригинал. В дальнейшем я расскажу, как сделать флешку-ключ нечитаемой. Ну не вообще, а всякими проводниками, коммандерами, приложениями и проч. Нечитаемой ничем, кроме вашего приложения. Подсказка: на флешке будет чужая для Windows файловая система.


Михаил Гурчик





Подписывайтесь и читайте новости от ITквариат раньше остальных в нашем Telegram-канале !



Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!  




И еще об интересном...
  • LG G6: большой тест - обзор
  • AppleTV: консоль, медиапроигрыватель или…
  • Бюджетный и производительный. Компактный NAS-сервер Thecus N2810
  • Материнская плата ASRock Fatal1ty H170 Performance/Hyper. Skylake опять можно разгонять
  • Вольный обзор языков программирования
  • Java — великий и могучий
  • Струйное многофункциональное устройство Canon PIXMA G3400

  • А что вы об этом думаете? Напишите нам!
    1. Очень познавательно, спасибо

    2. только не флэшку а флешку
      В названии правильно написано, а в тексте везде - флЭшка.
      Просто в Сети намного чаще встречается именно написание флешка, а потому ключи-теги могут не работать эффективно.
      и здесь на сайте везде - "флеш"

    3. "в Сети намного чаще встречается именно написание флешка" - именно об этом я и писал в комментах на KV.by :), впрочем, еще не поздно свериться с wordstat.yandex.ru...

    4. Сделал снова. В первый раз, наверное, забыл сохранить изменения.


    А что вы думаете? Напишите в комментариях!
    Кликните на изображение чтобы обновить код, если он неразборчив



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

    Полная версия правил
    ITквариат (АйТиквариат) Powered by © 1996-2024