用PHP分析PCAP
1 <html> 2 3 <head> 4 5 <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 6 7 <title>PCAP Parser</title> 8 </head> 9 <body> 10 11 <table border="1"> 12 13 <tr align="center" bgcolor="#66cc66"><td><b>Subject</b></td><td><b>Content</b></td></tr> 14 15 <?php 16 17 date_default_timezone_set('PRC'); 18 19 20 // PCAP文件路径 21 if(isset($_GET['type']) && $_GET['type'] =='tcp'){ 22 23 24 $fpath = "./192.168.9.246[2089]-239.255.255.250[1900]-17-1556323793.pcap";//TCP 25 26 }else{ 27 28 $fpath = "./192.168.9.246[2089]-239.255.255.250[1900]-17-1556323793.pcap";//TCP 29 } 30 31 32 33 34 // 计算PCAP文件大小,单位byte 35 36 $TotalSize = filesize($fpath); 37 38 39 echo "<tr><td><b>".$fpath."</b> Size is:</td><td>".$TotalSize."</td></tr>"; 40 41 42 43 // 打开PCAP文件 44 45 $f = fopen($fpath, "rb"); 46 47 48 49 // 读取PCAP文件头,长度 24 bytes. 50 51 $FileHeader = fread($f, 24); 52 53 54 55 $vensCaplen = 0; 56 57 //var_dump(file($fpath));exit; 58 59 60 // 显示文件头信息,这里就不处理文件头信息了. 61 62 // 将2进制文件头信息转成16进制的字符 63 64 // 这里1个16进制的字符等于实际文件中的4bits长度,即半个byte的长度. 65 66 // 1byte = 8bits, 1个16进制的位等同于4个二进制位, 如:(dec)15=(hex)F=(bin)1111 67 68 // (24bytes * 8bits/byte) / 4bits = 48 69 70 // 所以在用16进制字符显示PCAP文件头信息时会看到有48个字符. 71 72 $FileHeader = bin2hex($FileHeader); 73 74 75 76 // 按32位字符长度分切,便于查看. 77 78 $FileHeader = chunk_split($FileHeader, 32, "<br />\r\n"); 79 80 81 82 // 显示头信息 83 84 echo "<tr><td>FileHeader is:</td><td>".$FileHeader."</td></tr>"; 85 86 echo "<tr bgcolor=\"#ff0000\" ><td colspan=2></td></tr>"; 87 88 89 90 // $position文件指针位置,初始化为24,跳过文件头,从24bytes后开始读取第一个数据包 91 92 $position = 24; 93 94 95 96 97 98 if(isset($_GET['page']) && !empty($_GET['page'])){ 99 100 $page = $_GET['page']-1; 101 102 }else{ 103 $page = 0; 104 } 105 106 if($page <0){ 107 $page = 0; 108 } 109 110 if(isset($_GET['vensCaplen']) && !empty($_GET['vensCaplen'])){ 111 $vensCaplen = $_GET['vensCaplen']; 112 $vensCaplenred = $_GET['vensCaplen']; 113 114 115 }else{ 116 $vensCaplen = 0; 117 $vensCaplenred = 0; 118 119 } 120 121 122 if($page == 0 || $page ==1){ 123 $vensCaplenred = 0; 124 } 125 126 127 //页大小 128 $vensnum = 5; 129 $html = ''; 130 131 for($i = 0;$i<$vensnum;$i++){ 132 133 // 移动文件指针至24bytes的位置 134 135 $vensInitmv = $vensCaplen+ 16*$vensnum*$page+16*$i + $position; 136 137 //$vensInitmv = $vensCaplen+ 16*$i + $position; 138 139 140 141 fseek($f, $vensInitmv); 142 $PackHeader = fread($f, 16); 143 144 $PackHeader = bin2hex($PackHeader); 145 146 // 从PackHeader截取8个16进制的字符串(即2进制的4*8=32bits,4个字节的长度) 147 148 // Timestamp:时间戳高位,精确到seconds 149 150 $Sec = substr($PackHeader, 0, 8); 151 $Sec = substr($Sec, 6, 2).substr($Sec, 4, 2).substr($Sec, 2, 2).substr($Sec, 0, 2); 152 153 $Sec = hexdec($Sec); 154 // Timestamp:时间戳低位,精确到microseconds 155 156 $nSec = substr($PackHeader, 8, 8); 157 158 $nSec = substr($nSec, 6, 2).substr($nSec, 4, 2).substr($nSec, 2, 2).substr($nSec, 0, 2); 159 160 $nSec = hexdec($nSec); 161 162 163 164 // 得出获取这一数据帧的时间 165 166 $DateTime = date("Y-m-d H:i:s", $Sec); 167 168 169 170 //var_dump($DateTime.".".$nSec); 171 172 173 $Caplen = substr($PackHeader, 16, 8); 174 175 $Caplen = substr($Caplen, 6, 2).substr($Caplen, 4, 2).substr($Caplen, 2, 2).substr($Caplen, 0, 2); 176 177 $Caplen = hexdec($Caplen); 178 179 // 移动文件指针跳过PCAP包头 180 fseek($f, $position+16); 181 182 // 按PCAP包头里的Caplen长度读取PCAP包体内容.一个PCAP包体就相当于OSI中的数据链路层(Data Link)的一个帧. 183 // 这里说"相当于"是因为在网络上实际传输的数据包在数据链路层上每一个Packet开始都会有7个用于同步的字节 184 //(10101010, 10101010, 10101010, 10101010, 10101010, 10101010, 10101010,)和一个用于标识该Packet开始的字节(10101011), 185 //最后还会有四个CRC校验字节;而PCAP文件中会把前8个字节和最后4个校验自己去掉,因为这些信息对于协议分析是没有用处的。 186 $PackData = fread($f, $Caplen); 187 188 // 取MAC地址,6个字节,48bits.转成16进制表示,字符长度为12.即平时在系统看到的物理地址. 189 // 注意:这里PHP函数substr直接从$PackData的二进制内容里取内容,函数参数的单位为Byte.而不是字符串的字符个数了 190 $Dst = bin2hex(substr($PackData, 0, 6)); 191 192 $Src = bin2hex(substr($PackData, 6, 6)); 193 194 // 取以太网类型,2个字节.并转成16进制表示. 195 $Ethertype = bin2hex(substr($PackData, 12, 2)); 196 $num = $vensnum*$page+$i+1; 197 $html .= <<<Eof 198 <tr bgcolor="#0066cc" ><td colspan=2>Pack $num </td></tr> 199 <tr><td>PackHeader is:</td><td> $PackHeader </td></tr> 200 <tr><td>DateTime:</td><td> $DateTime.$nSec </td></tr> 201 <tr><td>Pack Caplen is:</td><td> $Caplen </td></tr> 202 <tr><td>Src MAC is:</td><td>$Src</td></tr> 203 <tr><td>Dst MAC is:</td><td>$Dst</td></tr> 204 <tr><td>Ethertype is:</td><td>$Ethertype</td></tr> 205 Eof; 206 207 208 $vensCaplen += $Caplen; 209 210 211 212 if ($Ethertype == "0800") { 213 // IP包头里4bits的版本和4bits的首部长度连续共占1个字节.取1个字节.并转成16进制 214 215 $IPVersion_and_HeaderLen = bin2hex(substr($PackData, 14, 1)); 216 217 // IP版本号4bits,就取一个16进制的字符,转成10进制. 218 219 $IPVersion = hexdec(substr($IPVersion_and_HeaderLen, 0, 1)); 220 221 // IP首部长度4bits,也取一个16进制的字符,转成10进制并乘以4.这里乘以4是因为IP首部长度的单位是以32bits为一个单位,即4个byte为1个单位. 222 223 // 从这步得出的首部长度的单位为byte.基本上都是20 224 225 $IPHeaderLen = hexdec(substr($IPVersion_and_HeaderLen, 1, 1)) * 4; //20 + 12 ()+ 14 226 227 // 14-->32 228 229 // 总共跳过8个字节不做处理.(偷懒). 230 231 // 1字节的服务类型TOS(8bits), 232 233 // 2字节的IP包总长度(16bits), 234 235 // 2字节的标识(16bits) 236 237 // 2字节的标志和片偏移(3bits标识,13bits片偏移) 238 239 // 1字节的生存时间TTL(8bits) 240 241 242 243 // 第23字节开始取1个字节,8bits的协议类型.就是用来表示上层协议类型的东西(如:TCP,UDP).转成16进制表示. 244 245 $Proctol = bin2hex(substr($PackData, 23, 1)); 246 247 248 249 // 取4个字节的源IP地址.并转成常见的4段表示格式. 250 251 $SrcIP = bin2hex(substr($PackData, 26, 4)); 252 253 $SrcIP = hexdec($SrcIP[0].$SrcIP[1])."." 254 255 .hexdec($SrcIP[2].$SrcIP[3])."." 256 257 .hexdec($SrcIP[4].$SrcIP[5])."." 258 259 .hexdec($SrcIP[6].$SrcIP[7]); 260 261 // 取4个字节的目标IP地址.并转成常见的4段表示格式. 262 263 $DecIP = bin2hex(substr($PackData, 30, 4)); 264 265 $DecIP = hexdec($DecIP[0].$DecIP[1])."." 266 267 .hexdec($DecIP[2].$DecIP[3])."." 268 269 .hexdec($DecIP[4].$DecIP[5])."." 270 271 .hexdec($DecIP[6].$DecIP[7]); 272 273 274 // 根据协议类型开始处理OSI的传输层的数据 275 // 一般的协议类型:6 TCP, 17 UDP, 1 ICMP 276 277 // 在这里只处理TCP类型的协议. 278 279 $html .= <<<Eof 280 <tr><td>IP Version is:</td><td> $IPVersion </td></tr> 281 <tr><td>IP Header Len is:</td><td> $IPHeaderLen (bytes)</td></tr> 282 <tr><td>SrcIP Addr is:</td><td> $SrcIP </td></tr> 283 <tr><td>DecIP Addr is:</td><td> $DecIP </td></tr> 284 Eof; 285 //UDP 286 if ($Proctol == "011") { 287 288 289 $SrcPort = hexdec(bin2hex(substr($PackData, 34, 2))); 290 291 $DecPort = hexdec(bin2hex(substr($PackData, 36, 2))); 292 293 294 $SEQ = hexdec(bin2hex(substr($PackData, 38, 4))); 295 296 $NSEQ = hexdec(bin2hex(substr($PackData, 42, 4))); 297 298 299 $Data = substr($PackData, (14 + $IPHeaderLen + 8)); 300 301 $DataLen = strlen($Data); 302 303 $HexData = bin2hex($Data); 304 305 $vensData = str_replace("\r",'.',str_replace("\n", '.', $Data)); 306 $Data1 = $Data; 307 $Data= chunk_split($vensData,16,"\r\n"); 308 309 $vensc1 = chunk_split(chunk_split($HexData, 2, " "),48,"###"); 310 $vensc2 = chunk_split($vensData,16,"###"); 311 $arrayvensc1 = explode('###', $vensc1); 312 $arrayvensc2 = explode('###', $vensc2); 313 $countvens = count($arrayvensc1); 314 $newData = ''; 315 $newData1 = ''; 316 if($DataLen == 0 || $DataLen ==''){ 317 $newData1 = ''; 318 }else{ 319 $newData1 = '1'; 320 for ($ii=0; $ii < $countvens; $ii++) { 321 if($ii < 10){ 322 $vi = '00'.$ii; 323 }else if($i< 100){ 324 $vi = '0'.$ii; 325 }else{ 326 $vi = $ii; 327 } 328 if($ii == $countvens- 2 || $ii == $countvens- 1){ 329 $vstrlen = strlen($arrayvensc1[$ii]); 330 if($vstrlen<48){ 331 $cnum = 48 - $vstrlen; 332 for($iv=0;$iv<$cnum;$iv++) { 333 $arrayvensc1[$ii].=" "; 334 } 335 } 336 } 337 $newData .= $vi.' '.$arrayvensc1[$ii].' '.$arrayvensc2[$ii]."\r\n" ; 338 $newData1 = mb_convert_encoding($newData, 'UTF-8', 'UTF-8'); 339 } 340 341 } 342 343 $vensChunk = mb_convert_encoding(chunk_split(chunk_split($HexData, 2, " "),48,"\r\n"), 'UTF-8', 'UTF-8'); 344 345 $html .= <<<Eof 346 <tr><td>Data Proctol is:</td><td> $Proctol(UDP) </td></tr> 347 <tr><td>Src Port is:</td><td> $SrcPort </td></tr> 348 <tr><td>Dec Port is:</td><td> $DecPort </td></tr> 349 <tr><td>SEQ -> NSEQ is:</td><td> $SEQ -> $NSEQ </td></tr> 350 <tr bgcolor="#ff6600"><td>Data Len is:</td><td> $DataLen </td></tr> 351 <tr><td>Hex Data is:</td><td><textarea rows="10" style=" -break:break-all;width:600px;"> $vensChunk </textarea></td></tr> 352 <tr bgcolor="#ffcc66"><td>Binary Data is:</td><td><textarea rows="10" style=" -break:break-all;width:600px;"> $Data1 </textarea></td></tr> 353 <tr bgcolor="#ffcc66"><td>Binary Data is:</td><td><textarea rows="10" style=" -break:break-all;width:600px;"> $newData1 </textarea></td></tr> 354 Eof; 355 356 357 358 359 }else{ 360 $html .= "<tr bgcolor=red><td>WARNING1111:</td><td>This is not an TCP Data, I will jump to NEXT.</td></tr>"; 361 362 } 363 } 364 365 } 366 echo $html; 367 368 // $vensCaplen = 0; //这个值 和页码一起给定 369 //没有一共页数 370 //根据文件大小和 便宜量来判断是否有下一页 371 372 373 //-- -- 374 375 /* 376 377 $PackData = bin2hex($PackData); 378 379 $PackData = chunk_split($PackData, 32, "<br />\r\n"); 380 381 echo "<tr><td>Hex PackData is:</td><td>".$PackData."</td></tr>"; 382 383 */ 384 385 386 387 388 fclose($f); 389 390 391 ?> 392 393 394 </table> 395 <a href='http://localhost:8446/tcpudp/phpjiexies.php?type=add&page=<?php echo $page+2;?>&vensCaplen=<?php echo $vensCaplen;?>'><?php echo $page+2;?>下一页<?php echo $vensCaplen;?></a> 396 <a href=''>刷新</a> 397 398 399 <a href='http://localhost:8446/tcpudp/phpjiexies.php?type=edit&page=<?php echo $page;?>&vensCaplen=<?php echo $vensCaplenred;?>'><?php echo $page;?>上一页<?php echo $vensCaplenred;?></a> 400 401 <h1><?php echo $vensCaplen;?></h1> 402 403 </body> 404 </html>
文件链接:https://pan.baidu.com/s/1KwYZ_-Ot993ocK-2xLVXWg jadn

浙公网安备 33010602011771号