修改Windows下dnsapi.dll强制使用TCP进行DNS查询

首先我承认,我一时脑洞,好好的一个人,浪费几小时去折腾这破玩意。

先看看效果:
tcp dns

由于之前在路由上设置了内网的TCP转发,可惜DNS查询在Windows下默认使用的是UDP方式,而且居然没有修改的方式!
在网上搜索之后,发现可以通过修改 dnsapi.dll 的方式来实现强制使用TCP进行DNS查询,但是很可惜的是作者没说具体的方法。妈蛋我一下子就兴奋了,这是赤裸裸地挑衅啊!

知道该怎么做之后就是开工了,先去MSDN上看看关于 dnsapi.dll 的手册,找到下面2条:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682016(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/cc982162(v=vs.85).aspx
DnsQuery是系统查询DNS时调用的函数,DNS Constants是一些常量,对我们接下来修改dll会很有帮助。

由于是Windows 8.1系统,有32位和64位的dll,我们要分析修改2次。
首先是32位的dll,这个在 C:\Windows\SysWOW64\dnsapi.dll 。
Windows下自然是用Visual Studio调试,随便写个程序来调用dnsapi:

#include <Windows.h>
#include <WinDNS.h>

#pragma comment(lib, "Dnsapi.lib")

int main()
{
  DnsQuery(L"www.google.com", DNS_TYPE_A, DNS_QUERY_USE_TCP_ONLY | DNS_QUERY_BYPASS_CACHE, NULL, NULL, NULL);
  return 0;
}

然后就是调试,跟踪,可惜我没有去下载Windows的调试符号文件(pdb),不然可能会更轻松点。
跟到这个:
dnsapi-x86
很好,在前几行断点处可以看出 [ebx] 是我们传入的Options,这里我们可以看出他在和一些常量做比较,这个 4000000h 由于在常量表(DNS Query Options)找不到值为 0x04000000 的定义,我觉得可能这个值就是保留定义的,也不大可能用上,于是决定放弃这个数值,来加上 DNS_QUERY_USE_TCP_ONLY 标志。(主要是没有调试文件搞得调了半天,也没找到其他更好的修改方式了,如果有人知道,请务必告知!)
于是,就在图中 71B34795 改成:

__asm {
  or ecx, 2
  mov [ebx], ecx
  xor eax, eax
  nop
  nop
  nop
}

这样,对于Windows 8.1的32位的 dnsapi.dll (6.3.9600.17039) 做出的修改就是:

00003B95: 8B -> 83
00003B96: C1 -> C9
00003B97: 8B -> 02
00003B98: 53 -> 89
00003B99: 04 -> 0B
00003B9A: 25 -> 33
00003B9B: 00 -> C0
00003B9C: 00 -> 90
00003B9D: 00 -> 90
00003B9E: 04 -> 90

下面就是64位的dll,这个在 C:\Windows\System32\dnsapi.dll 。
调试的方法和32位的相同,记得要更换编译方式,然后开始调试反汇编代码。
dnsapi-x64
这里找到的代码和32位的大致相同。接下来打开IDA找到这个代码的位置。
dnsapi-x64-3
将其改成这个样子:
dnsapi-x64-4

这样,对于Windows 8.1的64位的 dnsapi.dll (6.3.9600.17039) 做出的修改就是:

00002C07: 0F -> 83
00002C08: BA -> C8
00002C09: E0 -> 02
00002C0A: 1A -> 90
00002C0B: 0F -> 49
00002C0C: 82 -> 89
00002C0D: 3E -> 45
00002C0E: 78 -> 00
00002C0F: 04 -> 90
00002C10: 00 -> 90

这样就算搞定了,强制设置上 DNS_QUERY_USE_TCP_ONLY 这个标志,也就是强制走TCP。

然后我们需要把文件拷回去,记得先要修改对应目录下的文件的安全性,然后改名成 dnsapi.dll.bak 做个备份,最后把我们的修改后的文件拷贝进去就好了。
fix files

最好重启一下,然后就可以在Wireshark中看到效果啦~
tcp dns

最后附上我修改好32位和64位的 dnsapi.dll (6.3.9600.17039) 文件:
https://bless.moe/io/win/mod/dnsapi/

另外,我们需要注意一点,像在 chrome://flags/ 开启了实验性异步 DNS 客户端的 Chrome 等软件会使用自带的DNS客户端,不走系统的DNS解析,所以可能还是UDP方式查询DNS。
-我费了这么大力气,就为了写篇文章都不行嘛,其实我觉得拿这玩意去投稿的话也能赚点稿费就是了-