Code: public static string PIDDecoderFromRegistry() { IList<byte> digitalProductId = null; { RegistryKey registry = null; registry = Registry.LocalMachine. OpenSubKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false); if (registry != null) { // TODO: For other products, key name maybe different. digitalProductId = registry.GetValue("DigitalProductId") as byte[]; registry.Close(); } else return null; } int keyStartIndex = 52; int keyEndIndex = keyStartIndex + 15; const int numLetters = 24; // Possible alpha-numeric characters in product key. char[] digits = new[] { 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9' }; // Check if Windows 8/Office 2013 Style Key (Can contain the letter "N") int containsN = (digitalProductId[keyStartIndex + 14] >> 3) & 1; digitalProductId[keyStartIndex + 14] = (byte)((digitalProductId[keyStartIndex + 14] & 0xF7) | ((containsN & 2) << 2)); // Length of decoded product key const int decodeLength = 29; // Length of decoded product key in byte-form. // Each byte represents 2 chars. const int decodeStringLength = 15; // Array of containing the decoded product key. char[] decodedChars = new char[decodeLength]; // Extract byte 52 to 67 inclusive. List<byte> hexPid = new List<byte>(); for (int i = keyStartIndex; i <= keyEndIndex; i++) { hexPid.Add(digitalProductId); } for (int i = decodeLength - 1; i >= 0; i--) { // Every sixth char is a separator. if ((i + 1) % 6 == 0) { decodedChars = '-'; } else { // Do the actual decoding. int digitMapIndex = 0; for (int j = decodeStringLength - 1; j >= 0; j--) { int byteValue = (digitMapIndex << 8) | hexPid[j]; hexPid[j] = (byte)(byteValue / numLetters); digitMapIndex = byteValue % numLetters; decodedChars = digits[digitMapIndex]; } } } // Remove first character and put N in the right place if (containsN != 0) { int firstLetterIndex = 0; for (int index = 0; index < numLetters; index++) { if (decodedChars[0] != digits[index]) continue; firstLetterIndex = index; break; } string keyWithN = new string(decodedChars); keyWithN = keyWithN.Replace("-", string.Empty).Remove(0, 1); keyWithN = keyWithN.Substring(0, firstLetterIndex) + "N" + keyWithN.Remove(0, firstLetterIndex); keyWithN = keyWithN.Substring(0, 5) + "-" + keyWithN.Substring(5, 5) + "-" + keyWithN.Substring(10, 5) + "-" + keyWithN.Substring(15, 5) + "-" + keyWithN.Substring(20, 5); return keyWithN; } return new string(decodedChars); } Credits to CODYQX4 and nononsense. Little mod by Josh Cell. If you needs of it for VB, here's the solution by The Dev: http://forums.mydigitallife.net/threads/35760-VB-NET-VS2010-Open-source-product-key-viewer
Code: Option Explicit Off Code: #Region "DigitalProductId Decryptor" Public KeyOutput As String Public WshShell As Object = CreateObject("WScript.Shell") Function ConvertToKey(ByVal Key) 'Offsets for Windows are 52-67 Try Const KeyOffset = 52 isWin8 = (Key(66) \ 6) And 1 Key(66) = (Key(66) And &HF7) Or ((isWin8 And 2) * 4) i = 24 'Hex Chars = "BCDFGHJKMPQRTVWXY2346789" Do Cur = 0 X = 14 Do Cur = Cur * 256 Cur = Key(X + KeyOffset) + Cur Key(X + KeyOffset) = (Cur \ 24) Cur = Cur Mod 24 X = X - 1 Loop While X >= 0 i = i - 1 KeyOutput = Mid(Chars, Cur + 1, 1) & KeyOutput Last = Cur Loop While i >= 0 If (isWin8 = 1) Then keypart1 = Mid(KeyOutput, 2, Last) insert = "N" KeyOutput = Replace(KeyOutput, keypart1, keypart1 & insert, 2, 1, 0) End If aa = Mid(KeyOutput, 1, 5) bb = Mid(KeyOutput, 6, 5) cc = Mid(KeyOutput, 11, 5) dd = Mid(KeyOutput, 16, 5) ee = Mid(KeyOutput, 21, 5) ConvertToKey = aa & "-" & bb & "-" & cc & "-" & dd & "-" & ee Catch ex As Exception MessageBox.Show("It looks like the Registry location you provided is invalid." & vbCrLf & _ "Please try again..." & vbCrLf & vbCrLf & "Error: " & _ ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Function #End Region Usage: Code: Me.Label1.Text = ConvertToKey(WshShell.RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion" & "\DigitalProductId"))
Okay. The CODYQX4 has been sent to me an working C# code that can correctly decode Windows 8 Product Keys. If he wants to post the code here are welcome to other members EDIT: Thanks The-Dev. I'll port and post here
See my above code, works straight up with VB.NET but will need porting for C#, am working on that now.
I can't post the CODY's Win 8 Decoder source without him authorization. As the lastest post, if he want will post here
Daz has reported that this still works, it is C++ but should be trivial to convert to C#. https://github.com/untermensch/ViewKey the problem with the VBS script is that string functions do not work with an index of zero this is what Daz did to fix it, its been so long since I have looked at this code I'm not sure how it even works. EDIT: I took a closer look, and this is the actual problem with the VBS script if Last is 0 then this line Code: keypart1 = Mid(KeyOutput, 2, Last) is asking for a zero length string so if the N is to be placed as the first character in the key you end up trying to replace a null string with a null string & "N" at this line Code: KeyOutput = Replace(KeyOutput, keypart1, keypart1 & insert, 2, 1, 0) I imagine this is why it fails to place the "N" in OP's example. LFMF Code: Set WshShell = CreateObject("WScript.Shell") MsgBox ConvertToKey(WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DigitalProductId")) Function ConvertToKey(Key) Const KeyOffset = 52 isWin8 = (Key(66) \ 6) And 1 Key(66) = (Key(66) And &HF7) Or ((isWin8 And 2) * 4) i = 24 Chars = "BCDFGHJKMPQRTVWXY2346789" Do Cur = 0 X = 14 Do Cur = Cur * 256 Cur = Key(X + KeyOffset) + Cur Key(X + KeyOffset) = (Cur \ 24) Cur = Cur Mod 24 X = X -1 Loop While X >= 0 i = i -1 KeyOutput = Mid(Chars, Cur + 1, 1) & KeyOutput Last = Cur Loop While i >= 0 If (isWin8 = 1) Then keypart1 = Mid(KeyOutput, 2, Last) insert = "N" KeyOutput = Replace(KeyOutput, keypart1, keypart1 & insert, 2, 1, 0) If Last = 0 Then KeyOutput = insert & KeyOutput End If a = Mid(KeyOutput, 1, 5) b = Mid(KeyOutput, 6, 5) c = Mid(KeyOutput, 11, 5) d = Mid(KeyOutput, 16, 5) e = Mid(KeyOutput, 21, 5) ConvertToKey = a & "-" & b & "-" & c & "-" & d & "-" & e End Function
Here's the code with some little mods from ATM: Code: public static string DecodeWinPkey() { IList<byte> digitalProductId = null; { RegistryKey registry = null; registry = Registry.LocalMachine. OpenSubKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false); if (registry != null) { // TODO: For other products, key name maybe different. digitalProductId = registry.GetValue("DigitalProductId") as byte[]; registry.Close(); } else return null; } int keyStartIndex = 52; int keyEndIndex = keyStartIndex + 15; const int numLetters = 24; // Possible alpha-numeric characters in product key. char[] digits = new[] { 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9' }; // Check if Windows 8/Office 2013 Style Key (Can contain the letter "N") int containsN = (digitalProductId[keyStartIndex + 14] >> 3) & 1; digitalProductId[keyStartIndex + 14] = (byte)((digitalProductId[keyStartIndex + 14] & 0xF7) | ((containsN & 2) << 2)); // Length of decoded product key const int decodeLength = 29; // Length of decoded product key in byte-form. // Each byte represents 2 chars. const int decodeStringLength = 15; // Array of containing the decoded product key. char[] decodedChars = new char[decodeLength]; // Extract byte 52 to 67 inclusive. List<byte> hexPid = new List<byte>(); for (int i = keyStartIndex; i <= keyEndIndex; i++) { hexPid.Add(digitalProductId); } for (int i = decodeLength - 1; i >= 0; i--) { // Every sixth char is a separator. if ((i + 1) % 6 == 0) { decodedChars = '-'; } else { // Do the actual decoding. int digitMapIndex = 0; for (int j = decodeStringLength - 1; j >= 0; j--) { int byteValue = (digitMapIndex << 8) | hexPid[j]; hexPid[j] = (byte)(byteValue / numLetters); digitMapIndex = byteValue % numLetters; decodedChars = digits[digitMapIndex]; } } } // Remove first character and put N in the right place if (containsN != 0) { int firstLetterIndex = 0; for (int index = 0; index < numLetters; index++) { if (decodedChars[0] != digits[index]) continue; firstLetterIndex = index; break; } string keyWithN = new string(decodedChars); keyWithN = keyWithN.Replace("-", string.Empty).Remove(0, 1); keyWithN = keyWithN.Substring(0, firstLetterIndex) + "N" + keyWithN.Remove(0, firstLetterIndex); keyWithN = keyWithN.Substring(0, 5) + "-" + keyWithN.Substring(5, 5) + "-" + keyWithN.Substring(10, 5) + "-" + keyWithN.Substring(15, 5) + "-" + keyWithN.Substring(20, 5); return keyWithN; } return new string(decodedChars); } BTW: Fixed to 1ST post
@Josh Cell Doens't seem to work for me: int containsN = (digitalProductId[keyStartIndex + 14] >> 3) & 1; fails with a NullReferenceException
This may sound silly, but is VS being an ass over capitals? I've had this issue more than once before. Code: int containsN = (DigitalProductId[keyStartIndex + 14] >> 3) & 1;
Code: public static string PIDDecoderFromRegistry() { IList<byte> digitalProductId = null; { RegistryKey registry = null; registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64). OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false); if (registry != null) { // TODO: For other products, key name maybe different. digitalProductId = registry.GetValue("DigitalProductId") as byte[]; registry.Close(); } else return null; } int keyStartIndex = 52; int keyEndIndex = keyStartIndex + 15; const int numLetters = 24; // Possible alpha-numeric characters in product key. char[] digits = new[] { 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9' }; // Check if Windows 8/Office 2013 Style Key (Can contain the letter "N") int containsN = (digitalProductId[keyStartIndex + 14] >> 3) & 1; digitalProductId[keyStartIndex + 14] = (byte)((digitalProductId[keyStartIndex + 14] & 0xF7) | ((containsN & 2) << 2)); // Length of decoded product key const int decodeLength = 29; // Length of decoded product key in byte-form. // Each byte represents 2 chars. const int decodeStringLength = 15; // Array of containing the decoded product key. char[] decodedChars = new char[decodeLength]; // Extract byte 52 to 67 inclusive. List<byte> hexPid = new List<byte>(); for (int i = keyStartIndex; i <= keyEndIndex; i++) { hexPid.Add(digitalProductId); } for (int i = decodeLength - 1; i >= 0; i--) { // Every sixth char is a separator. if ((i + 1) % 6 == 0) { decodedChars = '-'; } else { // Do the actual decoding. int digitMapIndex = 0; for (int j = decodeStringLength - 1; j >= 0; j--) { int byteValue = (digitMapIndex << 8) | hexPid[j]; hexPid[j] = (byte)(byteValue / numLetters); digitMapIndex = byteValue % numLetters; decodedChars = digits[digitMapIndex]; } } } // Remove first character and put N in the right place if (containsN != 0) { int firstLetterIndex = 0; for (int index = 0; index < numLetters; index++) { if (decodedChars[0] != digits[index]) continue; firstLetterIndex = index; break; } string keyWithN = new string(decodedChars); keyWithN = keyWithN.Replace("-", string.Empty).Remove(0, 1); keyWithN = keyWithN.Substring(0, firstLetterIndex) + "N" + keyWithN.Remove(0, firstLetterIndex); keyWithN = keyWithN.Substring(0, 5) + "-" + keyWithN.Substring(5, 5) + "-" + keyWithN.Substring(10, 5) + "-" + keyWithN.Substring(15, 5) + "-" + keyWithN.Substring(20, 5); return keyWithN; } return new string(decodedChars); }
@Alphawaves, about your deleted post 64-bit detection for 32-bit application was not that far of, should be: Code: RegistryKey registry = null; bool is64 = Environment.Is64BitOperatingSystem; if (is64) { // 64-bit registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false); } else { // 32-bit registry = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false); }