Serial Number Format
Layout of serial number
Serial number is a set of chunks. Each chunk starts from identifier byte that defines contents of the chunk. The last chunk always has id=255 and holds checksum of all chunks listed before.
Chunks may have fixed or variable length, depending of its type. For chunks of variable length the byte after identifier usually contains length of chunk. Detailed description of every chunk is below:
Format of chunks
| ID | Chunk | Length (bytes) | Description | Example |
|---|---|---|---|---|
| 0×01 | Version | 1 | Chunk holds version of serial number. Version has to be 1. | 01 01 |
| 0×02 | User Name | 1 + N | Chunk holds user name in UTF-8 encoding. The first byte after ID byte contains length of user name. Terminating ‘\0′ is not required. Maximal length of user name is 255 bytes. | 02 04 4A 5F 48 4E |
| 0×03 | 1 + N | Chunk holds e-mail in UTF-8 encoding. The first byte after ID byte contains length of e-mail. Terminating ‘\0′ is not required. Maximal length of e-mail is 255 bytes. | 03 07 61 40 62 2E 63 6F 6D | |
| 0×04 | Hardware Identifier | 1 + N | Chunk holds hardware identifier returned by VMProtectGetCurrentHWID(). The function returns base-64 encoded string, chunk holds decoded, binary representation of hardware identifier. Length of identifier should be a multiple of 4. Next byte after ID byte contains length of hardware identifier. Maximal length is 32 bytes. | 04 08 E1 E2 E3 E4 A1 A2 A3 A4 |
| 0×05 | Expiration Date | 4 | Chunk holds date of expiration for the serial number. Format of date is described below. | 05 01 0A 07 DA |
| 0×06 | Running Time Limit | 1 | Chunk holds 1 byte with number of minutes that application is allowed to run. Maximal allowed time is 255 minutes. | 06 05 |
| 0×07 | Product Code | 8 | Chunk holds 8 bytes of product code that is generated by VMProtect. Serial number holds this data in binary format, so they have to be converted from base-64 encoding. Please make sure that length of binary data is exactly 8 bytes. This chunk is required. Apllication will not work without it! | 07 01 02 03 04 05 06 07 08 |
| 0×08 | User Data | 1 + N | Chunk holds up to 255 bytes of user data. The next byte after ID byte contains length of the following data. Application can read this data by calling VMProtectGetSerialNumberData() function. | 08 05 01 02 03 04 05 |
| 0×09 | Maximal Build Date | 4 | Chunks holds maximal date of application build that will support this serial number. Date format is described below. | 09 01 0A 07 DA |
| 0xFF | Checksum | 4 | Chunk holds 4 bytes of checksum for all chunks listed before it. Details about calculating checksum are below. | FF 01 02 03 04 |
Date storage format
Serial number keeps date in 4 byte DWORD – 0xYYYYMMDD. Higher word contains year, lower word contains month and day. Bytes are ordered in little endian order – from lower to higher. If you have a pointer to the first byte of data, you may read and write it using the following code:
byte *pDate = 0xNNNNNN; // pointer to the stored date *(DWORD *)pDate = (2010 << 16) | (10 <<| 1; // October 1, 2010 DWORD dwExp = *(DWORD *)pDate;
Checksum computation
Checksum of the serial number is computed using SHA-1 algorithm. SHA-1 returns 5 32-bit numbers, the first one is used as checksum. Important: 32-bit number is stored in little endian order, not the big endian usually used to print SHA-1 hashes. So if your SHA-1 function returns string, you may need to reverse order of bytes before storing it to serial number.
Notes
Chunks with other identifiers are ignored by licensing module. New chunks may appear in the future versions. It is not recommended to create chunks using “free” identifiers! This may break serial numbers in the future when licensing system will use those chunks. And anyway protected application will not be able to read those chunks. If you need to store some information in the serial number, use User Data field.
Serial numbers don’t contain “SALT” – random data that make each number unique even for the same data. Salt will be added later while encryption of serial number. If you need to generate several different serial numbers for one customer you may append a number to the user name or use User Data field.