首页
社区
课程
招聘
[原创]RE: Hijack the rpc of services
2019-5-4 15:40 11599

[原创]RE: Hijack the rpc of services

2019-5-4 15:40
11599

       从操作系统的角度来说,自身集成了很多组件服务然后提供出一些调用标准供开发者使用。那么在Windows中,最常见的莫过于com组件和rpc调用了。本文主要分享的主题也就是rpc的相关劫持,相信独立写过IPC的同学都不会对rpc陌生,进程间通信方法中rpc的效率相对于其他方式有着明显的优势,而且也是Windows操作系统内部比较常用的通信方式。然而对于如何使用rpc微软官方也没有提供多少文档,尤其是在其通信标准和通信方式上,比如在通信方式上的管道、Socket以及AlpcPort/Port的协议选择,又或者是同步方式与异步方式的调用选择上都存在着一些门槛。然而本文并不是来跟大家讨论如何用rpc去做进程间通信的,而是想带大家了解下Windows操作系统内部使用rpc的部分组件并且实现对之劫持。

0x01 起源

        作者在总结出结论之前,最初也是因为对某些厂商在Windows系统服务层面的HIPS技术产生了浓厚的兴趣才去研究的。多半的应用层代码也是逆向自某产品的一个小模块。作者并没有其他企图,只是作为学习和成长的一个途径去研究这个课题而已。对这个模块研究完之后得到这样的结论:

       1. 对服务的创建/修改的HIPS并不是内核级别的注册表拦截,而是注入到services.exe进行的暗地操作;

       2. 这个应用层模块劫持了RPCRT4.dll的一些函数,即RPC Server的注册流程,同步式与内核模块实现阻断规则;

       3. services.exe具有相对较高的TOKEN令牌,很方便就可以获得到Client端的属性信息。
那么接下来就按照这个思路,自己进行一些尝试。

0x02 相关结构体

       如果是这方面的新手,建议跳转RPCDemo学习下。
       构建一个自己的rpc,首先需要一个idl接口描述,然后使用MIDL工具生成对应的客户端以及服务端的Stub文件。

服务端:
RPCRTAPI
RPC_STATUS
RPC_ENTRY
RpcServerRegisterIf (
    _In_ RPC_IF_HANDLE IfSpec,
    _In_opt_ UUID __RPC_FAR * MgrTypeUuid,
    _In_opt_ RPC_MGR_EPV __RPC_FAR * MgrEpv
    );

typedef void __RPC_FAR * RPC_IF_HANDLE;

服务端需要进行注册,最为主要的结构为 RPC_IF_HANDLE,在服务端,这个指针结构为:

typedef struct _RPC_SERVER_INTERFACE
{
    unsigned int Length;
    RPC_SYNTAX_IDENTIFIER InterfaceId;
    RPC_SYNTAX_IDENTIFIER TransferSyntax;
    PRPC_DISPATCH_TABLE DispatchTable;
    unsigned int RpcProtseqEndpointCount;
    PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint;
    RPC_MGR_EPV __RPC_FAR *DefaultManagerEpv;
    void const __RPC_FAR *InterpreterInfo;
    unsigned int Flags ;
} RPC_SERVER_INTERFACE, __RPC_FAR * PRPC_SERVER_INTERFACE;

然后需要关注的并不是 DispatchTable ,而是 InterpreterInfo 成员,它其实是:

typedef struct  _MIDL_SERVER_INFO_
    {
    PMIDL_STUB_DESC                     pStubDesc;
    const SERVER_ROUTINE     *          DispatchTable;
    PFORMAT_STRING                      ProcString;
    const unsigned short *              FmtStringOffset;
    const STUB_THUNK *                  ThunkTable;
    PRPC_SYNTAX_IDENTIFIER              pTransferSyntax;
    ULONG_PTR                           nCount;
    PMIDL_SYNTAX_INFO                   pSyntaxInfo;
    } MIDL_SERVER_INFO, *PMIDL_SERVER_INFO;

这里的 DispatchTable 才是我们所关心的位置。那么对于Windows的关键进程services.exe,可以看到他内部的一些逻辑:

140072320实际上就是 RPC_SERVER_INTERFACE 结构,我们可以发现 InterpreterInfo 是在140073D10的位置

