LHAフォーマット

読み:エルエイチエイ・フォーマット
読み:エルエッチエー・フォーマット
外語:LHA format 英語
品詞:固有名詞

ファイルアーカイバ、LHAで使われているファイルフォーマット(コンテナーフォーマット)の俗称。

目次

フォーマットそのものの公式な仕様書は公開されていない。

但しこれは技術が非公開という意味ではなく、人的リソースの都合から、仕様書の体裁で仕様をまとめる余裕がなかったためだと考えられる。

しかしLHAはオープンソースであるため、ソースや、作られるファイル自体を元に独自に解析・研究した結果が公開されている。

ファイルの基本構造

LHAが使うコンテナーフォーマットは、LArcのものの拡張である。

基本的には各ファイルごとに、次の構造になる。

[ヘッダー1][データ1][ヘッダー2][データ2]…[ヘッダーn][データn][00h]

ヘッダーは格納ファイルに常にあるが、データは無いことがある。LHA v2.14以降で対応した-lhd-(ディレクトリ名の格納)は、データサイズ0でありデータがない。

ヘッダーの最初の1バイトは基本ヘッダーそのものの長さとなっている。ここが00hとなると、それがファイル末端であることを表わす。

ヘッダーの基本構造

ヘッダーは、次のような構造をしている。

[基本ヘッダー][拡張ヘッダー1][拡張ヘッダー2]…[拡張ヘッダーn][0000h]

LHAのヘッダー形式はLEVEL 0/1/2の三種類がある。略してH0/H1/H2のように呼ばれる。LArcおよびLHarc(LHA 1.xx)はLHAでいうLEVEL 0に対応し、LEVEL 1/2はLEVEL 0の拡張である。

拡張ヘッダーはLEVEL 1/2で対応し、LEVEL 0には存在しない。

拡張ヘッダーの最初の2バイトは拡張ヘッダーそのものの長さとなっている。ここが0000hとなると、それが拡張ヘッダー末端であることを表わし、この後に(あれば)データが続く。

「基本ヘッダー」は、ファイルの基本的な情報を記録する領域である。タイムスタンプCRCなどはここにある。

「拡張ヘッダー」は、付加的な情報を格納するために使われる。この数も任意で、複数のヘッダーを持つことも可能。

なお、WORD以上の長さを持つパラメーターは、リトルエンディアンで値が格納される。

LEVEL 0(H0)

最も古い形式の基本ヘッダーで、LArc用に作られ使われた。LHarcもこの形式で、LHAであってもDOS版の自己解凍書庫はこのヘッダー形式である。

1バイト目が基本ヘッダーの長さで、最大255なので、実際の基本ヘッダー長の最大長は257バイトということになる。

位置サイズ内容
00hBYTE基本ヘッダー長(これ自身と拡張データ長を除く)
01hBYTEヘッダーのチェックサム(02hから基本ヘッダー長分の単純和 下位8ビット)
02h5BYTE圧縮方法 ("-lh5-"などの文字列)
07hDWORD圧縮後のデータ長
0BhDWORD元のファイルサイズ
0FhWORDファイルの更新時刻 (MS-DOS形式)
11hWORDファイルの更新日付 (MS-DOS形式)
13hBYTEファイル属性 (MS-DOS形式)
14hBYTE00h=ヘッダーのレベル
15hBYTEファイル名の長さ (最大233バイト)
16hnBYTEファイル名 (最大233バイト、パスも含む)
 WORD格納ファイル(圧縮前)のCRC
 nBYTE拡張データ(無い場合もある)

ファイル名はパスも含む。パスのデリミター文字は、'\'か'/'である。ASCIIZではないので、末端にNULは無い。

ヘッダー全体の長さが最大257バイトであるため、逆算してファイル名・パス名の最大長は233バイトになる。

拡張データは通常使われないが、UNIX版LHaでは、ファイル属性、ファイル更新日時、UID/GID属性などOSに必要な情報を格納しているとされる。UNIX関係の情報は、LEVEL 1では正規の方法で格納可能になった。

LEVEL 1(H1)

LHA 2.1x〜2.5xで標準となっているもの。拡張ヘッダーが追加され、付加的な情報はそちらに回されている。

H1の基本ヘッダー

