gpt4 book ai didi

c - WinDivert 问题 - 在 Windows 上将 DNS 重定向回自身

转载 作者:可可西里 更新时间:2023-11-01 14:14:38 75 4
gpt4 key购买 nike

我正在查看 basil00 的 torwall,为了好玩,我试图将其精简为仅拦截 DNS。 (为 webfiltering 目的提供一个 127.0.0.1 的答案给自己,学习项目)

然而,此时,我让它劫持了dns数据包,但它没有返回正确的地址。对于每个“被阻止”的域,它都是不同的。

例如,我将 cbc.ca 放在我的 hosts.deny 文件(黑名单)中,它返回一个地址 0.4.114.2

然后将slashdot加入黑名单,会返回0.4.0.1

这一直令人困惑和沮丧,经过三天的研究,我完全没有想法。

这是我程序的重定向部分的代码,似乎是出了问题的地方。(请注意,有些评论会很愚蠢,因为我正在为不同的目的破解一个程序并且还没有清理它)

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>


#include "windivert.h"

#include "domain.h"
#include "main.h"
#include "redirect.h"

#define MAX_PACKET 4096
#define NUM_WORKERS 4

// DNS headers
#define DNS_MAX_NAME 254
struct dnshdr
{
uint16_t id;
uint16_t options;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} __attribute__((__packed__));

struct dnsq
{
uint16_t type;
uint16_t class;
} __attribute__((__packed__));

struct dnsa
{
uint16_t name;
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t length;
uint32_t addr;
} __attribute__((__packed__));


static DWORD redirect_worker(LPVOID arg);
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len);


// State:
static bool redirect_on = false;
static HANDLE handle = INVALID_HANDLE_VALUE;
static HANDLE workers[NUM_WORKERS] = {NULL}; // Worker threads



// Send a packet asynchronously:
static void send_packet(HANDLE handle, void *packet, size_t packet_len,
PWINDIVERT_ADDRESS addr)
{
addr->Direction = WINDIVERT_DIRECTION_INBOUND;
WinDivertHelperCalcChecksums(packet, packet_len, 0);
if (!WinDivertSend(handle, packet, packet_len, addr, NULL))
debug("Send packet failed (err=%d)\n", (int)GetLastError());
}


// Start traffic redirect through Tor:
extern void redirect_start(void)
{
debug("DNS divert START\n");

if (handle != INVALID_HANDLE_VALUE)
return;

handle = WinDivertOpen(
"outbound and udp.DstPort == 53 or inbound and udp.DstPort = 53", 0, 0, 0);



// Launch threads:
redirect_on = true;
for (size_t i = 0; i < NUM_WORKERS; i++)
{
workers[i] = CreateThread(NULL, MAX_PACKET*3,
(LPTHREAD_START_ROUTINE)redirect_worker, (LPVOID)handle, 0, NULL);
if (workers[i] == NULL)
{
exit(EXIT_FAILURE);
}
}
}

// Stop traffic redirect through Tor:
extern void redirect_stop(void)
{
debug("DNS divert STOP\n");

if (handle == INVALID_HANDLE_VALUE)
return;

// Close the WinDivert handle; will cause the workers to exit.
redirect_on = false;
if (!WinDivertClose(handle))
{
exit(EXIT_FAILURE);
}
handle = INVALID_HANDLE_VALUE;

for (size_t i = 0; i < NUM_WORKERS; i++)
{
WaitForSingleObject(workers[i], INFINITE);
workers[i] = NULL;
}

}

// Redirect worker thread:
static DWORD redirect_worker(LPVOID arg)
{
HANDLE handle = (HANDLE)arg;

// Packet processing loop:
char packet[MAX_PACKET];
UINT packet_len;
WINDIVERT_ADDRESS addr;

while (redirect_on)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
// Silently ignore any error.
continue;
}

PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
PVOID data = NULL;
UINT data_len;
WinDivertHelperParsePacket(packet, packet_len, &iphdr, NULL, NULL,
NULL, &tcphdr, &udphdr, &data, &data_len);

int dnshandle = 0;
if (udphdr != NULL && ntohs(udphdr->DstPort) == 53)
dnshandle = handle_dns(handle, &addr, iphdr, udphdr, data, data_len);


if(dnshandle != 1)
{
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{


}
}
}
return 0;
}



