グラブル7周年イベント"STAY MOON"調査記録を解読する(2)

この記事はグラブル7周年イベント”STAY MOON”調査記録を解読する(1)の続きです。

まだ読んでない方はそちらを先に読んでいただけると助かります。

データの考察

前回解読したトップページの文章をクリックすると次のようなデータが表示されます。

日本語版のデータ

このデータも日本語版と英語版で少し内容が異なりますが、前回同様ひとまず日本語版で進めていきます。

文字を読める状態にする

対応表

前回作った対応表を使って対応するアルファベットと数字を書き込んでみました。

日本語版の置き換え後データ

画像の状態では扱いづらいのでテキストに書き起こします。

(一度画像に書き込んでおかないとどこまで書いたかわからなくなるのでこうしています。)

日本語版のデータ
F5 6D 65 73 73 61 67 65 5F 5F 5F 5F 5F 5F 74 6F 41 6C
6C 00 00 00 00 00 00 00 00 00 00 00 57 73 74 61 79 3A 610F
5473 306F 300C 7559 307E 308B 3053 3068 300D 3002 307B
304B 3001 300C 6EDE 5728 300D 300C 505C 6EDE 300D 300C
5EF6 671F 300D 300C 96E2 308C 306A 3044 300D 300C 5C45
7D9A 3051 308B 300D 306A 3069 3002 20 CA F5 5F 5F 5F
6E 61 63 6B 5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E 00 00 00
00 00 00 00 00 00 00 00 00 08 06 F5 5F 72 65 73 65 6E
64 5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C 00 00 00 00 00 00 00
00 00 00 00 0D 73 74 61 79 3A 96E2 308C 306A 3044 0D 55
F5 5F 5F 5F 6E 61 63 6B 5F 5F 5F 5F 5F 74 6F 4D 6F
6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 08 06 F5 5F 72
65 73 65 6E 64 5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C 00 00
00 00 00 00 00 00 00 00 00 0D 73 74 61 79 3A 96E2 308C 06A
3044 0D 55 F5 5F 5F 5F 6E 61 63 6B 5F 5F 5F 5F 5F 74
6F 4D 6F 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 08 06

この作業が一番大変でした💢

(打ち間違いなどあったらごめんなさい。)

何のデータなのかを考える

イベント説明

「正体不明の通信を傍受」「暗号解読班が調査中」とあるので、おそらくこのデータが傍受した通信のデータだと考えられます。

前回解読したトップページの文章が通信プロトコルの説明だと考えられるので、それを元にデータを解析していきます。

データを解析する

察しのいい方ならもうお気づきだと思いますが、このデータは16進数表記のバイナリデータと考えられます。

これを前回解読してわかった通信プロトコルを元に解析していきます。

説明1段落目
DISPATCH GUIDELINES
PACKET CONSISTS OF THE FOLLOWING
3 BLOCKS:

「発信ガイドライン: パッケージには以下の3ブロックが含まれています。」

らしいので各ブロックごとに確認していきます。

ヘッダ

説明2段落目
HEADER:
MESSAGE FLAG 0XF5 (1 BYTE) + DATA CLASS (7
BYTES) + DATA ADDRESS (11 BYTES) + DATA
LENGTH (12 BYTES) IN SEQUENCE TOTALS
31 BYTES.

ヘッダは

の合計31バイトのデータから構成されているようです。

先ほど書き起こしたデータから初めの31バイト分を確認してみます。

HEADER
F5 6D 65 73 73 61 67 65 5F 5F 5F 5F 5F 5F 74 6F
41 6C 6C 00 00 00 00 00 00 00 00 00 00 00 57

ここから更に分解して人間が読める状態にしていきます。

詳しい説明は省きますが下記のようなJavaScriptを使って16進数のデータを文字列に直しています。

function hexToText(hexText) {
    return String.fromCharCode(
        ...hexText
        .split(/[\n\s]/)
        .map(n => parseInt(n, 16))
    );
}
DataClass
6D 65 73 73 61 67 65

文字にするとmessageになります。

DataAddress
5F 5F 5F 5F 5F 5F 76 6F 41 6C 6C

文字にすると______toAllになります。

DataLength
00 00 00 00 00 00 00 00 00 00 00 57

10進数にすると87になります。

なのでこのデータは

となります!

本文

説明3段落目
DATA:
MESSAGES OF VARIABLE CLASS,
NUANCE, AND LENGTH. BYTE RANGE MATCHES
DATA LENGTH IN HEADER.

通信の本文にあたる部分は長さが可変で、ヘッダのData Lengthの長さになっているとのことです。

なので32バイト目から87バイト分が本文になります。

DATA
73 74 61 79 3A 610F
5473 306F 300C 7559 307E 308B 3053 3068 300D 3002 307B
304B 3001 300C 6EDE 5728 300D 300C 505C 6EDE 300D 300C
5EF6 671F 300D 300C 96E2 308C 306A 3044 300D 300C 5C45
7D9A 3051 308B 300D 306A 3069 3002

これを文字にすると

stay:意味は「留まること」。ほか、「滞在」「停滞」「延期」「離れない」「居続ける」など。

になります。

フッター

説明4段落目
FOOTER:
2 BYTE CHECKSUM ADDED TO EACH BYTE
IN HEADER AND DATA.

