macOS Universal binaries & Mach-O Format
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Mac OSのバイナリは通常、ユニバーサルバイナリとしてコンパイルされます。ユニバーサルバイナリは同じファイル内で複数のアーキテクチャをサポートできます。
これらのバイナリはMach-O構造に従い、基本的には以下で構成されています:
ヘッダー
ロードコマンド
データ
ファイルを検索するには: mdfind fat.h | grep -i mach-o | grep -E "fat.h$"
ヘッダーにはマジックバイトがあり、その後にファイルが含むアーキテクチャの数(nfat_arch
)が続き、各アーキテクチャにはfat_arch
構造体があります。
次のコマンドで確認できます:
または、Mach-O Viewツールを使用して:
おそらく考えているように、通常、2つのアーキテクチャ用にコンパイルされたユニバーサルバイナリは、1つのアーキテクチャ用にコンパイルされたもののサイズを2倍にします。
ヘッダーには、Mach-Oファイルとして識別するためのマジックバイトや、ターゲットアーキテクチャに関する情報など、ファイルに関する基本情報が含まれています。これを見つけるには: mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
さまざまなファイルタイプがあり、ソースコードの例はこちらで定義されています。最も重要なものは次のとおりです:
MH_OBJECT
: 再配置可能オブジェクトファイル(コンパイルの中間生成物、まだ実行可能ではない)。
MH_EXECUTE
: 実行可能ファイル。
MH_FVMLIB
: 固定VMライブラリファイル。
MH_CORE
: コードダンプ
MH_PRELOAD
: プリロードされた実行可能ファイル(XNUではもはやサポートされていない)
MH_DYLIB
: 動的ライブラリ
MH_DYLINKER
: 動的リンカー
MH_BUNDLE
: "プラグインファイル"。gccの-bundleを使用して生成され、NSBundle
またはdlopen
によって明示的にロードされる。
MH_DYSM
: 付随する.dSym
ファイル(デバッグ用のシンボルを含むファイル)。
MH_KEXT_BUNDLE
: カーネル拡張。
Or using Mach-O View:
ソースコードは、ライブラリをロードするために便利なフラグをいくつか定義しています:
MH_NOUNDEFS
: 未定義の参照なし(完全にリンク済み)
MH_DYLDLINK
: Dyld リンク
MH_PREBOUND
: 動的参照が事前にバインドされています。
MH_SPLIT_SEGS
: ファイルが r/o と r/w セグメントに分割されます。
MH_WEAK_DEFINES
: バイナリには弱い定義のシンボルがあります
MH_BINDS_TO_WEAK
: バイナリは弱いシンボルを使用します
MH_ALLOW_STACK_EXECUTION
: スタックを実行可能にします
MH_NO_REEXPORTED_DYLIBS
: ライブラリは LC_REEXPORT コマンドではありません
MH_PIE
: 位置独立実行可能ファイル
MH_HAS_TLV_DESCRIPTORS
: スレッドローカル変数を持つセクションがあります
MH_NO_HEAP_EXECUTION
: ヒープ/データページの実行はありません
MH_HAS_OBJC
: バイナリには oBject-C セクションがあります
MH_SIM_SUPPORT
: シミュレータサポート
MH_DYLIB_IN_CACHE
: 共有ライブラリキャッシュ内の dylibs/frameworks に使用されます。
メモリ内のファイルのレイアウトはここで指定されており、シンボルテーブルの位置、実行開始時のメインスレッドのコンテキスト、および必要な共有ライブラリが詳細に説明されています。動的ローダー (dyld) に対して、バイナリのメモリへのロードプロセスに関する指示が提供されます。
これは、前述の loader.h
で定義された load_command 構造体を使用します。
There are about 50 different types of load commands that the system handles differently. The most common ones are: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
, and LC_CODE_SIGNATURE
.
基本的に、このタイプのロードコマンドは、バイナリが実行されるときにデータセクションに示されたオフセットに従って、__TEXT(実行可能コード)と__DATA(プロセスのデータ)**セグメントをロードする方法を定義します。
これらのコマンドは、バイナリが実行されるときにプロセスの仮想メモリ空間にマッピングされるセグメントを定義します。
__TEXTセグメントのように、プログラムの実行可能コードを保持する異なるタイプのセグメントがあり、プロセスによって使用されるデータを含む**__DATAセグメントがあります。これらのセグメントはMach-Oファイルのデータセクションに位置しています**。
各セグメントはさらに複数のセクションに分割できます。ロードコマンド構造は、各セグメント内のこれらのセクションに関する情報を含んでいます。
ヘッダーの最初にはセグメントヘッダーがあります:
セグメントヘッダーの例:
このヘッダーは、その後に表示されるセクションヘッダーの数を定義します:
Example of section header:
もしセクションオフセット (0x37DC) + アーキテクチャが始まるオフセットを加えると、この場合 0x18000
--> 0x37DC + 0x18000 = 0x1B7DC
コマンドラインからヘッダー情報を取得することも可能です:
Common segments loaded by this cmd:
__PAGEZERO
: カーネルにアドレスゼロをマップするよう指示し、読み取り、書き込み、実行できないようにします。構造体内のmaxprotおよびminprot変数は、このページに読み取り・書き込み・実行権限がないことを示すためにゼロに設定されます。
この割り当ては、NULLポインタデリファレンスの脆弱性を軽減するために重要です。これは、XNUがハードページゼロを強制し、メモリの最初のページ(最初のページのみ)がアクセス不可であることを保証するためです(i386を除く)。バイナリは、最初の4kをカバーする小さな__PAGEZEROを作成し、残りの32ビットメモリをユーザーモードとカーネルモードの両方でアクセス可能にすることで、この要件を満たすことができます。
__TEXT
: 実行可能なコードを含み、読み取りおよび実行権限(書き込み不可)があります。 このセグメントの一般的なセクション:
__text
: コンパイルされたバイナリコード
__const
: 定数データ(読み取り専用)
__[c/u/os_log]string
: C、Unicodeまたはosログの文字列定数
__stubs
および__stubs_helper
: 動的ライブラリの読み込みプロセスに関与します
__unwind_info
: スタックのアンワインドデータ。
これらのすべてのコンテンツは署名されていますが、実行可能としてもマークされています(文字列専用セクションのように、この特権を必ずしも必要としないセクションの悪用の選択肢を増やします)。
__DATA
: 読み取り可能および書き込み可能なデータを含みます(実行不可)。
__got:
グローバルオフセットテーブル
__nl_symbol_ptr
: 非遅延(ロード時にバインド)シンボルポインタ
__la_symbol_ptr
: 遅延(使用時にバインド)シンボルポインタ
__const
: 読み取り専用データであるべき(実際にはそうではない)
__cfstring
: CoreFoundation文字列
__data
: グローバル変数(初期化済み)
__bss
: 静的変数(未初期化)
__objc_*
(__objc_classlist, __objc_protolist, など): Objective-Cランタイムによって使用される情報
__DATA_CONST
: __DATA.__constは定数であることが保証されていません(書き込み権限)、他のポインタやGOTも同様です。このセクションは、__const
、いくつかの初期化子、およびGOTテーブル(解決後)を読み取り専用にします。
__LINKEDIT
: リンカー(dyld)用の情報を含み、シンボル、文字列、および再配置テーブルのエントリなどがあります。これは、__TEXT
または__DATA
に含まれないコンテンツのための一般的なコンテナであり、その内容は他のロードコマンドで説明されています。
dyld情報: リベース、非遅延/遅延/弱バインディングオペコードおよびエクスポート情報
関数開始: 関数の開始アドレスのテーブル
コード内のデータ: __text内のデータアイランド
シンボルテーブル: バイナリ内のシンボル
間接シンボルテーブル: ポインタ/スタブシンボル
文字列テーブル
コード署名
__OBJC
: Objective-Cランタイムによって使用される情報を含みます。この情報は、__DATAセグメント内のさまざまな__objc_*セクションにも見つかる可能性があります。
__RESTRICT
: コンテンツのないセグメントで、**__restrict
**と呼ばれる単一のセクション(空)を持ち、バイナリを実行する際にDYLD環境変数を無視することを保証します。
コードで見ることができたように、セグメントはフラグもサポートしています(ただし、あまり使用されていません):
SG_HIGHVM
: コアのみ(使用されていない)
SG_FVMLIB
: 使用されていない
SG_NORELOC
: セグメントに再配置がない
SG_PROTECTED_VERSION_1
: 暗号化。Finderが__TEXT
セグメントのテキストを暗号化するために使用する例があります。
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
は、entryoff属性にエントリポイントを含みます。ロード時に、dyldは単にこの値を(メモリ内の)バイナリのベースに加算し、その後この命令にジャンプしてバイナリのコードの実行を開始します。
**LC_UNIXTHREAD
は、メインスレッドを開始する際にレジスタが持つべき値を含みます。これはすでに非推奨ですが、dyld
**はまだ使用しています。これによって設定されたレジスタの値を見ることができます:
LC_CODE_SIGNATURE
Mach-Oファイルのコード署名に関する情報を含みます。これは通常、署名バイナリを指すオフセットのみを含みます。これは通常、ファイルの非常に最後にあります。 ただし、このセクションに関する情報はこのブログ記事およびこのgistsで見つけることができます。
LC_ENCRYPTION_INFO[_64]
バイナリ暗号化のサポート。ただし、もちろん、攻撃者がプロセスを侵害することに成功した場合、彼はメモリを暗号化されていない状態でダンプすることができます。
LC_LOAD_DYLINKER
プロセスアドレス空間に共有ライブラリをマッピングする動的リンカ実行可能ファイルへのパスを含みます。値は常に/usr/lib/dyld
に設定されています。macOSでは、dylibのマッピングはユーザーモードで行われ、カーネルモードでは行われないことに注意することが重要です。
LC_IDENT
廃止されましたが、パニック時にダンプを生成するように設定されている場合、Mach-Oコアダンプが作成され、カーネルバージョンがLC_IDENT
コマンドに設定されます。
LC_UUID
ランダムUUID。XNUがプロセス情報の残りとキャッシュするため、直接的には何にでも役立ちます。クラッシュレポートで使用できます。
LC_DYLD_ENVIRONMENT
プロセスが実行される前にdyldに環境変数を示すことを許可します。これは、プロセス内で任意のコードを実行できる可能性があるため、非常に危険です。このロードコマンドは、#define SUPPORT_LC_DYLD_ENVIRONMENT
でビルドされたdyldでのみ使用され、DYLD_..._PATH
形式の変数に対してのみ処理をさらに制限します。
LC_LOAD_DYLIB
このロードコマンドは、ライブラリの動的依存関係を説明し、ローダー(dyld)に指定されたライブラリをロードおよびリンクするように指示します。Mach-Oバイナリが必要とする各ライブラリに対してLC_LOAD_DYLIB
ロードコマンドがあります。
このロードコマンドは、実際の依存動的ライブラリを説明する構造体dylibを含む**dylib_command
**型の構造体です:
この情報はCLIからも取得できます:
Some potential malware related libraries are:
DiskArbitration: USBドライブの監視
AVFoundation: 音声と映像のキャプチャ
CoreWLAN: Wifiスキャン。
Mach-Oバイナリは、LC_MAINで指定されたアドレスの前に実行されるコンストラクタを1つ以上含むことができます。 コンストラクタのオフセットは、__DATA_CONSTセグメントの**__mod_init_func**セクションに保持されています。
ファイルの中心にはデータ領域があり、これはロードコマンド領域で定義された複数のセグメントで構成されています。各セグメント内にはさまざまなデータセクションが格納される可能性があり、各セクションは特定のタイプに関連するコードまたはデータを保持しています。
データは基本的に、ロードコマンドLC_SEGMENTS_64によってロードされるすべての情報を含む部分です。
これには以下が含まれます:
関数テーブル: プログラム関数に関する情報を保持します。
シンボルテーブル: バイナリによって使用される外部関数に関する情報を含みます
内部関数、変数名なども含まれる可能性があります。
確認するには、Mach-O Viewツールを使用できます:
またはCLIから:
__TEXT
セグメント (r-x):
__objc_classname
: クラス名 (文字列)
__objc_methname
: メソッド名 (文字列)
__objc_methtype
: メソッドタイプ (文字列)
__DATA
セグメント (rw-):
__objc_classlist
: すべてのObjective-Cクラスへのポインタ
__objc_nlclslist
: 非遅延Objective-Cクラスへのポインタ
__objc_catlist
: カテゴリへのポインタ
__objc_nlcatlist
: 非遅延カテゴリへのポインタ
__objc_protolist
: プロトコルリスト
__objc_const
: 定数データ
__objc_imageinfo
, __objc_selrefs
, objc__protorefs
...
_swift_typeref
, _swift3_capture
, _swift3_assocty
, _swift3_types
, _swift3_proto
, _swift3_fieldmd
, _swift3_builtin
, _swift3_reflstr
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)