Created
January 20, 2026 15:03
-
-
Save nv1t/c044ce93204428c1f938d79433ed4d2b to your computer and use it in GitHub Desktop.
Offline Windows Product Key extractor. A Python script designed to parse the SOFTWARE registry hive from a mounted Windows drive. Uses regipy for hive parsing and includes logic to decode the binary DigitalProductId for both legacy (Win7) and modern (Win8/10/11) installations. Optimized for use with uv.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /// script | |
| # dependencies = [ | |
| # "regipy", | |
| # ] | |
| # /// | |
| """ | |
| Extracts the Windows Product Key from an offline Registry Hive (SOFTWARE). | |
| Usage: uv run extract_key.py /path/to/mounted/Windows/System32/config/SOFTWARE | |
| """ | |
| import os | |
| import argparse | |
| from regipy import RegistryHive | |
| def decode_key(digital_product_id): | |
| """Decodes the binary DigitalProductId into the 5x5 Product Key format.""" | |
| if not digital_product_id or len(digital_product_id) < 67: | |
| return None | |
| data = bytearray(digital_product_id) | |
| key_offset = 52 | |
| is_win8 = (data[66] // 6) & 1 | |
| data[66] = (data[66] & 0xF7) | ((is_win8 & 2) * 4) | |
| chars = "BCDFGHJKMPQRTVWXY2346789" | |
| key = "" | |
| last = 0 | |
| for i in range(24, -1, -1): | |
| current = 0 | |
| for j in range(14, -1, -1): | |
| current = current * 256 | |
| current = data[j + key_offset] + current | |
| data[j + key_offset] = current // 24 | |
| current = current % 24 | |
| key = chars[current] + key | |
| last = current | |
| if is_win8 == 1: | |
| key_part = key[1:last+1] | |
| insert = "N" | |
| key = key_part + insert + key[last+1:] | |
| return "-".join([key[i:i+5] for i in range(0, 25, 5)]) | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Extract Windows Key from an offline SOFTWARE Hive.") | |
| parser.add_argument("hive_path", help="Path to the SOFTWARE hive file") | |
| args = parser.parse_args() | |
| if not os.path.exists(args.hive_path): | |
| print(f"[-] Error: File not found at {args.hive_path}") | |
| return | |
| try: | |
| hive = RegistryHive(args.hive_path) | |
| target_path = r"\Microsoft\Windows NT\CurrentVersion" | |
| node = hive.get_key(target_path) | |
| values = {v.name: v.value for v in node.iter_values()} | |
| raw_id = values.get('DigitalProductId') or values.get('DigitalProductId4') | |
| if isinstance(raw_id, str): | |
| raw_id = raw_id.encode('iso-8859-1') | |
| if raw_id: | |
| product_key = decode_key(raw_id) | |
| product_name = values.get('ProductName', 'Unknown Version') | |
| print(f"\nOS: {product_name}\nKey: {product_key}\n") | |
| else: | |
| print("[-] DigitalProductId not found.") | |
| except Exception as e: | |
| print(f"[-] Error: {e}") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment