加密软件VMProtect教程:使用Windows、Net 、UNIX 秘钥生成器

VMProtect是新一代软件保护实用程序。VMProtect支持德尔菲、Borland C Builder、Visual C/C++、Visual Basic(本机)、Virtual Pascal和XCode编译器。

同时,VMProtect有一个内置的反汇编程序,可以与Windows和Mac OS X可执行文件一起使用,并且还可以链接编译器创建的MAP文件,以快速选择要保护的代码片段。

为了轻松实现应用程序保护任务的自动化,VMProtect实现了内置脚本语言。VMProtect完全支持Windows系列的32/64位操作系统(从Windows 2000开始)和Mac OSX(从版本10.6开始)。重要的是,无论目标平台如何,VMProtect都支持所有范围的可执行文件,即Windows版本可以处理Mac OS X版本的文件,反之亦然。

VMProtect最新版下载(qun:766135708)icon-default.png?t=N4P3https://www.evget.com/product/1859/download

VMProtect 是保护应用程序代码免遭分析和破解的可靠工具,但只有在正确构建应用程序内保护机制并且没有可能破坏整个保护的典型错误的情况下才能最有效地使用。

序列号生成器

有什么用?

除了 VMProtect,其他软件也可以生成序列号。这是自动发送序列号所必需的。客户购买产品,电子商务代理向供应商网站发送 HTTP 查询,生成器在服务器上运行并根据客户数据生成序列号。序列号被发送给客户和供应商。然后,供应商使用导入许可证对话框手动将序列号添加到 VMProtect。

怎么运行

VMProtect 的许可系统基于非对称算法,这就是为什么需要秘密产品密钥来生成序列号的原因。您可以在项目属性窗口中导出此密钥,并以任何合适的方式将其传递给生成器。

电子商务代理使用 HTTP 查询调用生成器。可以直接调用 PHP 生成器,基于 DLL 的生成器 - 间接调用,但原理是相同的:

  • 从电子商务代理接收用户数据
  • 添加供应商指定的所有必需信息
  • 生成序列号
  • 使用其中一种算法对其进行加密
  • 将结果发送给电商代理

有现成的序列号产生器么?

许可系统带有三个随时可用的序列号生成器作为 DLL,用于 .Net 平台和PHP。

是否可以自己创建?

是的你可以。序列号的格式在这里,序列号的加密算法在这里描述。

安全吗?

一般来说,可以,但是,您应循以下建议:

  • 使用 HTTPS——如果您的电子商务提供商可以发送 HTTPS 查询,并且您的网络托管提供商可以回答此类请求——您应该更喜欢这种变体而不是典型的 HTTP,因为在这种情况下,所有数据都以加密形式传输,生成的序列无法截取号码。
  • “隐藏”你的发电机——确保没有人可以偶尔打开发电机。www.site.com/keygen.php 地址是个坏主意。虽然 www.site.com/abc123.php 要好得多。确保您没有放置任何指向密钥生成器的外部链接,它没有列在网站目录中,也没有将它放入任何服务文件(如 robot.txt)中。对发电机的位置了解得越少越好。或者,您甚至可以将生成器放在另一个网站上。
  • 确保调用生成器的是电子商务代理——处理来自代理的查询的程序应该检查调用者的 IP 地址。电子商务提供商通常会发布用于查询序列号生成器的 IP 范围。在您的代理处找到该列表并在程序中添加支票。如果发送查询的 IP 地址超出指定的 IP 范围,则不要生成可理解的错误消息。要么不返回任何内容,要么生成一个简单的 404。不要提供任何有关查询失败原因的线索。
  • 检查输入参数——电子商务代理控制面板中的产品设置通常允许您指定代理为接收许可证而应进行的查询字符串。例如,您想要接收用户名、电子邮件地址、购买日期和订单 ID。因此,请确保所有这些参数都已传递并且所有参数都具有正确的格式。不要对错误的查询做出任何响应。每当对生成器进行错误查询时,向您自己的电子邮件发送消息。这应该有助于调查问题。
  • 添加“密码”指定电子商务代理发送的查询中的附加参数,即密码。它应该有一个不明显的名称和值。从接收方检查此参数。如果值错误或未指定参数 – 不生成序列号。

序号生成器

  • Windows版本
  • Net版本
  • UNIX 版本
  • 序列号格式
  • 序列号加密算法

Windows 密钥生成器

Windows 密钥生成器是用于 x86 和 x64 平台的 DLL 文件、一个 C 语言头文件和一个 MSVC 兼容的库文件。因此,库既可以静态链接也可以动态加载。

生成器的所有文件都位于Keygen\DLL文件夹中。生成序列号的测试应用程序也在那里。

生成器 API

