Рекомендации по защите

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

Процедура регистрации

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

function CheckRegistration(const RegNumber: String): Boolean;
begin
  if RegNumber='123' then
   Result:=True
  else
   Result:=False;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ...
  if not CheckRegistration(RegNumber) then
   exit;
  Application.CreateForm(TForm2, Form2);
  Form2.ShowModal;
  ...
end;

При подобном подходе к проверке регистрационного кода взломщику нет необходимости вникать в алгоритм проверки ключа, а будет достаточно изменить код в начале процедуры проверки таким образом, чтобы она всегда возвращала значение, соответствующее корректному регистрационному ключу:

function CheckRegistration(const RegNumber: String): Boolean;
begin
  Result:=True;
  exit;
  ...
end;

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

function CheckRegistration(const RegNumber: String): Boolean;
begin
  if RegNumber='123' then
   begin
    Application.CreateForm(TForm2, Form2);
    Result:=True
   end
  else
    Result:=False;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ...
  Form2:=nil;
  if not CheckRegistration(RegNumber) then
   exit;
  Form2.ShowModal;
  ...
end;

При подобной реализации функции CheckRegistration для "обхода" проверки регистрационного ключа взломщику будет необходимо досконально разбирать работу всей функции проверки ключа. При защите данного приложения с помощью VMProtect рекомендуется выполнить виртуализацию не только функции CheckRegistration, но и процедуры TForm1.Button1Click. Для еще большего усложнения процесса взлома приложения можно воспользоваться режимом защиты "Ультра", сочетающим мутацию кода приложения с его последующей виртуализацией.

Проверка регистрационных ключей

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

var ValidRegNumber: String;
...
function CheckRegistration(const RegNumber: String): Boolean;
begin
  if RegNumber=ValidRegNumber then
   Result:=True
  else
   Result:=False;
end;

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

var
  HashOfValidRegNumber: Longint;
...
// Пример использования обобщенного алгоритма хеширования Питера Вейнбергера (PJW)
function HashPJW(const Value: String): Longint;
var I:Integer;
    G:Longint;
begin
  Result:=0;
  for I:=1 to Length(Value) do
   begin
    Result:=(Result shl 4)+Ord(Value[I]);
    G:=Result and $F0000000;
    if G<&gt0 then
     Result:=(Result xor (G shr 24)) xor G;
   end;
end;

function CheckRegistration(const RegNumber: String): Boolean;
begin
  if HashPJW(RegNumber)=HashOfValidRegNumber then
   Result:=True
  else
   Result:=False;
end;
...
initialization
  HashOfValidRegNumber:=HashPJW(ValidRegNumber);

end.

При защите программы с помощью VMProtect целесообразно защитить функции HashPJW и CheckRegistration для усложнения работы взломщика.

Хранение результата проверки регистрации

Как правило, программисты, затратившие много времени на реализацию самой процедуры регистрации, не уделяют достаточного внимания защите самого результата регистрации программы. В приведенном ниже примере перед вызовом функции проверки корректности регистрационного номера контролируется состояние глобальной переменной, хранящей результат проверки регистрации. Для взломщика поиск глобальной переменной не представляет трудностей - достаточно будет сравнить сегменты данных ДО и ПОСЛЕ регистрации. Кстати, аналогичный принцип лежит в основе работы известной программы ArtMoney.

var IsRegistered: Boolean;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  ...
  if not IsRegistered then
   IsRegistered:=CheckRegistration(RegNumber);
  if  not IsRegistered then
   exit;
  ...
end;

Для исключения подобной ситуации рекомендуется результаты всех проверок, отвечающих за регистрацию программы, хранить в динамической памяти, так как в этом случае сканирование секций данных на предмет изменения ячеек памяти ДО и ПОСЛЕ регистрации окажется бесполезным. Простейший пример, демонстрирующий хранение результата в динамически выделяемой памяти, приведен ниже.

type PBoolean = ^Boolean;

var IsRegistered: PBoolean;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  ...
  if not IsRegistered^ then
   IsRegistered^:=CheckRegistration(RegNumber);
  if  not IsRegistered^ then
   exit;
  ...
end;
...
initialization
  New(IsRegistered);

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







© 2006-2015 Copyright VMProtect Software