COM object provides another options to create a new process besides using common Windows APIs such as CreateProcess
or ShellExecute
.
For threat actor, the good way of this kind of process creation is that the wmiprvse.exe
will break the process chain from its parent process as it is initiated from the COM object. So the new child process spawned will have no PID chain relationship with the initiator process wmi_create_process.exe
. This will makes investigation slightly difficult.
Reproduce the PoC in C++
- Initialize the COM library by calling
CoInitializeEx
CoInitializeEx(0, COINIT_MULTITHREADED);
2. Initiate a IWbemClassObject
interface by calling CoCreateInstance
. In order to call that interface, we have to pass the correct rclsid
and riid
into CoCreateInstance
as shown as below.
REFCLSID rclsid = CLSID_WbemLocator; // Unmarshaler CLSID, 4590f811–1d3a-11d0–891f-00aa004b2e24REFIID riid = IID_IWbemLocator ; // Interface UUID, dc12a687–737f-11cf-884d-00aa004b2e24CoCreateInstance(rclsid, NULL, 1, riid, (LPVOID*)&wbemLocator);
2. Call the ConnectServer
method from interface pointer wbemLocator
. It will setting up the wbemServices
object that bounds to the namespace ROOT\\CIMV2
there.
IWbemLocator interface only have one method which is
ConnectServer
IWbemServices* wbemServices = NULL;wbemLocator->ConnectServer((BSTR)L"ROOT\\CIMV2", NULL, NULL, 0, NULL, 0, 0, &wbemServices);
3. Calling GetObject
function from wbemService
object which will retrieve information from object path Win32_ProcessStartup
.
Output will be the oWin32ProcessStartup
class object pointer.
IWbemClassObject* oWin32ProcessStartup = NULL; wbemServices->GetObject((BSTR)L"Win32_ProcessStartup", 0, NULL, &oWin32ProcessStartup, NULL);
4. SpawnInstance
create new instance of a class based on the object classoWin32ProcessStartup
retrived from the steps above.
Output pStartupInstance
class object pointer will pass into ProcessStartupInformation
(Step 9) property later.
IWbemClassObject* pStartupInstance = NULL;oWin32ProcessStartup->SpawnInstance(0, &pStartupInstance);
5. Calling GetObject
function from wbemService
object which will retrieve information from object path Win32_Process
.
Param oWin32Process
will hold the result of the function called.
IWbemClassObject* oWin32Process = NULL; wbemServices->GetObject((BSTR)L"Win32_Process", 0, NULL, &oWin32Process, NULL);
6. GetMethod
returns information about the requested method Create
from object oWin32Process
.
Param pInParamsDefinition
will hold the result of the function called.
IWbemClassObject* pInParamsDefinition = NULL; oWin32Process->GetMethod((BSTR)L"Create", 0, &pInParamsDefinition, NULL);
7. SpawnInstance
called by pInParamsDefinition
object to create new instance of a class which will pass into ExecMethod
class later.
Output pParamsInstance
class object pointer will pass into ExecMethod
function later.
IWbemClassObject* pParamsInstance = NULL;pInParamsDefinition->SpawnInstance(0, &pParamsInstance);
8. Setting up CommandLine
property in pParamsInstance
object.
VARIANT varCommand;
VariantInit(&varCommand);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = wcCommandExecute; // Your command line here pParamsInstance->Put((BSTR)L"CommandLine", 0, &varCommand, 0);
9. Setting up ProcessStartupInformation
property in pParamsInstance
object.
VARIANT vtDispatch;
VariantInit(&vtDispatch);
vtDispatch.vt = VT_DISPATCH;
vtDispatch.byref = pStartupInstance; // From step 4
pParamsInstance->Put((BSTR)L"ProcessStartupInformation", 0, &vtDispatch, 0);
10. Spawn the new process by calling ExecMethod
from wbemServices
with Win32_Process
object path and Create
method with a predefined pParamsInstance
object from steps above.
IWbemClassObject* pOutParams = NULL; wbemServices->ExecMethod((BSTR)L"Win32_Process", (BSTR)L"Create", 0, NULL, pParamsInstance, &pOutParams, NULL);
Extra
You can refer to the full source code and the Ghidra decompiled code which is quite useful when reversing the malware that use this kind of technique to spawn new process.
Full Source Code
Ghidra Decompiled Code