我用来分析QQ协议的简单sniffer http://group.qqread.com/viewthread.php?tid=10960

我用来分析QQ协议的简单sniffer

[anda@thinkpad ~]$ cat qqmonitor.c

/*
* OICQ Simple sniffer programme for UNIX.
* Author < missanda@hotmail.com> QQ 8907673
*
**/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

void usage(void);
void usage(void)
{

    fprintf(stderr,"qqmonitor usage:/n");
    fprintf(stderr,"qqmonitor /n");
    fprintf(stderr,"example:/n");
    fprintf(stderr,"1. qqmonitor eth0/n");
    return;
}

static int sniffer_fd = 0;

void sniffer_exit(int signo);
void sniffer_exit(int signo)
{

    printf("sniffer signal %d recvied exiting .../n",signo);
    close(sniffer_fd);
    exit(0);
}

#define BUFFER_SIZE   65536   /*64K*/

static unsigned char buff[BUFFER_SIZE];

#define HWADDR(addr) /
  ((unsigned char *)&addr)[0], /
  ((unsigned char *)&addr)[1], /
  ((unsigned char *)&addr)[2], /
  ((unsigned char *)&addr)[3], /
  ((unsigned char *)&addr)[4], /
  ((unsigned char *)&addr)[5]

#define NIPQUAD(addr) /
  ((unsigned char *)&addr)[0], /
  ((unsigned char *)&addr)[1], /
  ((unsigned char *)&addr)[2], /
  ((unsigned char *)&addr)[3]

void parse_packet(unsigned char*buff,int len);
void parse_packet_arp(unsigned char*buff,int len);
void parse_packet_ip(unsigned char*buff,int len);

void parse_qq_login(unsigned char*buff,int len,int direction);
void parse_qq_login_token(unsigned char*buff,int len,int direction);
void parse_qq_unknown(unsigned char *buff,int len,int direction);

void parse_qq_login_token(unsigned char*buff,int len,int direction)
{

    unsigned char*p = NULL;
    int i = 0;
    uint32_t tmp32 = 0;

    if(!buff||len==0){
          return;
    }

    p = buff;

    printf("qq login token data %d bytes:/n",len);

    for(i=0;i           printf("%02X ",p );
          if(i&&((i%8)==0))
                printf("/n");
    }
    printf("/n");

    if(direction == 1){
          printf("reply data:/n");
          printf("request token %s/n",p[0]==0?"succeed":"failed");
          if(p[0] == 0x00){
                printf("token length %d bytes/n",p[1]);
                printf("login token : ");
                for(i=0;i                     printf("%02X ",p[i+1]);
                }
          }
    }
    else
    {
          printf("request data:/n");
          tmp32 = ntohl(*((uint32_t*)&p[0]));
          printf("request QQ %d/n",tmp32);
    }

    return ;
}