140073D10 结构为 MIDL_SERVER_INFO ,第二个成员即为服务端的DispatchTable

于是看到了这么多跟服务相关的函数表,那么劫持这张表里的关键点就可以达到预期

0x03 逆推实现

       由于RPCRT4.dll在不同版本中提供了不同的服务注册接口,存在一些兼容问题,那么没办法,只有把可能途经访问到的函数都做一下劫持。

劫持点如下标出,顺序为低版本到高版本:

RPC_STATUS RPC_ENTRY RpcEpRegisterW(
    RPC_IF_HANDLE      IfSpec,
    RPC_BINDING_VECTOR *BindingVector,
    UUID_VECTOR        *UuidVector,
    RPC_WSTR           Annotation
    )


RPC_STATUS RPC_ENTRY RpcServerRegisterIfEx(
    RPC_IF_HANDLE      IfSpec,
    UUID               *MgrTypeUuid,
    RPC_MGR_EPV        *MgrEpv,
    unsigned int       Flags,
    unsigned int       MaxCalls,
    RPC_IF_CALLBACK_FN *IfCallback
    )


RPC_STATUS RPC_ENTRY RpcServerRegisterIf3(
    RPC_IF_HANDLE      IfSpec,
    UUID               *MgrTypeUuid,
    RPC_MGR_EPV        *MgrEpv,
    unsigned int       Flags,
    unsigned int       MaxCalls,
    unsigned int       MaxRpcSize,
    RPC_IF_CALLBACK_FN *IfCallback,
    void               *SecurityDescriptor
    )

在注册过程中有一个最为明显的特征,可以标识出是我们想要的RPC组件服务进行了注册,就是IfSpec->InterfaceId.SyntaxGUID,本文讨论的这个GUID,目前为止还都是同一个:0x367ABB81, 0x9844, 0x35F1, 0xAD, 0x32, 0x98, 0xF0, 0x38, 0x00, 0x10, 0x03

即 {367ABB81-9844-35F1-AD32-98F038001003}。


劫持了一些我们感兴趣的RPC函数之后,却还有一个大的问题,那就是怎么拿到客户端的进程/线程信息~

幸运的是,RPCRT4.dll提供了一些函数,可以很方便的查到客户端是谁,I_RpcOpenClientThread, I_RpcOpenClientProcess。

而且services.exe的TOKEN所在组(应该是属于Admin),没有拒绝TOKEN的问题,但是换到一些低权限组那没办法,只能用一些别的方法了~


使用 I_RpcOpenClientThread / I_RpcOpenClientProcess时注意DesiredAccess不要太高就行,要啥权限就写啥权限,一般而言QUERY_INFORMATION就行。

详细的实现部分就不继续说了,见附件内容。



