前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET6实现破解Modbus poll点表配置文件

.NET6实现破解Modbus poll点表配置文件

作者头像
郑子铭
发布2023-12-13 11:18:38
1910
发布2023-12-13 11:18:38
举报
文章被收录于专栏:DotNet NB && CloudNative

  • 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
  • 📢本文作者:由webmote 原创
  • 📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔 !

序言

Modbus 协议是工控领域常见的一种通信协议,而Modbus Poll无疑是其中最好用的Master软件了,通过自定义的点表,可以通过查表的方式,快速的去响应主从机的动作和状态。

其中使用的点表配置文件格式为mbp,今天,我们的目标就是这个文件!

其中,对我们有意义的数据有起始地址,功能代码,点表列表数据,如何获取呢?

1. 分析文件格式

先谷歌一下,在百度一下,并未发现有人解析过mbp格式的文件,经过在官网的浏览,没有发现任何有用的信息,可见该文件格式是私密格式,如果给作者发邮件,不知道能否得到作者大大的指点,有社牛的朋友,可以试试。

chatgpt说: Modbus Poll 是一个用于 Modbus 通信协议的 Windows 应用程序,它允许用户进行 Modbus 通信的监视和测试。Modbus Poll 使用 MBP 格式来保存配置文件,其中包含了 Modbus 通信配置和设置。要解析 Modbus Poll 的 MBP 格式文件,需要了解该文件的具体结构和存储的内容。通常来说,MBP 文件是一个二进制文件,保存了 Modbus Poll 的配置信息,如串口设置、Modbus 寄存器的地址、功能码、数据格式等。

不过Chatgpt并没有鸟用。

好鸟一身毛,让我们打开mbp,直接查看吧。

好家伙,这文件也太不精简了,这么多预留字段,如何下手啊?

好的思路,胜过一千行代码,来吧,让我们打开Beyond Compare屠龙软件,多加一行点表,看看HEX有啥不同。

经过缜密的比对,已经看出来头信息的格式定义,以及点表的定义位置,那么,让我们打开VS,开启码农生活。

2. 解析文件头

本来想采用结构体定义,不过有些字段是可变长度的,处理起来并没有那么容易,干脆一不做二不休,直接使用接口定义解析。

代码语言:javascript
复制
public interface IParser
    {
        int Size { get; }
        /// <summary>
        /// 解析buffer
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="start">开始解析的地址</param>
        /// <returns>解析读取了多少字节</returns>
        int Parse(byte[] buffer, int start =0);
    }

通过size,返回该类的所占的字节长度,通过parse的返回值,获取buffer的当前指针。

定义好接口后,那么我们就来实现头的解析。

代码语言:javascript
复制
public class MbpHeader : IParser
    {
        public int Flag;
        public int Version;
        public int FuncCode;
        public int StartAddress;
        public int PointTableSize;
        public byte[] Reserve;
        public int Size { get; private set; }
        public MbpHeader()
        {
            Flag = 0x2454;
            Version = 0x00A8;
            FuncCode = 0;
            StartAddress = 0;
            PointTableSize = 0;
            Reserve = new byte[508];
            Size = 0x20C;
        }

        public int Parse(byte[] buffer, int start = 0)
        {
            int i = start;
            var flag = BitConverter.ToInt32(buffer, i);
            //if(flag != 0x2454 && flag != 0x2648)
            //{
            //    throw new NotSupportedException("报文头不对,不能解析");
            //}
            i += 4;
            var ver  = BitConverter.ToInt32(buffer, i);
            //if(ver != Version)
            //{
            //    throw new NotSupportedException("报文版本不对,不能解析");
            //}
            i += 4;
            FuncCode = BitConverter.ToInt32(buffer, i);
            i += 4;
            StartAddress = BitConverter.ToInt32(buffer, i);
            i += 4;
            PointTableSize = BitConverter.ToInt32(buffer, i);
            i += Reserve.Length;

            this.Size = i;
            return i;
            
        }
    }

代码中的FlagVersion是我们推测来的,不过经测试,大概率和版本有关。 这里注释掉对版本的限制,可以支持多个版本的解析。

3.解析点表列表

经过排查,点表的解析定在 0x20C的位置上,从这里开始进行循环检测。 代码如下:

代码语言:javascript
复制
public class MbpPointTable : IParser
    {
        public int[] Flags { get; set; }       
        public MbpTableItem Item { get; set; }       
        public int Size { get; private set; }
        public MbpPointTable()
        {
            Flags = new int[12];
            Item = new MbpTableItem();
        }

        public int Parse(byte[] buffer, int start = 0)
        {
            Size = 0;
            if (buffer == null) return 0;

            var i = start;
            if(buffer.Length < start + 4 * Flags.Length)
            {
                return 0;
            }
            for(var j=0; i < start + 4*Flags.Length; i+=4,j++)
            {
                Flags[j] = BitConverter.ToInt32(buffer, i);
            }
            //0xFF FE FF
            i += 3;           
            var size = Item.Parse(buffer, i);           
            i += size;
            //解析值
            var flag3 = BitConverter.ToInt32(buffer, i);
            if(flag3 == 0x55555555)
            {
                Size = i + 4 - start;
                return i+4;
            }
            else
            {
                return -1;
            }               
        }

    }

为了更方便的标识点表数据,还需要增加一个tableItem类。

代码语言:javascript
复制
public class MbpTableItem : IParser
    {
        public int Size { get; private set; }
        public byte Len { get; set; }
        public string Name { get; set; }

        public Int16 Value { get; set; }

        public int Parse(byte[] buffer, int start = 0)
        {
            if (buffer == null) return 0;
            if(buffer.Length> start)
            {
                Len = buffer[start];
                if(buffer.Length >= (start +1 + 2* Len))
                {
                    if (Len > 0)
                    {
                        this.Name += Encoding.Unicode.GetString(buffer, start + 1, 2 * Len);
                    }
                    else
                    {
                        this.Name = String.Empty;
                    }

                    return 1+ 2*Len;
                }
                else
                {
                    return 0;
                }
            }

            return 0;
        }       
    }

这里采用Unicode对名称进行解析,以支持中文名称。

4.测试例子

为了测试,还需要封装一个mbpFile的类,这里利用该类读取文件内容,并送给上述类进行解析。 代码如下:

代码语言:javascript
复制
var p = @"D:\遥测v1.0.1(7).mbp";
MbpFile mbp = new MbpFile(p);

Console.WriteLine($"header: func = {mbp.Header.FuncCode}, start = {mbp.Header.StartAddress}, item={mbp.Header.PointTableSize}");
var i = 0;
foreach(var item in mbp.PointTables)
{
    Console.WriteLine($"点表定义{i++}: {item.Item.Name} {item.Item.Value}"); 
}

输出结果如下:

啊哈哈,终于可以采用mbp文件,直接作为程序的配置文件了。 你用过modbus吗? 是不是觉得这种方式不错? 当然,自己定义一个格式,也许更加丰富!

号外

哦哦哦,神奇的一天又结束了,modbus这个协议确实不错,优秀!

👓都看到这了,还在乎点个赞吗?

👓都点赞了,还在乎一个收藏吗?

👓都收藏了,还在乎一个评论吗?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 序言
  • 1. 分析文件格式
  • 2. 解析文件头
  • 3.解析点表列表
  • 4.测试例子
  • 号外
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档