void parse_packet_ip(unsigned char*buff,int len)
{
    struct iphdr *ip = (struct iphdr *)buff;
    struct in_addr in;
    unsigned char *p = NULL;
    int data_len = 0;
    uint16_t cmd = 0;
    uint16_t seq = 0;
    uint16_t ver = 0;
    uint32_t id = 0;
    int port = 0;
    int direction = 0; /*1 = server -> client 0 = client -> server*/
    int i = 0;

#if 0
    printf("ip protocol/n");
    printf("version : %d/n",ip->version);
    printf("header length : %d bytes/n",ip->ihl*4);
    printf("tos : 0x%02X/n",ip->tos);
    printf("total length : %d/n",ntohs(ip->tot_len));
    printf("identification : %d/n",ntohs(ip->id));
    printf("flags: %02X %02X/n",((unsigned char*)&ip->frag_off)[0],((unsigned char*)&ip->frag_off)[1]);
    printf("ttl : %d/n",ip->ttl);
    printf("protocol : %d/n",ip->protocol);
    printf("checksum : 0x%02X%02X/n",((unsigned char*)&ip->check)[0],((unsigned char*)&ip->check)[1]);

#endif

    //printf("ip->protocol = %d/n",ip->protocol);
    switch(ip->protocol){
          case IPPROTO_TCP:
                /*TCP data*/
                p = buff + sizeof(struct iphdr) + sizeof(struct tcphdr);
                data_len = len - sizeof(struct iphdr) - sizeof(struct tcphdr);
                port = ((struct tcphdr*)(buff+sizeof(struct iphdr)))->source;
                port = ntohs(port);
          case IPPROTO_UDP:
                /*UDP data.*/
                p = buff + sizeof(struct iphdr) + sizeof(struct udphdr);
                data_len = len - sizeof(struct iphdr) - sizeof(struct udphdr);
                port = ((struct udphdr*)(buff+sizeof(struct iphdr)))->source;
                port = ntohs(port);
                break;
          default:
                //printf("unknow protocol./n");
                return;
                break;
    }

//     printf("data_len = %d p[0] = %02x p[%d] = %02x/n",data_len,p[0],data_len-1,p[data_len-1]);

    if(p[0]!=0x02 || p[data_len-1]!=0x03){
          //not oicq data.
          return;
    }

    printf("oicq data %s :/n",(ip->protocol==IPPROTO_TCP)?"tcp":"udp");
    printf("*source     ip address : %d.%d.%d.%d:%d/n",NIPQUAD(ip->saddr),port);
    printf("*destination ip address : %d.%d.%d.%d:%d/n",NIPQUAD(ip->daddr));

    // oicq 7 bytes header.
    ver = ntohs(*((uint16_t*)&p[1]));
    cmd = ntohs(*((uint16_t*)&p[3]));
    seq = ntohs(*((uint16_t*)&p[5]));

    printf("oicq version : 0x%04x/n",ver);
    printf("oicq command : 0x%04x/n",cmd);
    printf("oicq sequence : 0x%04x/n",seq);

    printf("data length   : %d/n",data_len);

    if(ver == 0x0100 || ver == 0x0000){
          direction = 1; /*server to client*/
    }
    else
    {
          direction = 0; /*client to server*/
    }

    p = &p[7];

    switch(cmd){
          //pre-login command -- high verion
          case 0x0062:
                printf("* login token %d bytes/n",data_len);
                parse_qq_login_token(p,data_len,direction);
                break;
          //logout command
          case 0x0001:
                printf("* logout/n");
                id = ntohl(*((uint32_t*)&p[0]));
                printf(" %d logouted /n",id);
                printf(" server address %d.%d.%d.%d/n",NIPQUAD(ip->daddr));
                printf(" client address %d.%d.%d.%d:%d/n/n",NIPQUAD(ip->saddr),port);
                break;
          //login command
          case 0x0022:
                printf("* login/n");
                parse_qq_login(p,data_len,direction);
                break;
          case 0x0002:
                printf("* keep alive/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0004:
                printf("* modify information/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0005:
                printf("* search onlines/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0006:
                printf("* get user information/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0009:
                printf("* add friend/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x000A:
                printf("* delete friend/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x000B:
                printf("* add friend authorize/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x000D:
                printf("* change status/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0012:
                printf("* ACK : system message/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0016:
                printf("* IM send/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0017:
                printf("* IM recv/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x001C:
                printf("* delete me./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x001D:
                printf("* request key./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0021:
                printf("* ????1/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0026:
                printf("* get friends list/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0027:
                printf("* get online friends list/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0029:
                printf("* ????2/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0030:
                printf("* group command/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0031:
                printf("* test./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x003C:
                printf("* group name command./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x003D:
                printf("* group members upload command./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x003E:
                printf("* friends remark command./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0058:
                printf("* group members upload command./n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x005C:
                printf("* get level/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0080:
                printf("* system message/n");
                parse_qq_unknown(p,data_len,direction);
                break;
          case 0x0081:
                printf("* friend change status/n");
                parse_qq_unknown(p,data_len,direction);
                break;

          default:
                printf("qq cmd = 0x%04x %d bytes/n",cmd,data_len);
                parse_qq_unknown(p,data_len,direction);
                break;
    }

    return ;
}

void parse_qq_unknown(unsigned char *buff,int len,int direction)
{

    int i = 0;

    if(!buff||len == 0)
          return;

    printf("dump data direction = %s:/n",direction?"s -> c":"c -> s");
    for(i=0;i           printf("%02X ",buff);
          if(i&&(i%16 == 0))
                printf("/n");
    }
    printf("/n");
    return ;
}

void parse_qq_login(unsigned char*buff,int len,int direction)
{
    uint32_t id = 0;
    unsigned char tea_key[16];
    unsigned char*p = NULL;
    unsigned char x[1];
    unsigned char data[65535];
    int len2 = 0;
    int e = -1;

    bzero(data,sizeof(data));

    if(len%4){
          return;
    }

    p = buff;

    if(direction == 0){
          //client to server
          printf(" login request data./n");
          // 4 bytes qq id
          id = ntohl(*((uint32_t*)&p[0]));
          printf(" id = /"%d/"/n",id);
          // 16 bytes TEA key
          bcopy(&p[4],tea_key,16);
          x[0] = p[20];
          printf(" TEA key %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x/n",tea_key[0],tea_key[1],tea_key[2],tea_key[3],tea_key[4],tea_key[5],tea_key[6],tea_key[7],tea_key[8],tea_key[9],tea_key[10],tea_key[11],tea_key[12],tea_key[13],tea_key[14],tea_key[15]);
          len2 = len - 4 - 16;

    }
    else
    {
          printf(" login respond data./n");

    }

    return ;

}

void parse_packet_arp(unsigned char*buff,int len)
{
    struct ether_arp *arp = (struct ether_arp *)buff;

#if 0
    printf("arp packet - time = %u/n",time(0));
    printf("hardware type : %d/n", ntohs(arp->arp_hrd));
    printf("protocol type : %02X-%02X/n", ((unsigned char*)&arp->arp_pro)[0],((unsigned char*)&arp->arp_pro)[1]);
    printf("hardware address length : %d/n", arp->arp_hln);
    printf("protocol address length : %d/n", arp->arp_pln);
    printf("operation code : %d/n", ntohs(arp->arp_op));
    printf("request hardware address : %02X:%02X:%02X:%02X:%02X:%02X/n",HWADDR(arp->arp_sha));
    printf("request ip     address : %d.%d.%d.%d", NIPQUAD(arp->arp_spa));
    printf("target hardware address : %02X:%02X:%02X:%02X:%02X:%02X/n",HWADDR(arp->arp_tha));
    printf("target ip     address : %d.%d.%d.%d/n",NIPQUAD(arp->arp_tpa));
#endif
    return;
}

void parse_packet(unsigned char*buff,int len)
{

    struct ethhdr *eth = (struct ethhdr *)buff;

#if 0
    /*DEBUG only*/
    printf("MAC header/n");
    printf("destination : %02X:%02X:%02X:%02X:%02X:%02X/n",HWADDR(eth->h_dest));
    printf("source     : %02X:%02X:%02X:%02X:%02X:%02X/n",HWADDR(eth->h_source));
    printf("protocol   : %02X-%02X/n",((unsigned char*)e->h_proto)[0],((unsigned char*)e->h_proto)[1]);
#endif
    switch(ntohs(eth->h_proto)){
          case ETH_P_IP:
                /*QQ data in it.*/
                //printf("ip protocol./n");
                parse_packet_ip(&buff[sizeof(struct ethhdr)],len - sizeof(struct ethhdr));
                break;
          case ETH_P_ARP:
                /*ARP request.*/
                //printf("arp protocol./n");
                parse_packet_arp(&buff[sizeof(struct ethhdr)],len - sizeof(struct ethhdr));                 break;
          default:
                //printf("unknow protocol./n");
                return;
    }

    return;
}

int main(int argc,char**argv)
{

    char ch = 0;
    int e = -1;
    int len = 0;
    char ifdev[256];
    struct ifreq ifr;

    if(argc!=2){
          usage();
          exit(-1);
    }

    if(getuid()!=0){
          fprintf(stderr,"only root can open SOCK_PACKET - frame type 0x800/n");
          exit(-1);
    }
    signal(SIGINT,sniffer_exit);
    signal(SIGTERM,sniffer_exit);
    signal(SIGCHLD,SIG_IGN);

    bzero(ifdev,sizeof(ifdev));

    bcopy(argv[1],ifdev,strlen(argv[1]));

    //only monitor local ethernet work
    //sniffer_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));

    /*set NIC to promisc mode.*/
    sniffer_fd = socket(AF_INET, SOCK_PACKET, htons(0x800));

    if(sniffer_fd<0){
          fprintf(stderr,"failed to create socket - PF_PACKET %0x/n",0x800);
          return -EFAULT;
    }

    bzero(&ifr,sizeof(ifr));

    sprintf(ifr.ifr_name,ifdev);

#if 1
    e = ioctl(sniffer_fd, SIOCGIFFLAGS, &ifr);

    if(e){
          fprintf(stderr,"failed to ioctl - SIOCGIFFLAGS - /"%s/"/n",ifdev);
          close(sniffer_fd);
          return -EFAULT;
    }

    ifr.ifr_flags |= IFF_PROMISC;
    e = ioctl(sniffer_fd, SIOCSIFFLAGS, &ifr);

    if(e){
          fprintf(stderr,"failed to ioctl - SIOCGIFFLAGS - /"%s/" - IFF_PROMISC/n",ifdev);
          close(sniffer_fd);
          return -EFAULT;
    }
#endif

    printf("oicq packet sniffer is starting .../n");

    while(1){

          bzero(buff,BUFFER_SIZE);

          //len = recv(sniffer_fd,buff,BUFFER_SIZE,0);
          len = read(sniffer_fd,buff,BUFFER_SIZE);

          if(len<=0){
                continue;
          }
          //printf("==>> %d bytes recevied./n",len);

          parse_packet(buff,len);

    }

    /*maybe never run to here. but make gcc happy.*/
    close(sniffer_fd);
    return 0;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值