Home » Support » User Manual » Licensing system » Serial number generators » Windows-version



Windows key generators are DLL-files for x86 and x64 platforms, a C language header file and an MSVC-compatible lib-file. Therefore, the library can be both linked statically and loaded dynamically.

All files of the generator are located in the Keygen\DLL folder. A test application generating serial numbers is also there.

Generator API

The generator exports just two functions: the first one generates a serial number, while the second one frees up memory allocated by the first one. Let’s start with the first and the main one:

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

The first parameter is a pointer to the VMProtectProductInfo structure, which contents are uploaded to VMProtect (see Exporting product parameters). The structure contains product private key, the algorithm used and the identifier of the product. More details on filling this structure follow below.

The second parameter is a pointer to the VMProtectSerialNumberInfo structure, which contents are moved to the generated serial number. The structure holds all fields of a serial number and a bit mask that defines which fields should be written to the serial number.

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

The flags field contains bit flags from the VMProtectSerialNumberFlags set described before the structure:

  • HAS_USER_NAME – put the user name from the pUserName variable into the serial number.
  • HAS_EMAIL – put the e-mail from the pEMail variable into the serial number.
  • HAS_EXP_DATE – the serial number will expire after the date specified in the dwExpDate variable.
  • HAS_MAX_BUILD_DATE – the serial number will only work with version of the product built up to the date specified in the dwMaxBuildDate variable.
  • HAS_TIME_LIMIT – the program stops working after the time specified in the nRunningTimeLimit variable expires (the time is specified in minutes and shouldn’t exceed 255).
  • HAS_HARDWARE_ID – the program works only on hardware with the id specified in the pHardwareID variable.
  • HAS_USER_DATA – put custom user data of nUserDataLength length at the address of pUserData to the serial number.

The third parameter is a pointer to a pointer. The address of the generated serial number is written there. After generating the serial number, it should be copied, and the address must be passed to the second API function of the generator that will free memory taken by the serial number.

void __stdcall VMProtectFreeSerialNumberMemory(char * pSerialNumber);

The VMProtectGenerateSerialNumber function returns a VMProtectErrors value that either contains 0 if the serial number is successfully generated, or an error code. Possible error codes are:

  • ALL_RIGHT – no errors, the serial number is generated.
  • UNSUPPORTED_ALGORITHM – an incorrect key encryption algorithm is passed in the first parameter of the function.
  • UNSUPPORTED_NUMBER_OF_BITS – an incorrect number of bits is passed in the first parameter of the function.
  • USER_NAME_IS_TOO_LONG – the length of the UTF-8 encoded user name exceeded 255 byte.
  • EMAIL_IS_TOO_LONG – the length of the UTF-8 encoded user e-mail exceeded 255 byte.
  • USER_DATA_IS_TOO_LONG – the length of the user data exceeded 255 byte.
  • HWID_HAS_BAD_SIZE – the hardware identifier has incorrect size.
  • PRODUCT_CODE_HAS_BAD_SIZE – the identifier of the product passed in the first parameter of the function has incorrect size.
  • SERIAL_NUMBER_TOO_LONG – the serial number is too long and can’t fit the number of bits specified in the algorithm.
  • BAD_PRODUCT_INFO – the first parameter of the function is incorrect or NULL.
  • BAD_SERIAL_NUMBER_INFO – the second parameter of the function is incorrect or NULL.
  • BAD_SERIAL_NUMBER_CONTAINER – the third parameter of the function doesn’t point to memory to write the serial number address to.
  • NOT_EMPTY_SERIAL_NUMBER_CONTAINER – the third parameter of the function doesn’t point to an empty memory cell, the cell must be NULL.
  • BAD_PRIVATE_EXPONENT – the first parameter of the function contains an incorrect value of the private exponent.
  • BAD_MODULUS – the first parameter of the function contains an incorrect value of modulus.

Errors can be of two categories: those caused by incorrect parameters or incorrect value of the first parameter, and all the rest. First category errors are rare and they indicate incorrect configuration of the structure. You should upload the product information again and check if the structure is filled correctly. An example of a proper filling of the structure can be found below.

Second category errors are caused by an attempt to put more data to the key than it can hold with its size. In this case we recommend to send a message to the e-commerce provider containing a text like “The key will be sent in 24 hours” instead of the actual serial number, and send all the required information to your own e-mail. In this case, the key is generated manually in VMProtect, some data are truncated to fit all crucial information to the maximum key size.

Example of usage

Below is a code example that calls the above functions and generates a serial number. Notice the block of code in the very beginning. The example will not work until you replace it with the one exported from VMProtect for your product:

// !!! 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);
                printf("Error: %d\n", res);

        return 0;

This is an example project for Microsoft Visual Studio from Keygen\DLL\Example. Below are the most interesting parts of the code with our comments.

First lines of the main function fill the VMProtectProductInfo structure with data, exported from VMProtect. This code is typical and it shouldn’t be changed to avoid errors. Then we create the VMProtectSerialNumberInfo structure and insert a bit combination of user name and e-mail to the flag field. In the next line, we put the user name and the password to the appropriate fields in the structure. Note, values are accepted in the UNICODE encoding. The key generator will transform them to UTF-8.

Then, we initialize a pointer variable where the address of the generated key will be stored, and call VMProtectGenerateSerialNumber, then analyze the return code. If there are no errors, the generated key goes out to console, and a call to free serial number memory function is made.

The rest fields of the VMprotectSerialNumberInfo structure

Some fields of the structure may needs some additional explanations. For example, dwExpDate and dwMaxBuildDate fields contain dates in the specific format: 0xYYYYMMDD, that is, the year is stored in the high wordб while the month and the day are in the respectively high and low bytes of the low word. To produce such a number, the following macros is used: MAKEDATE(y, m, d). You can call it like this: MAKEDATE(2010, 05, 12).

The pHardwareID field should contain a pointer to a string the VMProtectGetCurrentHWID method from the licensing SDK has returned.