Implementing MI Provider (6) - Build, Register, and Debug

This blog discusses how to build, register and debug MI provider.

Build

To build MI provider, open visual studio 2012, create an empty Visual C++ project named “process”, set type to DLL, and add all generated files into the project.

  • Open project property dialog box, navigate to linker page, click input option, Set Module Definition File to “Provider.DEF”. This will ensure DLL exports the set of APIS defined in provider.DEF file. NOTE, make sure the LIBRARY section of Provider.DEF file was set to process.DLL.
  • Select your target platform, if you want the provider to run on X64 platform, please create “X64” platform through “Configuration Manager …” button, otherwise keep the default option is “Win32”, which means target platform is X86.
  • Optionally, go to “C/C++” -> “code generation” page, select “Multi-threaded Debug (/MTd)” or “Multi-threaded (/MT)” for runtime library to avoid the issue that target test machine is missing the runtime DLL requested by your provider DLL.

Refer to MI API sample for the sample project, open the solution file within Visual studio 2012, which integrates windows 8 SDK installation directory, by build all projects, you will be able to get all of the MI provider's binaries, for example process.DLL.

 

Register

(1) Tool

Register-CimProvider.exe is the tool used to register MI provider, shipped with windows 8, which can be found under %system32% folder. Following diagram shows the process of the registration.

On windows 8, MI provider is managed by WMI service. Register-CimProvider.exe tool helps to register MI providers into the system (WMI). The tool creates mof and mfl files on the fly based on the schema definition from the DLL as described above, and then compile the mof/mfl files into WMI repository. The tool registers the providers' DLL as a COM server as well.

To register process.DLL, copy the compiled process.DLL to a Windows 8 or Windows Server 2012 machine, and invoke the following command line from elevated commandline prompt (cmd.exe):

 Register-CimProvider.exe -Namespace Root/Standardcimv2/sample -ProviderName process -Path process.dll -verbose -ForceUpdate

Upon that completes, process.dll should be successfully registered into system. By default, the provider is registered as a coupled provider, i.e, it runs in a Wmiprvse.exe process. And default hosting model value is NetworkServiceHost, which means the host process is running under NETWORK SERVICE account. process.mof will also be generated under current directory, which contains the detail registration schema of the provider.

(2) Provider Hosting Model

On windows 8, MI Provider's hosting model follows the same specification of WMI provider hosting model and security. Please refer following link for the details.

https://msdn.microsoft.com/en-us/library/windows/desktop/aa392783(v=vs.85).aspx

 

MI provider can be hosted as coupled provider and decoupled provider. As mentioned above, coupled provider will be hosted in wmiprvse.exe running under specific account which could be specified by -HostingModel argument, while a decoupled provider is running under any customized arbitrary process. WMI service controlled the lifecycle of a coupled provider, i.e., loading/unloading the provider time; while the lifecycle of a decoupled provider is completely controlled by its hosting process. MI API also provides a convenient API to host arbitrary MI provider within current process.

(3) Host Decoupled MI Provider

MI_Application_NewHostedProvider is the API to host provider as a decoupled provider under current process. Following is the pseudo code snippet of hosting a MI provider as a decoupled provider. Code snippet of hosting decoupled MI provider, (please refer to MI API sample dcuphost project for the complete implementation) 

  // load provider DLL
 hProvider = LoadLibraryExW(“process.DLL”, NULL, 0);
 // query MI_Main function from provider DLL
 mi_main = (MI_MainFunction)GetProcAddress(hProvider, MI_MAIN_FUNCNAME);
 // initialize MI_Application object
 result = MI_Application_Initialize(0, NULL, NULL, &application);
 // host the provider as decoupled provider
 result = MI_Application_NewHostedProvider(&application,
 pArgument->lpNamespace,
 pArgument->lpProviderName,
 mi_main,
 NULL,
 &hostedProvider);
 

Note that before hosting a MI provider as decoupled provider, it should be registered to the system as a decoupled provider firstly. Take process.dll for example, below is the command line to register it as a decoupled one,

 Register-CimProvider.exe -Namespace Root/StandardCimV2/dcupsample -ProviderName process -Path C:\temp\provider.dll -Decoupled O:BAG:BAD:(A;;0x1;;;BA)(A;;0x1;;;NS) -Impersonation True

 

Test/Validate

To validate the MI provider is functioning or not, there are couple of approaches listed as of following, see MI API sample for the sample code.

Methodology

Description

Wbemtest.exe

Send request to provider via this UI tool.

Cim Cmdlets

A set of new cmdlets shipped with windows 8

Cim based cmdlets

Create cdxml to define a set of cim-based cmdlets to access the provider

Application

Using MI C API or MI.net API to build an application to verify the provider

 

Un-register

How to un-register the MI provider completely from system? Unfortunately, Register-CimProvider.exe tool has no option to un-register a MI provider from system. It providers an option to generate uninstall mof and (or) mfl file during the registration time. The option name is GenerateUnregistration.

Take process provider for example, if you run following command line, processUninstall.mof and process.mof will be generated under current directory.

 Register-CimProvider.exe -Namespace Root/Standardcimv2/sample -ProviderName process -Path process.dll -verbose –ForceUpdate -GenerateUnregistration
 

processUninstall.mof contains instructions of unregistering the registered provider from system. It will delete registered non-abstract classes, related provider registration instances, and __Win32Porvider instance from system.

  #pragma classflags ("forceupdate")
 #pragma namespace ( "\\\\.\\Root\\Standardcimv2\\sample")
 
 #pragma deleteclass("MSFT_WindowsProcess",nofail)
 #pragma deleteclass("MSFT_WindowsServiceProcess",nofail)
 #pragma deleteinstance("__MethodProviderRegistration.Provider=\"\\\\\\\\.\\\\Root\\\\Standardcimv2\\\\sample:__Win32Provider.Name=\\\"process\\\"\"", nofail)
 #pragma deleteinstance("__InstanceProviderRegistration.Provider=\"\\\\\\\\.\\\\Root\\\\Standardcimv2\\\\sample:__Win32Provider.Name=\\\"process\\\"\"", nofail)
 #pragma deleteinstance("__Win32Provider.Name=\"process\"", nofail)

Notes regarding un-register MI provider,

Abstract classes registered by MI provider are not generated in Uninstall.mof. Because abstract classes might be referred by other providers under the same namespace, detecting that would cause complexity. As a MI provider developer, you can choose to delete all classes defined in the MI provider by adding deleteclass instructions for all classes into Uninstall.mof, as long as it can be guaranteed that there is no other provider be affected under the same namespace.

Registering MI provider will also create one registry key into the system. Process provider has the following registry key and value created,

  Windows Registry Editor Version 5.00  [HKEY_CLASSES_ROOT\CLSID\{EDCB2856-2E63-4F57-B3A1-F03CC7D9FEE3}] @="process"  [HKEY_CLASSES_ROOT\CLSID\{EDCB2856-2E63-4F57-B3A1-F03CC7D9FEE3}\InprocServer32] @="F:\\sdksrc\\book\\x64\\Debug\\process.dll" "ThreadingModel"="Free" 
To delete the registry key from system, run following command line,
 reg delete HKEY_CLASSES_ROOT\CLSID\{EDCB2856-2E63-4F57- B3A1-F03CC7D9FEE3} /f

 

Debug

MI provider could be hosted in wmiprvse.exe process, or hosted as decoupled provider. Decoupled provider is relatively easy to debug since the host process has to start in order to host decoupled provider. By attaching to host process, you can debug the provider. This section focuses on debugging coupled provider, all break points and techniques are applicable to decoupled provider as well.

Normal debugging tools include visual studio and windbg. Following content introduces both techniques.

To debug a coupled provider, you need to

(1) Launch the provider into host process

(2) Attach to the host process

(3) set breakpoints and debug.

To launch MI provider, you may send an operation request to the MI provider (via powershell/cim cmdlets for example), the provider will be loaded into host process.

To attach to host process, you can run “tasklist –m <>.DLL” to tell which process is loading the provider. And use either windbg or visual studio 2012 attach to the process.

And then set breakpoints and you will be able to debug through. Following picture shows a snapshot of debugging EnumerateInstances method of MSFT_WindowsProcess class.

 

Debug provider Load/Class Load function

These two functions will be invoked once and only once, which were already called by the time attaching debugger to the host process. To debug these functions, debugger has to attach to host process before they get invoked. And following are the tricks,

(1) Register the provider as decoupled provider and start a host process to host the provider. This way you can attach the debugger tool to the host process to debug the provider load and class load function.

(2) Find another provider which shares the same host process with the target provider. Invoke another provider firstly will launch the host process. By attaching to the process, you will be able to set deferred breakpoints at Load and class Load function to debug.

For example, by default process.dll hosting model is NetworkServiceHost, which is the same with Cimwin32.dll. By invoking “wmic os” on any command line console, you will be able to see a wmiprvse.exe host process was launched running under NETWORKING SERVICE account. Now attach debugger to the process, and then let the process continue running. Then if invoke the process.dll provider by enumerate instances of MSFT_WindowsProcess class from powershell console, you will be able to see that process.dll is being launched in the same host process.

If you are not able to use trick 2, then try to use gflags.exe to set following debugger for image file “wmiprvse.exe”.

 cdb.exe -server tcp:port=8080 -c "g"

Then invoke the provider from powershell console, now the host process will be launched but was blocked into cdb.exe, use windbg.exe to connect to the remote debugging server, and then set interested breakpoints before hit “g”.

 windbg.exe -remote tcp:server=<server>,port=8080

Now you are able to debug Load and class Load functions.

Warning, For trick (2), you might block other host process from being launched, since cdb won’t be able to create debugger server on the same tcp port more than once.

 

 

Happy Holidays! I hope "Implementing MI Provider" blogs helps. Fell free to comment, ask questions, or email haoweiqin@outlook.com for deep discussions regarding CIM, WMI, etc.

 

Haowei Qin

Senior SDE

Standards Based Management