通行证: 用户 密码 域名空间  下载中心 社区论坛 信息公告 my小屋
联系我们
设为首页
加入收藏

 

qq,asp,php,jsp,xml,sql,.net,编程 程序 网页图象 建站经验 私服
首页 | 新闻资讯 | 编程开发 | 网页设计 | 图形图象 | 网络媒体 | 网站模板 | 数 据 库 | 投稿
论坛 | 操作系统 | 系统优化 | 网络安全 | 黑客技术 | 硬件学堂 | 硬件报价 | 服 务 器 | 地图
专题 | 应用软件 | 聊天通讯 | q q 专栏 | 建站经验 | 在线工具 | 站长club | 注 册 表 | 旧版
社会 | 游戏娱乐 | 设计欣赏 | 疑难解答 | 社区论坛 | 网络赚钱 | 网站地图 | 广告服务 | 服务
当前位置:首页>>网络安全>>黑客技术>>正文 新版上线![旧版]
注:打开慢时请稍等
网络协议分析软件的编写

http://www.iyit.net  日期:2006-5-8 13:29:07  来源:黑客基地  点击:
参加讨论

前一阵子要写一个简单的arp协议的分析程序,在翻阅了一些资料以后,决定使用libpcap库来实现,但是后来涉及到写链路层数据的缘故(另外一个程序,这个程序就是发送一个假冒的arp request,在本文没有实现,今后有空再整理吧),所以放弃了libpcap。由于本人使用的是solaris环境,所以无法使用bpf,但是sun公司仍然为开发者提供了一个与设备底层无关的接口dlpi,dlpi的全称是data link provider interface,通过dlpi开发者可以访问数据链路层的数据包,在早期的sunos系统中基本上采用的是nit设备,但是现在solaris系统都使用了dlpi.关于dlpi的具体介绍大家可以访问网站www.opengroup.org/pubs/catalog/c811.htm,我这里就不多说了。
在搜索了许多资料之后发现目前关于dlpi的编程资料不多,没有具体的过程,后来翻阅了neal nuckolls写的一篇文章how to use the streams data link provider interface (dlpi),根据例子做了修改(主要是提供了协议分析的部分),现在把编写一个dlpi过程共享一下,希望能对大家有所帮助。建议大家可以先看看neal nuckolls的文章,其中有部分涉及到流编程的,可以参考http://docs.sun.com/app/docs/doc/816-4855的streams programming guide(不过这不是必须的)。
使用dlpi来访问数据链路层有几个步骤:
1、打开网络设备
2、将一个流 attach到一个特定的设备上,这里就是我们刚才打开的设备
3、将设备设置为混杂模式(可选)
4、把数据链路层sap绑定到流
5、调用ioctl,设置raw模式
6、配置其他模块(可选)
7、刷新缓存
8、接收数据进入分析阶段
第一步,我们首先打开一个网络设备,在本例中我们打开的是/dev/bge设备,这是本机的网络接口,注意不是/dev/bge0,通过open调用打开,并且返回一个描述符
fd=open(device, 2)
第二步,attach一个流到设备上,这是通过发送dl_attach_req原语来完成的
dlattachreq(fd, ppa)
int fd;
u_long ppa;
{
dl_attach_req_t attach_req;
struct strbuf ctl;
int flags;

attach_req.dl_primitive = dl_attach_req;
attach_req.dl_ppa = ppa;

ctl.maxlen = 0;
ctl.len = sizeof (attach_req);
ctl.buf = (char *) &attach_req;

flags = 0;

if (putmsg(fd, &ctl, (struct strbuf*) null, flags) < 0)
syserr("dlattachreq:  putmsg");
}
dl_attach_req_t是一个定义在dlpi.h中的结构体,我们通过填写结构体来发布原语,putmsg将消息发送到一个流,以上这个函数是dlpi中发布原语的主要格式
发布了dl_attach_req原语之后,还要确认是否成功,
dlokack(fd, bufp)
int fd;
char *bufp;
{
union dl_primitives *dlp;
struct strbuf ctl;
int flags;

ctl.maxlen = maxdlbuf;
ctl.len = 0;
ctl.buf = bufp;

strgetmsg(fd, &ctl, (struct strbuf*)null, &flags, "dlokack");

dlp = (union dl_primitives *) ctl.buf;

expecting(dl_ok_ack, dlp);

if (ctl.len < sizeof (dl_ok_ack_t))
err("dlokack:  response ctl.len too short:  %d", ctl.len);

if (flags != rs_hipri)
err("dlokack:  dl_ok_ack was not m_pcproto");

if (ctl.len < sizeof (dl_ok_ack_t))
err("dlokack:  short response ctl.len:  %d", ctl.len);
}
第三步,将设备设置为混杂模式下工作(可选)
dlpromisconreq(fd, dl_promisc_phys);
这一个步骤也是通过发布dlpi原语来实现的,具体代码后面给出
第四步,绑定流
dlbindreq(fd, sap, 0, dl_cldls, 0, 0);
dlbindack(fd, buf);
第五步,设置raw模式
strioctl(fd, dliocraw, -1, 0, null)
第六步,配置其他模块(在详细代码中给出)
第七步,刷新数据,这是通过ioctl调用实现的
ioctl(fd, i_flush, flushr)
第八步,这是我们最关心的步骤,实际上,前面的这些步骤我们都可以忽略,大致明白有这么个过程就可以了,到时候写代码的时候照搬这个框架就可以。使用dlpi编程并不难,关键在于大家要了解它的框架,没必要非得自己去写一个框架来,本文就是利用了michael r. widner的代码,今后如果要增加功能只需要往这个框架里填就可以了。
协议分析的过程是在函数filter完成的,函数申明如下
void filter(register char *cp,register u_int  pktlen);
该函数接收两个参数,cp是直接从设备缓存里拷贝过来的待分析数据,是链路层的封装数据,pktlen是数据的长度。在本文中由于操作环境是以太网,因此接收的数据链路层数据是以太网封装格式,如不清楚以太网封装的可以参考《tcp/ip详解 卷一:协议》,以太网封装三种标准的协议类型:ip协议、arp协议和rarp协议。14字节的以太网首部包括了6字节的目的地址,6字节的源地址和2字节的类型字段,ip的类型值为0x0800,arp的类型值为0x0806,rarp的类型值为0x8035。通过检查类型字段来区别接收到的数据是属于哪一种协议,函数实现代码如下
void filter(cp, pktlen)
register char *cp;
register u_int pktlen;
{
register struct ip     *ip;
register struct tcphdr *tcph;
register struct ether_header *eth;
char *head=cp;
static long line_count=0;//计数器,用来记录接收的数据次数

u_short ethertype=ntohs(((struct ether_header *)cp)->ether_type);
  //如果ethertype小于0x600说明这是一个符合802.3标准的数据格式,应当对数据作出调整
  if(ethertype < 0x600) {
    ethertype = *(u_short *)(cp + szeth + 6);
    cp+=8; pktlen-=8;
  }
  eth=(struct ether_header*)cp;
  fprintf(log,"%-5d",++line_count);
  if(ethertype == ethertype_ip) //检查协议类型是否ip协议
  {
  ip=(struct ip *)(cp+szeth);//调整指针的位置,szeth是以太网首部长度
  mac_info(e->ether_shost);//mac_info函数打印出物理地址
  fprintf(log,"(");
  ip_info(&ip->ip_src);//ip_info函数打印出ip地址
  fprintf(log,")");
  fprintf(log,"--->");
  mac_info(e->ether_dhost);
  fprintf(log,"(");
  ip_info(&ip->ip_dst);
  fprintf(log,")");
  fprintf(log,"\n");
  }
  else if(ethertype == arp_proto)//如果协议类型是arp
  {
     cp+=szeth;
     struct ether_arp *arp=(struct ether_arp *)cp;
     switch(ntohs(arp->ea_hdr.ar_op))//检查arp的操作
     {
       case arpop_request:   //如果是arp请求
           fprintf(log,"arp request:who has ");
           arp_ip_info(arp->arp_tpa);  //打印arp报文信息中的地址
           fprintf(log," tells ");
           arp_ip_info(arp->arp_spa);
           fprintf(log,"\n");
           break;
       case arpop_reply:     //arp应答
           fprintf(log,"arp reply: ");
           arp_ip_info(arp->arp_spa);
           fprintf(log," is at  ");
           mac_info((struct ether_addr*)&arp->arp_sha);
           fprintf(log,"\n");
           break;
      }        
      //可以在这里添加代码打印出arp数据报的具体内容
   }
}
程序的具体实现代码如下:
/*  程序sniffer.c的代码清单 */
#include <sys/stream.h>
#include <sys/dlpi.h>
#include <sys/bufmod.h>

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include <sys/time.h>
#include <sys/file.h>
#include <sys/stropts.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <net/if.h>
#include <net/if_arp.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/udp_var.h>
#include <netinet/in_systm.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>