生成器仅导出两个函数:第一个函数生成一个序列号,而第二个函数释放第一个函数分配的内存。让我们从第一个也是主要的开始:

VMProtectErrors __stdcall VMProtectGenerateSerialNumber (
VMProtectProductInfo * pProductInfo,
VMProtectSerialNumberInfo * pSerialInfo,
char ** pSerialNumber
);

第一个参数是指向VMProtectProductInfo结构的指针,其内容已上传到 VMProtect(请参阅导出产品参数)。该结构包含产品私钥、使用的算法和产品的标识符。有关填充此结构的更多详细信息如下。

第二个参数是指向VMProtectSerialNumberInfo结构的指针,其内容被移动到生成的序列号中。该结构包含序列号的所有字段和定义应将哪些字段写入序列号的位掩码。

struct VMProtectSerialNumberInfo
{
        INT              flags;
        wchar_t *        pUserName;
        wchar_t *        pEMail;
        DWORD            dwExpDate;
        DWORD            dwMaxBuildDate;
        BYTE             nRunningTimeLimit;
        char *           pHardwareID;
        size_t           nUserDataLength;
        BYTE *           pUserData;
}; 

flags字段包VMProtectSerialNumberFlags中的位标志,该集合在结构之前进行了描述:

  • HAS_USER_NAME – 将pUserName变量中的用户名放入序列号中。
  • HAS_EMAIL – 将pEMail变量中的电子邮件放入序列号中。
  • HAS_EXP_DATE – 序列号将在dwExpDate变量中指定的日期之后过期。
  • HAS_MAX_BUILD_DATE – 序列号仅适用于在dwMaxBuildDate变量中指定的日期之前构建的产品版本 。
  • HAS_TIME_LIMIT – 程序在nRunningTimeLimit变量指定的时间到期后停止工作(时间以分钟为单位指定,不应超过 255)。
  • HAS_HARDWARE_ID – 该程序仅适用于具pHardwar变量中指定的 ID 的硬件。
  • HAS_USER_DATA – 将nUserDataLength长度的自定义用户数据放在pUserData的地址到序列号。

第三个参数是指向指针的指针。生成的序列号的地址写在那里。生成序列号后,应该复制它,地址必须传递给生成器的第二个 API 函数,该函数将释放序列号占用的内存。

void __stdcall VMProtectFreeSerialNumberMemory ( char * pSerialNumber);

VMProtectGenerateSerialNumber函数返回一个VMProtectErrors值,如果成功生成序列号,则该值包含 0,或者包含一个错误代码可能的错误代码是:

  • ALL_RIGHT – 没有错误,序列号已生成。
  • UNSUPPORTED_ALGORITHM – 在函数的第一个参数中传递了不正确的密钥加密算法。
  • UNSUPPORTED_NUMBER_OF_BITS – 在函数的第一个参数中传递了不正确的位数。
  • USER_NAME_IS_TOO_LONG – UTF-8 编码的用户名长度超过 255 字节。
  • EMAIL_IS_TOO_LONG – UTF-8 编码的用户电子邮件的长度超过 255 字节。
  • USER_DATA_IS_TOO_LONG – 用户数据的长度超过 255 字节。
  • HWID_HAS_BAD_SIZE – 硬件标识符的大小不正确。
  • PRODUCT_CODE_HAS_BAD_SIZE – 在函数的第一个参数中传递的产品标识符大小不正确。
  • SERIAL_NUMBER_TOO_LONG – 序列号太长,无法满足算法中指定的位数。
  • BAD_PRODUCT_INFO – 函数的第一个参数不正确或为 NULL。
  • BAD_SERIAL_NUMBER_INFO – 函数的第二个参数不正确或为 NULL。
  • BAD_SERIAL_NUMBER_CONTAINER – 该函数的第三个参数未指向要写入序列号地址的内存。
  • NOT_EMPTY_SERIAL_NUMBER_CONTAINER – 函数的第三个参数不指向空内存单元,该单元必须为 NULL。
  • BAD_PRIVATE_EXPONENT – 函数的第一个参数包含不正确的私有指数值。
  • BAD_MODULUS – 函数的第一个参数包含不正确的模数值。

错误可以分为两类:由不正确的参数或第一个参数的不正确值引起的错误,以及其他所有错误。第一类错误很少见,它们表示结构配置不正确。您应该重新上传产品信息并检查结构是否填写正确。可以在下面找到正确填充结构的示例。

第二类错误是由于尝试向键中放入超过其大小所能容纳的更多数据而引起的。在这种情况下,我们建议向电子商务提供商发送一条消息,其中包含“密钥将在 24 小时内发送”之类的文本,而不是实际的序列号,并将所有必需的信息发送到您自己的电子邮箱。在这种情况下,密钥是在 VMProtect 中手动生成的,一些数据被截断以适应最大密钥大小的所有关键信息。