// Handle DNS requests.
// NOTES:
// - If anything goes wrong, we simply drop the packet without error.
// - An alternative approach would be to let Tor resolve the address, however,
// this would be slow.
static int handle_dns(HANDLE handle, PWINDIVERT_ADDRESS addr,
PWINDIVERT_IPHDR iphdr, PWINDIVERT_UDPHDR udphdr, char *data,
size_t data_len)
{

struct dnshdr *dnshdr = (struct dnshdr *)data;
data += sizeof(struct dnshdr);
data_len -= sizeof(struct dnshdr);

char name[DNS_MAX_NAME + 8]; // 8 bytes extra.
size_t i = 0;
while (i < data_len && data[i] != 0)
{
size_t len = data[i];
if (i + len >= DNS_MAX_NAME)
return -1;
name[i++] = '.';
for (size_t j = 0; j < len; j++, i++)
name[i] = data[i];
}

name[i++] = '\0';

// Generate a fake IP address and associate it with this domain name:
uint32_t fake_addr = domain_lookup_addr(name);
if (fake_addr == 0)
{

// This domain is blocked; so ignore the request.
// Construct a query response:
size_t len = sizeof(struct dnshdr) + data_len + sizeof(struct dnsa);
if (len > 512) // Max DNS packet size.
return -1;
len += sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_UDPHDR) + len;

char buf[len + 8]; // 8 bytes extra.
PWINDIVERT_IPHDR riphdr = (PWINDIVERT_IPHDR)buf;
PWINDIVERT_UDPHDR rudphdr = (PWINDIVERT_UDPHDR)(riphdr + 1);
struct dnshdr *rdnshdr = (struct dnshdr *)(rudphdr + 1);
char *rdata = (char *)(rdnshdr + 1);


UINT local_ip;
DivertHelperParseIPv4Address("127.0.0.1",&local_ip);

memset(riphdr, 0, sizeof(WINDIVERT_IPHDR));
riphdr->Version = 4;
riphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(uint32_t);
riphdr->Length = htons(len);
riphdr->Id = htons(0xF00D);
WINDIVERT_IPHDR_SET_DF(riphdr, 1);
riphdr->TTL = 64;
riphdr->Protocol = IPPROTO_UDP;
riphdr->SrcAddr = iphdr->DstAddr;
riphdr->DstAddr = iphdr->SrcAddr;

memset(rudphdr, 0, sizeof(WINDIVERT_UDPHDR));
rudphdr->SrcPort = htons(53); // DNS
rudphdr->DstPort = udphdr->SrcPort;
rudphdr->Length = htons(len - sizeof(WINDIVERT_IPHDR));

rdnshdr->id = dnshdr->id;
rdnshdr->options = htons(0x8180); // Standard DNS response.
rdnshdr->qdcount = htons(0x0001);
rdnshdr->ancount = htons(0x0001);
rdnshdr->nscount = 0;
rdnshdr->arcount = 0;

memcpy(rdata, data, data_len);
struct dnsa *rdnsa = (struct dnsa *)(rdata + data_len);
rdnsa->name = htons(0xC00C);
rdnsa->type = htons(0x0001); // (A)
rdnsa->class = htons(0x0001); // (IN)
rdnsa->ttl = htonl(0x00000258) ; // 1 second
rdnsa->length = htons(0x0004);
rdnsa->addr = htonl(local_ip); // Fake address

send_packet(handle, &buf, len, addr);



debug("address: %u\n",addr->Direction);
debug("Intercept DNS %s\n", (name[0] == '.'? name+1: name));
return 1;
}
// Re-inject the matching packet.


/*
/
*/
return 0;
}

这是它的域查找方面(主要是为了尝试获得我想要的结果而进行的破解:

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#include "domain.h"
#include "main.h"

#define RATE_LIMIT 8000

#define rand16() \
(rand() & 0xFF) | ((rand() & 0xFF) << 8)

// Domain blacklist:
struct blacklist
{
size_t size;
size_t len;
char **names;
};
static struct blacklist *blacklist = NULL;

// State:
static struct name *names[UINT16_MAX] = {NULL};

static HANDLE names_lock = NULL;

// Prototypes:
static struct blacklist *domain_blacklist_read(const char *filename);
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name);
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y);
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1);



// Initialize this module:
extern void domain_init(void)
{
// Load the domain blacklist.
blacklist = domain_blacklist_read("hosts.deny");

}

// Lookup an address given a domain name. If the name does not exist then
// create one.
extern uint32_t domain_lookup_addr(const char *name0)
{
if (name0[0] == '.')
name0++;

if (domain_blacklist_lookup(blacklist, name0))
{
debug("Block %s\n", name0);

return 0; // Blocked!
}
return;
}