基本ヘッダーの構造は次の通りである。

位置サイズ内容
00hBYTE基本ヘッダー長
01hBYTEヘッダーのチェックサム(02hから基本ヘッダー長分の単純和 下位8ビット)
02h5BYTE圧縮方法 ("-lh5-"などの文字列)
07hDWORD圧縮後のデータ長+拡張ヘッダー長の合計
0BhDWORD元のファイルサイズ
0FhWORDファイルの更新時刻 (MS-DOS形式)
11hWORDファイルの更新日付 (MS-DOS形式)
13hBYTE20h ダミーのファイル属性 (互換用)
14hBYTE01h=ヘッダーのレベル
15hBYTEファイル名の長さ (最大230バイト、0の場合は拡張ヘッダーに格納)
16hnBYTEファイル名 (最大230バイト、パスは含まない)
 WORD格納ファイル(圧縮前)のCRC
 BYTEOS識別子 (詳細後述)
 nBYTE拡張データ(無い場合もある)

基本ヘッダー長は、LEVEL 0の時と異なり、拡張ヘッダーの終端を表わすWORDの2バイト分が含まれる。

チェックサムのロジックはLEVEL 0と同じだが、02hから基本ヘッダー長分までなので、最初の拡張ヘッダーの拡張ヘッダー長2バイトまでが計算の対象となる。

拡張ヘッダー

LEVEL 1/2共通の拡張ヘッダーの基本構造は次の通り。

位置サイズ内容
00hWORDこの拡張ヘッダー長
02hBYTEこの拡張ヘッダーの種類
03hnBYTEこの拡張ヘッダーのデータ

拡張ヘッダーの種類は、OSに非依存(00h〜3fh)か依存(40h〜7fh)かで分類されており、様々なものがある。実装は、未対応のものは読み飛ばす。

  • OS非依存情報(00h〜3fh)
    • 00h : 共通ヘッダー
    • 01h : ファイル名ヘッダー
    • 02h : ディレクトリ名ヘッダー
    • 3fh : コメントヘッダー
  • OS依存情報(40h〜7fh)
    • 40h : MS-DOS ファイル属性ヘッダー
    • 44h : ファイル名ヘッダー (UTF-16LE)
    • 45h : ディレクトリ名ヘッダー (UTF-16LE)
    • 50h : UNIX パーミッションヘッダー
    • 51h : UNIX UID/GIDヘッダー
    • 52h : UNIX グループ名ヘッダー
    • 53h : UNIX ユーザー名ヘッダー
    • 54h : UNIX 最終更新日時ヘッダー

これ以外に、実装独自拡張の拡張ヘッダーもあるらしい。

H1の拡張ヘッダー

ファイル名の長さ=0の場合、次の拡張ヘッダーにファイル名を格納する。これにより、非常に長いファイル名も格納可能になった。

位置サイズ内容
00hWORD拡張ヘッダー長 (ファイル名の長さ+3)
02hBYTE01h ファイル名ヘッダー
03hnBYTEファイル名 (シフトJIS)

ディレクトリ指定がある時のみ、次の拡張ヘッダーがある。

位置サイズ内容
00hWORD拡張ヘッダー長 (ディレクトリ名の長さ+3)
02hBYTE02h ディレクトリ名ヘッダー
03hnBYTEディレクトリ名 (シフトJIS、パスのデリミターはFFh)

MS-DOSのファイル属性が20h以外の時のみ、次の拡張ヘッダーがある。

位置サイズ内容
00hWORD拡張ヘッダー長 (ディレクトリ名の長さ+3)
02hBYTE40h MS-DOSファイル属性ヘッダー
03hWORDMS-DOSファイル属性

拡張ヘッダーがある場合は、拡張ヘッダーのCRCを格納する次の拡張ヘッダーがある。

位置サイズ内容
00hWORD拡張ヘッダー長 (0005h または 0006h)
02hBYTE00h 共通ヘッダー
03hWORDヘッダーのCRC (基本ヘッダー/拡張ヘッダー全体の)
05hBYTE付加情報 (無い場合もある)

