假设当前OS是64-bits Win7。至少从2002.11.21开始,有些文章提到DNS Client Service自带一种日志。
对应:
%systemroot%\system32\dnsrslvr.log
Google for dnsrslvr.log,估计能找到一些对它的介绍。我本来对这个没啥兴趣,因为我常年禁用这个服务。但周大因故问起,我就用IDA逆了一下:
%systemroot%\system32\dnsrslvr.dll
为啥逆它呢?因为从注册表里看到:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Dnscache\Parameters ServiceDll REG_EXPAND_SZ %systemroot%\system32\dnsrslvr.dll
好吧,承认装X了,其实我是在Process Explorer中看到相应svchost.exe加载了它。
那么多svchost.exe,怎么快速知道哪个是该服务的宿主?
我可不是一个个找过去的,至少可以这样:
tasklist /svc /fi "services eq dnscache"
这是个64-bits进程,加载的是64-bits dll。
IDA64虽然用于反汇编64-bits PE,但其本身是个32-bits PE。
假设OS是64-bits Win7,IDA64访问%systemroot%\system32\dnsrslvr.dll时会报告无此文件。
64-bits OS上32-bits程序会碰上”File System Redirector”,比如:
%systemroot%\system32 %systemroot%\syswow64
如果自己写程序,可以禁用这种文件系统重定向:
Wow64DisableWow64FsRedirection Wow64RevertWow64FsRedirection
IDA64是已经存在的PE,用不上这招。
有个很矬的办法,因为cmd是64-bits的,从中copy时不会重定向,可以复制dnsrslvr.dll到其他不涉及重定向的普通目录,比如x:\tmp\,然后再用IDA64打开。
只是这样真地好吗?
我们是谁,我们是非正常人类研究中心的被研究人员,达文西是我们的同类。
说人话:
32-bits程序用%systemroot%\sysnative\可以访问原始的%systemroot%\system32\
TNND,说了半天已经离题万里了,现在回到IDA64逆向dnsrslvr.dll。
在Strings中搜dnsrslvr.log,查看交叉引用,定位如下代码:
ResolverInitialize ( x ) { ... DnsLogInit( "dnsrsvlr.log", "Logging for DNS resolver service" ); DnsLogIt( "dnsrslvr.log", "DNS Caching Resolver Service - ResolverInitialize" ); ... }
顾名思义,初始化日志文件、向日志文件写入日志,一切多么美好。等等,这两个破函数的第一形参有那么一点点不同:
dnsrsvlr.log // 这是哪位大哥手抖了一下?
dnsrslvr.log // 这是我们期望的
DnsLogInit()、DnsLogIt()不在dnsrslvr.dll中,而在dnsapi.dll中,继续逆后者。
int __fastcall DnsLogInit ( char * logfile ) { ... LoggingMode = 0; LineCount = 0; ... /* * 读写打开 */ logfd = fopen( logfile, "r+" ); if ( logfd ) { /* * 开启日志 */ LoggingMode = 1; fclose( logfd ); ... /* * 追加模式 */ logfd = fopen( logfile, "a" ); if ( logfd ) { /* * 输出日志 */ fprintf( logfd, ... ); fclose( logfd ); } } ... }
void DnsLogIt ( char * logfile, char *fmtstr, ... ) { ... va_list va; va_start( va, fmtstr ); /* * 这是个全局变量,位于dnsapi.dll中 */ if ( LoggingMode ) { if ( LineCount %systemroot%\system32\dnsrsvlr.log cacls %systemroot%\system32\dnsrsvlr.log /E /G "NETWORK SERVICE":W
用Administrator提前创建dnsrsvlr.log,让”NETWORK SERVICE”对之有写权限。
验证一下:
$ cacls %systemroot%\system32\dnsrsvlr.log C:\Windows\system32\dnsrsvlr.log BUILTIN\Administrators:F NT AUTHORITY\SYSTEM:F NT AUTHORITY\Authenticated Users:C BUILTIN\Users:R NT AUTHORITY\NETWORK SERVICE:(special access:) READ_CONTROL SYNCHRONIZE FILE_GENERIC_WRITE FILE_WRITE_DATA FILE_APPEND_DATA FILE_WRITE_EA FILE_EXECUTE FILE_WRITE_ATTRIBUTES
对付dnsrsvlr.log只是让LoggingMode为1。
真正写日志是输出到dnsrslvr.log,同要需要提前处理dnsrslvr.log:
type nul > %systemroot%\system32\dnsrslvr.log cacls %systemroot%\system32\dnsrslvr.log /E /G "NETWORK SERVICE":W
提前处理dnsrsvlr.log、dnsrslvr.log只涉及NTFS的DACLs,保持空文件就足够了,不需要提前填任何内容。
在dnsrslvr.dll中查看DnsLogInit()的交叉引用,看到两个:
ResolverInitialize() Areg_RegisterInit()
前者已经分析过了,后者有如下片段:
Areg_RegisterInit () { ... DnsLogInit( "asyncreg.log", "Logging for DNS client registration" ); DnsLogIt( "asyncreg.log", "Inside function Areg_RegisterInit" ); ... }
这次这位大哥没有手抖,只有一个文件:
%systemroot%\system32\asyncreg.log
考虑到DnsLogInit()中一上来就有一句”LoggingMode = 0″,我不确认是否存竞争环境。
想像这样一种情况,ResolverInitialize()成功,LoggingMode置1,Areg_RegisterInit()因为asyncreg.log的权限问题而失败,LoggingMode清零。
因此保险起见,也提前处理一下asyncreg.log好了:
type nul > %systemroot%\system32\asyncreg.log cacls %systemroot%\system32\asyncreg.log /E /G "NETWORK SERVICE":W
测试时碰上过dnsrsvlr.log、dnsrslvr.log被写入初始化日志,然后就没有下文了,再怎么刺激它,都没有新的日志被写入。
用64-bits cdb调试它:
$ tasklist /svc /fi "services eq dnscache" $ "C:\Program Files\Windows Kits\8.0\Debuggers\x64\cdb.exe" -noinh -snul -hd -o -p > dd dnsapi!LoggingMode l 1
发现不知何故LoggingMode为0,在cdb中手工将之置1即可达到预期效果:
> ed dnsapi!LoggingMode 1
当然,前提是相应文件权限已经调整到位。这种现象只出现过一次,再未复现,记录于此备忘。
在dnsapi.dll中检查LoggingMode的交叉引用,只在DnsLogInit()有机会将之置1。
简单看一下日志长什么样:
dnsrslvr.log
DNS_INFO_NO_RECORDSDNS Caching Resolver Service - R_ResolverQuery Arguments: Name: www.nsfocus.net Type: 1 Flags: 0x40006000 R_ResolverQuery - Returning status: 0x000025E5 DNS_ERROR_RECORD_DOES_NOT_EXISTDNS Caching Resolver Service - R_ResolverQuery Arguments: Name: www.nsfocus.net Type: 28 Flags: 0x40006000 R_ResolverQuery - Returning status: 0x00000000
asyncreg.log
Inside function Areg_RegisterInitDNS client registrationSystem Time Information
R_ResolverQuery()是dnsrslvr.dll中的函数,里面大量调用DnsLogIt()。
这种日志开销太大,不推荐。
我不负责地YY一下,ETW机制应该有完善的DNS日志支持,有兴趣者放狗搜搜。
至此技术细节都已到位,来个小结:
Q: 如何开启DNS Client Service日志
A: 以Administrator权限执行
net stop dnscache type nul > %systemroot%\system32\dnsrsvlr.log type nul > %systemroot%\system32\dnsrslvr.log type nul > %systemroot%\system32\asyncreg.log cacls %systemroot%\system32\dnsrsvlr.log /E /G "NETWORK SERVICE":W cacls %systemroot%\system32\dnsrslvr.log /E /G "NETWORK SERVICE":W cacls %systemroot%\system32\asyncreg.log /E /G "NETWORK SERVICE":W net start dnscache
Q: 假设已经启用这种日志,如何重新禁用
A: 以Administrator权限执行
net stop dnscache del %systemroot%\system32\dnsrsvlr.log del %systemroot%\system32\dnsrslvr.log del %systemroot%\system32\asyncreg.log net start dnscache
如果您需要了解更多内容,可以
加入QQ群:570982169
直接询问:010-68438880