[C#] - Compatible Windows 8 Product Key Decoder

Discussion in 'Mixed Languages' started by Josh Cell, Aug 8, 2012.

  1. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    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
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  2. QuantumBug

    QuantumBug MDL Developer

    Mar 7, 2012
    1,472
    1,292
    60
    #2 QuantumBug, Aug 8, 2012
    Last edited by a moderator: Apr 20, 2017
    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"))
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  3. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    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 :worthy:
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  4. QuantumBug

    QuantumBug MDL Developer

    Mar 7, 2012
    1,472
    1,292
    60
    Awesome, let me know if further help is needed :)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  5. petok

    petok MDL Member

    May 4, 2009
    161
    53
    10
    What is good for Windows 8 Product Key decode with vb.net or C#?
     
  6. QuantumBug

    QuantumBug MDL Developer

    Mar 7, 2012
    1,472
    1,292
    60
    See my above code, works straight up with VB.NET but will need porting for C#, am working on that now.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  7. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    I can't post the CODY's Win 8 Decoder source without him authorization.

    As the lastest post, if he want will post here ;)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. nononsence

    nononsence MDL Addicted

    Aug 18, 2009
    809
    802
    30
    #8 nononsence, Aug 9, 2012
    Last edited by a moderator: Apr 20, 2017
    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
    
     
  9. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,801
    44,845
    150
    It's not really mine, it is a tweaked open source with "N" fix by nononsense. I have my own functions though that loop through Office Registration. You can post it though.

    What you notice is I pass the keyStartIndex and a byte[] of DPID, everyone else just hardcodes it to Windows.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  10. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    #10 Josh Cell, Aug 9, 2012
    Last edited by a moderator: Apr 20, 2017
    (OP)
    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 :)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  11. FreeStyler

    FreeStyler MDL Guru

    Jun 23, 2007
    3,501
    3,608
    120
    @Josh Cell

    Doens't seem to work for me:
    int containsN = (digitalProductId[keyStartIndex + 14] >> 3) & 1; fails with a NullReferenceException
     
  12. QuantumBug

    QuantumBug MDL Developer

    Mar 7, 2012
    1,472
    1,292
    60
    #12 QuantumBug, Aug 9, 2012
    Last edited by a moderator: Apr 20, 2017
    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;
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  13. FreeStyler

    FreeStyler MDL Guru

    Jun 23, 2007
    3,501
    3,608
    120
    WTF :confused:

    digitalProductId is a C# variable, not the registry key :D
     
  14. QuantumBug

    QuantumBug MDL Developer

    Mar 7, 2012
    1,472
    1,292
    60
    :eek:

    My mistake.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  15. ViperMatrixXM

    ViperMatrixXM MDL Novice

    Aug 9, 2012
    13
    2
    0
    This actually works. The older one I have that works for 7 doesn't work for 8.
     
  16. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    You're compil'ng with a ANY-CPU?
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  17. FreeStyler

    FreeStyler MDL Guru

    Jun 23, 2007
    3,501
    3,608
    120
    AnyCPU works OK, how to force it to work on a 32-bit application?
     
  18. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,096
    120
    #18 Josh Cell, Aug 9, 2012
    Last edited by a moderator: Apr 20, 2017
    (OP)
    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);
            }


    ;)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  19. Alphawaves

    Alphawaves Super Moderator/Developer
    Staff Member

    Aug 11, 2008
    5,864
    20,047
    180
  20. FreeStyler

    FreeStyler MDL Guru

    Jun 23, 2007
    3,501
    3,608
    120
    #20 FreeStyler, Aug 13, 2012
    Last edited by a moderator: Apr 20, 2017
    @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);
                    }