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. Сделал снова. В первый раз, наверное, забыл сохранить изменения.


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



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

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

Что бывало...

Проверьте скорость вашего интернета!


Самое популярное
    
Наши друзья
Магазин кабелей и аксессуаров UGREEN

Студия 3D-печати PRO3D

Майки с картинками

Самоклейкин

Смарт

Hoster


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




В своём блоге я обещал рассказать, как определиться с флешкой, служащей ключом защиты приложения. Вначале флешку-ключ надо поименовать, как "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-2019