Retrieve/decrypt Windows 7 product key from Linux
Solution 1:
There is a great tool available for Linux called chntpw
. You can get it easily on Debian/Ubuntu via:
sudo apt install chntpw
To look into the relevant registry file mount the Windows disk and open it like so:
chntpw -e /path/to/windisk/Windows/System32/config/software
Now to get the decoded DigitalProductId
enter this command:
dpi \Microsoft\Windows NT\CurrentVersion\DigitalProductId
Solution 2:
For those who are not shy to do a little bit of coding.
I found an algorithm about 10 years ago and implemented it in C# (See below)
If you just want to run it on Windows
I took the liberty to convert it to a powershell script:
$dpid = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name "DigitalProductId"
# Get the range we are interested in
$id = $dpid.DigitalProductId[52..(52+14)]
# Character table
$chars = "BCDFGHJKMPQRTVWXY2346789"
# Variable for the final product key
$pkey = ""
# Calculate the product key
for ($i=0; $i -le 24; $i++) {
$c = 0
for($j=14; $j -ge 0; $j--) {
$c = ($c -shl 8) -bxor $id[$j]
$id[$j] = [Math]::Floor($c / 24) -band 255
$c = $c % 24
}
$pkey = $chars[$c] + $pkey
}
# Insert some dashes
for($i = 4; $i -gt 0; $i--) {
$pkey = $pkey.Insert($i * 5, "-")
}
$pkey
Run this and you get your product key. (So no coding for you after all)
Original post
So this is the actual C# code I dug up and commented.
public static string ConvertDigitalProductID(string regPath, string searchKey = "DigitalProductID") {
// Open the sub key i.E.: "Software\Microsoft\Windows NT\CurrentVersion"
var regkey = Registry.LocalMachine.OpenSubKey(regPath, false);
// Retreive the value of "DigitalProductId"
var dpid = (byte[])regkey.GetValue(searchKey);
// Prepare an array for the relevant parts
var idpart = new byte[15];
// Copy the relevant parts of the array
Array.Copy(dpid, 52, idpart, 0, 15);
// Prepare the chars that will make up the key
var charStore = "BCDFGHJKMPQRTVWXY2346789";
// Prepare a string for the result
string productkey = "";
// We need 24 iterations (one for each character)
for(int i = 0; i < 25; i++) {
int c = 0;
// Go through each of the 15 bytes of our dpid
for(int j = 14; j >= 0; j--) {
// Shift the current byte to the left and xor in the next byte
c = (c << 8) ^ idpart[j];
// Leave the result of the division in the current position
idpart[j] = (byte)(c / 24);
// Take the rest of the division forward to the next round
c %= 24;
}
// After each round, add a character from the charStore to our key
productkey = charStore[c] + productkey;
}
// Insert the dashes
for(int i = 4; i > 0; i--) {
productkey = productkey.Insert(i * 5, "-");
}
return productkey;
}
You'll have to pass it Software\Microsoft\Windows NT\CurrentVersion
as a Key, where it'll find the DigitalProductId
At that time MS Office Products used the same algorithm, so by providing the function with the relevant registry key it could calculate those product keys as well.
You can of course refactor the function so that it takes a byte array as input.
As for today. I just tested it on my Windows 10 Machine, and it still works.
Solution 3:
Here is a Python port of the other answer (adapted for Windows 8.1). The advantage of this over chntpw
is that it will work even with drives in read-only state.
Requirements:
pip install python-registry
Code:
#!/usr/bin/env python
import sys
from Registry import Registry
reg = Registry.Registry("/path/to/drive/Windows/System32/config/RegBack/SOFTWARE")
# Uncomment for registry location for Windows 7 and below:
#reg = Registry.Registry("/path/to/drive/Windows/system32/config/software")
key = reg.open("Microsoft\Windows NT\CurrentVersion")
did = bytearray([v.value() for v in key.values() if v.name() == "DigitalProductId"][0])
idpart = did[52:52+15]
charStore = "BCDFGHJKMPQRTVWXY2346789";
productkey = "";
for i in range(25):
c = 0
for j in range(14, -1, -1):
c = (c << 8) ^ idpart[j]
idpart[j] = c // 24
c %= 24
productkey = charStore[c] + productkey
print('-'.join([productkey[i * 5:i * 5 + 5] for i in range(5)]))