Win10 RPC调试中RPC Client PID的利用
2021-11-24 00:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:50 收藏

创建: 2021-11-19 09:52
更新: 2021-11-23 17:10
http://scz.617.cn:8/windows/202111190952.txt

目录


☆ 背景介绍

Win10 RPC调试时,知道RPC Client PID是一件有意义的事。有些RPC Server中的断点命中太过频繁,靠RPC Client PID进行过滤能有效调试。有些RPC Server调用栈回溯中出现远程过程,想知道哪个进程发起的RPC调用,想溯源。想拦截特定进程的域名解析,想干扰Win10的自动更新,等等。非常规需求,但大千世界芸芸众生,必有人产生过类似需求。

本文演示一些Win10 RPC调试技术中的黑魔法,让Win10 RPC调试之旅更有趣些。

☆ 阻断指定PID的FQDN解析

Win10 FQDN解析绝大多数时候都要过dnsrslvr!R_ResolverQuery,在Dnscahce服务中。对于ping这样转瞬即逝的进程,一般不易提前获知其PID,从而不易在Dnscahce服务中对ping的PID进行过滤,本小节不考虑这种情形,只考虑常驻进程的FQDN解析。

1) 获取Dnscache(DNS Client)服务所在进程PID

tasklist /svc /fi "services eq dnscache"

假设是svchost(564)。

2) 获取Firefox PID

打开Firefox,Process Explorer查看之,居然开了6个进程,1个父进程5个子进程,只有父进程(5384)有GUI。用Firefox访问"www.baidu.com",用Tcpview查看TCP连接,5384有到百度的长连接,但这不足以说明FQDN解析之RPC请求由5384发起,理论上可能有其他子进程参与其中。

假设事先并不清楚Firefox架构,应该用其他手段确认FQDN解析之RPC请求由5384发起,比如ALPCLogger,或直接上调试器。顺便期待一下,哪天Process Monitor支持ALPC ETW就好了,把ALPCLogger的功能揉进来。

3) 阻止指定客户端解析指定FQDN

dnsrslvr!R_ResolverQuery的形参中有FQDN,可以对FQDN进行过滤,但该函数形参中没有RPC Client PID。也可能通过某个形参可以间接获取RPC Client PID,只是我没逆向分析出来。

做了其他角度的逆向分析后,发现在dnsrslvr!R_ResolverQuery入口点

qwo(poi(@r12+0x68)+8)       // 可能是RPC Client PID
qwo(poi(@r12+0x68)+0x10)    // 可能是RPC Client TID

这是调用栈中某些底层函数留下的内存残像,与具体汇编代码相关。如遇不适用的情形,有兴趣者可自行逆向适配。

可在dnsrslvr!R_ResolverQuery入口点对PID、FQDN同时进行过滤,匹配时将FQDN替换成".",这将导致FQDN解析失败。

