I'm working with the PIDGenX function from the ProductKeyUtilities.dll library, which is used to validate product keys in the context of Volume Activation Management Tool (VAMT). I am receiving the error code 80070057, which corresponds to "The parameter is incorrect". This occurs when I attempt to validate a Windows product key and configuration file.
The key and configuration file are both valid as they work within VAMT, but I am unable to successfully use them in my C++ application that interacts directly with PIDGenX. Error code: 80070057 ("The parameter is incorrect")
DLL used: ProductKeyUtilities.dll
Function: PIDGenX
Parameters:
argv[1]: Product Key (e.g., W269N-WFGWX-YVC9B-4J6C9-T83GX)
argv[2]: Path to .xrm-ms file (e.g., pkconfig\pkconfig_win10.xrm-ms)
Code:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
CHAR m_productId2[24];
} DigitalProductId2;
typedef struct {
DWORD m_length;
WORD m_versionMajor;
WORD m_versionMinor;
BYTE m_productId2[24];
DWORD m_keyIdx;
CHAR m_sku[16];
BYTE m_abCdKey[16];
DWORD m_cloneStatus;
DWORD m_time;
DWORD m_random;
DWORD m_lt;
DWORD m_licenseData[2];
CHAR m_oemId[8];
DWORD m_bundleId;
CHAR m_hardwareIdStatic[8];
DWORD m_hardwareIdTypeStatic;
DWORD m_biosChecksumStatic;
DWORD m_volSerStatic;
DWORD m_totalRamStatic;
DWORD m_videoBiosChecksumStatic;
CHAR m_hardwareIdDynamic[8];
DWORD m_hardwareIdTypeDynamic;
DWORD m_biosChecksumDynamic;
DWORD m_volSerDynamic;
DWORD m_totalRamDynamic;
DWORD m_videoBiosChecksumDynamic;
DWORD m_crc32;
} DigitalProductId3;
typedef struct {
DWORD m_length;
WORD m_versionMajor;
WORD m_versionMinor;
CHAR m_productId2Ex[64];
CHAR m_sku[64];
CHAR m_oemId[8];
CHAR m_editionId[260];
BYTE m_isUpgrade;
BYTE m_reserved[7];
BYTE m_abCdKey[16];
BYTE m_abCdKeySHA256Hash[32];
BYTE m_abSHA256Hash[32];
CHAR m_partNumber[64];
CHAR m_productKeyType[64];
CHAR m_eulaType[64];
} DigitalProductId4;
typedef DWORD (STDAPICALLTYPE *pPIDGenX)(LPWSTR pk, LPWSTR config, LPWSTR mpc, LPWSTR oemID, DigitalProductId2 *dpid2, DigitalProductId3 *dpid3, DigitalProductId4 *dpid4);
int wmain(int argc, wchar_t** argv) {
if (argc != 3) {
wprintf(L"Usage: %s [key] [file]\n", argv[0]);
exit(1);
}
// Load the DLL
HMODULE hMod = LoadLibraryA("ProductKeyUtilities.dll");
if (!hMod) {
printf("Failed to load DLL. Error code: %lu\n", GetLastError());
exit(1);
}
// Get the PIDGenX function
pPIDGenX PIDGenX = (pPIDGenX)GetProcAddress(hMod, "PidGenX");
if (!PIDGenX) {
printf("Failed to find PIDGenX function. Error code: %lu\n", GetLastError());
FreeLibrary(hMod);
exit(1);
}
// Initialize the structures
DigitalProductId2 dpid2 = {0};
DigitalProductId3 dpid3 = {0};
DigitalProductId4 dpid4 = {0};
// Set the lengths for dpid3 and dpid4
dpid3.m_length = sizeof(dpid3);
dpid4.m_length = sizeof(dpid4);
// Set the OEM ID (can be empty or some value)
WCHAR oemId[8] = L"OEMID"; // or L""
// Call the function
int res = PIDGenX(argv[1], argv[2], L"12345", oemId, &dpid2, &dpid3, &dpid4);
// Check result
if (res != 0) {
printf("PIDGenX failed with error code: %x\n", res);
} else {
printf("PIDGenX succeeded. Product ID: %s\n", dpid4.m_productId2Ex);
}
FreeLibrary(hMod);
return 0;
}
I discovered IonBazan/pidgenx when search for PidGenX
examples in GitHub, and noticed some major differences:
DigitalProductId2
isn't CHAR[24]
, but rather WCHAR[24]
.CHAR
(and not BYTE
) fields in DigitalProductId4
are WCHAR
After that, only typedef definitions are updated (basically the structures are C):
typedef struct {
WCHAR m_productId2[24];
} DigitalProductId2;
typedef struct {
DWORD m_length;
WORD m_versionMajor;
WORD m_versionMinor;
BYTE m_productId2[24];
DWORD m_keyIdx;
CHAR m_sku[16];
BYTE m_abCdKey[16];
DWORD m_cloneStatus;
DWORD m_time;
DWORD m_random;
DWORD m_lt;
DWORD m_licenseData[2];
CHAR m_oemId[8];
DWORD m_bundleId;
CHAR m_hardwareIdStatic[8];
DWORD m_hardwareIdTypeStatic;
DWORD m_biosChecksumStatic;
DWORD m_volSerStatic;
DWORD m_totalRamStatic;
DWORD m_videoBiosChecksumStatic;
CHAR m_hardwareIdDynamic[8];
DWORD m_hardwareIdTypeDynamic;
DWORD m_biosChecksumDynamic;
DWORD m_volSerDynamic;
DWORD m_totalRamDynamic;
DWORD m_videoBiosChecksumDynamic;
DWORD m_crc32;
} DigitalProductId3;
typedef struct {
DWORD m_length;
WORD m_versionMajor;
WORD m_versionMinor;
WCHAR m_productId2Ex[64];
WCHAR m_sku[64];
WCHAR m_oemId[8];
WCHAR m_editionId[260];
BYTE m_isUpgrade;
BYTE m_reserved[7];
BYTE m_abCdKey[16];
BYTE m_abCdKeySHA256Hash[32];
BYTE m_abSHA256Hash[32];
WCHAR m_partNumber[64];
WCHAR m_productKeyType[64];
WCHAR m_eulaType[64];
} DigitalProductId4;
As DigitalProductId4.m_productId2Ex
is WCHAR[24]
and printf
only prints ASCII formatted string, we need to update to wprintf
:
// Check result
if (res != 0) {
printf("PIDGenX failed with error code: %x\n", res);
} else {
wprintf(L"PIDGenX succeeded. Product ID: %s\n", dpid4.m_productId2Ex);
}
Test result:
C:\Users\winapiadmin\Downloads\pkeychecker\PKCONFIG>verify.exe W269N-WFGWX-YVC9B-4J6C9-T83GX pkconfig\pkconfig_win10.xrm-ms
PIDGenX succeeded. Product ID: 12345-03311-000-000001-03-1033-9200.0000-0782025
C:\Users\winapiadmin\Downloads\pkeychecker\PKCONFIG>verify.exe W269N-WFGWX-YVC9B-4J6C9-T83GX pkconfig\pkconfig_winNext.xrm-ms
PIDGenX succeeded. Product ID: 12345-03311-000-000001-03-1033-9200.0000-0782025
C:\Users\winapiadmin\Downloads\pkeychecker\PKCONFIG>verify.exe W269N-WFGWX-YVC9B-4J6C9-T83GX pkconfig\pkconfig_win8.1.xrm-ms
PIDGenX failed with error code: 8a010001