29网络偷包

偷包,就是在网络传输过程中,截取某一数据包,进行解析获取其发送的数据。

 

原理与TCP通信类似。只需在创建套接字时,参数不同。

 

fd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);

PF_INET                      IPV4协议

SOCK_RAW            对原始网络协议访问

IPPROTO_TCP:   TCP 协议

注意:第三参数必须指定协议的类型,不可以是0,只能接受某一种协议的数据,不可以是所有IP数据包。

 

注意:

char szBuf[1024];

iRet = read(fd, szBuf, sizeof(szBuf));

 

此时szBuf接受的包是数据,不是字符串,可能是乱码或其他乱七八的东东。

 

 

因此,对数据包进行解析:

 

IP数据报的格式:

(1)一个 IP 数据报由首部和数据两部分组成。

(2)首部的前一部分是固定长度,共 20 字节,是所有 IP 数据报必须具有的。

(3)在首部的固定部分的后面是一些可选字段,其长度是可变的。

 

定义IP数据包格式的一个结构体:

typedef struct tagIpHeader

{

      unsigned char ucHeadLen:4;

      unsigned char ucVer:4;

 

      unsigned char ucTos;

      unsigned short usLen;

      unsigned short usIdent;

 

      unsigned short usOffset:13;

      unsigned short usFlag:3;

 

      unsigned char ucTTL;

      unsigned char ucProtocol;

 

      unsigned short usChkSum;

 

      unsigned int uiSrcIp;

      unsigned int uiDstIp;

     

      char data[0];

}IPHEAD_S;

 

再将接收到的szBuf,转换,再将结构体的信息输出

IPHEAD_S *pIpHead = (IPHEAD_S*)szBuf;

 

 

TCP 报文段首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项 (n 是整数)。

注意:TCP 首部的最小长度是 20 字节。而UDP是28字节。

 

 

定义TIP报文段格式的一个结构体:

typedef struct tagTcpHeader

{

      unsigned short srcPort;

      unsigned short dstPort;

      unsigned int   uiSeq;

      unsigned int   uiSeqQ;

      unsigned short fin:1;

      unsigned short syn:1;

      unsigned short rst:1;

      unsigned short psh:1;

      unsigned short ack:1;

      unsigned short urg:1;

      unsigned short res:6;

      unsigned short usHeadLen:4;

      unsigned short usWinLen;

      unsigned short usChkSum;

      unsigned short usUrgPtr;

      unsigned char  data[0];

}TCPHEAD_S;

 

 

例子:

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<string.h>

#define RAW_PORT  8888

 

//IP数据包格式

typedef struct tagIpHeader

{

      unsigned char ucHeadLen:4;

      unsigned char ucVer:4;

 

      unsigned char ucTos;

      unsigned short usLen;

      unsigned short usIdent;

 

      unsigned short usOffset:13;

      unsigned short usFlag:3;

 

      unsigned char ucTTL;

      unsigned char ucProtocol;

 

      unsigned short usChkSum;

 

      unsigned int uiSrcIp;

      unsigned int uiDstIp;

     

      char data[0];

}IPHEAD_S;

 

//TCP数据报格式

typedef struct tagTcpHeader

{

      unsigned short srcPort;

      unsigned short dstPort;

      unsigned int   uiSeq;

      unsigned int   uiSeqQ;

      unsigned short fin:1;

      unsigned short syn:1;

      unsigned short rst:1;

      unsigned short psh:1;

      unsigned short ack:1;

      unsigned short urg:1;

      unsigned short res:6;

      unsigned short usHeadLen:4;

      unsigned short usWinLen;

      unsigned short usChkSum;

      unsigned short usUrgPtr;

      unsigned char  data[0];

}TCPHEAD_S;

 

//IP信息

void PrintIpHead(IPHEAD_S *pIpHead)