ヘッダーのCRCは、まずCRC領域を0000hとして、基本ヘッダーの先頭から拡張ヘッダー終端を表わすWORDの0000hまでを計算する。実際に照合する場合も、ここを0000hと想定し、最後にこの領域と比較することになる。ヘッダー最後の付加情報は仕様が未確定である。

拡張ヘッダー列の終端には、次のヘッダーがある。

位置サイズ内容
00hWORD0000h

LEVEL 2(H2)

H2の基本構造

LHA 2.6x以降、UNLHA32.DLLで標準となっている形式。

タイムスタンプの格納形式が変更された他、基本ヘッダーの構造が整理されている。

ファイル名については、常に拡張ヘッダーに格納されるようになった。

H2の基本ヘッダー

基本ヘッダーの構造は次の通りである。

位置サイズ内容
00hWORDヘッダー長 (この領域からデータ部直前までの長さ)
02h5BYTE圧縮方法 ("-lh5-"などの文字列)
07hDWORD圧縮後のデータ長
0BhDWORD元のファイルサイズ
0FhDWORDファイルの更新時刻 (time_t形式)
13hBYTE20h ダミーのファイル属性 (互換用)
14hBYTE02h=ヘッダーのレベル
15hWORD格納ファイル(圧縮前)のCRC
17hBYTEOS識別子 (詳細後述)

H2の拡張ヘッダー

基本的にLEVEL 1と同じ。以下の4つは、同じなので再度の説明を略す。

  • 01h ファイル名ヘッダー
  • 02h ディレクトリ名ヘッダー
  • 40h MS-DOSファイル属性ヘッダー
  • 00h 共通ヘッダー

拡張ヘッダー列の終端には、同様に次のヘッダーがあるが、若干仕様が違う。

位置サイズ内容
00hWORD0000h
02hBYTEダミー

基本ヘッダー先頭から、終端ヘッダー末の0000hまでの長さが256の倍数の時、ダミーの1バイトを追加し、ヘッダーサイズを1バイト増やす。

これは、ヘッダー長が256の倍数になると下位1バイトが00hとなってしまい、ファイル終端と区別が付かなくなるためで、これを回避する目的がある。

LEVEL 3(H3)

UNLHA32.DLLにはLEVEL 3のヘッダーがあることが知られているが、使われていない。

基本ヘッダーの仕様が若干異なるほか、拡張ヘッダーの仕様も変更されており、拡張ヘッダー長領域がDWORDに拡張されている。

LEVEL 3では、LEVEL 2に加え、次の拡張ヘッダーが利用できる。

  • 3fh : コメントヘッダー

Unicodeファイル名

UNLHA32.DLL ver 2.39a以降で、Unicodeファイル名にも対応した。

ファイル名とディレクトリ名について、それぞれ拡張ヘッダーが用意されている。

Unicodeファイル名は、次のヘッダーに格納する。

位置サイズ内容
00hWORD拡張ヘッダー長 (ファイル名の長さ+3)
02hBYTE44h ファイル名ヘッダー (UTF-16LE)
03hnWORDファイル名 (UTF-16LE)

Unicodeディレクトリ名は、次のヘッダーに格納する。

位置サイズ内容
00hWORD拡張ヘッダー長 (ディレクトリ名の長さ+3)
02hBYTE45h ディレクトリ名ヘッダー (UTF-16LE)
03hnWORDファイル名 (UTF-16LE)

シフトJISで扱えない文字を含む場合はUnicodeファイル名として保存される。

この場合、従来のファイル名ヘッダー(01h)、ディレクトリ名ヘッダー(02h)は使用されないため、未対応のソフトウェアでは正しく扱えないアーカイブができてしまうことになる。

UNIXの拡張ヘッダー

UNIXでは、UNIXのファイル属性等を保存する必要があり、そのための拡張ヘッダーが用意されている。

UNIX用の実装LHaで使われているが、下記のうち、グループ名ヘッダーとユーザー名ヘッダーは実際には使われていない。

パーミッション情報は、次のヘッダーに格納する。

位置サイズ内容
00hWORD拡張ヘッダー長 (0005h)
02hBYTE50h UNIX パーミッションヘッダー
03hWORDパーミッション情報

UID/GID情報は、次のヘッダーに格納する。

