func.4 objects

進捗しない日記 プログラミングとか

Doki Doki Literature Club!キャラクターファイルのデコード

久しぶりに書こうかなと思ったので。
非公式日本語化mod導入した後の内容です。
いくつかのネタバレを含むので既プレイ向けです。
未プレイの方はSteamで無料なので是非。どんなゲームかはタグを見れば分かるはず。
store.steampowered.com

特に内容に関しての考察はしません。

デコード

エンディングまで迎えられたということは、キャラクターファイルの存在は知っていることと思います。
これらのファイルは、ある程度の暗号化はされているものの内容が存在していて、親切にもいくつかは日本語化されています。

とりあえずデコードが簡単なファイルから。

yuri.chr

テキストエディタ(notepad++とかsakura editorとかなんでも)で開くと、明らかに暗号化された文章が得られます。
文章が=で終わっているのでbase64でデコードします。
おわり。

デコードにはbase64のデコードができるサービスを使えばらくちんです。こことか。
ちなみに内容は日本語で約10000字と結構しっかりした詩...日記?です。
翻訳者さん本当にありがとうございます。
英語の原文は、調べてみると
Untitled • Linda Watson のようです。

それと、このファイルは日本語化した際でも、モニカがキャラクターファイル置き直すイベントが起こるまでは英語化された暗号データになっていました。
おそらくシステムの仕様なので、いい感じの頃合い*1を見計らってchrファイルを保存しましょう。
言語を判断する方法として、英語化暗号データは比較的ランダムな記号列に見え、日本語化暗号データだと44●●が頻出します(ひらがなが44●●にエンコードされるため)

~♥

natuki.chr

これもテキストエディタで開くとJFIFっぽい感じなので、拡張子をJFIFにして開きます。
かなり丸く歪んだ画像が得られるので、UnityやBlenderでSphereオブジェクトを作ってテクスチャとして貼り付けます。
おわり。

こんな感じの画像が得られます。
Screen capture - a07ec4c42787ef61a2f9e6eb7e81fbf8 - Gyazo

この画像についてはきっと文芸部の考察班が解釈してくれていることでしょう。

sayori.chr

難易度が上がります。
テキストエディタで開くとOggっぽい雰囲気を感じるので、拡張子をoggにして開きます。
すると、ノイズのようなデータが得られます。どうも特定の周波数帯にデータをのせている感じがするので、スペクトログラムで表示します。(多分pythonなりでコードを書くのが楽かも)
結果、以下の画像のようにQRコードが得られます。これを頑張ってスキャンすると、URLに飛びます。
f:id:f4sn:20180216160254p:plain:w150
おわり。

飛ぶリンクはここのようです。
……ようです、というのは、実はQRコードが上手く読み取れなかったのでredditのSpoilerを見てしまいました。
ただQRコードを目diffした感じ全く同じもののようだったので、おそらく正しいと思います。

追記。読み取れなかったのが悔しかったので、読み取れるQRコードを作りました。最後にあります。

monika.chr

テキストエディタで開くと、臼NGなファイル*2と分かるので拡張子をpngにします。
画像ファイルが得られるので、デコードに必要そうな部分だけをトリミングして以下の画像を得ます。
f:id:f4sn:20180216163155p:plain:w150
かなり見辛いですが、画像の下の方で白黒のデータが途切れているため、左上から右→下に向かって読めば良いと分かります。
後はRMagickなりOpenCVなりPILなりで画素を取り、01に変換していい感じ*3に文字変換すると、そこそこ長い記号列を得ます。
この記号列も=で終わっているためbase64でデコードすれば読める文章が得られます。
おわり。

得られた文章はこれでした。日本語化はされていませんでした……というか画像埋め込みなので不可能なのかも。
もしくはこれもデータを取ったタイミングが悪かっただけかもしれません。まぁGoogle翻訳にぶち込んだらよろし。(yuri.chrのとか英語で読む気はしない)

使ったコードは

from PIL import Image
im = Image.open("a.jpg").convert('HSV')
size = im.size
bi = ""
st = ""
for y in range(size[1]):
    for x in range(size[0]):
        v = im.getpixel((x,y))[2]
        bi += "0" if v < 127 else "1"
while bi:
    st += chr(int(bi[0:8], 2))
    bi = bi[8:]
print st.decode('base64')

こんな感じ。

おまけ

途中でナツキが出してくる詩に、
f:id:f4sn:20180216174354p:plain:w150
こういう詩があります。
明らかにbase64でデコードできます。
OCRしたかったのですが、手書きフォントはつらそうだと思ってこの記号列を手打ちしてデコードしました。これはこれでつらい*4

以下の文を得られます。

第三の目を開け

ナイフ越しに、彼女の柔肌をあたかも自分の触覚の延長で有るかのように感じ取ることができる。
私は身悶えする。
この手に負えないほどの快楽に抗おうと何かが、ひどく微かであるが奥底で叫んでいる。
それでも、既に狂気に侵されているのを自覚している。
私は……自分を抑えられない。

第三の目(Third Eye)というのはモニカのpngファイルから得られる文章にも書いてありましたね……。
考察班の方がんばってください。


以上です。CTFを感じました。
2年前には既に書かれていた内容のyuri.chrを除き、全てにThird Eyeに関係するテキストがあるのでこれがこのゲームの隠れたテーマの一つなのでしょう。
軽く調べた感じでもまだまだ隠し要素はあるみたいなので面白そうです。きっと日本語化もされているはず。ありがたや。

追記

やっぱりQRコードが読み取れなかったのが悔しいので、画像にちょっとだけ手を加えます。

そもそもQRコードは誤り訂正があるので、多少の損失なら影響がないはずです。が、取れなかった。
おそらくは矩形を取得するためのシンボルの内2つが取得できていないからなので、これを人力で補完します。
こうしてできたのが以下の画像です。
f:id:f4sn:20180328180900p:plain:w150
この画像はちゃんとそこいらのQRコードリーダーでも認識しました。
めでたしめでたし。

*1:モニカだけがいないシナリオの時が良いかと

*2:pngをテキストエディタで見ると臼NGという文字列が先頭にくる

*3:8bit毎にascii文字にしていくだけ

*4:このフォントqがgに見えてつらかった