aboutsummaryrefslogtreecommitdiff
path: root/help/ru/recommendations.htm
blob: b459b3af0bc0e1c88775029e3569d4c6a95f2d5c (plain)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <link rel="Stylesheet" type="text/css" href="default.css" />
  <meta http-equiv="Content-Type" content=
  "text/html; charset=utf-8" />

  <title>Рекомендации по защите</title>
</head>

<body>
  <h1>Рекомендации по защите</h1>

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

  <h3>Процедура регистрации</h3>

  <p>Типичной ошибкой программистов, разрабатывающих собственную
  схему регистрации экземпляра приложения, является вынос процедуры
  проверки корректности введенного регистрационного ключа в
   отдельную функцию c понятным возвращаемым значением:</p>
  <pre class="indent code">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;
</pre>

  <p>При подобном подходе к проверке регистрационного кода
  взломщику нет необходимости вникать в алгоритм проверки ключа, а
  будет достаточно изменить код в начале процедуры проверки таким
  образом, чтобы она всегда возвращала значение,
  соответствующее корректному регистрационному ключу:</p>
  <pre class="indent code">function CheckRegistration(const RegNumber: String): Boolean;
begin
  Result:=True;
  exit;
  ...
end;
</pre>

  <p>Гораздо более эффективным способом является встраивание
  проверки корректности регистрационного кода в логику работы
  программы таким образом, чтобы невозможно было отделить алгоритм
  проверки регистрационного кода от алгоритма работы вызывающей эту
  проверку процедуры. Также рекомендуется "примешивать" логику
  работы программы в процедуру проверки регистрационного кода так,
  чтобы "обход" регистрационной процедуры приводил к ошибкам в
  работе приложения. Для примера, приведенного выше, это можно
  сделать следующим образом:</p>
  <pre class="indent code">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;
</pre>

  <p>При подобной реализации функции CheckRegistration для "обхода"
  проверки регистрационного ключа взломщику будет необходимо
  досконально разбирать работу всей функции проверки ключа. При
  защите данного приложения с помощью VMProtect рекомендуется
  выполнить виртуализацию не только функции CheckRegistration, но и
  процедуры TForm1.Button1Click. Для еще большего усложнения
  процесса взлома приложения можно воспользоваться <a href="project_functions.htm#CompilationTypes">режимом защиты
  "Ультра"</a>, сочетающим мутацию кода приложения с его последующей
  виртуализацией.</p>

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

  <p>Очень часто программисты допускают грубейшие ошибки при
  реализации самой проверки правильности регистрационного ключа,
  производя сравнение введенного ключа с его корректным значением.
  При подобной реализации взломщик легко сможет подобрать
  корректное значение ключа, просмотрев в процессе трассировки
  аргументы, с которыми вызывается функция сравнения строк:</p>
  <pre class="indent code">var ValidRegNumber: String;
...
function CheckRegistration(const RegNumber: String): Boolean;
begin
  if RegNumber=ValidRegNumber then
   Result:=True
  else
   Result:=False;
end;
</pre>

  <p>Для исключения подобной ситуации при сравнении введенного
  значения ключа с его допустимым значением рекомендуется
  использовать их хеши, а не реальные значения. По своей сути
  хеш-функция необратима, а значит, по результатам проверки хешей
  невозможно определить значение допустимого ключа. При взломе
  приложения будет необходимо потратить гораздо больше времени на
  изучение программы, так как придется исследовать гораздо больше
  участков кода, а не только процедуру проверки корректности
  введенного ключа:</p>
  <pre class="indent code">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&lt;&amp;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.
</pre>

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

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

  <p>Как правило, программисты, затратившие много времени на
  реализацию самой процедуры регистрации, не уделяют достаточного
  внимания защите самого результата регистрации программы. В
  приведенном ниже примере перед вызовом функции проверки
  корректности регистрационного номера контролируется состояние
  глобальной переменной, хранящей результат проверки регистрации.
  Для взломщика поиск глобальной переменной не представляет
  трудностей - достаточно будет сравнить сегменты данных ДО и ПОСЛЕ
  регистрации. Кстати, аналогичный принцип лежит в основе работы
  известной программы ArtMoney.</p>
  <pre class="indent code">var IsRegistered: Boolean;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  ...
  if not IsRegistered then
   IsRegistered:=CheckRegistration(RegNumber);
  if  not IsRegistered then
   exit;
  ...
end;
</pre>

  <p>Для исключения подобной ситуации рекомендуется результаты всех
  проверок, отвечающих за регистрацию программы, хранить в
  динамической памяти, так как в этом случае сканирование секций
  данных на предмет изменения ячеек памяти ДО и ПОСЛЕ регистрации
  окажется бесполезным. Простейший пример, демонстрирующий хранение
  результата в динамически выделяемой памяти, приведен ниже.</p>
  <pre class="indent code">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);
</pre>

  <p>Выше приведены простейшие примеры реализации встроенных в
  приложение механизмов защиты. Варианты реальной реализации
  процедуры регистрации, функции проверки регистрационного ключа
  или организации хранения результата проверки регистрационного
  ключа ограничены только фантазией разработчика. Однако в любом
  случае при разработке механизмов защиты приложения следует знать
  о возможных ошибках и не повторять их.</p><br />
  <br />
  <br />
  <br />
  <br />
  <hr noshade="noshade" size="1" />

  <div align="center">
    © 2006-2015 Copyright VMProtect Software
  </div>
</body>
</html>