{

      printf("\n--------------- IP_HEAD -------------\n");

      printf("srcPort : %d\n", pIpHead->ucVer);

      printf("HeadLen : %d\n", pIpHead->ucHeadLen);

      printf("TOS     : %d\n", pIpHead->ucTos);

      printf("DataLen : %d\n", ntohs(pIpHead->usLen));

      printf("Ident   : %d\n", ntohs(pIpHead->usIdent));

      printf("Flag    : %d\n", pIpHead->usFlag);

      printf("Offset  : %d\n", pIpHead->usOffset);

      printf("TTL     : %d\n", pIpHead->ucTTL);

      printf("Protocol: %d\n", pIpHead->ucProtocol);

      printf("ChkSum  : %d\n", ntohs(pIpHead->usChkSum));

 

 

      struct sockaddr_in addr;

      addr.sin_addr.s_addr = pIpHead->uiSrcIp; //s_addr is network-endian

      printf("Src IP  : %s\n", inet_ntoa(addr.sin_addr));

     

      addr.sin_addr.s_addr = pIpHead->uiDstIp;

      printf("Dst IP  : %s\n", inet_ntoa(addr.sin_addr));

     

      printf("\n-------------------------------------\n");

 

}

 

//TCP信息

void PrintTcpHead(TCPHEAD_S *pTcpHead)

{

      printf("\n--------------- TCP_HEAD -------------\n");

      printf("srcPort : %d\n", htons(pTcpHead->srcPort));

      printf("dstPort : %d\n", pTcpHead->dstPort);

      printf("uiSeq   : %d\n", pTcpHead->uiSeq);

      printf("uiSeqQ : %d\n",  htons(pTcpHead->uiSeqQ));

      printf("fin:%d syn:%d tst:%d psh:%d ack:%d urg:%d res:%d:%d\n",

                 pTcpHead->fin,pTcpHead->syn,pTcpHead->rst,

                 pTcpHead->psh,pTcpHead->ack,pTcpHead->urg,pTcpHead->res);

      printf("usHeadLen: %d\n", pTcpHead->usHeadLen);

      printf("usWinLen  : %d\n", htons(pTcpHead->usWinLen));

      printf("usChkSum  : %d\n", htons(pTcpHead->usChkSum));

      printf("usUrgPtr: %d\n", htons(pTcpHead->usUrgPtr));

      printf("ChkSum  : %d\n", htons(pTcpHead->usChkSum));

 

      printf("\n-------------------------------------\n");

 

}

 

 

void CaptureData()

{

      int fd;

      int iRet;

      struct sockaddr_in addr;

      socklen_t  addrlen = sizeof(addr);

     

      fd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); //capture TCP data-packet

      //fd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); //capture TCP data-packet

      if (fd < 0)

      {

           perror("Fail to socket!");

           return;

      }

     

      addr.sin_family = AF_INET;

      addr.sin_port   = htonl(RAW_PORT);

      addr.sin_addr.s_addr = htonl(INADDR_ANY);

 

      iRet = bind(fd, (struct sockaddr*)&addr, addrlen);

      if (iRet)

      {

           perror("Fail to bind!");

           close(fd);

           return;

      }

 

      char szBuf[1024];

      while(1)

      {

           memset(szBuf, 0, sizeof(szBuf));

           iRet = read(fd, szBuf, sizeof(szBuf));

           if (iRet < 0)

           {

                 perror("Fail to read!");

                 break;

           }

 

           //解析数据包

           IPHEAD_S *pIpHead = (IPHEAD_S*)szBuf;

           PrintIpHead(pIpHead);

           //解析TCP报文的数据

           TCPHEAD_S *pTcpHead=(TCPHEAD_S *)pIpHead;

           printf("data: %s\n", pTcpHead->data);

           //printf("Recv:%s\n", szBuf);

          

      }

      close(fd);

 

      return; 

 

}

 

 

int main()

{

      CaptureData();

 

      return 0;

}

 

大小序问题:

在数据包格式中看到,版本在前,首部长度在后。但是在结构体中,首部长度在前,版本在后。

解析:因此char是一个字节,而在数据包中,版本+首部长度=1字节。并且是大字节序,接受到后在内存中是小字节序。此时首部长度将被放在高位,版本被放在地位。因此进行调换。

 

DataLen和 Ident   的转换也是如此。

      printf("DataLen : %d\n", ntohs(pIpHead->usLen));

      printf("Ident   : %d\n", ntohs(pIpHead->usIdent));

posted @ 2018-06-23 00:05  gd_沐辰  阅读(510)  评论(0编辑  收藏  举报