#include <netdb.h>
#include <arpa/inet.h>


#define maxdlbuf 32768
#define maxwait 15
#define maxdladdr 1024
#define         bitsperbyte        8

#define bcopy(s1, s2, len) memcpy(s2, s1, len)
#define index(s, c) strchr(s, c)
#define rindex(s, c) strrchr(s, c)

#define bcmp(s1, s2, len) (memcmp(s1, s2, len)!=0)

#define err stderr

char    *device,
       *progname,
       *logname;
file    *log;
int     debug=0;
long databuf[maxdlbuf];
int sap=0;
#define nit_dev     "/dev/bge"
#define chunksize   4096      
int     if_fd = -1;
int     packet[chunksize+32];


int promisc = 1;
int bufmod = 0;
int filter_flags=0;

int maxbuflen=128;

void pexit(err,msg)
int err; char *msg;
{ perror(msg);
 exit(err); }

void zexit(err,msg)
int err; char *msg;
{ fprintf(err,msg);
 exit(err); }
#define arp_proto   (0x0806)
#define ip          ((struct ip *)packet)
#define ip_offset   (0x1fff)
#define szeth       (sizeof(struct ether_header))
#define arplen      (sizeof(struct ether_arp))
#define maclen      (6)
#define ipalen      (4)
#define iplen       (ntohs(ip->ip_len))
#define iphlen      (ip->ip_hl)
#define inet_addrstrlen 16

 

