diff --git a/Product.cs b/Product.cs new file mode 100644 index 0000000..7b98d81 --- /dev/null +++ b/Product.cs @@ -0,0 +1,27 @@ +using System; + +namespace VSKeyExtractor; + +/// +/// Represents a product entry with its display name, GUID, and MPC value. +/// +/// Gets the product name. +/// Gets the product GUID. +/// Gets the product MPC value. +internal record struct Product(string Name, Guid GUID, string MPC) +{ + /// + /// Gets the product name. + /// + public string Name { get; } = Name; + + /// + /// Gets the product GUID. + /// + public Guid GUID { get; } = GUID; + + /// + /// Gets the product MPC value. + /// + public string MPC { get; } = MPC; +} diff --git a/Program.cs b/Program.cs index 7e99e0f..d6f4556 100644 --- a/Program.cs +++ b/Program.cs @@ -6,81 +6,99 @@ using System.Text; using System.Text.RegularExpressions; -namespace VSKeyExtractor -{ - internal struct Product - { - public string Name { get; } - public Guid GUID { get; } - public string MPC { get; } - public Product(string name, Guid guid, string mpc) - { - Name = name; - GUID = guid; - MPC = mpc; - } - } +namespace VSKeyExtractor; - class Program - { - private static readonly IReadOnlyList Products = new List() - { - new Product("Visual Studio Express 2012 for Windows Phone" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04937"), - new Product("Visual Studio Professional 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04938"), - new Product("Visual Studio Ultimate 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04940"), - new Product("Visual Studio Premium 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04941"), - new Product("Visual Studio Test Professional 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04942"), - new Product("Visual Studio Express 2012 for Windows Desktop", new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "05695"), +/// +/// Console entry point for extracting Visual Studio product license keys from the Windows registry. +/// +class Program +{ + /// + /// Known Visual Studio product names, registry product codes, and license identifiers. + /// The application iterates over this list and tries to locate a matching encrypted license entry + /// under the registry path used by Visual Studio installations. + /// + private static readonly IReadOnlyList Products = + [ + // Visual Studio 2012 family. + new Product("Visual Studio Express 2012 for Windows Phone" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04937"), + new Product("Visual Studio Professional 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04938"), + new Product("Visual Studio Ultimate 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04940"), + new Product("Visual Studio Premium 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04941"), + new Product("Visual Studio Test Professional 2012" , new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "04942"), + new Product("Visual Studio Express 2012 for Windows Desktop", new Guid("77550D6B-6352-4E77-9DA3-537419DF564B"), "05695"), - new Product("Visual Studio 2013 Professional" , new Guid("E79B3F9C-6543-4897-BBA5-5BFB0A02BB5C"), "06177"), - new Product("Visual Studio 2013 Ultimate" , new Guid("E79B3F9C-6543-4897-BBA5-5BFB0A02BB5C"), "06181"), + // Visual Studio 2013 family. + new Product("Visual Studio 2013 Professional" , new Guid("E79B3F9C-6543-4897-BBA5-5BFB0A02BB5C"), "06177"), + new Product("Visual Studio 2013 Ultimate" , new Guid("E79B3F9C-6543-4897-BBA5-5BFB0A02BB5C"), "06181"), - new Product("Visual Studio 2015 Enterprise" , new Guid("4D8CFBCB-2F6A-4AD2-BABF-10E28F6F2C8F"), "07060"), - new Product("Visual Studio 2015 Professional" , new Guid("4D8CFBCB-2F6A-4AD2-BABF-10E28F6F2C8F"), "07062"), + // Visual Studio 2015 family. + new Product("Visual Studio 2015 Enterprise" , new Guid("4D8CFBCB-2F6A-4AD2-BABF-10E28F6F2C8F"), "07060"), + new Product("Visual Studio 2015 Professional" , new Guid("4D8CFBCB-2F6A-4AD2-BABF-10E28F6F2C8F"), "07062"), - new Product("Visual Studio 2017 Enterprise" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08860"), - new Product("Visual Studio 2017 Professional" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08862"), - new Product("Visual Studio 2017 Test Professional" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08866"), + // Visual Studio 2017 family. + new Product("Visual Studio 2017 Enterprise" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08860"), + new Product("Visual Studio 2017 Professional" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08862"), + new Product("Visual Studio 2017 Test Professional" , new Guid("5C505A59-E312-4B89-9508-E162F8150517"), "08866"), - new Product("Visual Studio 2019 Enterprise" , new Guid("41717607-F34E-432C-A138-A3CFD7E25CDA"), "09260"), - new Product("Visual Studio 2019 Professional" , new Guid("41717607-F34E-432C-A138-A3CFD7E25CDA"), "09262"), + // Visual Studio 2019 family. + new Product("Visual Studio 2019 Enterprise" , new Guid("41717607-F34E-432C-A138-A3CFD7E25CDA"), "09260"), + new Product("Visual Studio 2019 Professional" , new Guid("41717607-F34E-432C-A138-A3CFD7E25CDA"), "09262"), - new Product("Visual Studio 2022 Enterprise" , new Guid("1299B4B9-DFCC-476D-98F0-F65A2B46C96D"), "09660"), - new Product("Visual Studio 2022 Professional" , new Guid("1299B4B9-DFCC-476D-98F0-F65A2B46C96D"), "09662"), + // Visual Studio 2022 family. + new Product("Visual Studio 2022 Enterprise" , new Guid("1299B4B9-DFCC-476D-98F0-F65A2B46C96D"), "09660"), + new Product("Visual Studio 2022 Professional" , new Guid("1299B4B9-DFCC-476D-98F0-F65A2B46C96D"), "09662"), - new Product("Visual Studio 2026 Enterprise Insider" , new Guid("0EB1B2EC-090C-4540-B219-F529C658360C"), "09760"), - new Product("Visual Studio 2026 Professional Insider" , new Guid("0EB1B2EC-090C-4540-B219-F529C658360C"), "09762"), + // Visual Studio 2026 Insider builds. + new Product("Visual Studio 2026 Enterprise Insider" , new Guid("0EB1B2EC-090C-4540-B219-F529C658360C"), "09760"), + new Product("Visual Studio 2026 Professional Insider" , new Guid("0EB1B2EC-090C-4540-B219-F529C658360C"), "09762"), - new Product("Visual Studio 2026 Enterprise" , new Guid("97372B8F-5B80-4DA7-8476-FF55D6368CBD"), "09860"), - new Product("Visual Studio 2026 Professional" , new Guid("97372B8F-5B80-4DA7-8476-FF55D6368CBD"), "09862"), + // Visual Studio 2026 release builds. + new Product("Visual Studio 2026 Enterprise" , new Guid("97372B8F-5B80-4DA7-8476-FF55D6368CBD"), "09860"), + new Product("Visual Studio 2026 Professional" , new Guid("97372B8F-5B80-4DA7-8476-FF55D6368CBD"), "09862"), - }; + ]; - static void Main() - { - foreach (var product in Products) ExtractLicense(product); - } + /// + /// Starts the extraction process for every known product in the static product list. + /// + static void Main() + { + foreach (var product in Products) ExtractLicense(product); + } - private static void ExtractLicense(Product product) + /// + /// Reads the encrypted license blob for a specific product from the registry, decrypts it, + /// and searches the decrypted text for a key formatted as five groups of five alphanumeric + /// characters separated by hyphens. + /// + /// The product metadata used to locate the registry entry. + private static void ExtractLicense(Product product) + { + // Visual Studio stores encrypted license data beneath this registry path. + var encrypted = Registry.GetValue($"HKEY_CLASSES_ROOT\\Licenses\\{product.GUID}\\{product.MPC}", "", null); + if (encrypted == null) return; + try { - var encrypted = Registry.GetValue($"HKEY_CLASSES_ROOT\\Licenses\\{product.GUID}\\{product.MPC}", "", null); - if (encrypted == null) return; - try - { - var secret = ProtectedData.Unprotect((byte[])encrypted, null, DataProtectionScope.CurrentUser); - var str = Encoding.Unicode.GetString(secret); - foreach (var sub in str.Split('\0')) - if (!string.IsNullOrWhiteSpace(sub)) + // Decrypt the protected blob using the current user's DPAPI context. + var secret = ProtectedData.Unprotect((byte[])encrypted, null, DataProtectionScope.CurrentUser); + // Convert the decrypted binary data into a Unicode string for token scanning. + var str = Encoding.Unicode.GetString(secret); + foreach (var sub in str.Split('\0')) + if (!string.IsNullOrWhiteSpace(sub)) + { + Debug.WriteLine($"sub: {sub}"); + // Search each token for a license-key-shaped value. + var match = Regex.Match(sub, @"\w{5}-\w{5}-\w{5}-\w{5}-\w{5}"); + if (match.Success) { - Debug.WriteLine($"sub: {sub}"); - var match = Regex.Match(sub, @"\w{5}-\w{5}-\w{5}-\w{5}-\w{5}"); - if (match.Success) - { - Console.WriteLine($"Found key for {product.Name}: {match.Captures[0]}"); - } + Console.WriteLine($"Found key for {product.Name}: {match.Captures[0]}"); } - } - catch (Exception) {/*just void em*/} + } + } + catch (Exception) + { + // Ignore malformed or inaccessible registry entries and continue with the next product. } } } diff --git a/README.de.md b/README.de.md new file mode 100644 index 0000000..599b874 --- /dev/null +++ b/README.de.md @@ -0,0 +1,68 @@ +# VSKeyExtractor + +VSKeyExtractor ist ein kleines Kommandozeilenwerkzeug, das versucht, den Lizenzschlüssel aus einer lokalen Visual Studio-Installation zu extrahieren. + +Es durchsucht bekannte Visual Studio-Produkt-Einträge, liest die verschlüsselten Lizenzdaten aus der Windows-Registrierung, entschlüsselt sie im Kontext des aktuellen Benutzers und sucht nach einem Schlüssel im Format `AAAAA-BBBBB-CCCCC-DDDDD-EEEEE`. + +## Funktionen + +- Liest Visual-Studio-Lizenzdaten aus der Windows-Registrierung +- Unterstützt mehrere Visual-Studio-Produktgenerationen +- Versucht, geschützte Lizenzdaten mit dem aktuellen Benutzerprofil zu entschlüsseln +- Gibt gefundene schlüsselartige Werte in der Konsole aus + +## Voraussetzungen + +- Windows +- Eine Visual-Studio-Installation mit vorhandenen lokalen Lizenzdaten +- Die benötigte .NET-Runtime für das jeweilige Projekt + +## Funktionsweise + +Das Tool prüft Registrierungswerte an den bekannten Visual-Studio-Lizenzpfaden und versucht anschließend, die gespeicherten Daten zu entschlüsseln. Wenn im entschlüsselten Text ein passender Schlüssel gefunden wird, wird er in die Standardausgabe geschrieben. + +Falls kein Schlüssel gefunden wird, fährt das Tool einfach mit dem nächsten bekannten Produkt-Eintrag fort. + +## Anwendung starten + +Du kannst das Projekt direkt mit `dotnet run` starten. + +### .NET Framework / Windows-Target + +```powershell +dotnet run --project .\VSKeyExtractor.csproj +``` + +### SDK-style-Projekt + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj +``` + +### Bestimmtes Target Framework ausführen + +Wenn du das SDK-style-Projekt verwendest und ein bestimmtes Framework starten möchtest, kannst du Folgendes nutzen: + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj -f net8.0-windows +``` + +Weitere unterstützte Target Frameworks können `net9.0-windows` oder `net10.0-windows` sein, abhängig vom installierten .NET SDK. + +## Beispielausgabe + +```text +Found key for Visual Studio 2022 Professional: ABCDE-FGHIJ-KLMNO-PQRST-UVWXY +``` + +## Hinweise + +- Führe das Tool auf dem Rechner aus, auf dem Visual Studio aktiviert wurde. +- Das Tool kann nur Daten lesen, die für das aktuelle Benutzerprofil verfügbar sind. +- Einige Einträge können nicht verfügbar, fehlerhaft oder geschützt sein; das ist erwartbar. + +## Übersetzungen + +- [English](README.md) +- [Français](README.fr.md) +- [Español](README.es.md) diff --git a/README.es.md b/README.es.md new file mode 100644 index 0000000..5a3e6de --- /dev/null +++ b/README.es.md @@ -0,0 +1,68 @@ +# VSKeyExtractor + +VSKeyExtractor es una pequeña herramienta de línea de comandos que intenta extraer la clave de licencia utilizada para activar una instalación local de Visual Studio. + +Recorre entradas conocidas de productos de Visual Studio, lee los datos de licencia cifrados del registro de Windows, los descifra en el contexto del usuario actual y busca una clave con formato `AAAAA-BBBBB-CCCCC-DDDDD-EEEEE`. + +## Características + +- Lee datos de licencia de Visual Studio desde el registro de Windows +- Admite varias generaciones de productos de Visual Studio +- Intenta descifrar blobs de licencia protegidos con el perfil del usuario actual +- Muestra en la consola cualquier valor que parezca una clave + +## Requisitos + +- Windows +- Una instalación de Visual Studio con datos de licencia locales disponibles +- El runtime de .NET necesario para el proyecto que quieras ejecutar + +## Cómo funciona + +La herramienta comprueba valores del registro en las rutas de licencia conocidas de Visual Studio y después intenta descifrar los datos almacenados. Si encuentra una clave coincidente en el texto descifrado, la escribe en la salida estándar. + +Si no encuentra ninguna clave, simplemente continúa con la siguiente entrada de producto conocida. + +## Ejecutar la aplicación + +Puedes ejecutar el proyecto directamente con `dotnet run`. + +### Destino .NET Framework / Windows + +```powershell +dotnet run --project .\VSKeyExtractor.csproj +``` + +### Proyecto estilo SDK + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj +``` + +### Ejecutar un framework de destino específico + +Si usas el proyecto estilo SDK y quieres apuntar a un framework concreto, puedes usar: + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj -f net8.0-windows +``` + +Otros frameworks de destino admitidos pueden incluir `net9.0-windows` o `net10.0-windows`, según el SDK de .NET instalado. + +## Ejemplo de salida + +```text +Found key for Visual Studio 2022 Professional: ABCDE-FGHIJ-KLMNO-PQRST-UVWXY +``` + +## Notas + +- Ejecuta la herramienta en el equipo donde se activó Visual Studio. +- La herramienta solo puede leer datos disponibles para el perfil de usuario actual. +- Algunas entradas pueden no estar disponibles, estar dañadas o protegidas; esto es esperable. + +## Traducciones + +- [English](README.md) +- [Deutsch](README.de.md) +- [Français](README.fr.md) diff --git a/README.fr.md b/README.fr.md new file mode 100644 index 0000000..216b64a --- /dev/null +++ b/README.fr.md @@ -0,0 +1,68 @@ +# VSKeyExtractor + +VSKeyExtractor est un petit outil en ligne de commande qui tente d’extraire la clé de licence utilisée pour activer une installation locale de Visual Studio. + +Il parcourt les entrées connues des produits Visual Studio, lit les données de licence chiffrées dans le registre Windows, les déchiffre dans le contexte de l’utilisateur actuel et recherche une clé au format `AAAAA-BBBBB-CCCCC-DDDDD-EEEEE`. + +## Fonctionnalités + +- Lit les données de licence Visual Studio depuis le registre Windows +- Prend en charge plusieurs générations de produits Visual Studio +- Tente de déchiffrer les blobs de licence protégés avec le profil de l’utilisateur actuel +- Affiche dans la console toute valeur ressemblant à une clé + +## Prérequis + +- Windows +- Une installation de Visual Studio avec des données de licence locales présentes +- Le runtime .NET requis pour le projet que vous souhaitez exécuter + +## Fonctionnement + +L’outil vérifie les valeurs du registre aux emplacements de licence connus de Visual Studio, puis tente de déchiffrer les données stockées. Si une clé correspondante est trouvée dans le texte déchiffré, elle est écrite dans la sortie standard. + +Si aucune clé n’est trouvée, l’outil passe simplement à l’entrée de produit suivante. + +## Exécuter l’application + +Vous pouvez exécuter le projet directement avec `dotnet run`. + +### Cible .NET Framework / Windows + +```powershell +dotnet run --project .\VSKeyExtractor.csproj +``` + +### Projet de style SDK + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj +``` + +### Exécuter un framework cible spécifique + +Si vous utilisez le projet de style SDK et souhaitez cibler un framework particulier, vous pouvez utiliser : + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj -f net8.0-windows +``` + +D’autres frameworks cibles pris en charge peuvent inclure `net9.0-windows` ou `net10.0-windows`, selon le SDK .NET installé. + +## Exemple de sortie + +```text +Found key for Visual Studio 2022 Professional: ABCDE-FGHIJ-KLMNO-PQRST-UVWXY +``` + +## Remarques + +- Exécutez l’outil sur la machine où Visual Studio a été activé. +- L’outil ne peut lire que les données disponibles pour le profil utilisateur actuel. +- Certaines entrées peuvent être indisponibles, endommagées ou protégées ; c’est normal. + +## Traductions + +- [English](README.md) +- [Deutsch](README.de.md) +- [Español](README.es.md) diff --git a/README.md b/README.md index 267b14b..ace3e28 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,68 @@ # VSKeyExtractor -A small tool to extract the license key that was used to activate your local installation of Visual Studio + +VSKeyExtractor is a small command-line tool that attempts to extract the license key used to activate a local Visual Studio installation. + +It scans known Visual Studio product entries, reads the encrypted license data from the Windows registry, decrypts it with the current user context, and looks for a key formatted like `AAAAA-BBBBB-CCCCC-DDDDD-EEEEE`. + +## Features + +- Reads Visual Studio license data from the Windows registry +- Supports multiple Visual Studio product generations +- Tries to decrypt protected license blobs with the current user profile +- Prints any key-shaped values it finds to the console + +## Requirements + +- Windows +- Visual Studio installation with local license data present +- The required .NET runtime for the project you want to run + +## How it works + +The tool checks registry values under the Visual Studio licensing locations, then tries to decrypt the stored data. If a matching key is found in the decrypted text, it is written to standard output. + +If no key is found, the tool simply continues with the next known product entry. + +## Run the application + +You can run the project directly with `dotnet run`. + +### .NET Framework / Windows target + +```powershell +dotnet run --project .\VSKeyExtractor.csproj +``` + +### SDK-style project + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj +``` + +### Run a specific target framework + +If you are using the SDK-style project and want to target a specific framework, you can use: + +```powershell +dotnet run --project .\VSKeyExtractor_net.csproj -f net8.0-windows +``` + +Other supported target frameworks may include `net9.0-windows` or `net10.0-windows`, depending on the installed .NET SDK. + +## Example output + +```text +Found key for Visual Studio 2022 Professional: ABCDE-FGHIJ-KLMNO-PQRST-UVWXY +``` + +## Notes + +- Run the tool on the machine where Visual Studio was activated. +- The tool can only read data that is available to the current user profile. +- Some entries may be unavailable, malformed, or protected, which is expected. + +## Translations + +- [Deutsch](README.de.md) +- [Français](README.fr.md) +- [Español](README.es.md) diff --git a/VSKeyExtractor.csproj b/VSKeyExtractor.csproj index bec5d7d..67a0a59 100644 --- a/VSKeyExtractor.csproj +++ b/VSKeyExtractor.csproj @@ -61,6 +61,7 @@ + @@ -68,6 +69,9 @@ + + + diff --git a/VSKeyExtractor.sln b/VSKeyExtractor.sln index 1edc15f..e021b94 100644 --- a/VSKeyExtractor.sln +++ b/VSKeyExtractor.sln @@ -1,10 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.3.11312.210 d18.3 +VisualStudioVersion = 18.3.11312.210 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSKeyExtractor", "VSKeyExtractor.csproj", "{CCC458E3-BA11-4AE2-B492-5E5DFCC0DC82}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSKeyExtractor_net", "VSKeyExtractor_net.csproj", "{BD3CD1BA-4974-0E77-CFA3-C4A839BA8062}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {CCC458E3-BA11-4AE2-B492-5E5DFCC0DC82}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCC458E3-BA11-4AE2-B492-5E5DFCC0DC82}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCC458E3-BA11-4AE2-B492-5E5DFCC0DC82}.Release|Any CPU.Build.0 = Release|Any CPU + {BD3CD1BA-4974-0E77-CFA3-C4A839BA8062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD3CD1BA-4974-0E77-CFA3-C4A839BA8062}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD3CD1BA-4974-0E77-CFA3-C4A839BA8062}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD3CD1BA-4974-0E77-CFA3-C4A839BA8062}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/VSKeyExtractor.slnx b/VSKeyExtractor.slnx new file mode 100644 index 0000000..77ae766 --- /dev/null +++ b/VSKeyExtractor.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/VSKeyExtractor_net.csproj b/VSKeyExtractor_net.csproj new file mode 100644 index 0000000..f06876d --- /dev/null +++ b/VSKeyExtractor_net.csproj @@ -0,0 +1,24 @@ + + + + Exe + Properties + net481;net8.0-windows + latest + + + + + $(TargetFrameworks);net9.0-windows + + + $(TargetFrameworks);net10.0-windows + + + + + + + + + \ No newline at end of file