読者です 読者をやめる 読者になる 読者になる

備忘録

備忘録

.protoをバイナリから作る

リバースエンジニアリング Protocol Buffers

Ⅰ. はじめに

.protoファイルが手元に無い場合はバイナリデータから元データをMessagePackのように完全に復元させることは困難です。
少しでも.protoファイルを楽して作る方法をメモ。

私の知る限りバイナリから自動で.protoを生成するツールは公開されていません。

また、なぜ復元が困難かについてはココで原理を理解するとわかります。
https://developers.google.com/protocol-buffers/docs/encoding

また、この記事でサンプルとして使う元データは以下の通りです。

armor.proto

message Armor {
  required uint64 Id = 1;
  required string Name = 2;
  repeated Option Attribute = 3;
}

message Option {
  required uint32 Id = 1;
  required string Detail = 2;
}

データ(C#)

var armors = new List<Armor>();

var fireOption = new Option() { Id = 1001, Detail = "火属性 耐性" };
var waterOption = new Option() { Id = 1002, Detail = "水属性 耐性" };
var woodOption = new Option() { Id = 1003, Detail = "木属性 耐性" };

armors.Add(new Armor() { Id = 100001, Name = "防具001", Attribute = new Option[] { fireOption } });
armors.Add(new Armor() { Id = 100002, Name = "防具002", Attribute = new Option[] { waterOption } });
armors.Add(new Armor() { Id = 100003, Name = "防具003", Attribute = new Option[] { waterOption, woodOption } });

Ⅱ. protofudger を使う方法

GO言語で書かれた非常に優秀なツールです。

ただし、文字列が 1024 * 32バイト(32,768バイト)を超えると例外を吐くので、
fork して修正したものも置いておきます。

https://github.com/deoxxa/protofudger

  • fork

https://github.com/kagasu/protofudger

使い方
protofudger.exe binary_file > out.txt
出力結果
1: {
  1: (varint) 100001
  2: (string) "防具001"
  3: {
    1: (varint) 1001
    2: (string) "火属性 耐性"
  }
}
1: {
  1: (varint) 100002
  2: (string) "防具002"
  3: {
    1: (varint) 1002
    2: (string) "水属性 耐性"
  }
}
1: {
  1: (varint) 100003
  2: (string) "防具003"
  3: {
    1: (varint) 1002
    2: (string) "水属性 耐性"
  }
  3: {
    1: (varint) 1003
    2: (string) "木属性 耐性"
  }
}

Ⅲ. Protobuf Viewerを使う方法


macOSでのみ動作します。(2017/03/17時点)
GUIがあるのでmacOSが使える状況であればコレが一番使いやすいです。

https://sourceforge.net/projects/protobufviewer/

Ⅳ. protoc を使う方法

こちらからダウンロードできます。
https://github.com/google/protobuf/releases

また、NuGetから Google.ProtocolBuffers パッケージをインストールすると protoc.exe も含まれています。

使い方
protoc.exe --decode_raw < binary_file > out.txt
作った.protoをテストする場合
protoc --decode=PackageName.MessageName MessageName.proto < decrypted.bytes > out.txt
出力結果
1 {
  1: 100001
  2: "\351\230\262\345\205\267001"
  3 {
    1: 1001
    2: "\347\201\253\345\261\236\346\200\247 \350\200\220\346\200\247"
  }
}
1 {
  1: 100002
  2: "\351\230\262\345\205\267002"
  3 {
    1: 1002
    2: "\346\260\264\345\261\236\346\200\247 \350\200\220\346\200\247"
  }
}
1 {
  1: 100003
  2: "\351\230\262\345\205\267003"
  3 {
    1: 1002
    2: "\346\260\264\345\261\236\346\200\247 \350\200\220\346\200\247"
  }
  3 {
    1: 1003
    2: "\346\234\250\345\261\236\346\200\247 \350\200\220\346\200\247"
  }
}