一般情况下,ICMP包都是会被IP给封装起来传送,那有没有办法让IP不去封装这个ICMP包呢??
用VB+WinSock API 可以实现吗??

解决方案 »

  1.   

    一般情况下,ICMP包都是会被IP给封装起来传送,然后若对方用snort拦截的话,会显示是UDP包,有没有办法让snort拦截到的是ICMP包?
    用VB+WinSock API 可以实现吗??
      

  2.   

    没明白你的意思。能说的清楚点么?要分析是否是ICMP包需要分析IP包的头。拦截到后就能分析的。
    这个是C下的,构件一个ICMP报文头的代码
    typedef struct iphdr { unsigned int version:4; // IP版本号,4表示IPV4 unsigned int h_len:4; // 4位首部长度 unsigned char tos; // 8位服务类型TOS unsigned short total_len; // 16位总长度(字节)  unsigned short ident; //16位标识 unsigned short frag_and_flags; // 3位标志位 unsigned char ttl; //8位生存时间 TTL unsigned char proto; // 8位协议 (TCP, UDP 或其他) unsigned short checksum; // 16位IP首部校验和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目的IP地址}IpHeader;   然后定义一个ICMP首部:typedef struct _ihdr { BYTE i_type; //8位类型 BYTE i_code; //8位代码 USHORT i_cksum; //16位校验和  USHORT i_id; //识别号(一般用进程号作为识别号) USHORT i_seq; //报文序列号  ULONG timestamp; //时间戳}IcmpHeader;   这时可以同过WSASocket建立一个原始套接口:SockRaw=WSASocket(          AF_INET, //协议族           SOCK_RAW, //协议类型,SOCK_RAW表示是原始套接口           IPPROTO_ICMP, //协议,IPPROTO_ICMP表示ICMP数据报          NULL, //WSAPROTOCOL_INFO置空          0, //保留字,永远置为0          WSA_FLAG_OVERLAPPED //标志位          );  注:为了使用发送接收超时设置(设置SO_RCVTIMEO, SO_SNDTIMEO),必须将标志位置为WSA_FLAG_OVERLAPPED   随后你可以使用fill_icmp_data子程序填充ICMP报文段:fill_icmp_data函数:void fill_icmp_data(char * icmp_data, int datasize){ IcmpHeader *icmp_hdr; char *datapart; icmp_hdr = (IcmpHeader*)icmp_data; icmp_hdr->i_type = ICMP_ECHOREPLY; //类型为ICMP_ECHOREPLY icmp_hdr->i_code = 0; icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); //识别号为进程号  icmp_hdr->i_cksum = 0; //校验和初始化 icmp_hdr->i_seq = 0; //序列号初始化 datapart = icmp_data + sizeof(IcmpHeader); //数据端的地址为icmp报文地址加上ICMP的首部长度 memset(datapart,"A", datasize - sizeof(IcmpHeader)); //这里我填充的数据全部为"A",你可以填充任何代码和数据,实际上木马和控制端之间就是通过数据段传递数据的。}   再使用CheckSum子程序计算ICMP校验和:   调用方法:((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);CheckSum函数: USHORT CheckSum (USHORT *buffer, int size) { unsigned long cksum=0; while(size >1)   {     cksum+=*buffer++;    size -=sizeof(USHORT);  }  if(size ) cksum += *(UCHAR*)buffer;  cksum = (cksum >> 16) + (cksum & 0xffff);  cksum += (cksum >>16);  return (USHORT)(~cksum);}// CheckSum函数是标准的校验和函数,你也可以用优化过的任何校验和函数来代替它  随后,就可以通过sendto函数发送ICMP_ECHOREPLY报文:  sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));作为服务端的监听程序,基本的操作相同,只是需要使用recvfrm函数接收ICMP_ECHOREPLY报文并用decoder函数将接收来的报文解码为数据和命令:recv_icmp=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);decode_resp(recvbuf,recv_icmp,&from);decoder函数:void decoder(char *buf, int bytes,struct sockaddr_in *from) { IpHeader *iphdr; IcmpHeader *icmphdr; unsigned short iphdrlen; iphdr = (IpHeader *)buf; //IP首部的地址就等于buf的地址 iphdrlen = iphdr->h_len * 4 ; // 因为h_len是32位word,要转换成bytes必须*4 icmphdr = (IcmpHeader*)(buf + iphdrlen); //ICMP首部的地址等于IP首部长加buf printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); //取出源地址 printf(" icmp_id=%d. ",icmphdr->i_id); //取出进程号 printf(" icmp_seq=%d. ",icmphdr->i_seq); //取出序列号 printf(" icmp_type=%d",icmphdr->i_type); //取出类型 printf(" icmp_code=%d",icmphdr->i_code); //取出代码 for(i=0;//取出数据段}