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;
如果用这种方式,破解者根本不需要理解您的注册算法(无论它多么复杂),只需要修改 CheckRegistration 函数,让它永远返回 True 即可。
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;
破解者可以通过跟踪这段代码(通过查看字符串比较函数的参数值)很容易就获取正确的密钥值,因此我们推荐您使用密钥 Hash 值来比较:
var
HashOfValidRegNumber: Longint;
...
// An example of using Peter Weinberger's (PJW) generic hashing algorithm
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<>0 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);
var IsRegistered: Boolean;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
...
if not IsRegistered then
IsRegistered:=CheckRegistration(RegNumber);
if not IsRegistered then
exit;
...
end;
这样,存储验证结果的全局变量就可以被检查,这个变量可以在软件的其它部分使用。要找到这个全局变量并不困难(只需在注册前和注册后检查两个数据片段是否改变就可以了),例如,著名的 ArtMoney 软件就是这样编写的。我们推荐您在内存中动态存储注册验证结果,而不是静态存储在硬盘里。如果全局变量在动态内存中存储,破解者就没有机会扫描注册前和注册后的数据片段了。使用动态内存存储验证结果的例子如下:
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);