#define maxbuflen  (8192)
time_t  lasttime = 0;

 

char *ptm(t)
register time_t *t;
{ register char *p = ctime(t);
 p[strlen(p)-6]=0;
 return(p);
}

char *nowtm()
{ time_t tm;
 time(&tm);
 return( ptm(&tm) );
}


void print_data(uchar_t *buf,int size)
{
int i=0;
char *p=buf;
for(;i<size;i++){
if(i%16 == 0) fprintf(log,"\n");
if(i%2 == 0) fprintf(log," ");
fprintf(log,"%02x",*p++&0x00ff);
}
fprintf(log,"\n");
}
//打印物理地址
void mac_info(struct ether_addr*mac)
{
  fprintf(log,"%02x:%02x:%02x:%02x:%02x:%02x",
          mac->ether_addr_octet[0],
          mac->ether_addr_octet[1],
          mac->ether_addr_octet[2],  
          mac->ether_addr_octet[3],  
          mac->ether_addr_octet[4],
          mac->ether_addr_octet[5]);
}
//打印ip地址char buf[maxdlbuf];
 
void ip_info(struct in_addr *ip)
{
  char str[inet_addrstrlen];
  inet_ntop(af_inet,ip,str,sizeof(str));
  if(*str)
  fprintf(log,"%s",str);
 
}
//打印ip地址的另外一个版本
void arp_ip_info(uchar_t pa[])
{
   fprintf(log,"%d.%d.%d.%d",pa[0],pa[1],pa[2],pa[3]);
}

