In C++: Code: // Note that TCHAR map should be set to "wchar_t" or you can change all "WCHAR" instances in code to "wchar_t" typedef HRESULT (__stdcall *PidGenXFn) ( WCHAR* szProductKey, // Product Key to decode WCHAR* szPKeyConfigPath, // Path to "pkeyconfig.xrm-ms" WCHAR* szPID, // Microsoft Product ID Family (use "55041") void* pUnknown1, // Unknown (use NULL) WCHAR* szProductId, // Calculated Product ID ("55041-XXX-XXXXXXX-XXXXX") struct DigitalProductId* pDigPid, // Calculated DigitalProductId structure struct DigitalProductId4* pDigPid4 // Calculated DigitalProductId4 structure ); struct DigitalProductId { unsigned int uiSize; BYTE bUnknown1[4]; char szProductId[28]; char szEditionId[16]; BYTE bUnknown2[112]; }; struct DigitalProductId4 { unsigned int uiSize; BYTE bUnknown1[4]; WCHAR szAdvancedPid[64]; WCHAR szActivationId[72]; WCHAR szEditionType[256]; BYTE bUnknown2[96]; WCHAR szEditionId[64]; WCHAR szKeyType[64]; WCHAR szEULA[64]; }; WCHAR* g_szPKeyConfigPath; PidGenXFn g_pPidGenX; HRESULT __fastcall DecodeKey(String szKey) { Memo1->Lines->Append("Product Key: " + szKey); WCHAR *pkeyconfig; WCHAR *lib; pkeyconfig = L"pkeyconfig.xrm-ms"; lib = L"pidgenx.dll"; // start load HMODULE hPidGenX = LoadLibrary(lib); if(hPidGenX == NULL) { Memo1->Lines->Append("Error: Could not load library - file not found?"); return -1; } // assuming load succeeded, get the Memo1->Lines->Appendction pointer g_pPidGenX = (PidGenXFn)GetProcAddress(hPidGenX, "PidGenX"); if(g_pPidGenX == NULL) { Memo1->Lines->Append("Error: Could not load library - wrong file?"); return -1; } bool bLastWasComment = false; // end load WCHAR szProductId[24]; szProductId[0] = L'\0'; // not really used, as everything is in DigitalProductId4, DigitalProductId sDPid; sDPid.uiSize = sizeof(DigitalProductId); // nearly all the information (apart from Product Id) gets put in this structure DigitalProductId4 sDPid4; sDPid4.uiSize = sizeof(DigitalProductId4); // and finally... HRESULT hResult = g_pPidGenX( szKey.w_str(), // wchar_t of String with key pkeyconfig, // pkeyconfig file path L"XXXXX", // You can put anything here, but in most PID checkers it's "XXXXX" NULL, // Unknown (?) szProductId, &sDPid, &sDPid4 ); // now interpret the results... String szValid; switch(hResult) { case PGX_OK: szValid = "Valid"; break; case PGX_INVALIDKEY: szValid = "Invalid"; break; case PGX_MALFORMEDKEY: szValid = "Malformed"; break; default: szValid = "ERROR"; break; } Memo1->Lines->Append("Validity: " + szValid); // if(hResult == PGX_OK) { Memo1->Lines->Append("Product ID: " + (String)szProductId); // ^^ Memo1->Lines->Append("AdvID: " + (String)sDPid4.szAdvancedPid); Memo1->Lines->Append("Activation ID: " + (String)sDPid4.szActivationId); Memo1->Lines->Append("Edition Type: " + (String)sDPid4.szEditionType); Memo1->Lines->Append("Edition ID: " + (String)sDPid4.szEditionId); Memo1->Lines->Append("Key Type: " + (String)sDPid4.szKeyType); Memo1->Lines->Append("EULA: " + (String)sDPid4.szEULA); // Crypto ID - this is the id of the public key used WCHAR szCryptoId[4]; szCryptoId[0] = L'\0'; swscanf_s(sDPid4.szAdvancedPid, L"XXXXX-00%3s-%*3s-%*6s-%*2s-%*4s-%*9s-%*7s", szCryptoId, 4); Memo1->Lines->Append()"Crypto ID: " + (String)szCryptoId); } //unload library FreeLibrary(hPidGenX); return hResult; } Usage: Code: String key = Edit1->Text; // where "Edit1->Text" is the key in unicode DecodeKey(key); // Show the magic // End of the magic You should change "Memo1->Lines->Append" to your function which will print results on output Also, remember to change TCHAR map in compiler to wchar_t.
Sorry for the new post but I think it is major update for you. I have reflected VAMT 2.0 and updated the DigitalProductId3 and DigitalProductId4 structures as follows: Code: struct DigitalProductId { unsigned int uiSize; unsigned short MajorVersion; unsigned short MinorVersion; char szProductId[24]; unsigned int uiKeyIdx; char szEditionId[16]; BYTE bCdKey[16]; unsigned int uiCloneStatus; unsigned int uiTime; unsigned int uiRandom; unsigned int uiLt; unsigned int uiLicenseData[2]; char sOemId[8]; unsigned int uiBundleId; char sHardwareIdStatic[8]; unsigned int uiHardwareIdTypeStatic; unsigned int uiBiosChecksumStatic; unsigned int uiVolSerStatic; unsigned int uiTotalRamStatic; unsigned int uiVideoBiosChecksumStatic; char sHardwareIdDynamic[8]; unsigned int uiHardwareIdTypeDynamic; unsigned int uiBiosChecksumDynamic; unsigned int uiVolSerDynamic; unsigned int uiTotalRamDynamic; unsigned int uiVideoBiosChecksumDynamic; unsigned int uiCRC32; }; struct DigitalProductId4 { unsigned int uiSize; unsigned short MajorVersion; unsigned short MinorVersion; WCHAR szAdvancedPid[64]; WCHAR szActivationId[64]; WCHAR szOemID[8]; WCHAR szEditionType[260]; BYTE bIsUpgrade; BYTE bReserved[7]; BYTE bCDKey[16]; BYTE bCDKey256Hash[32]; BYTE b256Hash[32]; WCHAR szEditionId[64]; WCHAR szKeyType[64]; WCHAR szEULA[64]; }; Now all the bytes of these structures are known but some of them are always just NULL so they are not that important. I hope you like it What is more, PidgenX's 4th argument is known now: Code: int PidGenX(string productKey, string configFile, string mpc, string oemId, [Out] DigitalProductId2 productId2, [In, Out] DigitalProductId3 productId3, [In, Out] DigitalProductId4 productId4); where DigitalProductId2 is just a structure of one String so can be simply replaced with String.
Thanks for sharing When I originally created this thread there were key checkers, although none of them were open source and most of the code floating around was either messy or incomplete. It's been great to see others posting their version of the code and the applications that have been developed in the process.
@FreeStyler Basically you set "magicbyte" nr 42h in the buffer that return DigitalProductId, loop decode and append N char if "magicbyte" is set.
My code is way more complicated but this is the most important thing I changed after Windows 8 CP release: Code: String prefix = StringReplace(Form5->XMLDocument1->DocumentElement->ChildNodes->First()->GetNodeName(), "Configurations", "", TReplaceFlags() << rfReplaceAll << rfIgnoreCase); //where `Form5->XMLDocument1->DocumentElement->ChildNodes->First()->GetNodeName()` is "pkc:Configurations" or "Configurations" String configurations = prefix + "Configurations"; String actconfigid = prefix + "ActConfigId"; String editionid = prefix + "EditionId"; String productdescription = prefix + "ProductDescription"; Note that this is C++ VCL code. The idea is simple: Let's make a string named prefix. The prefix is everything that stays before "Configurations", "ActConfigId", etc. To check which prefix you should use, open the first node (named for ex. "pkc:Configurations") and assign to prefix its name with replaced "Configurations" with empty string -> prefix == "pkc:" for win7 or "" for win8. Use prefix+your_node_name to open next XML nodes. I hope you understand what I mean
Freestyler, in my pidchecker i found that when using the build 8250 xrm-ms along with pidgenx.dll from that build i get the error. if using the pidgenx.dll from build 8102 with the Win8CP xrm-ms there is no error.
I think we should create a single post with all the informations needed for coders - reading the whole topic may be a bit difficult, dont you think? @FreeStyler, yep, I have done it just after the Windows 8 CP release