做一个工具4-5

环境

  • 2022-05-10
  • Windows 10
  • 开发工具 VS 2022
  • 开发语言 C#
  • 一个 .pcap 文件

任务

  • 任务:pcap文件解析。

  • 参考资料

  • 作业:编程解析第三天的pcap文件,遍历文件中的所有数据包,打印所有数据包时间、长度信息。

    示例:

    • 总计124个数据包:
    • [2022-01-12 15:00:01] 128 Bytes
    • [2022-01-12 15:00:02] 1064 Bytes
    • [2022-01-12 15:00:03] 1460 Bytes
    • ······

作业

  • 思路分析
    1. 文件读取用FileStream 
    2.  读取/解析pcap数据报存储格式的数据
       2.1 读取Pcap Header的Magic(4B) 判断大小端
       	2.1.1 如果是小端数据,则需要Reverse函数,交换字节顺序。			
       2.2  读取数据包的时间戳(高低都要)
       2.3  读取数据包长度
       2.4 通过定位来截取需要的字节Seek;或者通过 字节数组 的截取
       2.5 将读取的2进制文件转成16进制(方便对照)	
       2.6 将数据转换成10进制
    3. 用FileStream写入解析出来的数据 
    
  • 难点
     时间戳:格林威治时间1970年01月01日00时00分00秒起至当下的总秒数。(这是Unix的)
     时间戳:DateTime.Now.Ticks;是从0001 年 1 月 1 日午夜 12:00:00 开始,单位是微秒。(这是C#系统的)
     
     pcap的Timestamp(4B):时间戳高位,精确到seconds,这是Unix时间戳。捕获数据包的时间一般是根据这个值。
     我是在C#里,所以我需要将解析出来的这个时间戳*1000,
    
  • 问题
    时间戳计算不成功,之前我转的是整型int(int32)*1000后,时间戳就变负数了,后改为长整型long(int64)*1000;且要将开始时间设为格林威治【DateTime dateTimeStart = new DateTime(1970, 1, 1, 0, 0, 0);】的那个时间,然后才能计算出真正的时间。

代码


using System.Text;
using ReadAndPrint;

var path = @"D:/day3.pcap";
var filePath = $@"D:/Log/{
      
       DateTime.Now.ToString("yyyyMMdd-HHmmss")}.txt";
PcapHelper pcap = new PcapHelper();