void death()
{ register struct crec *cle;

   
   fprintf(log,"\nlog ended at => %s\n",nowtm());
   fflush(log);
   if(log != stdout)
       fclose(log);
   exit(1);
}

 

err(fmt, a1, a2, a3, a4)
char *fmt;
char *a1, *a2, *a3, *a4;
{
(void) fprintf(stderr, fmt, a1, a2, a3, a4);
(void) fprintf(stderr, "\n");
(void) exit(1);
}

void
sigalrm()
{
(void) err("sigalrm:  timeout");
}

strgetmsg(fd, ctlp, datap, flagsp, caller)
int fd;
struct strbuf *ctlp, *datap;
int *flagsp;
char *caller;
{
int rc;
static char errmsg[80];


(void) signal(sigalrm, sigalrm);
if (alarm(maxwait) < 0) {
(void) sprintf(errmsg, "%s:  alarm", caller);
syserr(errmsg);
}


*flagsp = 0;
if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
(void) sprintf(errmsg, "%s:  getmsg", caller);
syserr(errmsg);
}


if (alarm(0) < 0) {
(void) sprintf(errmsg, "%s:  alarm", caller);
syserr(errmsg);
}


if ((rc & (morectl | moredata)) == (morectl | moredata))
err("%s:  morectl|moredata", caller);
if (rc & morectl)
err("%s:  morectl", caller);
if (rc & moredata)
err("%s:  moredata", caller);


本新闻共2页,当前在第1页  1  2  


编辑:黑鹰 [发送给好友] [打印本页] [关闭窗口] [返回顶部]
上一篇:网管维护局域网技巧大汇总
下一篇:网上保障个人隐私信息的十大原则
转载请注明来源:www.iyit.net
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。

 相关文章
最新更新 热点排行 推荐新闻
网站服务器通用和专用保护方法比较分析
网站服务器通用和专用保护方法比较分析
跨站式sql注入技巧
全面解析“网络钓鱼”式攻击
揭开网络钓鱼(phishing)秘密
网站服务器通用和专用保护方法比较分析
网站服务器通用和专用保护方法比较分析
跨站式sql注入技巧
全面解析“网络钓鱼”式攻击
揭开网络钓鱼(phishing)秘密
google hacking的实现以及应用(下)
google hacking的实现以及应用(上)
网络最经典命令行-网络安全工作者的必
刍议ipv6的安全问题
鲜为人知的“windows 2000/xp受限”问
网站服务器通用和专用保护方法比较分析
网站服务器通用和专用保护方法比较分析
跨站式sql注入技巧
全面解析“网络钓鱼”式攻击
揭开网络钓鱼(phishing)秘密
新开放qq免费挂级网站
免费在qq上看在线电影电视听音乐
免费把qq炫铃设为本机qq的系统提示音
qq珊瑚虫外挂4.0版本发布!
腾讯qq调整升级条件不再诱发网民“通宵
优秀公益广告作品欣赏(8)
流金岁月!cpu历史上最难忘的十个第一
java数据类型转换
qq挂机的n种快速方法
asp自动解压rar文件
巧用photoshop图案工具
用photoshop制成浪漫的“珍珠项链”
第二十章 开发delphi对象式数据管理功
sql简明教程(1)
vbscript和javascript互相调用 
jsp教程(四)-jsp actions的使用
操作系统被入侵后的修复过程
五一别忘电脑防毒 养成良好上网习惯
google对ie浏览器将捆绑搜索功能表担忧
新版上线,今日正式开通!!!
 友情链接
设置首 页 - 版权声明 - 广告服务 - 关于我们 - 联系我们 - 友情连接
copyrights © 2004-2006 iyit.net all rights reserved.
网站合作、广告联系qq:147007642、466949678
易特网络技术 点击这里给我发消息