質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

4104閲覧

特定の文字列を保存したファイルをPHPのmime_content_typeで判定すると実行ファイルとして認識される問題について

mirror0770

総合スコア1

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

2グッド

3クリップ

投稿2020/10/24 01:02

問題について

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

である。

何かご存じの方がいらっしゃれば情報頂けると幸いです。

mpyw, Y.H.👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

ockeghem

総合スコア11701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mirror0770

2020/10/24 12:40

ご回答いただきありがとうございます。 私も https://github.com/file/file/blob/master/magic/Magdir/msdos のコードに行き着いたんですがなにをしているかわからなかったので 解説していただいて助かりました それにしてもこういう現象が発生すると mime_content_typeでのファイル判定を 今後使いづらいという認識になってしまいましたね…
ockeghem

2020/10/24 14:46

はい。日本での利用ケースを考えると、0x8Cから始まるデータはShift_JISテキストという場合の方が多いでしょうから、困ったものだと思います
guest

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

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mirror0770

2020/10/24 12:46 編集

ご回答いただきありがとうございます。 お二人回答頂いてどちらもほぼ同じ内容でしたので すみませんが回答時間のはやい方をベストアンサーにさせて頂きました。 16ビットx86のMOV命令がshift-jisの文字コードと被っていたんですね。 勉強させていただきありがとうございます
dodox86

2020/10/24 12:50

コメントおよびお気遣いいただきどうもありがとうございます。 いえ、ockeghemさんの方がPHPの事情に言及し、質問にも依っていて良回答だったと思います。私も勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問