[C#] Decrypt Office 2010 Digital Product ID

Discussion in 'Mixed Languages' started by Josh Cell, Jul 11, 2011.

  1. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    #1 Josh Cell, Jul 11, 2011
    Last edited by a moderator: Apr 20, 2017
    Hi, Well I'm planning an update to Advanced Tokens Manager, and then came this problem;

    I found nothing about it, the more I tried did not work well :/

    formload decrypt code, this is an example

    Code:
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Microsoft.Win32;
    using System.Collections;
    
    namespace Get_Office_ProductKey
    {
        public partial class PKeys : Form
        {
    
            public enum Key { Windows, XP, Office10, Office11, Office14 };
            public static byte[] GetRegistryDigitalProductId(Key key)
            {
                byte[] digitalProductId = null;
                RegistryKey registry = null;
                switch (key)
                {
                    // Open the XP subkey readonly.
                    case Key.XP:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Windows NT\CurrentVersion",
                                false);
                        break;
                    // Open the Office 10 subkey readonly.
                    case Key.Office10:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Office\10.0\Registration\" +
                              @"{90280409-6000-11D3-8CFE-0050048383C9}",
                              false);
                       break;
                    // Open the Office 11 subkey readonly.
                    case Key.Office11:
                       break;
                    // Open the Windows subkey readonly.
                    case Key.Windows:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Windows NT\CurrentVersion",
                                false);
                        break;
                    // Open the Office 14 subkey readonly.
                    case Key.Office14:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Office\14.0\Registration\" +
                              @"{90140000-0011-0000-0000-0000000FF1CE}",
                              false);
                        break;
                }
                if (registry != null)
                {
                    // TODO: For other products, key name maybe different.
                    digitalProductId = registry.GetValue("DigitalProductId")
                      as byte[];
                    registry.Close();
                }
                return digitalProductId;
            }
            public static string DecodeProductKey(byte[] digitalProductId)
            {
                // Offset of first byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
                const int keyStartIndex = 52;
                // Offset of last byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
                const int keyEndIndex = keyStartIndex + 15;
                // Possible alpha-numeric characters in product key.
                char[] digits = new char[]
          {
            'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 
            'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
          };
                // 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.
                ArrayList hexPid = new ArrayList();
                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) | (byte)hexPid[j];
                            hexPid[j] = (byte)(byteValue / 24);
                            digitMapIndex = byteValue % 24;
                            decodedChars = digits[digitMapIndex];
                        }
                    }
                }
                return new string(decodedChars);
            }  
       
            public PKeys()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                //Usage
                byte[] results = PKeys.GetRegistryDigitalProductId(PKeys.Key.Office14); // Change product here, ie: Office14, windows, XP etc..
               textBox1.Text = PKeys.DecodeProductKey(results);
            }
        }
    }
    
    
    


    Thanks for alphawaves for the code example

    By putting the code in action, displays a set of 25 characters, divided into five dashes

    The key shown is incorrect, it isn't the real key installed

    I tried it with VL keys, same problem with Retail

    With "keyfinders", is shown the correct serial

    Thank you.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  2. user_hidden

    user_hidden MDL Expert

    Dec 18, 2007
    1,026
    986
    60
    To retrieve the Office 2010 key , microsoft made a modification in binary data so you must extract the bytes range
    from 808 to 822 from REG_BINARY value of DigitalProductID at the registry path instead of the default Range from 52 to 66.
     
  3. user_hidden

    user_hidden MDL Expert

    Dec 18, 2007
    1,026
    986
    60
    #3 user_hidden, Jul 11, 2011
    Last edited by a moderator: Apr 20, 2017
    btw, MAK keys will not be listed i don't think but KMS, Retail and OEM will.
    MAK key may show default KMS key as stored in registry.
    For the above I presume CODY & Bosch made their backup tool ask the user for the key?

    here is a simple VBS code snippet:


    Code:
     
     const HKEY_LOCAL_MACHINE = &H80000002  
     strKeyPath = "SOFTWARE\Microsoft\Office\14.0\Registration\{90140000-0011-0000-0000-0000000FF1CE}"
     strValueName = "DigitalProductId" 
     strComputer = "." 
     dim iValues() 
     Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _  
           strComputer & "\root\default:StdRegProv") 
     oReg.GetBinaryValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,iValues 
     Dim arrDPID 
     arrDPID = Array() 
     For i = 808 to 822
     ReDim Preserve arrDPID( UBound(arrDPID) + 1 ) 
     arrDPID( UBound(arrDPID) ) = iValues(i) 
     Next 
    
     Dim arrChars 
     arrChars = Array("B","C","D","F","G","H","J","K","M","P","Q","R","T","V","W","X","Y","2","3","4","6","7","8","9") 
      
     For i = 24 To 0 Step -1 
     k = 0 
     For j = 14 To 0 Step -1 
      k = k * 256 Xor arrDPID(j) 
      arrDPID(j) = Int(k / 24) 
      k = k Mod 24 
     Next 
     strProductKey = arrChars(k) & strProductKey 
     If i Mod 5 = 0 And i <> 0 Then strProductKey = "-" & strProductKey 
     Next 
     strFinalKey = strProductKey 
    
     Set wshShell=CreateObject("wscript.shell") 
     strPopupMsg = "Your Microsoft Office 2010 Product Key is:" & vbNewLine & vbNewLine & strFinalKey 
     strPopupTitle = "Product Key" 
     wshShell.Popup strPopupMsg,,strPopupTitle,vbCancelOnly+vbinformation 
     WScript.Quit 
    
     
  4. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #4 CODYQX4, Jul 11, 2011
    Last edited: Apr 15, 2019
    .
     
  5. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #5 CODYQX4, Jul 11, 2011
    Last edited: Apr 15, 2019
    .
     
  6. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    #6 Josh Cell, Jul 12, 2011
    Last edited by a moderator: Apr 20, 2017
    (OP)


    Thanks user_hidden and CODY, I worked to adapt the code, currently running, thanks for aphawaves for logical interpretations

    Code:
    
            public enum Key { Windows, Office };
            public static byte[] GetRegistryDigitalProductId(Key key)
            {
                byte[] digitalProductId = null;
                RegistryKey registry = null;
                switch (key)
                {
                    // Open the Windows subkey readonly.
                    case Key.Windows:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Windows NT\CurrentVersion",
                                false);
                        break;
                    case Key.Office:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Office\14.0\Registration\" +
                              @"{90140000-0011-0000-0000-0000000FF1CE}",
                              false);
                        break;
                }
                if (registry != null)
                {
                    // TODO: For other products, key name maybe different.
                    digitalProductId = registry.GetValue("DigitalProductId")
                      as byte[];
                    registry.Close();
                }
                return digitalProductId;
            }
            public static string DecodeWindowsProductKey(byte[] digitalProductId)
            {
                // Offset of first byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
                const int keyStartIndex = 52;
                // Offset of last byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
                const int keyEndIndex = keyStartIndex + 15;
                // Possible alpha-numeric characters in product key.
                char[] digits = new char[]
          {
            'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 
            'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
          };
                // 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.
                ArrayList hexPid = new ArrayList();
                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) | (byte)hexPid[j];
                            hexPid[j] = (byte)(byteValue / 24);
                            digitMapIndex = byteValue % 24;
                            decodedChars = digits[digitMapIndex];
                        }
                    }
                }
                return new string(decodedChars);
            }
            public static string DecodeOfficeProductKey(byte[] digitalProductId)
            {
                const int keyStartIndex = 0x328;
                const int keyEndIndex = keyStartIndex + 15;
    
                // Possible alpha-numeric characters in product key.
                char[] digits = new char[]
                {
                  'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 
                  'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
                };
    
                // 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.
                ArrayList hexPid = new ArrayList();
                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) | (byte)hexPid[j];
                            hexPid[j] = (byte)(byteValue / 24);
                            digitMapIndex = byteValue % 24;
                            decodedChars = digits[digitMapIndex];
                        }
                    }
                }
                return new string(decodedChars);
            }
    
    


    usage:

    Code:
    
                byte[] wresults = Form1.GetRegistryDigitalProductId(ATM.Key.Windows);
                windowslabel.Text = Form1.DecodeWindowsProductKey(wresults);
                byte[] oresults = Form1.GetRegistryDigitalProductId(ATM.Key.Office);
                officelabel.Text = Form1.DecodeOfficeProductKey(oresults);
    
    
    Thanks for the code, very helpful

    @user_hidden

    VBS code is great script :)

    Thanks for the range info.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  7. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #7 CODYQX4, Jul 12, 2011
    Last edited: Apr 15, 2019
    .
     
  8. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    #8 Josh Cell, Jul 12, 2011
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Hmm

    Updated code

    Code:
    
            public enum Key { Windows, Office, OfficeWOW };
            public static byte[] GetRegistryDigitalProductId(Key key)
            {
                byte[] digitalProductId = null;
                RegistryKey registry = null;
                switch (key)
                {
                    // Open the Windows subkey readonly.
                    case Key.Windows:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Windows NT\CurrentVersion",
                                false);
                        break;
                    case Key.Office:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Microsoft\Office\14.0\Registration\" +
                              @"{90140000-0011-0000-0000-0000000FF1CE}",
                              false);
                        break;
                    case Key.OfficeWOW:
                        registry =
                          Registry.LocalMachine.
                            OpenSubKey(
                              @"SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Registration\" +
                              @"{90140000-0011-0000-0000-0000000FF1CE}",
                              false);
                        break;
                }
                if (registry != null)
                {
                    // TODO: For other products, key name maybe different.
                    digitalProductId = registry.GetValue("DigitalProductId")
                      as byte[];
                    registry.Close();
                }
                return digitalProductId;
            }
            public static string DecodeWindowsProductKey(byte[] digitalProductId)
            {
                // Offset of first byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
                const int keyStartIndex = 52;
                // Offset of last byte of encoded product key in 
                //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
                const int keyEndIndex = keyStartIndex + 15;
                // Possible alpha-numeric characters in product key.
                char[] digits = new char[]
          {
            'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 
            'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
          };
                // 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.
                ArrayList hexPid = new ArrayList();
                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) | (byte)hexPid[j];
                            hexPid[j] = (byte)(byteValue / 24);
                            digitMapIndex = byteValue % 24;
                            decodedChars = digits[digitMapIndex];
                        }
                    }
                }
                return new string(decodedChars);
            }
            public static string DecodeOfficeProductKey(byte[] digitalProductId)
            {
                const int keyStartIndex = 0x328;
                const int keyEndIndex = keyStartIndex + 15;
    
                // Possible alpha-numeric characters in product key.
                char[] digits = new char[]
                {
                  'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', 
                  'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9',
                };
    
                // 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.
                ArrayList hexPid = new ArrayList();
                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) | (byte)hexPid[j];
                            hexPid[j] = (byte)(byteValue / 24);
                            digitMapIndex = byteValue % 24;
                            decodedChars = digits[digitMapIndex];
                        }
                    }
                }
                return new string(decodedChars);
            }
    
    


    Usage

    Code:
                //for any Windows Platform
                byte[] wresults = Form1.GetRegistryDigitalProductId(ATM.Key.Windows);
                windowslabel.Text = Form1.DecodeWindowsProductKey(wresults);
                //for x86 office on x86 systems, and x64 office on x64 systems
                byte[] oresults = Form1.GetRegistryDigitalProductId(ATM.Key.Office);
                officelabel.Text = Form1.DecodeOfficeProductKey(oresults);
                //for x86 office on x64 systems
                byte[] owowresults = Form1.GetRegistryDigitalProductId(ATM.Key.OfficeWOW);
                officelabel.Text = Form1.DecodeOfficeProductKey(oresults);
    
    
    :D
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  9. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    This is method works on Retail licences?
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  10. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #10 CODYQX4, Jul 12, 2011
    Last edited: Apr 15, 2019
    .
     
  11. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    #11 Josh Cell, Jul 22, 2011
    Last edited by a moderator: Apr 20, 2017
    (OP)


    Cody, can you tell how to use your code?

    I'm having problems with my code, because DigitalProductID isn't in the same key in other Office builds

    I added your code on my assembly as Logic.cs, and changed the Namespace to Logic, class is KeyOfficePartial...

    It is missing just like decode product key...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  12. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #12 CODYQX4, Jul 22, 2011
    Last edited: Apr 15, 2019
    .
     
  13. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    #13 Josh Cell, Jul 22, 2011
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Ok, more like I will apply within the code?

    I tried these forms can not decode product key;
    Code:
                List<string> serial = new List<string>();
                serial = Logic.KeyOfficePartial.GetRegistryDigitalProductId(KeyOfficePartial.GetKeysFromRegistry);
                textbox1.Text = Logic.KeyOfficePartial.DecodeProductKey(serial);
    Based in my code structure

    Code:
                    byte[] oresults = ATM.GetRegistryDigitalProductId(ATM.Key.OfficeWOW);
                         textbox1.Text = ATM.DecodeOfficeProductKey(oresults);
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  14. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #14 CODYQX4, Jul 23, 2011
    Last edited: Apr 15, 2019
    .
     
  15. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    I'm not getting to make it work;

    The biggest problem is search the registry key DigitalProductID, which varies from place to each build of the office ...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  16. CODYQX4

    CODYQX4 MDL Developer

    Sep 4, 2009
    4,814
    45,666
    150
    #16 CODYQX4, Jul 23, 2011
    Last edited: Apr 15, 2019
    .
     
  17. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    I solved the problem another way, using an external program;

    Thank you for your attention.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  18. steve6341

    steve6341 MDL Novice

    Jul 25, 2011
    1
    0
    0
    Just wanted to throw my 2 cents in. I had been looking for a solution to the problem of an invalid product key being extracted...

    The blurb about
    fixed my problems.

    Just out of curiosity, how do know that or find that?!?

    Thanks
     
  19. user_hidden

    user_hidden MDL Expert

    Dec 18, 2007
    1,026
    986
    60
    by using "the force"
     
  20. Josh Cell

    Josh Cell MDL Developer

    Jan 8, 2011
    3,519
    7,119
    120
    Using brute force against the windows :p
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...