文章作者:Eros412
信息来源:邪恶八进制信息安全团队
类型:网络编程
前言:ipconfig.exe 使用IpReleaseAddress()这个函数完成DHCP_RELEASE,以下是模仿整个过程的部分代码
复制内容到剪贴板
代码:
#include<packet32.h>
#include<winsock.h>
#include<Iphlpapi.h>
#include<stdio.h>
#include<windows.h>
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"Iphlpapi.lib")
typedef struct _myparam
{
char myip[15];//本机ip
char gatewayip[15];//网关ip
unsigned char mymac[6];//本机mac
unsigned char gatewaymac[6];//网关mac
}MYPARAM,*PMYPARAM;
#pragma pack(push,1)
typedef struct _ethdr //14字节的ethernet首部
{
unsigned char eh_dst[6];//目标地址的mac(网关mac)
unsigned char eh_src[6];//源地址的mac(本机mac)
unsigned short eh_type;//类型,本程序的是IP
}ETHERNETHEADER,*PETHERNETHEADER;
typedef struct ip_hdr //20个字节IP首部
{
unsigned char h_verlen;//版本
unsigned char tos;//首部长度
unsigned short total_len;//总长度,ipheader+udpheader+dhcpheader+数据
unsigned short ident;//Identification
unsigned short frag_and_flags;//是否是碎片包
unsigned char ttl; //Time to live
unsigned char proto; //DHCP的protocol是UDP,0x11
unsigned short checksum;//20个字节IP首部的校验和
unsigned int sourceIP;//源地址的IP(本机ip)
unsigned int destIP;//目标地址的IP(网关ip)
}IPHEADER,*PIPHEADER;
typedef struct tsd_hdr//12个字节伪首部
{
unsigned long saddr;//源地址的IP(本机ip)
unsigned long daddr;//目标地址的IP(网关ip)
unsigned char mbz; //0
unsigned char ptcl;//协议
unsigned short tcpl;//psdheader+udpheader+dhcpheader+数据的长度
}PSDHEADER,*PPSDHEADER;
typedef struct udp_hdr //8个字节UDP首部
{
unsigned short sourceport; //源端口 ,DHCP客户端==68
unsigned short destport;//目标端口,DHCP服务端==67
unsigned short udp_length; //udp首部+dhcp首部+数据的长度
unsigned short udp_checksum; //psd首部+udp首部+dhcp首部+数据的校验和
} UDPHEADER,*PUDPHEADER;
typedef struct dhcp_header //240个字节的DHCP首部
{
unsigned char MessageType; //类型,0x01==BOOT_REQUEST,0x02==BOOT_REPLY,
unsigned char HardwareType;//硬件类型 (Ethernet)
unsigned char HardwareAddrLen;//MAC的长度,6
unsigned char Hops;//每经过一个DHCP中继加1
unsigned long TranID;//Transaction ID
unsigned short Secondselaps;//0
unsigned short BootpFlag;//0
DWORD ClientIP;//0
DWORD YourIP;//源地址的IP(本机ip)
DWORD NextServerIP;//0
DWORD RelayAgentIP;//0
unsigned char ClientMac[6];//源地址的mac(本机mac)
unsigned char PAdding[10];//0
unsigned char ServerName[64];//0
unsigned char BootFileName[128];//0
unsigned long MagicCookie;//每个机子有不同的号
}DHCPHEADER, *PDHCPHEADER;
typedef struct dhcp_option
{
unsigned char OptionNum;
unsigned char OptionLen;
}DHCPOPTION, *PDHCPOPTION;
typedef struct dhcp_type//3个字节的类型部分
{
DHCPOPTION option;
unsigned char value;
}DHCPTYPE, *PDHCPTYPE;
typedef struct server_iden//这边用来填写网关的ip地址
{
DHCPOPTION option;
DWORD value;
}SERVERIDEN, *PSERVERIDEN;
typedef struct client_iden/这边用来填写本机的mac
{
DHCPOPTION option;
unsigned char value[7];
unsigned char end;
}CLIENTIDEN, *PCLIENTIDEN;
#pragma pack(pop)
USHORT checksum(USHORT *buffer, int size)//校验和
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;//把数据的前两个字节先换位,因为两个UCHAR变一个USHORT,类似htons(),然后加起来,指针向后移,一直加完全部数据
size-=sizeof(USHORT);
}
if(size)//加上最后一个字节
cksum+=*(UCHAR*)buffer;
cksum=(cksum >> 16)+(cksum&0xffff);//高位向左移,加上低位;(cksum >> 16)如果cksum是0x12340000,就变成0x1234;(cksum&0xffff)如果cksum是0x12345678,就变成0x5678
cksum+=(cksum >>16);//cksum再加上高位
return (USHORT)(~cksum);//取反(低位的)
}
//一些定义
#define IP 0x0800
#define BOOT_REQUEST 1
#define ETHERNET 1
#define BROADCAST 0x8000
#define DHCP_MESSAGE_TYPE 53
#define DHCP_REALEASE 7
#define SERVER_ID 54
#define CLIENT_ID 61
void main(){
MYPARAM myparam;
unsigned char ipbuf[342]={0};//完整的RAWPACKET == ETHERNET_HEADER+IPHEADER+UDPHEADER+DHCPHEADER+数据
unsigned char udpchecksum[320]={0};//加 PSDHEADER和UDPHEADER ,计算udpheader的checksum
unsigned char udpbuf[308]={0};//加 UDPHEADER
unsigned char mybuf[300]={0};//没有 UDPHEADER
char classid[50]={0};//通过classid的比较来选定ADAPTER
char clsid[50]={0};
IPHEADER ipheader;
ipheader.h_verlen=(4<<4 | sizeof(IPHEADER)/sizeof(DWORD));//4<<4 ,BINARY 100向左移4位,变成1000000,原本的0x04变成0x40。sizeof(IPHEADER)/sizeof(DWORD),sizeof(DWORD)==4,20/4==5。所以0x40|0x05==0x45
ipheader.tos=0;
ipheader.total_len=htons(sizeof(IPHEADER)+sizeof(udpbuf));
ipheader.ident=htons(11670);
ipheader.frag_and_flags=0;//不是碎片包
ipheader.ttl=128;//最大为255,0xFF
ipheader.proto=IPPROTO_UDP;
ipheader.checksum=0;//计算校验和时checksum的部分是零,计算后填入,当对方接受数据包时,数据包再checksum一次,这时真确的包会返回0,这是校验和的精华所在
PIP_ADAPTER_INFO padapter;//通过GetAdaptersInfo获取本机ip,本机mac,网关ip
padapter = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO) );
DWORD length=sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo( padapter, &length) == ERROR_BUFFER_OVERFLOW) {
free(padapter);//释放内存
padapter = (IP_ADAPTER_INFO *) malloc (length);
}
GetAdaptersInfo( padapter, &length);
while(padapter){
unsigned char mygateway[255]={0};
strcpy((char *)mygateway,padapter->GatewayList.IpAddress.String);
if(mygateway[0]!=0x00) //测试GATEWAY地址,如果有就用这个INTERFACE的
{
strncpy(myparam.myip,padapter->IpAddressList.IpAddress.String,15);
strncpy(myparam.gatewayip,padapter->GatewayList.IpAddress.String,15);
strcpy(classid,padapter->AdapterName);//提取classid
strcpy(classid,classid+1);
classid[strlen(classid)-1]='\0';
for (int i=0;i<(int)padapter->AddressLength;i++)
myparam.mymac[i]=(int)padapter->Address[i];//拷贝6个字节的mac
break;
}
padapter=padapter->Next;//loop
}
/*
printf("IpAddress - %s\n",myparam.myip);
printf("Gateway IpAddress - %s\n",myparam.gatewayip);//打印获得的ip、mac
printf("MAC Address - ");
for(int j=0;j<6;j++)
if (j == 5)
printf("%.2X\n\n",myparam.mymac[j]);
else
printf("%.2X-",myparam.mymac[j]);
*/
ULONG MacAddr;
IPAddr DestIp=0;
ULONG PhysAddrLen = 6;
BYTE *bPhysAddr;
int s;
DestIp = inet_addr(myparam.gatewayip);
memset(&MacAddr, 0xff, sizeof (MacAddr));
SendARP(DestIp, NULL, &MacAddr, &PhysAddrLen);//通过 SendARP()获得网关的MAC,可以参考MSDN
bPhysAddr = (BYTE *) & MacAddr;
for (s = 0; s < (int) PhysAddrLen; s++)
myparam.gatewaymac[s]=(int)bPhysAddr[s];//拷贝6个字节的mac(网关)
ETHERNETHEADER ethdr;
ethdr.eh_type=htons(IP);
for(int k=0;k<6;k++)
ethdr.eh_dst[k]=myparam.gatewaymac[k];//拷贝6个字节的mac(网关)
for(k=0;k<6;k++)
ethdr.eh_src[k]=myparam.mymac[k];//拷贝6个字节的mac(本机)
ipheader.sourceIP=inet_addr(myparam.myip);
ipheader.destIP=inet_addr(myparam.gatewayip);
ipheader.checksum=checksum((unsigned short *)&ipheader,sizeof(ipheader));//校验IP首部
PSDHEADER psdheader;
psdheader.saddr=inet_addr(myparam.myip);
psdheader.daddr=inet_addr(myparam.gatewayip);
psdheader.mbz=0;
psdheader.ptcl=IPPROTO_UDP;
psdheader.tcpl=htons(sizeof(udpbuf));
UDPHEADER udpheader;
//从 %systemroot%\system32\drivers\etc\services可以找到端口号
//bootps 67/udp dhcps #Bootstrap Protocol Server
//bootpc 68/udp dhcpc #Bootstrap Protocol Client
udpheader.destport=htons(67);//htons就是把数据的两个字节互相换位
udpheader.sourceport=htons(68);
udpheader.udp_checksum=0;//udpheader的校验和ipheader的一样,计算校验和时checksum的部分是零,计算后填入,当对方接受数据包时,数据包再checksum一次,这时真确的包会返回0。
udpheader.udp_length=htons(sizeof(UDPHEADER)+sizeof(mybuf));
DHCPHEADER dhcpheader;
dhcpheader.MessageType=BOOT_REQUEST;
dhcpheader.HardwareType=ETHERNET;
dhcpheader.HardwareAddrLen=sizeof(myparam.mymac);
dhcpheader.Hops=0;
dhcpheader.TranID=htonl(0x8db96125);
dhcpheader.Secondselaps=0;
dhcpheader.BootpFlag=htons(BROADCAST);
dhcpheader.ClientIP=inet_addr(myparam.myip);
dhcpheader.NextServerIP=0;
dhcpheader.RelayAgentIP=0;
dhcpheader.YourIP=0;
for(int j=0;j<6;j++)
dhcpheader.ClientMac[j]=myparam.mymac[j];//拷贝MAC
memset(dhcpheader.PAdding,0,sizeof(dhcpheader.PAdding));//这些都为空
memset(dhcpheader.ServerName,0,sizeof(dhcpheader.ServerName));
memset(dhcpheader.BootFileName,0,sizeof(dhcpheader.BootFileName));
dhcpheader.MagicCookie=0x63538263;//这是本机的
memcpy(mybuf,&dhcpheader,sizeof(dhcpheader));
/*
DHCP_DISCOVER 0x01
DHCP_REQUEST 0x03
DHCP_DECLINE 0x04
DHCP_ACK 0x05
DHCP_NAK 0x06
DHCP_RELEASE 0x07
DHCP_INFORM 0x08
*/
DHCPTYPE dhcptype;
dhcptype.option.OptionNum=DHCP_MESSAGE_TYPE;
dhcptype.option.OptionLen=sizeof(UCHAR);
dhcptype.value=DHCP_REALEASE;
memcpy(mybuf+sizeof(dhcpheader),&dhcptype,sizeof(dhcptype));
SERVERIDEN serverid;
serverid.option.OptionLen=sizeof(DWORD);
serverid.option.OptionNum=SERVER_ID;
serverid.value=inet_addr(myparam.gatewayip);//写入网关的ip
memcpy(mybuf+sizeof(dhcpheader)+sizeof(dhcptype),&serverid,sizeof(serverid));
CLIENTIDEN clientid;
clientid.end=0xFF;//数据结尾
clientid.value[0]=0x01;
for(j=0;j<6;j++)
clientid.value[j+1]=myparam.mymac[j]; //写入本机的mac
clientid.option.OptionLen=sizeof(clientid.value);
clientid.option.OptionNum=CLIENT_ID;
memcpy(mybuf+sizeof(dhcpheader)+sizeof(dhcptype)+sizeof(serverid),&clientid,sizeof(clientid));
memcpy(udpbuf,&udpheader,sizeof(udpheader));
memcpy(udpbuf+sizeof(udpheader),mybuf,sizeof(mybuf));//这边+sizeof(udpheader)的意思是移动udpbuf的指针,然后把数据拷贝到udpbuf的尾端
memcpy(udpchecksum,&psdheader,sizeof(psdheader));
memcpy(udpchecksum+sizeof(psdheader),udpbuf,sizeof(udpbuf));
udpheader.udp_checksum=checksum((unsigned short *)udpchecksum,sizeof(udpchecksum));//校验UDP首部和后面的数据
memset(udpbuf,0,sizeof(udpbuf));
memcpy(udpbuf,&udpheader,sizeof(udpheader));
memcpy(udpbuf+sizeof(udpheader),mybuf,sizeof(mybuf));
memcpy(ipbuf,ðdr,sizeof(ethdr));
memcpy(ipbuf+sizeof(ethdr),&ipheader,sizeof(ipheader));
memcpy(ipbuf+sizeof(ipheader)+sizeof(ethdr),udpbuf,sizeof(udpbuf));
/*
for(int i=0;i<(int)sizeof(ipbuf);i++){//这里打印出构造好的数据
static int count=1;
if(count%16==0)
printf("%.2X\n",ipbuf[i]);
else
printf("%.2X ",ipbuf[i]);
count++;
}
printf("\n\n");
*/
ULONG len;
LPADAPTER lpadapter;
LPPACKET lpPacket;
char adapter[65535]={0};
PacketGetAdapterNames((char*)adapter,&len);//把全部ADAPTER的名称提取到char adapter[65535]
char adapterlist[10][1024];
char * temp1;
char * temp2;
temp1=adapter;//temp1指向当前的
temp2=adapter;//temp2指向之前的
int num=0;
while((*temp1!='\0')||(*(temp1-1)!='\0')){//这边提取ADAPTER的名称,char adapter[65535]包含全部的名称,以‘\0’间隔
if(*temp1=='\0'){
memcpy(adapterlist[num],temp2,2*(temp1-temp2));
temp2=temp1+1;
num++;
}
temp1++;
}
int adapternum=num;
int mynum=0;
for(num=0;num<adapternum;num++){
strcpy(clsid,adapterlist[num]);//这边提取classid
strcpy(clsid,clsid+13);
clsid[strlen(clsid)-1]='\0';
if (strcmp(clsid,classid)==0)//通过classid的比较来选定ADAPTER
mynum=num;
}
lpadapter=PacketOpenAdapter(adapterlist[mynum]);//打开指定的ADAPTER
lpPacket=PacketAllocatePacket();//为包分配内存
PacketInitPacket(lpPacket,ipbuf,sizeof(ipbuf)); //把构造好的数据放入RAWPACKET
if(PacketSendPacket(lpadapter,lpPacket,TRUE)==FALSE)//发包
{
printf("发送失败!%d\n",GetLastError());//代码里省略了很多检查ERROR的部分,减少代码的长度
return ;
}
PacketFreePacket(lpPacket); //释放内存
PacketCloseAdapter(lpadapter);//关闭ADAPTER
}