// Read the blacklist file:
static struct blacklist *domain_blacklist_read(const char *filename)
{
struct blacklist *blacklist =
(struct blacklist *)malloc(sizeof(struct blacklist));
if (blacklist == NULL)
{

exit(EXIT_FAILURE);
}
blacklist->size = 0;
blacklist->len = 0;
blacklist->names = NULL;

FILE *stream = fopen(filename, "r");
if (stream == NULL)
{
return blacklist;
}

// Read blocked domains:
int c;
char buf[256];
while (true)
{
while (isspace(c = getc(stream)))
;
if (c == EOF)
break;
if (c == '#')
{
while ((c = getc(stream)) != '\n' && c != EOF)
;
continue;
}
size_t i = 0;
while (i < sizeof(buf)-1 && (c == '-' || c == '.' || isalnum(c)))
{
buf[i++] = c;
c = getc(stream);
}
if (i >= sizeof(buf)-1 || !isspace(c))
{

exit(EXIT_FAILURE);
}
buf[i] = '\0';
if (blacklist->len >= blacklist->size)
{
blacklist->size = (blacklist->size == 0? 32: 2 * blacklist->size);
blacklist->names = (char **)realloc(blacklist->names,
blacklist->size * sizeof(char *));
if (blacklist->names == NULL)
{

exit(EXIT_FAILURE);
}
}
size_t size = (i+1) * sizeof(char);
char *name = (char *)malloc(size);
if (name == NULL)
{

exit(EXIT_FAILURE);
}
for (size_t j = 0; j < i; j++)
name[j] = buf[i - 1 - j];
name[i] = '\0';
blacklist->names[blacklist->len++] = name;
}

fclose(stream);

qsort(blacklist->names, blacklist->len, sizeof(char *),
domain_blacklist_compare_0);
return blacklist;
}

// Check if a domain matches the blacklist or not:
static bool domain_blacklist_lookup(struct blacklist *blacklist,
const char *name)
{
if (blacklist->len == 0)
return false;

size_t len = strlen(name);
ssize_t lo = 0, hi = blacklist->len-1;
while (lo <= hi)
{
ssize_t mid = (lo + hi) / 2;
int cmp = domain_blacklist_compare(name, len, blacklist->names[mid]);
if (cmp > 0)
hi = mid-1;
else if (cmp < 0)
lo = mid+1;
else
return true;
}
return false;
}

// Domain compare function(s):
static int __cdecl domain_blacklist_compare_0(const void *x, const void *y)
{
const char *name0 = *(const char **)x;
const char *name1 = *(const char **)y;
return strcmp(name0, name1);
}
static int domain_blacklist_compare(const char *name0, size_t len,
const char *name1)
{
size_t i = 0;
ssize_t j = (ssize_t)len - 1;
for (; j >= 0 && name1[i] != '\0'; i++, j--)
{
int cmp = (int)name1[i] - (int)name0[j];
if (cmp != 0)
return cmp;
}
if (j < 0 && name1[i] != '\0')
return 1;
return 0;
}

感谢任何帮助。

此外,我已将代码上传至:Github

谢谢。

最佳答案

这里发生了两件事之一。您正在错误地读取和写入 DNS 数据包,或者您未能在使用地址之前将地址与主机顺序转换为网络顺序或从主机顺序转换为网络顺序。

我敢打赌你会错误地读写 DNS 数据包。我已经使用 WinDivert 实现了我自己的过滤系统,我在其中劫持并通过我自己的本地 DNS 服务器传递所有 DNS 流量,我看到这些伪造的地址与我解析和编写 DNS 时得到的结果完全一样数据包错误。

坏消息是, 我无法为您指出一个完整的 C/C++ DNS 库,因为我知道没有任何库能真正简化工作 (也许,请参阅编辑)。我个人使用 C++ 和 WinDivert 编写了我的转移代码,然后使用 Arsoft.Tools.Net C# DNS 库实际运行本地 DNS 服务器并操纵 DNS 响应。

C++ 中有一个自称为 boost::net::dns 的项目,因为我认为作者希望它成为 boost 的一部分,但事实并非如此,而且很可能不会。避免使用此库,因为用于解析和存储多个 A 记录的内部机制被窃听和损坏,您将得到与此处相同的古怪结果。我试图与他一起解决问题,但他只对指责我的代码感兴趣。

如果我能找到一个在 C++ 中处理 DNS 数据包的合适的库,我会再次查看并更新我的答案。不要尝试自己做,我们正在讨论整个协议(protocol)和完整的 RFC 书籍,以便您自己正确地做这件事。

更新

正如所 promise 的,这里是我搜索的一些结果:

Mozilla Necko(以前称为 Netlib) http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/

C-战神: https://github.com/bagder/c-ares

C-Ares 编译的替代库列表: http://c-ares.haxx.se/otherlibs.html

此外,它是特定于 Linux 的但非常干净的代码。您或许可以窃取 libcrafter 的 DNS 类并将它们移动到您自己的项目中。

https://github.com/pellegre/libcrafter/blob/master/libcrafter/crafter/Protocols/DNS.h

同样,除非您的“学习项目”是理解和重建互联网的基本支柱之一,否则不要自己实现。尝试使用之前列出的库之一来处理您的 DNS 数据包。

关于c - WinDivert 问题 - 在 Windows 上将 DNS 重定向回自身,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28622432/

75 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com