揭开木马的神秘面纱(三)

       揭开木马的神秘面纱(三)  
       在揭开木马的神秘面纱(二)发表后,有很多朋友来信询问新型木马的详细情况,本文会详细的分析Win2000下一种新型木马的内部构造和防御方法。(本文默认的操作系统为Win2000,开发环境为VC++6.0。)  
  大家知道,一般的“古典”型木马都是通过建立TCP连接来进行命令和数据的传递的,但是这种方法有一个致命的漏洞,就是木马在等待和运行的过程中,始终有一个和外界联系的端口打开着,这是木马的阿喀琉斯之踵(参看希腊神话《特洛伊战纪》),也是高手们查找木马的杀手锏之一(Netstat大法)。所谓道高一尺,魔高一丈,木马也是在斗争中不断进步不断成长的,其中一种ICMP木马就彻底摆脱了端口的束缚,成为黑客入侵后门工具中的佼佼者。  
      什么是ICMP呢?ICMP全称是Internet   Control   Message   Protocol(互联网控制报文协议)它是IP协议的附属协议,用来传递差错报文以及其他需要注意的消息报文,这个协议常常为TCP或UDP协议服务,但是也可以单独使用,例如著名的工具Ping(向Mike   Muuss致敬),就是通过发送接收ICMP_ECHO和ICMP_ECHOREPLY报文来进行网络诊断的。  
     实际上,ICMP木马的出现正是得到了Ping程序的启发,由于ICMP报文是由系统内核或进程直接处理而不是通过端口,这就给木马一个摆脱端口的绝好机会,木马将自己伪装成一个Ping的进程,系统就会将ICMP_ECHOREPLY(Ping的回包)的监听、处理权交给木马进程,一旦事先约定好的ICMP_ECHOREPLY包出现(可以判断包大小、ICMP_SEQ等特征),木马就会接受、分析并从报文中解码出命令和数据。  
  ICMP_ECHOREPLY包还有对于防火墙和网关的穿透能力。对于防火墙来说,ICMP报文是被列为危险的一类:从Ping   of   Death到ICMP风暴到ICMP碎片攻击,构造ICMP报文一向是攻击主机的最好方法之一,因此一般的防火墙都会对ICMP报文进行过滤;但是ICMP_ECHOREPLY报文却往往不会在过滤策略中出现,这是因为一旦不允许ICMP_ECHOREPLY报文通过就意味着主机没有办法对外进行Ping的操作,这样对于用户是极其不友好的。如果设置正确,ICMP_ECHOREPLY报文也能穿过网关,进入局域网。  
  为了实现发送/监听ICMP报文,必须建立SOCK_RAW(原始套接口),首先,我们需要定义一个IP首部:  
  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(icmp_data,datasize);  
  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;i<ICMP_DATA_SIZE;i++)   printf("%c",*(buf+iphdrlen+i+12));   //取出数据段  
  }  
  注:在WIN2000下使用SOCK_RAW需要管理员的权限。  
   
  对于ICMP木马,除非你使用嗅探器或者监视windows的SockAPI调用,否则从网络上是很难发现木马的行踪的(关于进程的隐藏及破解会在下一篇文章中进行讨论),那么,有什么可以补救的方法呢?有的,就是过滤ICMP报文,对于win2000可以使用系统自带的路由功能对ICMP协议进行过滤,win2000的Routing   &   Remote   Access功能十分强大,其中之一就是建立一个TCP/IP协议过滤器:打开Routing   &   Remote   Access,选中机器名,在IP路由->General->网卡属性中有两个过滤器-输入过滤和输出过滤,只要在这里将你想过滤的协议制定为策略,ICMP木马就英雄无用武之地了;不过值得注意的是,一旦在输入过滤器中禁止了ICMP_ECHOREPLY报文,你就别想再用Ping这个工具了;如果过滤了所有的ICMP报文,你就收不到任何错误报文,当你使用IE访问一个并不存在的网站时,往往要花数倍的时间才能知道结果(嘿嘿,网络不可达、主机不可达、端口不可达报文你一个都收不到),而且基于ICMP协议的tracert工具也会失效,这也是方便和安全之间的矛盾统一了吧。  
  本文的撰写是为了深入地研究Win2000的入侵和防御技术,探讨TCP/IP协议和Windows编程技巧,请不要将文中的内容用于任何违法的目的,文中所附为试验性的ICMP通讯程序,仅仅提供通过ICMP_ECHOREPLY进行通讯交换数据的功能以供研究;如果你对本文中的内容或代码有疑问,请Mail   to:Shotgun@xici.net,但是出于网络安全的考虑,本人不会提供任何木马软件及代码。

 