bp dnsrslvr!R_ResolverQuery "r [email protected];r $t1=poi(@r12+0x68);
.if(qwo(@$t1+8)==0n5384 and qwo(@$t0)==0x2e007700770077 and
qwo(@$t0+8)==0x64006900610062 and qwo(@$t0+0x10)==0x6f0063002e0075 and
by(@$t0+0x18)=0x6d){ezu @$t0 \".\"}.else{du @$t0};gc"

为显示方便,上面这个断点做了折行处理,在cdb中使用时,请恢复成一行。

本例阻止Firefox(5384)解析"www.baidu.com",Firefox(5384)可以解析其他FQDN,其他进程可以正常解析任意FQDN(包括百度)。上例断点条件未使用字符串比较技巧,所以显得很野蛮,自用时换字符串比较好了。

在这个位置取RPC Client PID是Hacking方案,上下文相关,切勿用于产品。

☆ 干扰Win10自动更新

靠前述获取PID的黑魔法观察wuauserv服务发起的FQDN解析。wuauserv服务与很多其他服务共用svchost(872),理论上只过滤PID不够,但其他服务产生的干扰可以忽略。

$ tasklist /svc /fi "services eq wuauserv"

Image Name                     PID Services
========================= ======== ============================================
svchost.exe                    872 Appinfo, BITS, CertPropSvc, DoSvc, DsmSvc,
                                   gpsvc, IKEEXT, iphlpsvc, lfsvc, ProfSvc,
                                   Schedule, seclogon, SENS, SessionEnv,
                                   Themes, UserManager, UsoSvc, Winmgmt,
                                   wisvc, wlidsvc, WpnService, wuauserv

Wireshark抓包当然是可以的,只是干扰更多,不如调试器里直接过滤PID来得爽。

调试svchost(564)

bp dnsrslvr!R_ResolverQuery "r [email protected];r $t1=poi(@r12+0x68);du @$t0;.if(qwo(@$t1+8)==0n872){}.else{? qwo(@$t1+8);? qwo(@$t1+0x10);gc}"

RPC Client PID是svchost(872)时断下,看到若干FQDN,比如

sls.update.microsoft.com
fe2.update.microsoft.com
download.windowsupdate.com

可以搞个条件断点,发现svchost(872)试图解析"download.windowsupdate.com"时将FQDN替换成"."。之后Guest的"Checking for updates"报错

There were some problems installing updates, but we'll try again later. If you keep seeing this and want to search the web or contact support for information, this may help: (0x8024402f)

阻止Win10自动更新有略显"正经"的其他办法,此处只是用它演示RPC调试黑魔法。有些缺乏经验者,在此可能设问,在hosts中将"download.windowsupdate.com"解析成"127.0.0.1"不就得了,可以自己试试再说。假设能上调试器,可以热Patch绕过微软域名保护,有兴趣者不妨调试一下。

☆ 调试winlogon时反向溯源

有次调试主控台winlogon进程,设断winlogon!SignalManagerSetSignal。主控台出现新的密码输入界面时,点击残障人士按钮,触发断点,调用栈回溯如下

 # Call Site
00 winlogon!SignalManagerSetSignal
01 winlogon!WlStateMachineSetSignal+0x2a
02 winlogon!WlAccessibilityOnWin32KMessage+0x10e
03 winlogon!WMsgKMessageHandler+0x18d04
04 winlogon!I_WMsgkSendMessage+0x4d
05 RPCRT4!Invoke+0x73
06 RPCRT4!Ndr64AsyncServerWorker+0x392
07 RPCRT4!DispatchToStubInCNoAvrf+0x24
08 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1bd
09 RPCRT4!RPC_INTERFACE::DispatchToStub+0xcb
0a RPCRT4!LRPC_SCALL::DispatchRequest+0x34c
0b RPCRT4!LRPC_SCALL::HandleRequest+0x2bc
0c RPCRT4!LRPC_ADDRESS::HandleRequest+0x36c
0d RPCRT4!LRPC_ADDRESS::ProcessIO+0x91b
0e RPCRT4!LrpcIoComplete+0xaa
0f ntdll!TppAlpcpExecuteCallback+0x25e
10 ntdll!TppWorkerThread+0x8d9
11 KERNEL32!BaseThreadInitThunk+0x14
12 ntdll!RtlUserThreadStart+0x21

知道winlogon会RPC出去,没想到还有其他进程RPC到winlogon,想溯这个RPC的源。

bp winlogon!I_WMsgkSendMessage "r $t1=poi(@r12+0x68);? qwo(@$t1+8);? qwo(@$t1+0x10)"

Evaluate expression: 5760 = 00000000`00001680
Evaluate expression: 5860 = 00000000`000016e4

据此确认上述IID、ProcNum的RPC Client是LogonUI(5760)。

假设正断在winlogon!I_WMsgkSendMessage,另开cdb调试LogonUI(5760),查看TID(0x16e4)的调用栈回溯

~~[16e4] kn

 # Call Site
00 ntdll!NtWaitForMultipleObjects+0x14
01 KERNELBASE!WaitForMultipleObjectsEx+0xef
02 user32!MsgWaitForMultipleObjectsEx+0x15b
03 combase!ASTAWaitContext::KernelWait+0x59
04 combase!ASTAWaitContext::Wait+0x308
05 combase!ASTAWaitInNewContext+0xc3
06 combase!ASTAThreadWaitForHandles+0x75
07 combase!CoWaitForMultipleHandles+0xcb
08 Windows_UI_XamlHost!ASTAThreadHost::ASTAThreadHostThreadProc+0x76
09 Windows_UI_XamlHost!ASTAThreadHost::s_ASTAThreadHostThreadProc+0x19
0a SHCORE!_WrapperThreadProc+0xed
0b KERNEL32!BaseThreadInitThunk+0x14
0c ntdll!RtlUserThreadStart+0x21

未看到想像中的RPCRT4!NdrpClientCall3,发生了什么?

这个问题当成Win10 RPC调试的课后作业留给那些永远充满好奇心的人们。有兴趣者可以尝试回答这个问题,会让你的调试技能进阶,不用告诉我答案。

☆ 关于取RPC Client PID/TID的补充说明

在RPC Server侧的调用栈回溯中,某些函数通过其形参可以方便地获取RPC ClientPID/TID,但那些函数入口点处尚未进行RPC形参反序列化,无法直接取到RPC形参;远程过程本身已获取RPC形参,又缺失了获取RPC Client PID/TID的途径。换句话说,有些位置取PID/TID方便,有些位置取RPC形参方便,很少有位置取这两种信息都方便。要想在单点位置同时获取这两种信息,只能动用上下文相关的Hacking方案。

☆ 参考资源


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247484966&idx=1&sn=59ff70986f63c47f252d7a55ce4bdb04&chksm=fab2c519cdc54c0f8a8688d13f8c067e3d6748a0f342428cab85ef051691ee05addb1abe57c7#rd
如有侵权请联系:admin#unsafe.sh