位置サイズ内容
00hWORD拡張ヘッダー長 (0007h)
02hBYTE51h UNIX UID/GIDヘッダー
03hWORDGID
05hWORDUID

グループ名は、次のヘッダーに格納できるが、使われていない。

位置サイズ内容
00hWORD拡張ヘッダー長 (グループ名の長さ+3)
02hBYTE52h UNIX グループ名ヘッダー
03hnBYTEグループ名

ユーザー名は、次のヘッダーに格納できるが、使われていない。

位置サイズ内容
00hWORD拡張ヘッダー長 (ユーザー名の長さ+3)
02hBYTE53h UNIX ユーザー名ヘッダー
03hnBYTEユーザー名

最終更新日時は、次のヘッダーに格納する。

位置サイズ内容
00hWORD拡張ヘッダー長 (0007h)
02hBYTE54h UNIX 最終更新日時ヘッダー
03hDWORD最終更新日時 (time_t形式)

シンボリックリンク

UNIXのシンボリックリンクは、ディレクトリ名と同様、-lhd-形式で格納される。

ディレクトリ名の格納と殆ど同じだが、ディレクトリ名を格納する所に「シンボリックリンクファイル名|リンク先」という形式で文字列が格納される。

CRC

計算に使われるCRCは、一般的な16ビットのCRC-16、多項式11000000000000101(x16+x15+x2+x0)である。

OS識別子

LEVEL 1以降の基本ヘッダーにある1バイトの領域に、OSの情報を書き込むことができる。公式なものと非公式なものがあるとされる。

  • 公式なもの
    • 'M' : MS-DOS
    • 'U' : UNIX
    • 'm' : Mac OS
    • 'H' : Human68K
    • '2' : OS/2
    • 'C' : CP/M
    • '9' : OS9
    • 'K' : OS/68K
    • '3' : OS/386
    • 'F' : FLEX
    • 'R' : Runser
  • 非公式なもの
    • 'W' : Windows NT
    • 'w' : Windows 95
    • 'T' : TownsOS
    • 'X' : XOSK
    • 00h : generic

Windowsでも、OS識別子はMS-DOSの'M'がそのまま使われている。

バッファーオーバーフロー脆弱性

LHAに限ったことではないが、LHAの実装の多くにはセキュリティ面での脆弱性があり、特にバッファーオーバーフロー脆弱性を持つものが多い。

例えば、拡張ヘッダーID 0x01(ファイル名)や0x02(パス名)に長い名前が格納された場合、バッファーオーバーフローが発生する実装がある。

それだけではなく、ヘッダー処理自体でバッファーオーバーフローを発生させる恐れもある。

LHAの基本ヘッダーは最大でも257バイトであり、これ以上に伸びることはない。一方で拡張ヘッダーは理論上64Kiバイト程度まで存在できる(H2の場合)ものの、多くの実装(純正版LHA含む)では4Kiバイト程度しかバッファを確保していない。

通常の用途で拡張ヘッダーが4Kiバイトを超えることは無いが、悪意を持ってヘッダーを細工し、巨大な拡張ヘッダーを作ることは可能で、このためバッファーオーバーフローを誘発させることが可能となる。

UNLHA32.DLL

こういった悪意あるLZHファイルは、殆どのウイルス対策ソフトでは検疫できない。LHAフォーマットに充分に対応していないからである。

UNLHA32.DLLの作者Miccoによると、脆弱性情報の公開については、ZIPCAB7-Zipでは進んでいるが、LHAでは後れをとっており更に今後も望むことができない、とする。このため、安全のためにLZH書庫は(特に企業では)利用を自粛し、ゲートウェイ形式で検疫をしている場合はLZH書庫自体の拒絶をするべきとした注意喚起を2010(平成22)年6月5日に発表した。

また、UNLHA32.DLLは、UNARJ32.DLL、LHMeltと共に開発を中止するとしている。

関連するリンク
.LZH ファイル構造・ヘッダ構造 解説
用語の所属
LHA
関連する用語
コンテナーフォーマット

コメントなどを投稿するフォームは、日本語対応時のみ表示されます


KisoDic通信用語の基礎知識検索システム WDIC Explorer Version 7.04a (27-May-2022)
Search System : Copyright © Mirai corporation
Dictionary : Copyright © WDIC Creators club