Windows序列号生成器
VMProtect 是新一代软件盗版保护解决方案。VMProtect 是目前强大的反盗版解决方案之一,许多领先的软件发行商都在使用它。VMProtect允许保护可执行文件(EXE,SCR),动态链接库(DLL,OCX,BPL)和驱动程序(SYS)。
加密解密技术交流群(766135708)
Windows 密钥生成器是用于 x86 和 x64 平台的 DLL 文件、一个 C 语言头文件和一个 MSVC 兼容的库文件。因此,库既可以静态链接也可以动态加载。生成器的所有文件都位于Keygen\DLL文件夹中。生成序列号的测试应用程序也在那里。
生成器 API
生成器仅导出两个函数:第一个函数生成一个序列号,而第二个函数释放第一个函数分配的内存。让我们从第一个开始:
VMProtectErrors __stdcall VMProtectGenerateSerialNumber ( VMProtectProductInfo * pProductInfo, VMProtectSerialNumberInfo * pSerialInfo, char ** pSerialNumber );第一个参数是指向VMProtect ProductInfo结构的指针,其内容已上传到 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"john@doe.com"; 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,然后分析返回码。如果没有错误,生成的密钥将输出到控制台,并调用免费序列号记忆功能。
VMprotect SerialNumberInfo 结构的其余字段
结构的某些字段可能需要一些额外的解释。例如,dwExpDate和dwMaxBuildDate字段包含特定格式的日期:0xYYYYMMDD,即年存储在高位字中,月和日分别存储在低位字的高低字节中。为了产生这样的数字,使用了以下宏:MAKEDATE(y, m, d)。您可以这样称呼它:MAKEDATE(2010, 05, 12)。pHardwareID字段应包含指向许可 SDK的VMProtectGetCurrentHWID方法返回的字符串的指针。