标题: Win10 RPC调试中RPC Client PID的利用 创建: 2021-11-19 09:52 更新: 2021-11-23 17:10 链接: https://scz.617.cn/windows/202111190952.txt -------------------------------------------------------------------------- 目录: ☆ 背景介绍 ☆ 阻断指定PID的FQDN解析 1) 获取Dnscache(DNS Client)服务所在进程PID 2) 获取Firefox PID 3) 阻止指定客户端解析指定FQDN ☆ 干扰Win10自动更新 ☆ 调试winlogon时反向溯源 ☆ 关于取RPC Client PID/TID的补充说明 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 背景介绍 Win10 RPC调试时,知道RPC Client PID是一件有意义的事。有些RPC Server中的断 点命中太过频繁,靠RPC Client PID进行过滤能有效调试。有些RPC Server调用栈回 溯中出现远程过程,想知道哪个进程发起的RPC调用,想溯源。想拦截特定进程的域 名解析,想干扰Win10的自动更新,等等。非常规需求,但大千世界芸芸众生,必有 人产生过类似需求。 本文演示一些Win10 RPC调试技术中的黑魔法,让Win10 RPC调试之旅更有趣些。 Guest环境如下 -------------------------------------------------------------------------- Win10 Win10企业版2016 LTSB 1607(OS Build 14393.4704) dnsapi.dll 10.0.14393.4350 (rs1_release.210407-2154) dnsrslvr.dll 10.0.14393.4350 (rs1_release.210407-2154) ntdll.dll 10.0.14393.4704 (rs1_release.211004-1917) rpcrt4.dll 10.0.14393.4704 (rs1_release.211004-1917) -------------------------------------------------------------------------- ☆ 阻断指定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 $t0=@r8;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" 本例阻止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 $t0=@r8;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 au.download.windowsupdate.com ctldl.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。主控台出 现新的密码输入界面时,点击残障人士按钮,触发断点,调用栈回溯如下 # Child-SP RetAddr Call Site 00 00000086`66efee08 00007ff7`90f65902 winlogon!SignalManagerSetSignal 01 00000086`66efee10 00007ff7`90f99122 winlogon!WlStateMachineSetSignal+0x2a 02 00000086`66efee40 00007ff7`90f94944 winlogon!WlAccessibilityOnWin32KMessage+0x10e 03 00000086`66efee70 00007ff7`90f7bbfd winlogon!WMsgKMessageHandler+0x18d04 04 00000086`66efeef0 00007fff`8817a583 winlogon!I_WMsgkSendMessage+0x4d 05 00000086`66efef40 00007fff`881d6162 RPCRT4!Invoke+0x73 06 00000086`66efefb0 00007fff`8814a284 RPCRT4!Ndr64AsyncServerWorker+0x392 07 00000086`66eff0d0 00007fff`8814919d RPCRT4!DispatchToStubInCNoAvrf+0x24 08 00000086`66eff120 00007fff`88149a4b RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1bd 09 00000086`66eff1f0 00007fff`881310ac RPCRT4!RPC_INTERFACE::DispatchToStub+0xcb 0a 00000086`66eff250 00007fff`8813152c RPCRT4!LRPC_SCALL::DispatchRequest+0x34c 0b 00000086`66eff330 00007fff`8811ae1c RPCRT4!LRPC_SCALL::HandleRequest+0x2bc 0c 00000086`66eff450 00007fff`8811c67b RPCRT4!LRPC_ADDRESS::HandleRequest+0x36c 0d 00000086`66eff500 00007fff`88143a2a RPCRT4!LRPC_ADDRESS::ProcessIO+0x91b 0e 00000086`66eff640 00007fff`88d0d35e RPCRT4!LrpcIoComplete+0xaa 0f 00000086`66eff6e0 00007fff`88d0ecc9 ntdll!TppAlpcpExecuteCallback+0x25e 10 00000086`66eff790 00007fff`885b84d4 ntdll!TppWorkerThread+0x8d9 11 00000086`66effb90 00007fff`88d41791 KERNEL32!BaseThreadInitThunk+0x14 12 00000086`66effbc0 00000000`00000000 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 据此确认RPC Client是LogonUI(5760)。 假设正断在winlogon!I_WMsgkSendMessage,另开cdb调试LogonUI(5760),查看 TID(0x16e4)的调用栈回溯 ~~[16e4] kn # Child-SP RetAddr Call Site 00 0000001c`f0fff428 00007fff`860b8c1f ntdll!NtWaitForMultipleObjects+0x14 01 0000001c`f0fff430 00007fff`87f7e6fb KERNELBASE!WaitForMultipleObjectsEx+0xef 02 0000001c`f0fff730 00007fff`87cd78f9 user32!MsgWaitForMultipleObjectsEx+0x15b 03 0000001c`f0fff810 00007fff`87cd8038 combase!ASTAWaitContext::KernelWait+0x59 04 0000001c`f0fff880 00007fff`87cd5cef combase!ASTAWaitContext::Wait+0x308 05 0000001c`f0fffb90 00007fff`87cd5be5 combase!ASTAWaitInNewContext+0xc3 06 0000001c`f0fffc70 00007fff`87c52acb combase!ASTAThreadWaitForHandles+0x75 07 0000001c`f0fffce0 00007fff`7dcd0952 combase!CoWaitForMultipleHandles+0xcb 08 0000001c`f0fffd20 00007fff`7dcd0e69 Windows_UI_XamlHost!ASTAThreadHost::ASTAThreadHostThreadProc+0x76 09 0000001c`f0fffda0 00007fff`85ce3fad Windows_UI_XamlHost!ASTAThreadHost::s_ASTAThreadHostThreadProc+0x19 0a 0000001c`f0fffdd0 00007fff`885b84d4 SHCORE!_WrapperThreadProc+0xed 0b 0000001c`f0fffec0 00007fff`88d41791 KERNEL32!BaseThreadInitThunk+0x14 0c 0000001c`f0fffef0 00000000`00000000 ntdll!RtlUserThreadStart+0x21 未看到想像中的RPCRT4!NdrpClientCall3,发生了什么? 这个问题当成Win10 RPC调试的课后作业留给那些永远充满好奇心的人们。有兴趣者 可以尝试回答这个问题,会让你的调试技能进阶,不用告诉我答案。 ☆ 关于取RPC Client PID/TID的补充说明 在RPC Server侧的调用栈回溯中,某些函数通过其形参可以方便地获取RPC Client PID/TID,但那些函数入口点处尚未进行RPC形参反序列化,无法直接取到RPC形参; 远程过程本身已获取RPC形参,又缺失了获取RPC Client PID/TID的途径。换句话说, 有些位置取PID/TID方便,有些位置取RPC形参方便,很少有位置取这两种信息都方便。 要想在单点位置同时获取这两种信息,只能动用上下文相关的Hacking方案。 ☆ 参考资源 [1] 《DNS系列(11)--研究Win10 FQDN解析》 https://scz.617.cn/windows/202103071208.txt [2] 《RpcView简介》 https://scz.617.cn/windows/202110270957.txt [3] 《利用findrpc寻找RPC接口信息》 https://scz.617.cn/python/202111061555.txt [4] 《Win10中rpcexts.dll已废》 https://scz.617.cn/windows/202111152036.txt [5] 《用RPC/ALPC调试手段分析Win10 FQDN解析过程》 https://scz.617.cn/windows/202111161210.txt [6] 《Win10 FQDN解析时绕过hosts文件》 https://scz.617.cn/windows/202111181224.txt