调用CreateService()创建服务会被360拦截。用Rpc接口创建服务就能绕过。

srv-2.png

SCMR

pipe protocol uuid IDL file
\\pipe\svcctl MS-SCMR {367ABB81-9844-35F1-AD32-98F038001003} 微软官方文档

SCMR(Service Control Manager Remote Protocol)是基于RPC的协议,用于配置和控制远程计算机上运行的服务程序。该协议维护一个内部数据库来存储服务程序配置和状态。服务控制管理器协议对该内部数据库具有独占访问权。

在一个操作系统实例上只有一个 SCM 和一个对应的 SCM 数据库。对此内部数据库的任何更新都只能通过服务控制管理器远程协议进行。SCM 负责序列化对 SCM 数据库的所有并发访问。SCM数据库常驻内存;每次 SCM 重新启动时(每次重新启动后)都会重新创建它。SCM 数据库的一部分是从持久存储(有关注册服务的所有信息)和部分非持久存储(服务的当前活动状态)中检索的。

当添加、配置服务时,持久性信息由 SCM 修改,或删除。任何直接在持久化存储中直接修改数据库持久化部分的尝试都是不支持的场景,并且会导致可能的不一致。最后,如果 SCM 被强制终止,操作系统将关闭并重新启动。

通俗地说服务是存放在系统维护的SCM数据库里面的,我们调用创建、删除服务的函数都是对数据库的操作。SCMR对应的Rpc接口为\\pipe\svcctl,根据微软描述,SCMR没有标准分配,只有 Microsoft 使用其他协议中指定的分配程序进行的私有分配。也就是说,RpcView里面是看不见这个Rpc接口的

srv-3.png

微软在其官方文档中提供了该协议的操作示例

srv-4.png

Demo代码

基于上述假设编写测试代码。将微软提供的IDL代码保存为scmr.idl,同时微软还提到该IDL还依赖ms-dtyp.idl,都将其保存下来并编译。因为是Rpc客户端,我们只需要scmr.idl编译生成的scmr_c.cscmr_h.h,和ms-dtyp.idl编译生成的ms-dtyp_h.h相关代码。最后的文件如下图

srv-5.png

导入完成之后需要修复一些编译上的错误,“类型重定义错误”将相关代码代码注释就能解决。

“无法解析外部符号”需要添加rpcrt4.lib,添加代码如下

#pragma comment(lib, "rpcrt4.lib")

void __RPC_FAR* __RPC_USER MIDL_user_allocate (size_t size)
{
    return HeapAlloc (GetProcessHeap (), 0, size);
}

void __RPC_USER MIDL_user_free (void* p)
{
    HeapFree (GetProcessHeap (), 0, p);
}

之后main函数中导入scmr_h.h就可以调用ROpenSCManagerW()RCreateService()函数创建服务

srv-6.png

编译,在装有火绒的虚拟机上试试看。结果如下图,代码可以运行,证明我们的思路是对的,后面就是启动服务并运行了。

为什么选火绒?因为360太卡了。

srv-7.png

启动服务调用的函数顺序为:

  1. ROpenSCManagerW()打开SCM管理器
  2. ROpenServiceW()打开指定服务句柄
  3. RStartServiceW()启动服务

关键代码如下:

    SC_RPC_HANDLE schSCManager = nullptr;
    ROpenSCManagerW (NULL, NULL, SC_MANAGER_ALL_ACCESS, (SC_RPC_HANDLE*)&schSCManager);

    SC_RPC_HANDLE hService = nullptr;
    ROpenServiceW (schSCManager,
                   (LPWSTR)L"TestServiceName",
                   SC_MANAGER_ALL_ACCESS,
                   &hService);

    RStartServiceW (hService, 0, nullptr);

	// 最后关闭句柄
    RCloseServiceHandle ((LPSC_RPC_HANDLE)hService);

编译运行,结果没有如预期那样正确,notepad程序启动成功,但是服务程序崩溃,控制台返回错误代码1053(服务未及时响应启动或控制请求)。究其原因,是因为服务在启动的时候需要进行初始化(默认30s),超时则会返回1053错误,而我们的服务程序是直接调用了系统的notepad,notepad并不是正常的服务程序。

此时如果我们手动启动TestService服务,Process Hacker会卡住大概30秒,然后返回"服务没有及时响应启动或控制请求"错误提示,notepad会在服务停止之后关闭。

srv-8.png

有两个解决方案,一种是使用cmd /k notepad.exe的形式启动服务程序;另一种是写一个正常的服务程序,创建服务启动服务程序并让其调用notepad.exe。

第一种方案只需要将RCreateServiceW()函数中lpBinaryPathName参数的值修改为cmd /k C:\\Windows\\System32\\notepad.exe就可以了。

第二种方案也不难,网上有现成的服务程序模板代码直接拿过来改。完成之后再启动服务就正常了。

srv-9.png

武器化

题外话

sc.exe sdset test "D:(D;;DCLCWPDTSDCC;;;IU)(D;;DCLCWPDTSDCC;;;SU)(D;;DCLCWPDTSDCC;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"