标题: Win10 FQDN解析时绕过hosts文件 创建: 2021-11-18 12:24 更新: 链接: https://scz.617.cn/windows/202111181224.txt Guest的hosts文件中有一条 127.0.0.1 geo2.adobe.com ping它时确实解析成127地址。现在想通过调试手段达成一种效果,绕过hosts文件, 使得ping时看到真实IP。有人要问,直接删掉hosts中相关条目不就是了?不错,有 化繁为简的心智,后面的内容不用看了。 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) -------------------------------------------------------------------------- 参看 《DNS系列(11)--研究Win10 FQDN解析》 https://scz.617.cn/windows/202103071208.txt 《用RPC/ALPC调试手段分析Win10 FQDN解析过程》 https://scz.617.cn/windows/202111161210.txt Win10 FQDN解析绝大多数时候都要过dnsrslvr!R_ResolverQuery,在Dnscahce服务中。 参看 https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsquery_w https://docs.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryex https://docs.microsoft.com/en-us/windows/win32/api/windns/ns-windns-dns_query_request https://docs.microsoft.com/en-us/windows/win32/dns/dns-constants 可从DNSAPI!DnsQuery_W、DNSAPI!DnsQueryEx等函数推测dnsrslvr!R_ResolverQuery 部分形参。下面是逆向工程得到的dnsrslvr!R_ResolverQuery函数原型,不一定靠谱, 但就原始需求而言,够用了。 -------------------------------------------------------------------------- dnsrslvr!R_ResolverQuery ( a1, // rcx a2, // rdx /* * FQDN */ LPWSTR pwsName, // r8 /* * DNS Record Types * * DNS_TYPE_A(1) * DNS_TYPE_AAAA(0x1c) */ WORD wType, // r9 a5, // poi(@rsp+0x28) /* * 该值为TRUE时,不调用dnsrslvr!Cache_GetRecordsForRpc,忽略所有 * DNS Cahce条目 */ BOOL BypassCache, // poi(@rsp+0x30) a7, // poi(@rsp+0x38) /* * DNS Query Options * * DNS_QUERY_BYPASS_CACHE(8) * DNS_QUERY_NO_HOSTS_FILE(0x40) * * "*pOptions"为0x48时,不调用dnsrslvr!Cache_GetRecordsForRpc * "*pOptions"为0x40时,忽略DNS Cache中源自hosts文件的条目 * "*pOptions"为0x8时,忽略DNS Cache中非源自hosts文件的条目 * * 该参与BypassCache互不相干,但都能达到绕过hosts文件的效果 */ PDWORD pOptions, // poi(@rsp+0x40) a9, // poi(@rsp+0x48) a10 // poi(@rsp+0x50) ) -------------------------------------------------------------------------- 在Guest中确定Dnscache(DNS Client)服务所在进程PID $ tasklist /svc /fi "services eq dnscache" Image Name PID Services ========================= ======== ============================================ svchost.exe 564 CryptSvc, Dnscache, LanmanWorkstation, NlaSvc, TermService 调试Guest的svchost(564),设置条件断点 bp dnsrslvr!R_ResolverQuery "r $t0=@r8;.if(qwo(@$t0)==0x32006f00650067 and qwo(@$t0+8)==0x6f00640061002e and qwo(@$t0+0x10)==0x63002e00650062 and dwo(@$t0+0x18)==0x6d006f){kpn}.else{du @$t0;gc}" FQDN是"geo2.adobe.com"时断下,否则显示FQDN后继续。dnsrslvr!R_ResolverQuery 会被频繁命中,若不设过滤条件,无法有效调试。 先在Guest中修改hosts,注释掉"127.0.0.1 geo2.adobe.com"。然后在Guest中 "ping geo2.adobe.com"触发上述断点,停在dnsrslvr!R_ResolverQuery入口。在 Guest中用Process Monitor监控svchost(564)的的网络行为。回到cdb中,gu让 dnsrslvr!R_ResolverQuery正常执行,这会触发53/UDP通信,Process Monitor中查 看UDP通信的调用栈回溯。 -------------------------------------------------------------------------- 0 ntoskrnl.exe EtwpTraceNetwork+0x60 0xfffff802b7e2bf5c 1 tcpip.sys UdpSendMessagesOnPathCreation+0xcd3 0xfffff8054d82bb53 2 tcpip.sys UdpSendMessages+0x1f3 0xfffff8054d82a083 3 tcpip.sys UdpTlProviderSendMessagesCalloutRoutine+0x15 0xfffff8054d829e85 4 ntoskrnl.exe KeExpandKernelStackAndCalloutInternal+0x85 0xfffff802b7cb0c25 5 tcpip.sys UdpTlProviderSendMessages+0x6c 0xfffff8054d80314c 6 afd.sys AfdFastDatagramSend+0x543 0xfffff8054e6aa673 7 afd.sys AfdFastIoDeviceControl+0x15ed 0xfffff8054e69309d 8 ntoskrnl.exe IopXxxControlFile+0x7e1 0xfffff802b8013ed1 9 ntoskrnl.exe NtDeviceIoControlFile+0x56 0xfffff802b80136e6 10 ntoskrnl.exe KiSystemServiceCopyEnd+0x13 0xfffff802b7d75103 11 ntdll.dll NtDeviceIoControlFile+0x14 0x7fff88d95d64 12 mswsock.dll MSAFD_WSPSendMsg+0x37d 0x7fff84a989fd 13 mswsock.dll WSPIoctl+0x7f0 0x7fff84a949f0 14 WS2_32.dll WSAIoctl+0x1be 0x7fff87efb5de 15 WS2_32.dll WSASendMsg+0x112 0x7fff87efaf72 16 DNSAPI.dll Send_MessagePrivateEx+0x2c8 0x7fff848394c8 17 DNSAPI.dll sendUsingServerInfo+0x6b 0x7fff84838e8b 18 DNSAPI.dll sendUdpToNextDnsServers+0x180 0x7fff84838d20 19 DNSAPI.dll Send_AndRecvUdpWithParam+0x27c 0x7fff8483868c 20 DNSAPI.dll Send_AndRecv+0x1c2 0x7fff848377a2 21 DNSAPI.dll Query_Wire+0x4ef 0x7fff8483748f 22 DNSAPI.dll Query_SingleNamePrivate+0x6da 0x7fff848336da 23 DNSAPI.dll Query_SingleNameDualAddr+0xf6 0x7fff84835446 24 DNSAPI.dll Query_NextName+0x38b 0x7fff8482d93b 25 DNSAPI.dll Query_Main+0x904 0x7fff848315e4 26 dnsrslvr.dll ResolverQuery+0x103 0x7fff7c354863 27 dnsrslvr.dll R_ResolverQuery+0x233 0x7fff7c354733 28 RPCRT4.dll Invoke+0x73 0x7fff8817a583 29 RPCRT4.dll Ndr64AsyncServerWorker+0x392 0x7fff881d6162 30 RPCRT4.dll DispatchToStubInCNoAvrf+0x24 0x7fff8814a284 31 RPCRT4.dll RPC_INTERFACE::DispatchToStubWorker+0x1bd 0x7fff8814919d 32 RPCRT4.dll RPC_INTERFACE::DispatchToStub+0xcb 0x7fff88149a4b 33 RPCRT4.dll LRPC_SCALL::DispatchRequest+0x34c 0x7fff881310ac 34 RPCRT4.dll LRPC_SCALL::HandleRequest+0x2bc 0x7fff8813152c 35 RPCRT4.dll LRPC_ADDRESS::HandleRequest+0x36c 0x7fff8811ae1c 36 RPCRT4.dll LRPC_ADDRESS::ProcessIO+0x91b 0x7fff8811c67b 37 RPCRT4.dll LrpcIoComplete+0xaa 0x7fff88143a2a 38 ntdll.dll TppAlpcpExecuteCallback+0x25e 0x7fff88d0d35e 39 ntdll.dll TppWorkerThread+0x8d9 0x7fff88d0ecc9 40 KERNEL32.DLL BaseThreadInitThunk+0x14 0x7fff885b84d4 41 ntdll.dll RtlUserThreadStart+0x21 0x7fff88d41791 -------------------------------------------------------------------------- 结合其他调试分析,一个简化版调用栈回溯如下 -------------------------------------------------------------------------- dnsrslvr!R_ResolverQuery dnsrslvr!R_ResolverQuery+0x22e dnsrslvr!ResolverQuery dnsrslvr!ResolverQuery+0xfd DNSAPI!Query_Main DNSAPI!Query_Main+0x8ff DNSAPI!Query_NextName DNSAPI!Query_NextName+0x386 DNSAPI!Query_SingleNameDualAddr DNSAPI!Query_SingleNameDualAddr+0xf1 DNSAPI!Query_SingleNamePrivate DNSAPI!Query_SingleNamePrivate+0xee ntdll!LdrpDispatchUserCallTarget dnsrslvr!Cache_Query dnsrslvr!Cache_Query+0x27 // cmp al,48h // 检查Options // DNS_QUERY_BYPASS_CACHE、DNS_QUERY_NO_HOSTS_FILE同时置位时 // 返回FALSE,不调用dnsrslvr!Cache_GetRecordsForRpc dnsrslvr!Cache_Query+0x3c // cmp dword ptr [rcx+120h],edi // 检查BypassCache // 为TRUE时返回FALSE,不调用dnsrslvr!Cache_GetRecordsForRpc dnsrslvr!Cache_Query+0xa6 dnsrslvr!Cache_GetRecordsForRpc dnsrslvr!Cache_GetRecordsForRpc+0x14f dnsrslvr!Cache_FindEntry // du @rcx // 在DNS Cache中寻找FQDN dnsrslvr!Cache_GetRecordsForRpc+0x1d0 // test byte ptr [r14+14h],40h // 0x40置位时表示该DNS Cache条目来自hosts文件 dnsrslvr!Cache_GetRecordsForRpc+0x1db // test dil,8 // 检查Options // DNS_QUERY_BYPASS_CACHE(8)置位时 // 忽略DNS Cache中非源自hosts文件的条目 dnsrslvr!Cache_GetRecordsForRpc+0x2b2 // test dil,40h // 检查Options // DNS_QUERY_NO_HOSTS_FILE(0x40)置位时 // 忽略DNS Cache中源自hosts文件的条目 DNSAPI!Query_SingleNamePrivate+0x6d5 DNSAPI!Query_Wire DNSAPI!Query_Wire+0x4ea DNSAPI!Send_AndRecv DNSAPI!Send_AndRecv+0x1bd DNSAPI!Send_AndRecvUdpWithParam DNSAPI!Send_AndRecvUdpWithParam+0x277 DNSAPI!sendUdpToNextDnsServers DNSAPI!sendUdpToNextDnsServers+0x17b DNSAPI!sendUsingServerInfo DNSAPI!sendUsingServerInfo+0x66 DNSAPI!Send_MessagePrivateEx DNSAPI!Send_MessagePrivateEx+0x2c2 WS2_32!WSASendMsg // 53/UDP通信 -------------------------------------------------------------------------- 下列断点均让hosts文件整体失效,可配合条件断点,只让hosts中匹配FQDN失效。 bp dnsrslvr!R_ResolverQuery "ed @rsp+0x30 1;du @r8;gc" bp dnsrslvr!R_ResolverQuery "ed poi(@rsp+0x40) dwo(poi(@rsp+0x40)) | 0x48;du @r8;gc" bp dnsrslvr!R_ResolverQuery "ed poi(@rsp+0x40) dwo(poi(@rsp+0x40)) | 0x40;du @r8;gc" 其中前两个断点基本等价,完全忽略DNS Cache。最后的断点只忽略DNS Cache中源自 hosts文件的条目,不忽略DNS Cache中非源自hosts文件的条目。 强调一下,对Guest所在Win10环境,拦截dnsrslvr!R_ResolverQuery,给Options或 上DNS_QUERY_BYPASS_CACHE(8),无法绕过hosts文件。 简单说说调试分析思路。再说一遍,Process Monitor是一种调试器,用它看调用栈 得到逻辑框架。看微软文档再结合逆向工程,测出dnsrslvr!R_ResolverQuery的 BypassCache、pOptions形参意义。动态调试,用数据断点找出几个关键代码点。 本篇对绝大多数人而言,属于无用的知识,但肯定对某些人有价值。好了,就说这么 多。