问题
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