<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /><title>PCAP Parser</title></head><table border="1"><tr align="center" bgcolor="#66cc66"><td><b>Subject</b></td><td><b>Content</b></td></tr><?phpdate_default_timezone_set('PRC');// PCAP文件路径$fpath = "./22-srcport-80-qq.pcap";// 计算PCAP文件大小,单位byte$TotalSize = filesize($fpath);echo "<tr><td><b>".$fpath."</b> Size is:</td><td>".$TotalSize."</td></tr>";// 打开PCAP文件$f = fopen($fpath, "rb");// 读取PCAP文件头,长度 24 bytes.$FileHeader = fread($f, 24);// 显示文件头信息,这里就不处理文件头信息了.// 将2进制文件头信息转成16进制的字符// 这里1个16进制的字符等于实际文件中的4bits长度,即半个byte的长度.// 1byte = 8bits, 1个16进制的位等同于4个二进制位, 如:(dec)15=(hex)F=(bin)1111// (24bytes * 8bits/byte) / 4bits = 48// 所以在用16进制字符显示PCAP文件头信息时会看到有48个字符.$FileHeader = bin2hex($FileHeader);// 按32位字符长度分切,便于查看.$FileHeader = chunk_split($FileHeader, 32, "<br />/r/n");// 显示头信息echo "<tr><td>FileHeader is:</td><td>".$FileHeader."</td></tr>";echo "<tr bgcolor=/"#ff0000/" ><td colspan=2></td></tr>";// $position文件指针位置,初始化为24,跳过文件头,从24bytes后开始读取第一个数据包$position = 24;// 数据包序列$n = 0;// 从24bytes后开始读取文件直至文件结束while($position < $TotalSize) { // 自定义的数据包序列 $n++; echo "<tr bgcolor=/"#0066cc/" ><td colspan=2>Pack $n </td></tr>"; // 移动文件指针至24bytes的位置 fseek($f, $position); // 读取16bytes的PCAP包头信息(PackHeader) $PackHeader = fread($f, 16); // 将PackHeader转成16进制的字符串 $PackHeader = bin2hex($PackHeader); echo "<tr><td>PackHeader is:</td><td>".$PackHeader."</td></tr>"; // 从PackHeader截取8个16进制的字符串(即2进制的4*8=32bits,4个字节的长度) // Timestamp:时间戳高位,精确到seconds $Sec = substr($PackHeader, 0, 8); $Sec = substr($Sec, 6, 2).substr($Sec, 4, 2).substr($Sec, 2, 2).substr($Sec, 0, 2); $Sec = hexdec($Sec); // Timestamp:时间戳低位,精确到microseconds $nSec = substr($PackHeader, 8, 8); $nSec = substr($nSec, 6, 2).substr($nSec, 4, 2).substr($nSec, 2, 2).substr($nSec, 0, 2); $nSec = hexdec($nSec); // 得出获取这一数据帧的时间 $DateTime = date("Y-m-d H:i:s", $Sec); echo "<tr><td>DateTime:</td><td>".$DateTime.".".$nSec."</td></tr>"; // pack length // Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。 $Caplen = substr($PackHeader, 16, 8); $Caplen = substr($Caplen, 6, 2).substr($Caplen, 4, 2).substr($Caplen, 2, 2).substr($Caplen, 0, 2); $Caplen = hexdec($Caplen); echo "<tr><td>Pack Caplen is:</td><td>".$Caplen."</td></tr>"; // 移动文件指针跳过PCAP包头. fseek($f, $position+16); // 按PCAP包头里的Caplen长度读取PCAP包体内容.一个PCAP包体就相当于OSI中的数据链路层(Data Link)的一个帧. // 这里说"相当于"是因为在网络上实际传输的数据包在数据链路层上每一个Packet开始都会有7个用于同步的字节(10101010, 10101010, 10101010, 10101010, 10101010, 10101010, 10101010,)和一个用于标识该Packet开始的字节(10101011),最后还会有四个CRC校验字节;而PCAP文件中会把前8个字节和最后4个校验自己去掉,因为这些信息对于协议分析是没有用处的。 $PackData = fread($f, $Caplen); // 取MAC地址,6个字节,48bits.转成16进制表示,字符长度为12.即平时在系统看到的物理地址. // 注意:这里PHP函数substr直接从$PackData的二进制内容里取内容,函数参数的单位为Byte.而不是字符串的字符个数了. $Dst = bin2hex(substr($PackData, 0, 6)); $Src = bin2hex(substr($PackData, 6, 6)); echo "<tr><td>Src MAC is:</td><td>".$Src."</td></tr>"; echo "<tr><td>Dst MAC is:</td><td>".$Dst."</td></tr>"; // 取以太网类型,2个字节.并转成16进制表示. $Ethertype = bin2hex(substr($PackData, 12, 2)); echo "<tr><td>Ethertype is:</td><td>".$Ethertype."</td></tr>"; // 这里只分析以太网类型为0800的数据包,即只分析IP包,其他的arp什么的完蛋去~ // 这里就开始进入OSI的网络层(Network) if ($Ethertype == "0800") { // IP包头里4bits的版本和4bits的首部长度连续共占1个字节.取1个字节.并转成16进制 $IPVersion_and_HeaderLen = bin2hex(substr($PackData, 14, 1)); // IP版本号4bits,就取一个16进制的字符,转成10进制. $IPVersion = hexdec(substr($IPVersion_and_HeaderLen, 0, 1)); echo "<tr><td>IP Version is:</td><td>".$IPVersion."</td></tr>"; // IP首部长度4bits,也取一个16进制的字符,转成10进制并乘以4.这里乘以4是因为IP首部长度的单位是以32bits为一个单位,即4个byte为1个单位. // 从这步得出的首部长度的单位为byte.基本上都是20 $IPHeaderLen = hexdec(substr($IPVersion_and_HeaderLen, 1, 1)) * 4; echo "<tr><td>IP Header Len is:</td><td>".$IPHeaderLen."(bytes)</td></tr>"; // 14-->32 // 总共跳过8个字节不做处理.(偷懒). // 1字节的服务类型TOS(8bits), // 2字节的IP包总长度(16bits), // 2字节的标识(16bits) // 2字节的标志和片偏移(3bits标识,13bits片偏移) // 1字节的生存时间TTL(8bits) // 第23字节开始取1个字节,8bits的协议类型.就是用来表示上层协议类型的东西(如:TCP,UDP).转成16进制表示. $Proctol = bin2hex(substr($PackData, 23, 1)); // 取4个字节的源IP地址.并转成常见的4段表示格式. $SrcIP = bin2hex(substr($PackData, 26, 4)); $SrcIP = hexdec($SrcIP[0].$SrcIP[1])."." .hexdec($SrcIP[2].$SrcIP[3])."." .hexdec($SrcIP[4].$SrcIP[5])."." .hexdec($SrcIP[6].$SrcIP[7]); // 取4个字节的目标IP地址.并转成常见的4段表示格式. $DecIP = bin2hex(substr($PackData, 30, 4)); $DecIP = hexdec($DecIP[0].$DecIP[1])."." .hexdec($DecIP[2].$DecIP[3])."." .hexdec($DecIP[4].$DecIP[5])."." .hexdec($DecIP[6].$DecIP[7]); echo "<tr><td>SrcIP Addr is:</td><td>".$SrcIP."</td></tr>"; echo "<tr><td>DecIP Addr is:</td><td>".$DecIP."</td></tr>"; // 根据协议类型开始处理OSI的传输层的数据. // 一般的协议类型:6 TCP, 17 UDP, 1 ICMP // 在这里只处理TCP类型的协议. if ($Proctol == "06") { echo "<tr><td>Data Proctol is:</td><td>".$Proctol."(TCP)</td></tr>"; $SrcPort = hexdec(bin2hex(substr($PackData, 34, 2))); $DecPort = hexdec(bin2hex(substr($PackData, 36, 2))); echo "<tr><td>Src Port is:</td><td>".$SrcPort."</td></tr>"; echo "<tr><td>Dec Port is:</td><td>".$DecPort."</td></tr>"; $SEQ = hexdec(bin2hex(substr($PackData, 38, 4))); $NSEQ = hexdec(bin2hex(substr($PackData, 42, 4))); echo "<tr><td>SEQ -> NSEQ is:</td><td>".$SEQ."->".$NSEQ."</td></tr>"; // ... $Data = substr($PackData, 54); $DataLen = strlen($Data); $HexData = bin2hex($Data); echo "<tr bgcolor=/"#ff6600/"><td>Data Len is:</td><td>".$DataLen."</td></tr>"; echo "<tr><td>Hex Data is:</td><td><textarea rows=/"10/" style=/"word-break:break-all;width:600px;/">".chunk_split($HexData, 32, "/r/n")."</textarea></td></tr>"; echo "<tr bgcolor=/"#ffcc66/"><td>Binary Data is:</td><td><textarea rows=/"10/" style=/"word-break:break-all;width:600px;/">".$Data."</textarea></td></tr>"; } else { echo "<tr bgcolor=red><td>WARNING:</td><td>This is not an TCP Data, I will jump to NEXT.</td></tr>"; } } else { echo "<tr bgcolor=red><td>WARNING:</td><td>This is not an IP PackData, I will jump to NEXT.</td></tr>"; } //-- --/* $PackData = bin2hex($PackData); $PackData = chunk_split($PackData, 32, "<br />/r/n"); echo "<tr><td>Hex PackData is:</td><td>".$PackData."</td></tr>";*/ $position = $position + 16 + $Caplen;}fclose($f);?></table>
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
新闻热点
疑难解答