附录:  
  1、发送ICMP_ECHOREPLY报文的程序代码  
  #include   <winsock2.h>  
  #include   <stdio.h>  
  #include   <stdlib.h>  
   
  #define   ICMP_ECHO   8   //ICMP回显请求报文的类型值为8  
  #define   ICMP_ECHOREPLY   0   //ICMP回显应答报文的类型值为0  
  #define   ICMP_MIN   8   //   ICMP报文的最小长度是8字节(仅为首部)  
  #define   ICMP_DEST_IP   "127.0.0.1"   //目标主机的IP  
  #define   ICMP_PASSWORD   1234   //密码设置,用来识别控制端  
   
  //   定义IP   首部    
  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;  
   
   
  #define   STATUS_FAILED   0xFFFF  
  #define   DEF_PACKET_SIZE   64   //定义报文的大小为64字节  
  #define   MAX_PACKET   6500   //定义最大报文的大小为6500字节  
   
  #define   xmalloc(s)   HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))  
  #define   xfree(p)   HeapFree   (GetProcessHeap(),0,(p))  
   
  void   fill_icmp_data(char   *,int);   //填充ICMP报文的子程序  
  USHORT   checksum(USHORT   *,   int);   //计算校验和的子程序    
   
  int   main(int   argc,   char   **argv)  
  {  
  WSADATA   wsaData;  
  SOCKET   sockRaw   =   (SOCKET)NULL;  
  struct   sockaddr_in   dest,from;  
  struct   hostent   *   hp;  
  int   bread,datasize,retval,bwrote;  
  int   fromlen   =   sizeof(from);  
  int   timeout   =   1000;  
  char   *icmp_data;  
  char   *recvbuf;  
  unsigned   int   addr=0;  
  USHORT   seq_no   =   0;  
  static   int   nCount=0;  
   
  if((retval=WSAStartup(MAKEWORD(2,1),&wsaData))   !=   0)  
  {fprintf(stderr,"WSAStartup   failed:   %d/n",retval);ExitProcess(STATUS_FAILED);}  
  if((sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)    
  {fprintf(stderr,"WSASocket()   failed:   %d/n",WSAGetLastError());ExitProcess(STATUS_FAILED);}  
  __try  
  {  
  if((bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout)))==SOCKET_ERROR)  
  {fprintf(stderr,"Failed   to   set   recv   timeout:   %d/n",WSAGetLastError());__leave;}   //设置接收超时  
  if((bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout)))==SOCKET_ERROR)  
  {fprintf(stderr,"Failed   to   set   send   timeout:   %d/n",WSAGetLastError());__leave;}   //设置发送超时  
  memset(&dest,0,sizeof(dest));  
  dest.sin_family   =   AF_INET;  
  dest.sin_addr.s_addr   =   inet_addr(ICMP_DEST_IP);  
  datasize=DEF_PACKET_SIZE;  
  datasize+=sizeof(IcmpHeader);    
  icmp_data=xmalloc(MAX_PACKET);  
  recvbuf=xmalloc(MAX_PACKET);  
  if(!icmp_data)   {fprintf(stderr,"HeapAlloc   failed   %d/n",GetLastError());__leave;}  
  memset(icmp_data,0,MAX_PACKET);  
  printf("/nSend   Packet   to   %s   Success!/n",ICMP_DEST_IP);  
  fill_icmp_data(icmp_data,datasize);   //填充ICMP报文  
  ((IcmpHeader*)icmp_data)->timestamp   =   GetTickCount();   //设置时间戳  
  ((IcmpHeader*)icmp_data)->i_seq   =   ICMP_PASSWORD;   //设置序列号,实际使用时可以用这个密码验证  
  ((IcmpHeader*)icmp_data)->i_cksum   =   checksum((USHORT*)icmp_data,   datasize);   //计算校验和  
  bwrote=sendto(sockRaw,icmp_data,datasize,0,(struct   sockaddr*)&dest,sizeof(dest));   //发送报文  
  if   (bwrote   ==   SOCKET_ERROR)  
  {  
  if   (WSAGetLastError()   ==   WSAETIMEDOUT)   printf("Timed   out/n");  
  fprintf(stderr,"sendto   failed:   %d/n",WSAGetLastError());  
  __leave;  
  }  
  if   (bwrote   <   datasize   )   fprintf(stdout,"Wrote   %d   bytes/n",bwrote);  
  }  
  __finally    
  {  
  if   (sockRaw   !=   INVALID_SOCKET)   closesocket(sockRaw);  
  WSACleanup();  
  }  
  return   0;  
  }  
   
  //计算校验和函数  
  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);  
  }  
   
  //填充ICMP数据报函数  
  void   fill_icmp_data(char   *   icmp_data,   int   datasize)  
  {  
  int   i;  
  char   SendMsg[20]="Hello   World!";  
  IcmpHeader   *icmp_hdr;  
  char   *datapart;  
  icmp_hdr   =   (IcmpHeader*)icmp_data;  
  icmp_hdr->i_type   =   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);  
  for(i=0;i<sizeof(SendMsg);i++)   datapart[i]=SendMsg[i];    
  }  
   
   
  2、接收ICMP_ECHOREPLY报文的程序代码  
  #include   <winsock2.h>  
  #include   <stdio.h>  
  #include   <stdlib.h>  
   
  #define   ICMP_ECHO   8  
  #define   ICMP_ECHOREPLY   0  
  #define   ICMP_MIN   8   //   minimum   8   byte   icmp   packet   (just   header)  
  #define   ICMP_PASSWORD   1234  
   
  /*   The   IP   header   */  
  typedef   struct   iphdr   {  
  unsigned   int   h_len:4;   //4位首部长度  
  unsigned   int   version:4;   //IP版本号,4表示IPV4  
  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;  
   
   
  #define   STATUS_FAILED   0xFFFF  
  #define   DEF_PACKET_SIZE   640  
  #define   MAX_PACKET   6500  
   
  #define   xmalloc(s)   HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))  
  #define   xfree(p)   HeapFree   (GetProcessHeap(),0,(p))  
   
  void   fill_icmp_data(char   *,   int);  
  USHORT   checksum(USHORT   *,   int);  
  void   decode_resp(char   *,int   ,struct   sockaddr_in   *);  
   
  int   main(int   argc,   char   **argv){  
   
  WSADATA   wsaData;  
  SOCKET   sockRaw   =   (SOCKET)NULL;  
  struct   sockaddr_in   dest,from;  
  struct   hostent   *   hp;  
  int   bread,datasize,retval;  
  int   fromlen   =   sizeof(from);  
  int   timeout   =   1000;  
  char   *icmp_data;  
  char   *recvbuf;  
  unsigned   int   addr=0;  
  USHORT   seq_no   =   0;  
   
  if   ((retval   =   WSAStartup(MAKEWORD(2,1),&wsaData))   !=   0){  
  fprintf(stderr,"WSAStartup   failed:   %d/n",retval);  
  ExitProcess(STATUS_FAILED);  
  }  
  sockRaw   =   WSASocket   (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);  
   
  if   (sockRaw   ==   INVALID_SOCKET)   {  
  fprintf(stderr,"WSASocket()   failed:   %d/n",WSAGetLastError());  
  ExitProcess(STATUS_FAILED);  
  }  
  __try{  
  bread   =   setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));  
  if(bread   ==   SOCKET_ERROR)    
  {  
  fprintf(stderr,"failed   to   set   recv   timeout:   %d/n",WSAGetLastError());  
  __leave;  
  }  
  bread   =   setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));  
  if(bread   ==   SOCKET_ERROR)    
  {  
  fprintf(stderr,"failed   to   set   send   timeout:   %d/n",WSAGetLastError());  
  __leave;  
  }  
  memset(&dest,0,sizeof(dest));  
  dest.sin_family   =   AF_INET;  
  dest.sin_addr.s_addr   =   inet_addr("207.46.230.218");//任意IP地址  
  datasize   =   DEF_PACKET_SIZE;  
  datasize   +=   sizeof(IcmpHeader);    
  icmp_data   =   xmalloc(MAX_PACKET);  
  recvbuf   =   xmalloc(MAX_PACKET);  
  if   (!icmp_data)   {  
  fprintf(stderr,"HeapAlloc   failed   %d/n",GetLastError());  
  __leave;  
  }  
  memset(icmp_data,0,MAX_PACKET);  
  while(1)   {  
  static   int   nCount   =   0;  
  int   bwrote;  
  fill_icmp_data(icmp_data,datasize);  
  ((IcmpHeader*)icmp_data)->i_cksum   =   0;  
  ((IcmpHeader*)icmp_data)->timestamp   =   GetTickCount();  
  ((IcmpHeader*)icmp_data)->i_seq   =   1111;  
  ((IcmpHeader*)icmp_data)->i_cksum   =   checksum((USHORT*)icmp_data,   datasize);  
  bwrote   =   sendto(sockRaw,icmp_data,datasize,0,(struct   sockaddr*)&dest,sizeof(dest));  
  bread   =   recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct   sockaddr*)&from,&fromlen);  
  if   (bread   ==   SOCKET_ERROR){  
  if   (WSAGetLastError()   ==   WSAETIMEDOUT)   {  
  continue;  
  }  
  fprintf(stderr,"recvfrom   failed:   %d/n",WSAGetLastError());  
  __leave;  
   
  }  
  decode_resp(recvbuf,bread,&from);  
  Sleep(1000);  
  }  
  }  
  __finally   {  
  if   (sockRaw   !=   INVALID_SOCKET)   closesocket(sockRaw);  
  WSACleanup();  
  }  
  return   0;  
  }  
   
  void   decode_resp(char   *buf,   int   bytes,struct   sockaddr_in   *from)    
  {  
  int   i;  
  IpHeader   *iphdr;  
  IcmpHeader   *icmphdr;  
  unsigned   short   iphdrlen;  
  iphdr   =   (IpHeader   *)buf;  
  iphdrlen   =   iphdr->h_len   *   4   ;    
  icmphdr   =   (IcmpHeader*)(buf   +   iphdrlen);  
  if(icmphdr->i_seq==ICMP_PASSWORD)//密码正确则输出数据段  
  {  
  printf("%d   bytes   from   %s:",bytes,   inet_ntoa(from->sin_addr));  
  printf("   IcmpType   %d",icmphdr->i_type);  
  printf("   IcmpCode   %d",icmphdr->i_code);  
  printf("/n");  
  for(i=0;i<50;i++)   printf("%c",*(buf+iphdrlen+i+12));  
  }  
  else   printf("Other   ICMP   Packets!/n");  
  printf("/n");    
  }  
   
   
  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);  
  }  
   
  void   fill_icmp_data(char   *   icmp_data,   int   datasize){  
  IcmpHeader   *icmp_hdr;  
  char   *datapart;  
  icmp_hdr   =   (IcmpHeader*)icmp_data;  
  icmp_hdr->i_type   =   ICMP_ECHO;  
  icmp_hdr->i_code   =   0;  
  icmp_hdr->i_id   =   (USHORT)GetCurrentProcessId();  
  icmp_hdr->i_cksum   =   0;  
  icmp_hdr->i_seq   =   12;  
  datapart   =   icmp_data   +   sizeof(IcmpHeader);  
  memset(datapart,‘A‘,   datasize   -   sizeof(IcmpHeader));  
  }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值