Форум программистов, компьютерный форум, киберфорум
Dinkin
Войти
Регистрация
Восстановить пароль
Карта форума Блоги Сообщество Поиск Заказать работу  
Рейтинг: 4.20. Голосов: 5.

Защита приложения Builder c++

Запись от Dinkin размещена 10.05.2017 в 17:09
Обновил(-а) Dinkin 06.06.2017 в 17:33

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

1 Сравнения паролей

Ни когда не хранить пароль в открытом виде в коде, а так же не сравнивать в веденое значение с тем что храним… Тут даже навыков не надо, что бы это прочитать.
Если уж логика программы такова что приходится хранить пароль в коде, то храните его уже в MD5…В случае если строку прочтут, то не смогут восстановить по ней пароль, а собственно и ввести его:

C++
1
2
3
4
5
 //Так делать нельзя
 if(Edit1->Text=="Очень сложный пароль")
   {
       //Активация прошла
   }
C++
1
2
3
4
5
 //Делать нужно так 
 if(MD5(Edit1->Text)=="BC3EFCAB952E094CB11BF964ACFDC23D") //Тут мы возводим введенный пароль в MD5 и сравниваем с уже хранимым значением в MD5
   {
       //Активация прошла
   }
А еще луче совместить данный способ с 5 пунктом

2 Прерывание процедур

Старайтесь вообще отказаться при сравнивании паролей или регистраций от ShowMessage или других модальных сообщений, которые делают прерывание процедуры, тем самым дают знать, где Вы делаете проверку.
Как вариант держать отдельную форму для таких уведомлений. Бонусом будет если до проверки и после проверки будет добавлен какой то код, что усложнит поиски.

C++
1
2
3
4
5
 //Так делать нельзя
 if(MD5(Edit1->Text)!="BC3EFCAB952E094CB11BF964ACFDC23D")
   {
       ShowMessage("Пароль введен не верно");
   }
C++
1
2
3
4
5
6
7
8
9
10
11
 //Как вариант делать так
 if(MD5(Edit1->Text)!="BC3EFCAB952E094CB11BF964ACFDC23D")
   {
       // какой то код
 
       //показываем форму с надписью о неверном пароле
       TForm * f = new TForm (Application);
       f->Show();
 
       // какой то код
   }
3 Возращения значений функции

Не делайте отдельные функции для авторизаций или хотя бы делайте их частью чего то жизни - важного для работы программы.
Для взломщика не чего не стоит подменить возвращающее значение, при этом даже ему ненужно знать пароль…тут и ломать не чего.
К примеру можно создать сам TSocket для общения с сервером при положительном вводе пароля. Это очень хороший прием, так как взломщик не сможет простыми манипуляциями этого добиться, и ему как вариант придется писать дополнительную dll.


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


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Ниже функция авторизации возвращает результат как булевое значение
 
//Так делать нельзя 
bool __fastcall TForm1::try_pass()
{
  if(MD5(Edit1->Text)=="BC3EFCAB952E094CB11BF964ACFDC23D")
    return true;
     else
     return false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if (try_pass()==true)
 {
  //Авторизация выполнена
 }
}
//---------------------------------------------------------------------------
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//как луче сделать
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   // какой то код
   if(MD5(Edit1->Text)=="BC3EFCAB952E094CB11BF964ACFDC23D")
   {
 
     // какой то код
 
     //Авторизация выполнена
 
     //создаем для примера жизненно-важную кнопку, без которой программа будет не полноценной
     TButton * b = new TButton (this);
     b->OnClick = ...
 
     // какой то код
   }
   // какой то код
}
//---------------------------------------------------------------------------
4 Статичные переменные и глобальные переменные

