Windows版
描述
Windows 密钥生成器是用于 x86 和 x64 平台的 DLL 文件、C 语言头文件和与 MSVC 兼容的 lib 文件。因此,该库既可以静态链接,也可以动态加载。
生成器的所有文件都位于 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; };
标志 字段包含来自结构之前描述的 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 – 该程序仅适用于具有在 phardwareID 变量中指定的 id 的硬件。
- HAS_USER_DATA – 将 pUserData 地址处 nUserDataLength 长度的自定义用户数据放入序列号。
第三个参数是一个指向指针的指针。生成的序列号的地址写在那里。生成序列号后,应将其复制,并且必须将地址传递给生成器的第二个 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 为您的产品导出的示例,否则该示例将不起作用:
////////////////////////////////////////////////////////////////////////// // !!! 此代码块应由 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("序列号: \n%s\n", pBuf); VMProtectFreeSerialNumberMemory(pBuf); } else { printf("错误: %d\n", res); } return 0; }
这是来自 Keygen\DLL\Example 的 Microsoft Visual Studio 示例工程。下面是代码中最有趣的部分以及我们的注释。
主函数的第一行用从 VMProtect 导出的数据填充 VMProtectProductInfo 结构。此代码是典型的,不应更改以避免错误。然后我们创建VMProtectSerialNumberInfo 结构并将用户名和电子邮件的位组合插入到标志字段中。在下一行中,我们将用户名和密码放在结构中的相应字段中。请注意,值在 UNICODE 编码中被接受。密钥生成器会将它们转换为 UTF-8。
然后,我们初始化一个指针变量,将存储生成的密钥的地址,并调用 VMProtectGenerateSerialNumber ,然后分析返回码。如果没有错误,生成的密钥将输出到控制台,并调用空闲序列号内存函数。
VMprotectSerialNumberInfo 结构的其余字段
结构的某些字段可能需要一些额外的解释。例如,dwExpDate 和 dwMaxBuildDate 字段包含特定格式的日期: 0xYYYYMMDD ,即年份存储在高位字б中,月和日分别存储在低位字的高位和低位字节中。为了产生这样的数字,使用了以下宏:MAKEDATE(y, m, d)。您可以这样称呼它:MAKEDATE(2010, 05, 12)。
phardwareID 字段应包含指向许可 SDK 中的 VMProtectGetCurrentHWID 方法返回的字符串的指针。