2バイトのチェックサムだそうです。

該当部分は

Checksum
20 CA

になります。

これは誤り検出の一種でデータが正しく受信されているか確認するために使います。

ヘッダと本文のデータ列の和が0x20CAになるか確認してみます。

function checksum(dataText) {
    return dataText
        .replace(/[\n\s]/g, "")// スペースと改行を取り除く
        .match(/.{2}/g)// 2文字ごとに分割する(1バイト分)
        .map(n => parseInt(n, 16))// 10進数に直す
        .reduce((sum, n) => sum + n)// 全て足す
        .toString(16);// 16進数にする
}

上記のJavaScriptで確認したところ0x2121になりました。

違うじゃん…。

これは見なかったことにしましょう。

(英語版やこれ以降の通信データはchecksumと一致していました。)

まとめ

以上の解析方法で今回のデータをすべて解析するとこうなります!

傍受した通信データ
F5
6D 65 73 73 61 67 65
5F 5F 5F 5F 5F 5F 74 6F 41 6C
6C 00 00 00 00 00 00 00 00 00 00 00 57
73 74 61 79 3A
610F 5473 306F 300C 7559 307E 308B 3053
3068 300D 3002 307B 304B 3001 300C 6EDE
5728 300D 300C 505C 6EDE 300D 300C 5EF6
671F 300D 300C 96E2 308C 306A 3044 300D
300C 5C45 7D9A 3051 308B 300D 306A 3069 3002
20 CA

F5 
5F 5F 5F 6E 61 63 6B
5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E
00 00 00 00 00 00 00 00 00 00 00 00
08 06

F5 
5F 72 65 73 65 6E 64
5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C
00 00 00 00 00 00 00 00 00 00 00 0D
73 74 61 79 3A 96E2 308C 306A 3044
0D 55

F5
5F 5F 5F 6E 61 63 6B
5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E
00 00 00 00 00 00 00 00 00 00 00 00
08 06

F5
5F 72 65 73 65 6E 64
5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C
00 00 00 00 00 00 00 00 00 00 00 0D
73 74 61 79 3A 96E2 308C 06A 3044
0D 55

F5
5F 5F 5F 6E 61 63 6B
5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E
00 00 00 00 00 00 00 00 00 00 00 00
08 06

(わかりやすいように改行をいれています)

読める状態にしたもの
message
______toAll
stay:意味は「留まること」。
ほか、「滞在」「停滞」「延期」「離れない」「居続ける」など。

___nack
_____toMoon

_resend
______toAll
stay:離れない

___nack
_____toMoon

_resend
______toAll
stay:離れjい

___nack
_____toMoon

「離れjい」はData Lengthを見る限り誤字だと思われます。

ヘッダのData Classにあたる部分をみると

といった感じなので月からの「stay」というメッセージが受信側に届かず何回も再送信している…といったやり取りに見えます。

一体誰に対しての通信を傍受したのか…気になりますね。

めちゃくちゃしっかり作りこまれていて面白かったです。

(一部の誤字やデータの改行がぐちゃぐちゃなのはすごく気になりますが…)

誤字脱字などあれば@totoraj_gameまで知らせていただけるとありがたいです。

よければ筆者のツイートを拡散していただけると嬉しいです。

長くなりましたがここまで読んでいただきありがとうございました!!!

(内容は同じですが英語版の解析結果も載せておきます。)

英語版の解析結果

英語版の通信データ

EnglishData
F5
6D 65 73 73 61 67 65
5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C
00 00 00 00 00 00 00 00 00 00 00 5C
73 74 61 79 3A 20 64 65 66 2E 20 74 6F 20 73 74
6F 70 20 73 6F 6D 65 77 68 65 72 65 2E 20 53 79
6E 2E 20 5B 73 6F 6A 6F 75 72 6E 5D 2C 20 5B 64
65 6C 61 79 5D 2C 20 5B 70 6F 73 74 70 6F 6E 65
5D 2C 20 5B 72 65 6D 61 69 6E 5D 2C 20 5B 70 65
72 73 69 73 74 5D 2C 20 65 74 63 2E
29 2D

F5
5F 5F 5F 6E 61 63 6B
5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E
00 00 00 00 00 00 00 00 00 00 00 00
08 06

F5
5F 72 65 73 65 6E 64
5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C
00 00 00 00 00 00 00 00 00 00 00 0D
73 74 61 79 3A 20 72 65 6D 61 69 6E 2E
0C DD

F5
5F 5F 5F 6E 61 63 6B
5F 5F 5F 5F 5F 74 6F 4D 6F 6F 6E
00 00 00 00 00 00 00 00 00 00 00 00
08 06

F5
5F 72 65 73 65 6E 64
5F 5F 5F 5F 5F 5F 74 6F 41 6C 6C
00 00 00 00 00 00 00 00 00 00 00 0D
73 74 61 79 3A 20 72 65 6D 61 69 6E 2E
0C DD
English
message
______toAll
stay: def. to stop somewhere.
Syn. [sojourn], [delay], [postpone], [remain], [persist], etc.

___nack
_____toMoon

_resend
______toAll
stay: remain.

___nack
_____toMoon

_resend
______toAll
stay: remain.

___nack
_____toMoon