Глобальные переменные очень легко найти и подменить их значение. Как и другие константы переменных, они всегда находится в определённом месте приложений. Злоумышленнику стоит только раз определить местоположение и поставить на нем «Point»…и по прицепу программ как «ArtMoney» или «O`matic»…значение данных переменных будет всегда изменено.

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

Как пример, можно сделать так:
C++
1
2
3
4
5
6
 // было
 int i =10;
 
 // Стало
 int *i = new int[1];
 i[0]   = 10;
Бонусом для данного типа данных можно сделать пересоздания переменой во время работы приложения:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 //Объявляем глобально
 int *i= new int[1];
 
 //Где то присваиваем ей значение
 i[0]   = 10;
 
 /*Ниже код пересоздает перемееную*/
 //создаем перемеренную провайдера, что бы сохранить данные
 int *j = new int[1];
 
 j[0]   = i[0];
 
 //удаляем и персоздаем заново, но уже с другим адресом
 delete [] i;
 i= new int[1];
 i[0]   = j[0];
 
 delete [] j;
5 Контейнеры для хранения данных

Хорошим ходом для защиты данных и их вскрытия, может послужить создания контейнера, в котором данные хранятся в зашифрованном виде.
Принцип такой:
  1. Создается контейнер
  2. Есть функция, которая предварительно шифрует параметры и кладет их в контейнер
  3. Другая функция по ключу вынимает данные и расшифровывает.
Данный метод сводит к минимум возможность нахождения и вскрытия данных. Ниже приведен простейший пример реализации на основе TStringList.

C++
1
2
 //Глобально объявляем наш простенький контейнер
 TStringList * tajna = new TStringList;
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//---------------------------------------------------------------------------
void __fastcall TForm1::AddString(AnsiString st)
{
 //Функция предварительно шифрует и добавляет строку в контейнер
 double z;
 for (int i=1;i<=st.Length();i++)
 {
  z=i;
  char mask=sin(z)*400-sin(z)*250/20;
  st[z]=(st[z] ^ mask);
 }
 tajna->Add(st);
}
//---------------------------------------------------------------------------
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
AnsiString __fastcall TForm1::GetString(int id)
{
 //функция выбирает id строки, дешифрует и возвращает
 AnsiString st = tajna->Strings[id];
 
 double z;
 for (int i=1;i<=st.Length();i++)
 {
  z=i;
  char mask=sin(z)*400-sin(z)*250/20;
  st[z]=(st[z] ^ mask);
 }
 
 return st;
}
//---------------------------------------------------------------------------
6 Защита исполняемого файла

Для того что бы защитить свое приложение от модификаций (не путаем с запущенным приложением), мы можем в конец файла дописывать его хеш значение, а после из тела программы проверить на модификацию.
В случае если при сравнении значения будут разница, мы можем понять был ли исходный файл модифицирован и предпринять какие то меры.
Надо помнить, что при модификации самого файла, злоумышленник может и вписать новое значения хеш. Что бы этого не случилось, в получения хеш значения мы добавляем «Соль». Ниже пример кода для приложения что дописывает хеш в конец файла, а так же код для сверки непосредственно в само приложение.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  //Функия для приложения которое будет дописывать в конец строки его хеш значение
  #include <IdHashMessageDigest.hpp>
 
  if(OpenDialog1->Execute())
   {
     //выбираем файл и получем его Хеш + "СОЛЬ"
     TIdHashMessageDigest5 *MD5 = new TIdHashMessageDigest5();
     TMemoryStream * F = new TMemoryStream;
     TByteDynArray   Key;
 
     F->LoadFromFile(OpenDialog1->FileName);
     F->Position = 0;
 
     Key = MD5->HashStringAsHex(MD5->HashStreamAsHex(F)+"Соль").BytesOf();
 
     //Дописываем это значение в конец  файла (значение можно и зашифровать, тут как фантазия ляжет)
     F->WriteBuffer(&Key[0],Key.Length);
 
     //подменяем наше приложение на  с проверочной строкой
     F->SaveToFile(OpenDialog1->FileName);
 
     //Очищаем данные
     delete F,MD5;
   }
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 //Функция "самозащиты", которая проверяет запущенное приложение на модернизацию
 //#include <IdHashMessageDigest.hpp>
 
  //выбираем файл
  TIdHashMessageDigest5 *MD5 = new TIdHashMessageDigest5();
  TMemoryStream * F = new TMemoryStream;
  TMemoryStream * F1 = new TMemoryStream;
  TByteDynArray   Key;
 
  F->LoadFromFile(Application->ExeName);
  F->Position = 0;
 
  //Отделяем проверочную строкуот корня файла и получаем хеш и делаем сравнение
  F1->CopyFrom(F,F->Size-32);
  F1->Position = 0;
 
  F->Position =F1->Size;
  Key.set_length(32);
  F->ReadBuffer(&Key[0],32);
 
  if(MD5->HashStringAsHex(MD5->HashStreamAsHex(F1)+"Соль")!=TEncoding::UTF8->GetString(Key))
   {
        //Данные не сошлись, завершаем экстренно приложение
        ExitProcess(0);
   }
 
  //Очищаем данные
  delete F,F1,MD5;
  Key.set_length(0);
Добавлю что метод сверки луче помещать в тело других функций, но ни как не в событие создания формы, дабы его просто напросто не отключили.

Минусом данной реализации является дальнейшая подпись приложения электронно-цифровой подписью (если конечно Вы ей пользуетесь).



Заключение

Примеры что приведены выше являются элементарными и их модернизация ограничена только Вашей фантазий, хоть для кого то они и покажутся спорными.
Добавлю от себя, если планируете проект в массы, не поленитесь и задумайтесь об его защите.
Размещено в Без категории
Показов 5250 Комментарии 4
Всего комментариев 4
Комментарии
  1. Старый комментарий
    Аватар для Eva Rosalene
    Цитата:
    C++
    1
    2
    3
    
    //удаляем и персоздаем заново, но уже с другим адресом
    delete [] i;
    i[0]   = j[0];
    Только
    C++
    1
    2
    3
    
    delete [] i;
    i = new int[1];
    i[0] = j[0];
    Запись от Eva Rosalene размещена 11.05.2017 в 13:01 Eva Rosalene вне форума
    Обновил(-а) Eva Rosalene 11.05.2017 в 13:39
  2. Старый комментарий
    Аватар для Dinkin
    FraidZZ, спасибо за внимательность, действительно пропустил строчку создания..видимо удалил лишнее когда переносил текст.
    Запись от Dinkin размещена 11.05.2017 в 13:34 Dinkin вне форума
  3. Старый комментарий
    Аватар для Eva Rosalene
    А я вообще в исправлении мимо буквы промазал
    Странный день какой-то.
    Запись от Eva Rosalene размещена 11.05.2017 в 13:39 Eva Rosalene вне форума
  4. Старый комментарий
    Аватар для Dinkin
    ну там интуитивно понятно было =)
    Запись от Dinkin размещена 11.05.2017 в 13:40 Dinkin вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru