Command line 用protoc和无模式对protobuf重新编码

Command line 用protoc和无模式对protobuf重新编码,command-line,protocol-buffers,protoc,Command Line,Protocol Buffers,Protoc,我正在玩一个应用程序,并试图对它可以导出和导入的数据文件进行反向工程。这些文件是二进制的protobufs。我的目标是能够导出文件、转换为文本、使用其他数据记录对其进行修改、重新编码为二进制,并将其重新导入,以避免繁琐的手动数据输入应用程序。我在windows机器上使用了protoc二进制文件和--decode_raw,可以生成可读性很好的分层数据,而不知道实际使用的.proto模式。使用Marc Gravell的解析器会得到类似的结果(有些含糊不清的地方我不太明白)。我的问题如下: 是否有一种

我正在玩一个应用程序,并试图对它可以导出和导入的数据文件进行反向工程。这些文件是二进制的protobufs。我的目标是能够导出文件、转换为文本、使用其他数据记录对其进行修改、重新编码为二进制,并将其重新导入,以避免繁琐的手动数据输入应用程序。我在windows机器上使用了
protoc
二进制文件和
--decode_raw
,可以生成可读性很好的分层数据,而不知道实际使用的
.proto
模式。使用Marc Gravell的解析器会得到类似的结果(有些含糊不清的地方我不太明白)。我的问题如下:

  • 是否有一种简单的方法可以使用
    protoc
    或其他工具重新编码
    --decode_raw
    的输出以生成原始二进制文件?我知道原始解码是在对未知模式进行假设,到目前为止,这些假设似乎可以产生可理解的结果。原始解码上是否有数据丢失,从而阻止重新编码为原始编码?难道仅仅是
    protoc
    开发人员认为不需要这个功能吗?有了这个功能,我可以修改文本并重新编码,并且有机会生成有效的二进制文件
  • 如果#1无效,给定原始输出,如何创建
    .proto
    文件和文本消息输入文件,使用
    protoc--encode
    对原始二进制文件重新编码?我希望有一个指向示例文本文件的指针,可以用作
    protoc
    的命令行输入,以便我学习所需的语法。我看到的示例内容似乎都是为了使用
    protoc
    生成源代码。我测试的二进制protobufs已经解码为字符串、整数和一些十六进制值(我仍然需要破译),它们与应用程序中可见的数据很好地对应,因此我有信心,如果我看到工作示例,我可以生成所需的模式
  • 一些偏好:我正在修补我的手机和我的windows笔记本电脑,我宁愿不需要安装python或其他编程平台。我只想在命令行上使用protoc和文本/十六进制编辑器

    谢谢你的帮助

    [编辑:我找到了一个提供示例输入的网页,该网页为我提供了取得一些进展所需的线索。该网页是,因此感谢@at_ishikawa花时间创建的。通过这些示例,我了解如何格式化消息文件以生成二进制文件。但是,看起来我尝试解码的二进制文件可能不适用命令行。请参见下面我的新问题。]

    新问题:我的目标仍然是将二进制代码解码为文本消息,编辑文本消息以添加更多数据记录,并对修改后的文本消息重新编码以生成新的二进制代码,希望该应用程序能够成功导入该二进制代码。 使用--decode_raw,我可以看到我的二进制文件具有以下格式:

    
        1 {
          1: "ThisItem:name1"
          2 {
    
            1: "name1"
            2: <string>
            4: <string>
            5: 1
          }
        }
        
        1 {
          1: "ThisItem:name2"
          2 {
            1: "name2"
            2: <string>
            4: <string>
            5: 1
          }
        }
        
        1 {
          1: "ThatItem:name1"
          2 {
            1: "name1"
            3: <string>
            5: <data structure>
            8: <string>
          }
        }
        
        1 {
          1: "ThatItem:name2"
          2 {
            1: "name2"
            3: <string>
            5: <data structure>
            8: <string>
          }
        }
        
        1 {
          1: "ThisItem:name3"
          2 {
            1: "name3"
            2: <string>
            4: <string>
            5: 1
          }
        }
    
    
    
    1 {
    1:“此项:名称1”
    2 {
    1:“名称1”
    2: 
    4: 
    5: 1
    }
    }
    1 {
    1:“此项:名称2”
    2 {
    1:“名称2”
    2: 
    4: 
    5: 1
    }
    }
    1 {
    1:“该项目:名称1”
    2 {
    1:“名称1”
    三:
    5: 
    8: 
    }
    }
    1 {
    1:“该项目:名称2”
    2 {
    1:“名称2”
    三:
    5: 
    8: 
    }
    }
    1 {
    1:“此项:名称3”
    2 {
    1:“姓名3”
    2: 
    4: 
    5: 1
    }
    }
    
    因此,我看到了数据结构的几个特征:

    
        syntax = "proto3";
        
        message RecordList {
            repeated Record records = 1;
        }
        
        message Record {
            string id = 1;
            ThisItem item = 2;
            ThatItem item = 2;  //  Problem here, each record uses field 2, but with different message types.
        //  Each record has either a ThisItem or ThatItem.  Parsing the id field could tell which,
        //  but that doesn't appear possible with protoc on the command line.
        }
        
        message ThisItem {
            string id = 1;
            string <element2> = 2;
            string <element4> = 4;
            int32 <element5> = 5;
        }
        
        message ThatItem {
            string id = 1;
            string <element3> = 3;
            <message type> <element5> = 5;
            string <element8> = 8;
        }
    
    
  • 该文件是许多记录的串联,每个记录具有相同的字段号1。因此,它们需要使用相同的消息格式
  • 每个记录在字段2中都有一个子消息,但这些消息有两种不同的格式
  • 每个记录都有一个字段编号1,它是一个前缀“ThisItem”或“ThatItem”,显然标识字段2的消息类型,还有一个后缀,与“内部”消息中的第一个字符串匹配
  • 然后,我可以制作一个.proto文件来几乎支持这种结构:

    
        syntax = "proto3";
        
        message RecordList {
            repeated Record records = 1;
        }
        
        message Record {
            string id = 1;
            ThisItem item = 2;
            ThatItem item = 2;  //  Problem here, each record uses field 2, but with different message types.
        //  Each record has either a ThisItem or ThatItem.  Parsing the id field could tell which,
        //  but that doesn't appear possible with protoc on the command line.
        }
        
        message ThisItem {
            string id = 1;
            string <element2> = 2;
            string <element4> = 4;
            int32 <element5> = 5;
        }
        
        message ThatItem {
            string id = 1;
            string <element3> = 3;
            <message type> <element5> = 5;
            string <element8> = 8;
        }
    
    
    
    syntax=“proto3”;
    消息记录列表{
    重复记录=1;
    }
    消息记录{
    字符串id=1;
    该项=2;
    ThatItem=2;//这里的问题是,每条记录使用字段2,但消息类型不同。
    //每个记录都有一个ThisItem或ThatItem。分析id字段可以知道是哪个,
    //但在命令行上使用protoc时,这似乎是不可能的。
    }
    消息此项{
    字符串id=1;
    字符串=2;
    字符串=4;
    int32=5;
    }
    该项目的消息{
    字符串id=1;
    字符串=3;
    = 5;
    字符串=8;
    }
    
    因此,我不确定是否有方法在命令行上解码/编码此二进制文件。是否有一些语法可用于记录消息通过解析字段1中的字符串在字段2的两个可能选择之间切换?如果没有,我将需要在程序中读取和解析记录,这是我想要避免的

    我意识到的另一种可能性是:我可以使用一个子消息并跳过未使用的字段,而不是两个不同的子消息
    ThisItem
    ThatItem
    。子消息将在一种情况下填充字段1、2、4和5,在另一种情况下填充字段1、3、5和8。难度是字段5,即o中的整数1一个是ne,另一个是数据结构。我不知道如何管理它。整数1是空消息的二进制编码吗


    谢谢你的帮助。

    让我看看是否能帮你回答这个问题

    1.使用protoc重新编码
    protoc--decode_raw
    是一条死胡同,以后不能使用protoc进行编码。这是因为没有s
    records {
      id: "1"
      item {
        id: "1.1"
        element2: "e2"
        element4: "e4"
        element5: 5
      }
    }
    records {
      id: "2"
      item {
        id: "2.1"
        element2: "e2"
        element4: "e4"
        element5: 5
      }
    }
    
    message Record {
        string id = 1;
        ThisItem item = 2;
        ThatItem item = 2;  //  Problem here, each record uses field 2, but with different message types.
    //  Each record has either a ThisItem or ThatItem.  Parsing the id field could tell which,
    //  but that doesn't appear possible with protoc on the command line.
    }
    
    message Record {
        optional string id = 1;
        oneof datafields {
            bytes data = 2;
            ThisItem thisitem = 3;
            ThatItem thatitem= 4;
        }
    }
    
    import myschema_pb2
    from google.protobuf import text_format
    
    ### Read objects from PB and load into RecordList
    mylist=myschema_pb2.RecordList()
    f=open('objects.pb','rb')
    mylist.ParseFromString(f.read())
    f.close()
        
    ### Parse general data into ThisItem or ThatItem
    for rec in mylist.records:
      bin1 = rec.data
      ss=rec.id
      itemID=ss[0:ss.find(':')]
      if itemID == 'ThisItem':
        rec.thisitem.ParseFromString(rec.data) # parses data into thisitem and clears data
      elif itemID == 'ThatItem':
        rec.thatitem.ParseFromString(rec.data) # parses data into thatitem and clears data
      else:
        print('unknown')
    
    ### Generalize ThisItem and ThatItem into data
    for rec in newlist.records:
      ss=rec.id
      itemID=ss[0:ss.find(':')]
      if itemID == 'ThisItem':
        rec.data=rec.thisitem.SerializeToString()
      elif itemID == 'ThatItem':
        rec.data=rec.thatitem.SerializeToString()
      else:
        print('unknown')