如何在 Windows 中拦截 DNS 查询

2024-04-26

我正在研究如何在 Windows 中拦截 DNS 查询, 以一种不需要将 DLL 注入到每个进程中的方式,并且理想情况下能够根据发出查询的进程做出决策,因此简单的 DNS 代理服务器是不够的。

从表面上看,DNS 查询所采用的路径如下所示, 某些应用程序从 ws2_32.dll(或 dnsapi.dll 中的 DnsQuery)调用 gethostbyname

[dll 做了一些事情]

最终调用 dnsrslvr.dll 中的某些内容,该 dll 在 svshost 进程中作为名为“Dnscache”的服务运行,该服务根据 TaskExplorer 从 DNS 服务器在端口 53 上发送和接收 UDP 数据包

所以我想做的是在“Dnscache”服务之前拦截一些软件的 dns 查询,或者用自己的服务替换该服务。

所以我的问题是:这里的聪明人之一是否知道公共 DNS 查询 API 和 Dnscache 服务之间会发生什么,以及两者之间的最佳位置是什么?


你可以这样做标注驱动程序 https://learn.microsoft.com/en-us/windows-hardware/drivers/network/callout-driver。 您可以在 FWPM_LAYER_DATAGRAM_DATA_V4 的标注中捕获、解析和编辑 DNS 数据包。

这是FWPM_LAYER_DATAGRAM_DATA_V4回调的代码,用于获取DNS查询名称。

void NTAPI
CoDatagramDataV4(
IN  const FWPS_INCOMING_VALUES* inFixedValues,
IN  const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
IN  VOID*                       packet,
IN  const void*                 classifyContext,
IN  const FWPS_FILTER*          filter,
IN  UINT64                      flowContext,
OUT FWPS_CLASSIFY_OUT*          classifyOut
){
    classifyOut->actionType = FWP_ACTION_PERMIT;

    if (inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 != IPPROTO_UDP
        inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16 != 53 ||
        inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32 != FWP_DIRECTION_INBOUND)
    {
        // This can be filtered by FwpmFilterAdd in ring3.
        return;
    }
    PNET_BUFFER pNetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)packet);
    if (pNetBuffer == NULL)
    {
        PVOID pDataBuffer0 = ExAllocatePoolWithTag(NonPagedPool, nDataLength, TAG_NAME_CALLOUT);
        if (pDataBuffer0)
        {
            PVOID pDataBuffer = NdisGetDataBuffer(pNetBuffer, nDataLength, pDataBuffer0, 1, 0);
            if (pDataBuffer)
            {
                PCHAR  pszQuery = (PCHAR)pDataBuffer + 12/*sizeof DNS header*/;
                CHAR   szQueryName[MAX_DOMAIN_NAME_LEN] = { 0 };
                CHAR   cbLabel = pQuery[0];
                UINT32 nLen = 1;
                while (cbLabel != 0)
                {
                    for (CHAR i = 0; i < cbLabel; i++)
                    {
                        szQueryName[nLen - 1] = pszQuery[nLen]; nLen++;
                    }
                    cbLabel = pszQuery[nLen];
                    szQueryName[nLen - 1] = cbLabel != 0 ? '.' : 0;
                    nLen++;
                }
                // Here szQueryName is DNS query name such as 'www.google.com'.
            }
        }
        ExFreePoolWithTag(pDataBuffer0, 'Tsnd');
    }
}

And you can check the DNS structure by using wireshark like this. enter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Windows 中拦截 DNS 查询 的相关文章

随机推荐