問題について
shift-jisの特定の文字列を保存したファイルをmime_content_typeで判定すると
application/x-dosexec
と判定されてしまう。
特定の文字列について
公開フラグ
(16進数表記)
8C F6 8A 4A 83 74 83 89 83 4F
ファイルのマジックナンバー(file signature)の存在は理解しているが、
上記の16進数の並びで
application/x-dosexec
と判定される理由がわからない。
マジックナンバーの参考サイト
https://en.wikipedia.org/wiki/List_of_file_signatures
上記の参考サイトによると
実行ファイルのマジックナンバーは
4D 5A
である。
何かご存じの方がいらっしゃれば情報頂けると幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
![guest](/img/icon/icnUserSample.jpg)
回答2件
0
ベストアンサー
非常に興味深い挙動なので調べてみました。まず、これが application/x-dosexec となるのは、PHP 7.2.0以降であることがわかりました。
mime_content_type関数は内部でlibmagicというライブラリを使ってMIMEの判定をしています。libmagicを利用するもっとも有名なソフトはfileコマンドでして、「公開フラグ」をShift_JISで保存したファイル(flag.txtとします)を判定すると、
Shell
1$ file --mime-type flag.txt 2flag.txt: application/x-dosexec
となります。ちなみに、DOS Executableではあるが、EXE形式ではなく、COM形式という意味のようです。
libmagicはmagic(5)という形式のテキストデータベース(をコンパイルしたもの)によってファイルの形式を判定します。当該のルールは以下のようです。
0 ubyte 0x8c # skip "AppleWorks word processor data" like ARTICLE.1 ./apple >4 string !O==== # skip some unknown basic binaries like RocketRnger.SHR >>5 string !MAIN # skip "GPG symmetrically encrypted data" ./gnu # skip "PGP symmetric key encrypted data" ./pgp # openpgpdefs.h: fourth byte < 14 indicate cipher algorithm type >>>4 ubyte >13 DOS executable (COM, 0x8C-variant) # the remaining files should be DOS *.COM executables # dosshell.COM 8cc0 2ea35f07 e85211 e88a11 b80058 cd # hmload.COM 8cc8 8ec0 bbc02b 89dc 83c30f c1eb04 b4 # UNDELETE.COM 8cca 2e8916 6503 b430 cd21 8b 2e0200 8b # BOOTFIX.COM 8cca 2e8916 9603 b430 cd21 8b 2e0200 8b # RAWRITE3.COM 8cca 2e8916 d602 b430 cd21 8b 2e0200 8b # SHARE.COM 8cca 2e8916 d602 b430 cd21 8b 2e0200 8b # validchr.COM 8cca 2e8916 9603 b430 cd21 8b 2e028b1e # devload.COM 8cca 8916ad01 b430 cd21 8b2e0200 892e !:mime application/x-dosexec !:ext com # https://github.com/file/file/blob/master/magic/Magdir/msdos
これの意味ですが、オフセット0が0x8Cで、オフセット4から始まる文字列が O==== でなく、オフセット5から始まる文字列が MAIN でなく、オフセット4のバイト(符号なし)が 13より大きい場合、DOS executable (COM, 0x8C-variant) 、MIMEは application/x-dosexec となるようです。なぜ0x8Cで始まるデータを.COMとみなすかは、コメントに書かれた例示からわかります。多くのCOM形式のコマンドが0x8Cから始まっていることを利用しているようです。
libmagicはLinux等には元々あるライブラリですが、PHPでは外部ライブラリを呼ばず、libmagicを組み込んでいます。そして、magic形式のデータベースは、ext/fileinfo/data_file.c というファイルにC言語のソースコードとして提供されています。これの中身は巨大な配列です。
C
1$ head data_file.c 2/* This is a generated file, do not modify */ 3/* Usage: php create_data_file.php /path/to/magic.mgc > data_file.c */ 4const unsigned char php_magic_database[4932616] = { 50x1C, 0x04, 0x1E, 0xF1, 0x0E, 0x00, 0x00, 0x00, 0x6C, 0x2F, 0x00, 0x00, 0x96, 0x08, 0x00, 0x00, 60x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 9// 以下略
ソースコード上にコメントされているmagic.mgcはmagic形式をコンパイルしたバイナリファイルです。そして、これをC言語形式に変換したものがdata_file.cです。では、magic.mgcの元は…となるわけですが、どうもPHPのソースとしては同梱されていないようです。
これについて、調べた方がおられまして、以下のように書かれています。
で、PHP の libmagic だが php-src/create_data_file.php at master · php/php-src · GitHub を見るとどうやらコミッターの環境で file に含まれる magic を元に PHP 向けにカスタマイズして生成した data_file.c なるものを、 PHP 組み込みの libmagic として扱ってる模様。
file, Fileinfo に依る Office 2007+ ファイルの MIME TYPE 判定のバージョン差異について より引用
つまり、なぜご質問の挙動になるかは、細かいところは不明(data_file.cを解析すればわかりますが…)ですが、PHP 7.2.0からmagicデータベースの内容が変わった結果、0x8Cで始まるデータを application/x-dosexec と判定するようになったようです。
投稿2020/10/24 11:41
総合スコア11705
0
PHPでMIMEのContentType
を決定する為のもとのコードは知らないのですが、恐らくUNXのfile
コマンドと同等のことをしていると推測しての回答です。簡単に言うと、その特定文字列を持つファイルは古きMS-DOSの.COM形式の実行ファイルと判断しているようです。
特定の文字列「"公開フラグ"」を内容に持つファイルをdata.binとして、これをfile
コマンドでファイルタイプとMIMEのContentTypeを出力してみます。
sh
1$ od -t xC data.bin 20000000 8c f6 8a 4a 83 74 83 89 83 4f 30000012 4 5$ file data.bin 6data.bin: DOS executable (COM, 0x8C-variant) 7 8$ file -i data.bin 9data.bin: application/x-dosexec; charset=unknown-8bit 10
質問者さんご提示のものとほぼ同じですね。file
コマンドは各ファイルタイプをmagicデータとして持っています。使っているfile
コマンドはGNU版のものなので、file
コマンドのソースファイル、そのうちのこのmagicファイルのデータを覗いてみます。
file/magic/Magdir/msdos - github
このファイル中に以下のデータ行があります。これがfile
コマンドでのファイルタイプ判定に使われ、当該メッセージのもとなっている部分です。ファイルの先頭(オフセット0)が0x8c
であり、続いて決められたバイト数がそれらしき値であれば「DOS executable (COM, 0x8C-variant)」と判断します。ただ、それも100%確実なものではないので、不幸にも本質問で挙げられた結果となってしまっています。抜粋したコードでも「the remaining files should be DOS *.COM executables」と、"should be..."、「の、はずだ」と少し自信無さげなコメントがあります。
PlainText
1...抜粋 2 3# start with assembler instruction MOV 40 ubyte 0x8c 5# skip "AppleWorks word processor data" like ARTICLE.1 ./apple 6>4 string !O==== 7# skip some unknown basic binaries like RocketRnger.SHR 8>>5 string !MAIN 9# skip "GPG symmetrically encrypted data" ./gnu 10# skip "PGP symmetric key encrypted data" ./pgp 11# openpgpdefs.h: fourth byte < 14 indicate cipher algorithm type 12>>>4 ubyte >13 DOS executable (COM, 0x8C-variant) 13# the remaining files should be DOS *.COM executables 14# dosshell.COM 8cc0 2ea35f07 e85211 e88a11 b80058 cd 15# hmload.COM 8cc8 8ec0 bbc02b 89dc 83c30f c1eb04 b4 16# UNDELETE.COM 8cca 2e8916 6503 b430 cd21 8b 2e0200 8b 17# BOOTFIX.COM 8cca 2e8916 9603 b430 cd21 8b 2e0200 8b 18# RAWRITE3.COM 8cca 2e8916 d602 b430 cd21 8b 2e0200 8b 19# SHARE.COM 8cca 2e8916 d602 b430 cd21 8b 2e0200 8b 20# validchr.COM 8cca 2e8916 9603 b430 cd21 8b 2e028b1e 21# devload.COM 8cca 8916ad01 b430 cd21 8b2e0200 892e 22!:mime application/x-dosexec 23!:ext com 24
magicファイルについては、以下のmanページをご覧ください。
Linux man(4) MAGIC
多くの実行ファイルは様々な情報を収めたファイルヘッダーがあり、シグネチャと称して固定値が埋め込まれていますが。この0x8c
で始まるMS-DOS COM形式の実行ファイルはヘッダーはなく、先頭からいきなり16ビットx86のマシン語で始まります。0x8c
はx86アセンブリ言語でいうMOV
命令のマシン語のひとつです。MOV
命令で始めるプログラムがほとんどなので、そのような判定方法にしている(せざるを得ない)のだと考えられます。
投稿2020/10/24 12:00
総合スコア9256
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/24 12:40
2020/10/24 14:46