using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    
    
    // 将文件中的数据暂存至 字节数组b 中 
    int len = (int)fs.Length;
    byte[] b = new byte[fs.Length];
    fs.Read(b, 0, len);

    // 截取前4B 判断大小端 识别文件和字节顺序
    byte[] bMagic = b.Skip(0).Take(4).ToArray();
    pcap.isSmall(bMagic);

    long icapLen = 0;
    int position = 24;
    int counter = 1;

    do
    {
    
    
        // 数据包 时间戳 s:高精度 ms:低精度
        byte[] btimeStamp = b.Skip(position).Take(4).ToArray();
        // long s = pcap.Get10By2(btimeStamp);//由于写入的时间里也加入了这个方法,导致字节进行了两次交换,所以屏蔽了这一句;或者可修改时间的方法或者重新写一个参数为long类型的得到时间的方法。
        long ms = pcap.Get10By2(b.Skip(position + 4).Take(4).ToArray());

        // 数据包 长度信息
        byte[] bcapLen = b.Skip(position + 8).Take(4).ToArray();
        icapLen = pcap.Get10By2(bcapLen);

        // pcap.ByteToDate(btimeStamp) 解析这个时间戳,转换为抓包的时间
        pcap.WritePrint(filePath, $"[{
      
       pcap.ByteToDate(btimeStamp)}.{
      
      ms}] [{
      
      counter}]  {
      
      icapLen} Bytes ");

        position += (int)icapLen + 16;
        counter++;
	// 当icapLen<=0且position>=len的时候,结束循环 
    } while (icapLen > 0 && position < len);
    
    Console.WriteLine();

}
// 辅助类
		using System.Text;
		
		 /// <summary>
        /// 若isSmall为true,则字节数组进行翻转
        /// </summary>
        private bool bisSmall {
    
     get; set; } = false;


        /// <summary>
        /// 根据 16进制字符串 返回 10进制数字
        /// 16 => 10
        /// </summary>
        /// <param name="str16">16进制字符串</param>
        /// <returns>10进制数字</returns>
        public int Get10By16(string str16)
        {
    
    
            return System.Convert.ToInt32(str16, 16);
        }


        /// <summary>
        /// 将字节数组 转成 10进制数字
        /// </summary>
        /// <param name="b"></param>
        /// <returns>10进制数字</returns>
        public long Get10By2(byte[] b)
        {
    
    
            return System.Convert.ToInt64(Get16By2(b), 16);
        }


        /// <summary>
        /// 将字节数组 转化为 16进制的字符串
        /// 2 => 16
        /// </summary>
        /// <param name="b">字节数组</param>
        /// <returns>16进制的字符串</returns>
        public string Get16By2(byte[] b)
        {
    
    
            string str = "", str1 = "";

            // 判断数据是 大端读取 还是 小端读取
            // 是小端则进行翻转
            if (bisSmall)
                Array.Reverse(b);

            for (int i = 0; i < b.Length; i++)
            {
    
    
                str += string.Format("{0:X2}", b[i]);// D4C3B2A1
                str1 += string.Format("{0:x}", b[i]);// d4c3b2a1
            }
            return str;
        }


        public string ByteToDate(byte[] b)
        {
    
     
            // C# 需要精确到毫秒,而解析出来的高精度是到秒,所以*1000
            long unixDate = Get10By2(b) * 1000;
            // 相当于时间定位到格林威尔
            DateTime dateTimeStart = new DateTime(1970, 1, 1, 0, 0, 0);
            // 格林威尔时间+时间戳 ==》数据包抓包时间
            DateTime date = dateTimeStart.AddMilliseconds(unixDate).ToLocalTime();
            return date.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        /// 判断数据是 大端读取 还是 小端读取
        /// </summary>
        /// <param name="b">字节数组</param> 
        public void isSmall(byte[] b)
        {
    
    
            string sMagic = Get16By2(b);
            if (sMagic == "D4C3B2A1")
                bisSmall = true;
            else if (sMagic == "A1B2C3D4")
                bisSmall = false;
        }


        /// <summary>
        /// 将解析出来的数据写入Log
        /// </summary>
        /// <param name="b"></param>
        public void WritePrint(string filePath, string b)
        {
    
    
            // 创建文件夹
            CreateFolder(filePath);

            using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
            {
    
    
                fs.Write(Encoding.UTF8.GetBytes(b), 0, b.Length);
                fs.Write(Encoding.UTF8.GetBytes("\r\n")); // 数据换行
            }
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="filePath"></param>
        public void CreateFolder(string filePath)
        {
    
    
            //var fileName = Path.GetFileName(filePath); // 20220518-134243.txt
            var logPath = Path.GetDirectoryName(filePath);// D:\\Log
            if (Directory.Exists(logPath))
                Directory.CreateDirectory(logPath);

            // 创建文件
            CreateFile(filePath);
        }

        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="filePath"></param>
        public void CreateFile(string filePath)
        {
    
     
            if (!File.Exists(filePath))
            {
    
     using var fs = new FileStream(filePath, FileMode.Create); }
            //File.Create(filePath);     
        }

结果

[1] [2022-05-10 09:44:27.650676] 66 Bytes 
[2] [2022-05-10 09:44:27.702689] 66 Bytes 
[3] [2022-05-10 09:44:27.702731] 54 Bytes 
···
[57] [2022-05-10 09:44:28.504467] 1039 Bytes 
[58] [2022-05-10 09:44:28.545317] 54 Bytes 

参考文章

什么是Timestamp——时间戳?
C# unix时间戳转换

猜你喜欢

转载自blog.csdn.net/qq_41128526/article/details/124841784
4-5
今日推荐