使用示例

下面是调用上述函数并生成序列号的代码示例。注意最开始的代码块。在您将其替换为从 VMProtect 为您的产品导出的示例之前,该示例将不起作用:

//
// !!! this block should be generated by VMProtect !!! ///
//
VMProtectAlgorithms g_Algorithm = ALGORITHM_RSA;
size_t g_nBits = 0;
byte g_vModulus[1];
byte g_vPrivate[1];
byte g_vProductCode[1];
//
//
int _tmain(int argc, _TCHAR* argv[])
{
VMProtectProductInfo pi;
pi.algorithm = g_Algorithm;
pi.nBits = g_nBits;
pi.nModulusSize = sizeof(g_vModulus);
pi.pModulus = g_vModulus;
pi.nPrivateSize = sizeof(g_vPrivate);
pi.pPrivate = g_vPrivate;
pi.nProductCodeSize = sizeof(g_vProductCode);
pi.pProductCode = g_vProductCode;

VMProtectSerialNumberInfo si = {0};
si.flags = HAS_USER_NAME | HAS_EMAIL;
si.pUserName = L"John Doe";
si.pEMail = L"[email protected]";
char * pBuf = NULL;
VMProtectErrors res = VMProtectGenerateSerialNumber(&pi, &si, &pBuf);
if (res == ALL_RIGHT)
{
printf("Serial number:\n%s\n", pBuf);
VMProtectFreeSerialNumberMemory(pBuf);
}
else
{
printf("Error: %d\n", res);
}
return 0;

这是来自Keygen\DLL\Example的 Microsoft Visual Studio 示例项目。下面是代码中最有趣的部分以及我们的评论。

main函数的第一行使用从 VMProtect 导出的数据填充VMProtectProductInfo结构。此代码是典型的,不应更改以避免错误。然后我们创建VMProtectSerialNumberInfo结构并将用户名和电子邮件的位组合插入标志字段。在下一行中,我们将用户名和密码放入结构中的相应字段。请注意,值在 UNICODE 编码中被接受。密钥生成器会将它们转换为 UTF-8。

然后,我们初始化一个指针变量,用于存储生成的密钥的地址,并调用VMProtectGenerateSerialNumber,然后分析返回码。如果没有错误,生成的密钥将输出到控制台,并调用免费序列号记忆功能。

VMprotectSerialNumberInfo 结构的其余字段

结构的某些字段可能需要一些额外的解释。例如,dwExpDate和dwMaxBuildDate字段包含特定格式的日期:0xYYYYMMDD,即年存储在高位字中,月和日分别存储在低位字的高低字节中。为了产生这样的数字,使用了以下宏:MAKEDATE(y, m, d)。您可以这样称呼它:MAKEDATE(2010, 05, 12)。

pHardwareID字段应包含指向许可 SDK的VMProtectGetCurrentHWID方法返回的字符串的指针。

.Net 秘钥生成器

.Net密钥生成器 是包含生成序列号所需的所有内容的构建。源代码在Keygen\Net中作为两个项目:KeyGen(密钥生成器本身)和 Usage(密钥生成器的使用示例)。

密钥生成器在源代码中提供,以便在给定版本的 .Net Framework 下快速构建,但是我们强烈建议不要对代码应用任何更改。在 VMProtect 的未来版本中,可能会向生成器添加一些新的可能性,这可能会导致重复修改代码。此外,这可能会导致非常难以定位的错误。如果您在生成器的原始代码中发现错误或想提出改进建议,请联系支持团队。

使用生成器
以Usage项目中的代码为基础,然后将指向 VMProtect.KeyGen.dll 构建的链接添加到您的项目中。之后,您将能够在您的应用程序中生成序列号。为了正常运行,生成器必须“知道”您为哪个产品生成序列号。为此,在 VMProtect 中打开“Project | 导出密钥对”对话框并选择“KeyGen.Net 的参数”选项。下面的文本区域将包含文本信息,您应该将其作为字符串常量复制并粘贴到您的应用程序中。

下面是调用生成器的示例代码:

try
{
string data = @""; // put the exported data here
Generator g = new Generator(data);
g.UserName = "John Doe";
g.EMail = "[email protected]";
g.ExpirationDate = DateTime.Now.AddMonths(1);
g.MaxBuildDate = DateTime.Now.AddYears(1);
g.RunningTimeLimit = 15;
g.HardwareID = "AQIDBAgHBgU=";
g.UserData = new byte[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
string serial = g.Generate();
Console.WriteLine("Serial number:\n{0}\n", serial);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex);
}

您从 VMProtect 复制的字符串应该放在作为参数传递给序列号类构造函数的数据变量中。如果在解析产品数据时出现任何问题,构造函数将抛出包含问题描述的异常。如果构造函数成功完成其工作,则生成器已准备好生成序列号。

序列号可以包含使用生成器属性指定的各种信息。上面的示例显示了如何填写序列号的所有字段。某些领域有限制。例如,用户名和电子邮件不能接受超过 255 个字符的 UTF-8 编码字符串。如果提供的数据不正确,属性会抛出包含问题描述的异常。

生成器设置完成后,将调用Generate()方法。此方法生成一个序列号。在此步骤中,将序列号的所有数据合并,计算校验和并加密数据。如果数据量超过允许的长度,该方法将抛出异常。

如果需要生成多个序列号,可以连续多次使用生成器类,而不需要从头开始创建。要清除生成器的任何给定属性,只需为其分配一个空值即可

UNIX 密钥生成器

UNIX 版本的密钥生成器是一个 PHP 文件,其中包含生成序列号所需的所有信息。该文件位于Keygen\PHP中。下面我们描述使用这种生成器的要点。

配置生成器

在 PHP 文件的开头,设置代码位于:

//
// The following lines should be generated by VMProtect License Manager
$exported_algorithm = "RSA";
$exported_bits = 2048;
$exported_private = "PJvj4kEpoQMIpYK+9wEt......xKeiSZgzdiln8Q==";
$exported_modulus = "rOlny/3QgZb/VmGr3CmY......I6ESAUmtQ+RBqQ==";
$exported_product_code = "oLQdGUn8kVk=";
//

此代码由 VMProtect 自动生成(请参阅导出产品参数)并且对于每个特定产品都是唯一的。准确复制它至关重要,否则生成器将无法正常工作。

密钥的内容

生成器指定一个序列号的内容。这些内容在一个数组中指定,下面列出了密钥的所有可能参数。然而,在实际应用中,其中一些可能会被省略:

$params = array(
user_name => "John Doe", // UTF-8!
email => "[email protected]",
hwid => "vHGMdMRvGCPjWcCQ", // Exactly as returned by VMProtectGetCurrentHWID
expire_date => array(year => 2009, month => 10, day => 1),
maxbuild_date => array(year => 2009, month => 10, day => 1),
time_limit => 10,
user_data => base64_decode("CGCvRvMWcPHGdMjQ"), // string of bytes
);

成功的密钥生成处理函数

您可以在下面看到成功生成序列号时调用的最简单的函数。发送给它的唯一参数是序列号字符串。该函数必须将序列号传递给调用者(电子商务代理),通常使用echo命令。为了方便起见,该字符串被初步拆分为每个 75 个符号的子字符串。此外,此功能可以通过电子邮件将生成的序列号发送给开发人员或将其添加到数据库中。

function OnSerialGenerated($serial)
{
$serial = wordwrap($serial, 75, "\n", true);
echo $serial;
}

密钥生成器错误处理函数

需要我们注意的代码的最后一部分是出现问题时调用的函数。此函数接收带有错误消息的字符串,完成后调用die()函数。处理程序函数必须做两件事:代替密钥,向电子商务代理返回一条消息,说明将手动发送密钥。并向开发人员发送有关错误的详尽信息以修复它并手动生成密钥。

function OnSerialGenerationFailed($details)
{
echo "You will receive serial number in the next 24 hours"; // message to the customer
// mail("[email protected]", "Houston, we have a problem", $details); // message to vendor
}

有几种可能的错误原因:算法参数不正确,密钥参数不正确,用户名或电子邮件太长,或者序列号太长不适合算法中指定的位数. 这就是为什么OnSerialGenerationFailed函数必须向开发人员发送有关该问题的详细信息,以便他可以生成序列号并将其发送给客户。

其他需要考虑的事情

示例包含密钥生成器的简化版本。它没有考虑开发网络生成器的建议。它不检查调用方的 IP 地址,也不分析输入参数。在开发自己的生成器时请注意这一点。

用户名和电子邮件必须作为 UTF-8 字符串传递。确保您的电子商务代理以 UTF-8 编码发送这些数据,如果不是这样,则对信息进行转码。错误的编码不会导致生成错误的序列号,但这样的序列号显示的注册名可能与真实用户名不同,所以他或她可能会在“关于”窗口中看到它时感到惊讶。应用

非对称加密是一个复杂的数学过程。如果使用纯PHP实现,没有任何第三方库,生成序列号可能需要几十秒。生成器在可用时使用gmp_powm、bi_powmod、bcpowod函数。如果在您的主机上生成序列号的时间太长,我们建议要求主机提供商启用这些功能。例如,gmp_powm函数的运行速度是bcpowmod的十倍。

以上便是关于几个秘钥生成器的分享,如果您有任何疑问欢迎私聊我~

你可能感兴趣的:(VMProtect入门教程,windows,unix,代码混淆,密钥生成器,vmprotect)