控制演示版破解和软件盗版问题,为初学者 - 第 1 部分
本文是为那些在发布应用程序之前真正面临演示版破解问题的小型独立开发者而写的。
引言
在本文的早期版本中,我没有提供实现所述策略的源代码。我将更新本文,包含所需的源代码行,希望这能更清楚地解释我的概念。已经阅读过本文早期版本的读者可以直接跳转到标题“为实现我们的目标,请执行以下 2 个步骤:”下的更新部分。
一家组织良好的 IT 公司有其制定软件盗版和破解问题控制策略的专家,但对于初学者和独立开发者来说,这确实是一个痛苦的问题。
应用程序演示版用于宣传目的,通常会提供一个注册选项以升级到完整版。注册是通过客户提供许可证密钥以换取自动生成的许可证代码来完成的。
这是最薄弱的环节,如果许可证密钥被破解,演示版可以轻松转换为完整版,开发者的劳动成果控制权就会落入他人手中。
控制盗版所用方法
- 将加密狗(硬件)连接到软件
- 提供许可证密钥用于注册以换取许可证代码
总的来说,许可证密钥选项用于此目的。因此,问题在于尝试在演示版级别控制盗版,而策略是完全将演示版与应用程序的完整版隔离开来。
在制作应用程序的演示版时,会考虑许多方面。让我们来看看它们。
- 演示版提供一个有限天数的到期期限。如果客户在此期限内未注册,演示版将过期。
- 应用程序的功能被部分保留,而不是整个应用程序。只有在注册后,客户才能使用应用程序的全部功能。
- 要注册,客户需要提供许可证密钥以换取自动生成的许可证代码。
因此,应用程序注册是存在最大破解风险的点。
为克服这种情况,可以采取以下策略
- 演示版就是演示版,不提供升级到完整版的功能。
- 从完整版中,剥离出演示版的独立部分,仅包含部分功能,并具有有限的到期期限。
- 需要添加一个额外的功能,即对每个系统允许的演示版重新安装次数有限,并且每次安装都有有限的到期天数。在完成有限次数的安装后,除非系统被格式化,否则不应重新安装演示版。
为实现第三点,可以使用一个单独的控制台应用程序来创建一个保存安装日期和安装计数器值的文件。
安装计数器应在每次演示版重新安装时增加 +1
,安装日期应保持固定,用于演示版到期计算。
欺骗破解者
我们应尝试使用多种策略来保护上述文件内容不被恶意者接触。以下是一些建议
- 安装日期和安装计数器可以保存在单独的文件中。
- 可以使用多个特殊文件夹,如 *SystemRoot* 和 *Registry* 来单独存储这些文件/内容。
例如,可以通过以下方式获取特殊文件夹“ApplicationData”的路径
String appDataPath = Environment.GetFolderPath ( Environment.SpecialFolder.ApplicationData)
可以通过以下方式获取 *SystemRoot* 路径
String SysRtPath = Environment.GetEnvironmentVariable("SystemRoot");
- 在将安装日期存储到文件时,始终以随机格式存储,并在我们的代码需要时将其重新编译成正确格式。还可以包含一些垃圾数据来混淆。
- 可以采用加密策略来保护数据。
为实现我们的目标,请执行以下两个步骤
步骤 1
可以使用一个控制台应用程序来创建用于保存安装日期和重新安装计数器信息的文件。该控制台应用程序应作为主要输出附加到演示版的安装程序中,并在客户端机器上安装时执行,以存储该客户端系统的信息。
例如,如果我们想在安装过程中点击“注册”按钮时执行此文件,请在安装程序的 UI 编辑器的“注册用户对话框”的可执行属性中设置 said 控制台应用程序的“主要输出”。
请注意,以下源代码使用 *SystemRoot* 文件夹和 *Registry* 来存储我们的潜在数据文件。尽管源代码附带的帮助说明是自明的,但源代码的主要功能如下:
- 在“SystemRoot”文件夹中存储有限安装次数的信息以及安装计数器,同时控制安装次数限制。
- 更新每次增量安装的安装日期。
- 将信息存储在“注册表子项”中。
- 还插入了一些垃圾信息以迷惑破解者,程序员可以根据需要进行编辑。
源代码示例
// Demdsthlp file
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.IO;
namespace Demdthlp
{
class Program
{
RegistryKey rk, rgsk;
int d, m, y;
string revdt, Dtfor_SysRt;
string syrtdtflpth;
Program()
{
syrtdtflpth = Environment.GetEnvironmentVariable("SystemRoot");
d = 0; m = 0; y = 0; revdt = "MPAD";
}
// Date formatting and making a string to store in Registry key
// and SystemRoot folder
private void md_instdt()
{
string dd_num = "0";
string mm_num = "0";
DateTime dt = DateTime.Now;
d = dt.Day;
m = dt.Month;
y = dt.Year;
if (d < 10)
dd_num += d.ToString().Trim();
else
dd_num = d.ToString().Trim();
if (m < 10)
mm_num += m.ToString().Trim();
else
mm_num = m.ToString().Trim();
string strdt = dd_num + mm_num + Convert.ToString(y).Trim();
Dtfor_SysRt = strdt;
for (int i = 0; i < 8; i++)
revdt += strdt.Substring(7 - i, 1);
revdt += "NORKREV1602"; // Garbage info as strategy required
}
// Making a Fake Registry for above said purpose
private void ed_rgy()
{
rk = Registry.CurrentUser;
rk.DeleteSubKey("Software\\abcDem", false);
rgsk = rk.OpenSubKey("Software", true);
try
{
RegistryKey newrk = rgsk.CreateSubKey("abcDem");
newrk.SetValue("adem", revdt.ToString().Trim(), RegistryValueKind.String);
}
catch (Exception s)
{
Console.WriteLine(s.Message);
}
}
// Creating file in SystemRoot Folder
private void ed_sysrt()
{
syrtdtflpth += "\\demdt.dtd";
if (File.Exists(syrtdtflpth))
{
// Check install counter in file
string insCounter = RetuInstalCounter(syrtdtflpth);
int ncount = int.Parse(insCounter);
// Counter ==5 , don't update installation date so that demo can't be renewed
if (ncount >= 5)
{
Console.WriteLine("Sorry, Your Demo Trials Limit is Over.");
Console.ReadLine();
return;
}
else
{
// otherwise increase install counter by +1
ncount++; string strcount = "";
strcount = ncount.ToString().Trim();
Dtfor_SysRt += strcount;
try { File.Delete(syrtdtflpth); } // than delete installation date file
catch { }
// and recreate new file with fresh date
StreamWriter fsInstDtFile =
new StreamWriter(new FileStream(syrtdtflpth,
FileMode.Create,
FileAccess.Write));
fsInstDtFile.Write(Dtfor_SysRt);
fsInstDtFile.Close();
}
}
else
{
// If file doesn't exist, set install counter to 1 at 9th letter position,
// and add to file
Dtfor_SysRt += "1";
// Now write to file
StreamWriter fsInstDtFile =
new StreamWriter(
new FileStream
(syrtdtflpth,
FileMode.Create,
FileAccess.Write));
fsInstDtFile.Write(Dtfor_SysRt);
fsInstDtFile.Close();
}
}
private string RetuInstalCounter(string syrtdtflpth)
{
StreamReader fsInstDtFile =
new StreamReader(new FileStream(syrtdtflpth,
FileMode.Open,
FileAccess.Read));
string instdtAndCounter = fsInstDtFile.ReadToEnd();
fsInstDtFile.Close();
// now ripoff install counter
string inscount = instdtAndCounter.Substring(8, 1);
return inscount;
}
static void Main(string[] args)
{
Program p = new Program();
p.md_instdt();
p.ed_rgy();
p.ed_sysrt();
}
}
}
第二步
一个必须首先执行的特殊验证码应附加到我们应用程序的主可执行文件中。演示版安装后,每次应用程序运行时,此代码都会验证到期日期。
下面的源代码首先读取存储在 *SystemRoot* 文件夹中的文件信息,并完成以下步骤:
- 验证系统日期并计算已过天数
- 评估到期情况
源代码示例
// MainForm.cs
// This form shall be used in Main Project’s program.cs file
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.Win32;
using System.Globalization;
namespace Terminator
{
public partial class MainForm : Form
{
string SysRtDtFilePath;
public MainForm()
{
InitializeComponent();
SysRtDtFilePath = Environment.GetEnvironmentVariable("SystemRoot");
}
private void MainForm_Load(object sender, EventArgs e)
{
SysRtDtFilePath += "\\demdt.dtd";
if (File.Exists(SysRtDtFilePath))
{
try
{
StreamReader fsInstDtFile =
new StreamReader(new FileStream(SysRtDtFilePath,
FileMode.Open,
FileAccess.Read));
string instdt = fsInstDtFile.ReadToEnd();
if (String.IsNullOrEmpty(instdt) == false)
doEvaluation(instdt);
fsInstDtFile.Close();
}
catch
{
MessageBox.Show("File Read or system date format error", "Information",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("Either evaluation period expired or file manually corrupted.",
"Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void doEvaluation(string insdt)
{
string rightdt = insdt.Trim();
string dy = rightdt.Substring(0, 2);
string mon = rightdt.Substring(2, 2);
string yr = rightdt.Substring(4, 4);
// First make installation date string:
string mdt = dy + "/" + mon + "/" + yr; // +" " + "12:00:00";
DateTime curdt = DateTime.Today;
IFormatProvider culture = new CultureInfo("fr-FR", true);
DateTime Finstdt =
DateTime.Parse(mdt, culture, DateTimeStyles.NoCurrentDateDefault);
if (curdt < Finstdt)
{
label4.Text = "Invalid System date";
MessageBox.Show("Invalid System date", "Information",
MessageBoxButtons.OK, MessageBoxIcon.Information);
Application.Exit();
}
DateTime maxdt = Finstdt.AddDays(2);
TimeSpan diffs = maxdt - curdt; // get days lapsed
int d = diffs.Days;
if (d < 0)
{
label4.Text = "nil";
MessageBox.Show("Your evaluation period has been expired
or not Activated." + "\n" +
"This trial version is only for Demo purposes.
To freely use Data Theft controller (Demo) software" + "\n" +
"created by ABC Technologies,
you need to purchase this Software from ABC Technologies.");
Application.Exit();
}
else
{
label4.Text = d.ToString().Trim() + " days left";
btnStart.Visible = true;
}
}
private void btnStart_Click(object sender, EventArgs e)
{
Form fm = new Form1(); // First page of our application
this.Hide(); // hide main form
fm.ShowDialog(this);
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
现在将以下代码行添加到我们主应用程序的 *Program.cs* 文件中
namespace Terminator
{
static class Program
{
// my global variables
public static string strPwdFilePath =
Environment.GetEnvironmentVariable("SystemRoot");
public static bool isPwdEnabled = false;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
摘要
再次重申,本文仅为初学者提供保护其应用程序的基本知识。在此级别的策略可以更加复杂和具有竞争力。