自己动手写网络抓包工具Word下载.docx
- 文档编号:20166123
- 上传时间:2023-01-17
- 格式:DOCX
- 页数:10
- 大小:18.70KB
自己动手写网络抓包工具Word下载.docx
《自己动手写网络抓包工具Word下载.docx》由会员分享,可在线阅读,更多相关《自己动手写网络抓包工具Word下载.docx(10页珍藏版)》请在冰豆网上搜索。
=~IFF_PROMISC;
现在我们可以抓到本网段的所有IP数据包了,但是问题也来了:
那么多的数据,怎么处理?
CPU可能会被严重占用,而且绝大多数的数据我们可能根本就不敢兴趣!
那怎么办呢?
用if语句?
可能要n多个,而且丝毫不会降低内核的繁忙程度。
最好的办法就是告诉内核,把不感兴趣的数据过滤掉,不要往应用层送。
BPF就为此而生。
BPF(BerkeleyPacketFilter)是一种类是汇编的伪代码语言,它也有命令代码和操作数。
例如,如果我们只对用户192.168.1.4的数据感兴趣,可以用tcpdump的-d选项生成BPF代码如下:
$tcpdump-dhost192.168.1.4
(000)ldh[12]
(001)jeq#0x800jt2jf6
(002)ld[26]
(003)jeq#0xc0a80104jt12jf4
(004)ld[30]
(005)jeq#0xc0a80104jt12jf13
(006)jeq#0x806jt8jf7
(007)jeq#0x8035jt8jf13
(008)ld[28]
(009)jeq#0xc0a80104jt12jf10
(010)ld[38]
(011)jeq#0xc0a80104jt12jf13
(012)ret#96
(013)ret#0
其中第一列代表行号,第二列是命令代码,后面是操作数。
下面我们采用汇编注释的方式简单的解释一下:
(000)ldh[12];
loadh?
?
(2bytes)fromABSoffset12(theTYPEofethernetheader)
(001)jeq#0x800jt2jf6;
compareandjump,jumptoline2iftrue;
elsejumptoline6
(002)ld[26];
loadword(4bytes)fromABSoffset26(srcIPaddressofIPheader)
(003)jeq#0xc0a80104jt12jf4;
compareandjump,jumptoline12iftrue,elsejumptoline4
(004)ld[30];
loadword(4bytes)fromABSoffset30(dstIPaddressofIPheader)
(005)jeq#0xc0a80104jt12jf13;
seeline3
(006)jeq#0x806jt8jf7;
comparewithARP,seeline1
(007)jeq#0x8035jt8jf13;
comparewithRARP,seeline1
(008)ld[28];
srcIPaddressforotherprotocols
(009)jeq#0xc0a80104jt12jf10
(010)ld[38];
dstIPaddressforotherprotocols
(011)jeq#0xc0a80104jt12jf13
(012)ret#96;
return96bytestouserapplication
(013)ret#0;
dropthepacket
但是这样的伪代码我们是无法在应用程序里使用的,所以tcpdum提供了一个-dd选项来输出一段等效的C代码:
$tcpdump-ddhost192.168.1.4
{0x28,0,0,0x0000000c},
{0x15,0,4,0x00000800},
{0x20,0,0,0x0000001a},
{0x15,8,0,0xc0a80104},
{0x20,0,0,0x0000001e},
{0x15,6,7,0xc0a80104},
{0x15,1,0,0x00000806},
{0x15,0,5,0x00008035},
{0x20,0,0,0x0000001c},
{0x15,2,0,0xc0a80104},
{0x20,0,0,0x00000026},
{0x15,0,1,0xc0a80104},
{0x6,0,0,0x00000060},
{0x6,0,0,0x00000000},
该代码对应的数据结构是structsock_filter,该结构在linux/filter.h中定义如下:
structsock_filter//Filterblock
{
__u16code;
//Actualfiltercode
__u8jt;
//Jumptrue
__u8jf;
//Jumpfalse
__u32k;
//Genericmultiusefield
};
code对应命令代码;
jt是jumpiftrue后面的操作数,注意这里用的是相对行偏移,如2就表示向前跳转2行,而不像伪代码中使用绝对行号;
jf为jumpiffalse后面的操作数;
k对应伪代码中第3列的操作数。
了解了BPF伪代码和结构,我们就可以自己定制更加简单有效的BPFfilter了,如上例中的6-11行不是针对IP协议的,而我们的套接字已经指定只读取IP数据了,所以就可以把他们删除,不过要注意,行偏移也要做相应的修改。
另外,tcpdump默认只返回96字节的数据,但对大部分应用来说,96字节是远远不够的,所以tcpdump提供了-s选项用于指定返回的数据长度。
OK,下面我们就来看看怎样把过滤器安装到套接口上吧:
$tcpdumpip-d-s2048host192.168.1.2
(000)ldh[12]
(001)jeq#0x800jt2jf7
(002)ld[26]
(003)jeq#0xc0a80102jt6jf4
(004)ld[30]
(005)jeq#0xc0a80102jt6jf7
(006)ret#2048
(007)ret#0
structsock_filterbpf_code[]={
{0x28,0,0,0x0000000c},
{0x15,0,5,0x00000800},
{0x20,0,0,0x0000001a},
{0x15,2,0,0xc0a80102},
{0x20,0,0,0x0000001e},
{0x15,0,1,0xc0a80102},
{0x6,0,0,0x00000800},
{0x6,0,0,0x00000000}
structsock_fprogfilter;
filter.len=sizeof(bpf_code)/sizeof(bpf_code[0]);
filter.filter=bpf_code;
setsockopt(sock,SOL_SOCKET,SO_ATTACH_FILTER,&
filter,sizeof(filter));
最后加上信号处理器,以便能在程序退出前恢复网卡的工作模式。
到现在我们已经可以看到一个小聚规模抓包小工具了,呵呵,麻雀虽小,但也五脏俱全啊!
下面给出完整的代码。
#include&
lt;
sys/types.h&
gt;
sys/time.h&
sys/ioctl.h&
sys/socket.h&
linux/types.h&
netinet/in.h&
netinet/udp.h&
netinet/ip.h&
netpacket/packet.h&
net/ethernet.h&
arpa/inet.h&
string.h&
signal.h&
net/if.h&
stdio.h&
sys/uio.h&
fcntl.h&
unistd.h&
linux/filter.h&
stdlib.h&
#defineETH_HDR_LEN14
#defineIP_HDR_LEN20
#defineUDP_HDR_LEN8
#defineTCP_HDR_LEN20
staticintsock;
voidsig_handler(intsig)
structifreqethreq;
if(sig==SIGTERM)
printf("
SIGTERMrecieved,exiting...\n"
);
elseif(sig==SIGINT)
SIGINTrecieved,exiting...\n"
elseif(sig==SIGQUIT)
SIGQUITrecieved,exiting...\n"
//turnoffthePROMISCOUSmode
if(ioctl(sock,SIOCGIFFLAGS,&
ethreq)!
=-1){
}
close(sock);
exit(0);
intmain(intargc,char**argv){
intn;
charbuf[2048];
unsignedchar*ethhead;
unsignedchar*iphead;
structsigactionsighandle;
#if0
$tcpdumpip-s2048-dhost192.168.1.2
(001)jeq#0x800jt2jf7
(003)jeq#0xc0a80102jt6jf4
(005)jeq#0xc0a80102jt6jf7
(007)ret#0
#endif
{0x15,0,5,0x00000800},
{0x15,2,0,0xc0a80102},
{0x15,0,1,0xc0a80102},
{0x6,0,0,0x00000800},
sighandle.sa_flags=0;
sighandle.sa_handler=sig_handler;
sigemptyset(&
sighandle.sa_mask);
//sigaddset(&
sighandle.sa_mask,SIGTERM);
sighandle.sa_mask,SIGINT);
sighandle.sa_mask,SIGQUIT);
sigaction(SIGTERM,&
sighandle,NULL);
sigaction(SIGINT,&
sigaction(SIGQUIT,&
//AF_PACKETallowsapplicationtoreadpecketfromandwritepackettonetworkdevice
//SOCK_DGRAMthepacketexcludeethernetheader
//SOCK_RAWrawdatafromthedeviceincludingethernetheader
//ETH_P_IPallIPpackets
if((sock=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP)))==-1){
perror("
socket"
exit
(1);
ethreq)==-1){
ioctl"
if(ioctl(sock,SIOCSIFFLAGS,&
//attachthebpffilter
if(setsockopt(sock,SOL_SOCKET,SO_ATTACH_FILTER,&
filter,sizeof(filter))==-1){
setsockopt"
while
(1){
n=recvfrom(sock,buf,sizeof(buf),0,NULL,NULL);
if(n&
(ETH_HDR_LEN+IP_HDR_LEN+UDP_HDR_LEN)){
invalidpacket\n"
continue;
%dbytesrecieved\n"
n);
ethhead=buf;
Ethernet:
MAC[%02X:
%02X:
%02X]"
ethhead[0],ethhead[1],ethhead[2],
ethhead[3],ethhead[4],ethhead[5]);
-&
[%02X:
ethhead[6],ethhead[7],ethhead[8],
ethhead[9],ethhead[10],ethhead[11]);
type[%04x]\n"
(ntohs(ethhead[12]|ethhead[13]&
&
8)));
iphead=ethhead+ETH_HDR_LEN;
//headerlengthas32-bit
IP:
Version:
%dHeaderLen:
%d[%d]"
(*iphead&
4),(*iphead&
0x0f),(*iphead&
0x0f)*4);
TotalLen%d"
(iphead[2]&
8|iphead[3]));
IP[%d.%d.%d.%d]"
iphead[12],iphead[13],iphead[14],iphead[15]);
[%d.%d.%d.%d]"
iphead[16],iphead[17],iphead[18],iphead[19]);
%d"
iphead[9]);
if(iphead[9]==IPPROTO_TCP)
[TCP]"
elseif(iphead[9]==IPPROTO_UDP)
[UDP]"
elseif(iphead[9]==IPPROTO_ICMP)
[ICMP]"
elseif(iphead[9]==IPPROTO_IGMP)
[IGMP]"
else
[OTHERS]"
PORT[%d]-&
[%d]\n"
(iphead[20]&
8|iphead[21]),(iphead[22]&
8|iphead[23]));
本文来自CSDN博客,转载请标明出处:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 自己动手 网络 包工
![提示](https://static.bdocx.com/images/bang_tan.gif)