[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2019-5-5 13:33 被FaEry编辑 ,原因:
上传的附件:
收藏
点赞5
打赏
分享
最新回复 (22)
雪    币: 5023
活跃值: (2521)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
FaEry 6 2019-5-4 15:41
2
0
占楼层备用
最后于 2019-5-5 13:33 被FaEry编辑 ,原因:
雪    币: 78
活跃值: (1443)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Archar 2019-5-4 18:22
3
0
ding
雪    币: 89
活跃值: (274)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
红色神话 2019-5-4 18:34
4
0
没密码?
雪    币: 5023
活跃值: (2521)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
FaEry 6 2019-5-4 19:05
5
0
红色神话 没密码?
密码:97396
最后于 2019-5-5 09:56 被FaEry编辑 ,原因:
雪    币: 9171
活跃值: (2051)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
PPTV 2019-5-4 22:07
6
0
Hijack the rpc of services
雪    币: 6590
活跃值: (3020)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
asd 2019-5-4 23:21
7
0
支持一个 rpc资料太少了
雪    币: 4006
活跃值: (596)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
放学打我不 1 2019-5-5 01:27
8
0
密码错误?
雪    币: 17
活跃值: (283)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 1 2019-5-5 10:09
9
0
那个厂家?
雪    币: 253
活跃值: (497)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
chengqiyan 2019-5-11 17:24
10
0
win7测试无效..init HOOK成功 不进入自己的HOOK函数
最后于 2019-5-11 17:25 被chengqiyan编辑 ,原因:
雪    币:
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
德罗巴 2019-7-19 09:25
11
0
chengqiyan win7测试无效..init HOOK成功 不进入自己的HOOK函数
我测试的也无效,加了一个RpcServerRegisterIf的Hook也不行,不知道是不是注入的时候已经注册完毕了,按文章中的意思好像是每次创建服务都会有RPC Server注册?那不应该不走回调函数啊,求楼主大神进一步讲解一下,那个GUID是标识什么的也不是很懂
雪    币: 5023
活跃值: (2521)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
FaEry 6 2019-7-19 10:02
12
0
德罗巴 我测试的也无效,加了一个RpcServerRegisterIf的Hook也不行,不知道是不是注入的时候已经注册完毕了,按文章中的意思好像是每次创建服务都会有RPC Server注册?那不应该不走回调函 ...
......services.exe刚初始化的时候才会执行 这个rpc服务组件的注册,GUID就是组件的标识啊
雪    币: 17
活跃值: (283)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 1 2019-7-20 09:03
13
0
服务重定向一般都是做一个dummy sevice,实现所有服务接口。在这一层做权限控制。
雪    币: 50
活跃值: (36)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小乔xiaoqiao 2019-7-20 10:18
14
0
NtAlpcSendWaitReceivePort这个函数,楼主研究过吗
雪    币: 5023
活跃值: (2521)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
FaEry 6 2019-7-22 11:09
15
0
小乔xiaoqiao NtAlpcSendWaitReceivePort这个函数,楼主研究过吗
没研究过,rpc貌似就是用的这一类的API
雪    币: 3019
活跃值: (1159)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
zhouws 2 2019-7-22 12:00
16
0
看到楼主研究这个东西有点熟悉啊,特意找了下我大概7,8年前的文章。当时是可以过360的,不知道现在还有没效。楼主可以试下
雪    币: 83
活跃值: (1052)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
killpy 2 2019-7-23 13:09
17
0
这个能用来干啥?获取客户端线程 方法很多 没必要这样吧
雪    币:
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
德罗巴 2019-8-2 10:49
18
0
FaEry ......services.exe刚初始化的时候才会执行 这个rpc服务组件的注册,GUID就是组件的标识啊[em_88]
嗯嗯嗯,我想Hook RCreatSrtvices之类的函数来达到监控服务创建的目的,但是很难在services.exe刚初始化的时候就Hook呀,一开机就已经注册完了,我只能手动去找那个全局表的地址偏移了,根据系统版本选择不同的偏移量,来替换表中的API地址完成Hook,不知道这样稳不稳定
雪    币: 149
活跃值: (2058)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
saloyun 2020-2-29 10:32
19
0
mark
雪    币: 181
活跃值: (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Private丶 2020-11-16 15:34
20
0
注入时机应该是什么时候呢?ScEnableRpcInterface 这个函数应该只会调用一次吧,如何在调用ScEnableRpcInterface之前注入并Hook ?
雪    币: 2306
活跃值: (3412)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
Cc28256 3 2020-12-30 16:02
21
0
zhouws 看到楼主研究这个东西有点熟悉啊,特意找了下我大概7,8年前的文章。当时是可以过360的,不知道现在还有没效。楼主可以试下
老哥,这个截图的文章工程地址有吗,文章加密码了我看不见
雪    币: 181
活跃值: (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Private丶 2021-3-11 16:11
22
0
楼主这个方式是可行的,我已经试验成功了。不过楼主这种思路对注入时机有要求,需要services.exe在调用注册rpc接口那几个api之前就已经注入了。
这两天在考虑怎么优化这种方式,看了下nt5的源码,以及上面说的RPCDemo。我的思路是,在services.exe的数据段搜索那个特定的GUID,一旦找到,即找到了 RPC_SERVER_INTERFACE 那个结构体。接下来的方式都是一样的,劫持那张函数表。
雪    币: 5023
活跃值: (2521)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
FaEry 6 2021-3-15 10:37
23
0
Private丶 楼主这个方式是可行的,我已经试验成功了。不过楼主这种思路对注入时机有要求,需要services.exe在调用注册rpc接口那几个api之前就已经注入了。 这两天在考虑怎么优化这种方式,看了下nt5的 ...
是的,后加载的话靠特征可以做到的
游客
登录 | 注册 方可回帖
返回