How to programatically remove the Windows product key from registry in .NET?

左心房为你撑大大i 提交于 2019-12-11 00:26:38

问题


How could I programatically remove the Windows product key from registry in .NET (C# or VB.NET) to reproduce the same effect as when calling the Microsoft's legit slmgr.vbs script file with the /cpky argument?... so please do not misunderstand in my question "remove" for "uninstall". I just want to remove the bytes that correspond to the product key of Windows that is stored and encoded in the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion: DigitalProductId registry value, so the product key still installed but it becomes inaccessible for 3rd party applications like ProduKey.

I tried to inspect the slmgr.vbs script file (stored at C:\Windows\System32) and it leads me to this method block:

Private Sub ClearPKeyFromRegistry()
    Dim objService

    On Error Resume Next

    set objService = GetServiceObject("Version")
    QuitIfError()

    objService.ClearProductKeyFromRegistry()
    QuitIfError()

    LineOut GetResource("L_MsgClearedPKey")
End Sub

However I'm a little bit lost trying to find and to understand from where comes and what it does the GetServiceObject("Version") call, since it seems not to be a built-in VBS member neither it doesn't seem to be declared as any local member in the script file, and I didn't found any info regarding "GetServiceObject" on MSDN docs/VBS reference.

PS: Please note that I won't depend on the existance of the slmgr.vbs file to solve this issuea by simply calling that script file from C#...

UPDATE

I just scanned for the string "ClearProductKeyFromRegistry" in the dll files of the Windows filesystem, and found it in the sppwmi.dll file but unfortunately the function is not exported, then following with a simple research on Google it leads me to the ClearProductKeyFromRegistry method of the SoftwareLicensingService class on MSDN, but now I don't know how do I use that. I tried to find info about how to use a existing WMI provider in .NET, but all the info I see around the WWW is about how to implement/create a WMI provider.


回答1:


In that same script you will find the GetServiceObject method (and the constants and globals it uses). To find them, search for the following terms in the script:

  • Function GetServiceObject
  • ServiceClass =
  • g_objWMIService =
  • L_MsgClearedPKey =

So it's just a matter of tracing the code and converting the lines. Here's what I came up with for the full VBScript version of the method and it's dependencies:

private const L_MsgClearedPKey = "Product key from registry cleared successfully."
private const ServiceClass = "SoftwareLicensingService"

g_strComputer = "."
Set g_objWMIService = GetObject("winmgmts:\\" & g_strComputer & "\root\cimv2")

Private Sub ClearPKeyFromRegistry()  
    Dim objService

    On Error Resume Next

    set objService = GetServiceObject("Version")
    QuitIfError()

    objService.ClearProductKeyFromRegistry()
    QuitIfError()

    LineOut GetResource("L_MsgClearedPKey")
End Sub

Function GetServiceObject(strQuery)
    Dim objService
    Dim colServices

    On Error Resume Next

    Set colServices = g_objWMIService.ExecQuery("SELECT " & strQuery & 
        " FROM " & ServiceClass)
    QuitIfError()

    For each objService in colServices
        QuitIfError()
        Exit For
    Next

    QuitIfError()

    set GetServiceObject = objService
End Function

Next step is to reduce this down into one method. I went ahead and removed all the QuitIfError() calls and the On Error Resume Next, since we can just wrap our code in a try/catch block. After replacing the constants and globals, and combining the methods, I came up with this:

Dim objService
Dim colServices
Dim g_objWMIService

Set g_objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colServices = g_objWMIService.ExecQuery("SELECT Version FROM SoftwareLicensingService")

For each objService in colServices
    Exit For
Next

objService.ClearProductKeyFromRegistry()

LineOut "Product key from registry cleared successfully."

Now, since we're using WMI, we need to reference the system.management assembly and add a using:

using System.Management;

And then it's just a matter of conversion. Some of this I haven't done before, but it should do the trick:

private static void ClearProductKeyFromRegistry()
{
    const string query = "SELECT Version FROM SoftwareLicensingService";
    var searcherProd = new ManagementObjectSearcher("\\\\.\\ROOT\\cimv2", query);
    var results = searcherProd.Get();

    foreach (ManagementObject result in results)
    {
        result.InvokeMethod("ClearProductKeyFromRegistry", null);
        break;
    }

    Console.WriteLine("Product key from registry cleared successfully.");
}



回答2:


Finally I discovered the way to invoke a method, seeying this example. Then I just followed what I seen there, adapting it to my needs, so I wrote this useful code snippet developed in VB.NET:

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Removes the Windows product key from registry (to prevent unauthorized diffusion). 
''' <para></para>
''' It does not uninstall the product key.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <remarks>
''' <see href="https://msdn.microsoft.com/en-us/library/cc534586(v=vs.85).aspx"/>
''' </remarks>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="PlatformNotSupportedException">
''' Windows 7 or newer is required to use this feature.
''' </exception>
''' 
''' <exception cref="Exception">
''' Unknown error occurred during the product key removal attempt.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Sub RemoveWindowsProductKeyFromRegistry()

    ' If Not (WindowsUtils.IsWin7OrGreater) Then
    '     Throw New PlatformNotSupportedException("Windows 7 or newer is required to use this feature.")
    ' End If

    Using query As New ManagementObjectSearcher("SELECT * FROM SoftwareLicensingService")

        For Each product As ManagementObject In query.Get()

            Dim result As UInteger
            Try
                result = CUInt(product.InvokeMethod("ClearProductKeyFromRegistry", Nothing))

            Catch ex As COMException
                Marshal.ThrowExceptionForHR(ex.HResult)

            Catch ex As Exception
                Throw

            End Try

            If (result <> 0UI) Then
                Throw New Exception("Unknown error occurred during the product key removal attempt.")
            End If

        Next product

    End Using

End Sub

Plus this other snippet to bring a way to programatically install a product key (it works on my machine with Windows 10, but probably it needs more testing):

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Installs a Windows product key.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <remarks>
''' <see href="https://msdn.microsoft.com/en-us/library/cc534590(v=vs.85).aspx"/>
''' </remarks>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code>
''' Dim productKey As String = "YTMG3-N6DKC-DKB77-7M9GH-8HVXX"
''' InstallProductKey(productKey)
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="productKey">
''' The product key.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="PlatformNotSupportedException">
''' Windows 7 or newer is required to use this feature.
''' </exception>
''' 
''' <exception cref="ArgumentNullException">
''' productKey
''' </exception>
''' 
''' <exception cref="Exception">
''' The Software Licensing Service determined that the product key is invalid.
''' or
''' Unknown error occurred during the product key installation attempt.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Sub InstallProductKey(ByVal productKey As String)

    ' If Not (WindowsUtils.IsWin7OrGreater) Then
    '     Throw New PlatformNotSupportedException("Windows 7 or newer is required to use this feature.")
    ' End If

    Using query As New ManagementObjectSearcher("SELECT * FROM SoftwareLicensingService")

        For Each product As ManagementObject In query.Get()

            Dim result As UInteger
            Try
                result = CUInt(product.InvokeMethod("InstallProductKey", {productKey}))
                product.InvokeMethod("RefreshLicenseStatus", Nothing)

            Catch ex As COMException When (ex.HResult = -1073418160)
                Throw New Exception("The Software Licensing Service determined that the product key is invalid.", ex)

            Catch ex As COMException
                Marshal.ThrowExceptionForHR(ex.HResult)

            Catch ex As Exception
                Throw

            End Try

            If (result <> 0UI) Then
                Throw New Exception("Unknown error occurred during the product key installation attempt.")
            End If

        Next product

    End Using

End Sub


来源:https://stackoverflow.com/questions/44296456/how-to-programatically-remove-the-windows-product-key-from-registry-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!